Webtechnologien Wintersemester 2024

 

JavaScript & HTML

<!-- Ja -->
<script src="script.js"></script>

<!-- Nein -->
<script type="text/javascript" language="JavaScript" src="script.js"></script>

<!-- HTML5 -->
<script src="script.js" async defer></script>

<!-- Inline -->
<script>
   console.log('hallo');
</script>

<noscript> ... Normaler HTML-Code ... </noscript>
  • leeres Tag!
  • async: kein doc.write, Reihenfolge egal
  • defer: kein doc.write, erst wenn DOM ready
  • language: schlecht, kein Standard
  • type: nicht nötig
  • async on Wikipedia: https://twitter.com/mediawiki/status/630865572654264320

APIs

  • JS im Browser bedeutet vor allem: Zugriff auf Browser-APIs
  • Kategorien
    • Manipulation von Dokumenten
    • Speichern von Daten
    • Zugriff auf Betriebssystem (Dateien) oder Hardware (Sensoren, Aktoren)
    • Netzwerk
    • Audio / Video / Grafik
  • JS im Browser bedeutet vor allem: Zugriff auf Browser-APIs
  • JS wird in Sandbox ausgeführt und Entwickler bekommen nie Zugriff auf das System, das heißt, es muss für alles eine API bereitgestellt werden
    • API = vereinfachter / abtrahierter Zugriff auf System / Ressourcen / Sensoren etc
    • Wie Steckdose: direkt am Strom arbeiten wäre arbeitsintensiv und gefährlich
    • gut: einfach; schlecht: nicht real
  • die wohl wichtigste API ist die DOM-API
  • Storage: Cookies, WebStorage, IndexedDB, ehemals WebSQL
  • OS: File System, Clipboard
  • Hardware: Geolocation, Battery, Vibration
  • Netzwerk: Fetch, WebSockets, WebRTC
  • Audio/Video/Grafic: Web Audio, getUserMedia, Canvas

Document Object Model (DOM)

  • DOM ist eine API, die eine WebSite für JavaScript zugänglich macht
  • DOM erzeugt eine hierarchische Darstellung des Dokuments in Form einer Baumstruktur
  • Dieser Baum (DOM Tree) enthält Nodes
  • Nodes haben verschiedene Typen, bspw. Element oder Text und bieten Funktionen für Zugriff, Traversierung und Manipulation
  • DOM und JavaScript werden häufig fälschlicher Weise als eins gesehen, da JS lange Zeit quasi nur im Browser lief
  • Node bietet Zugriff auf Attribute und Kinder

DOM-Zugriff

  • Zugriff auf alles über globales Objekt window
window 
   .location
      .reload()
   .history
      .back()
      .forward()
      .replaceState({}, "/", "/hehe")
   .alert("Et boum!")
   .confirm("Seite wirklich verlassen?")
   .prompt("Wie ist Ihr Name?", "Alice")
   .open("https://google.de", "Suche")
  • jede Eigenschaft von window auch direkt verfügbar

Dokument

document
   .head / .body
   .contentEditable = true
   .links[0].href
   .cookie
   .createElement()
   .get*
   .querySelector*
  • Zugriff auf das eigentliche Dokument über document
  • querySelector gibt erste gefundene Node zurück

Nodes

Node.nodeValue
Node.getAttribute
Node.childNodes // direkte Kinder
Node.lastChild / Node.firstChild
Node.parentNode
Node.nextSibling / Node.previousSibling
  • Node-Objekt ist zentrales Objekt des DOM. (Nicht nur in HTML, sondern auch XML)

Events

onfocus // Feld fokusiert
onblur // Feld verlassen
onchange // Feld geändert
onclick // angeklickt
ondblclick // doppelt angeklickt
onkeydown // Taste gedrückt
onkeypress // Taste gehalten
onkeyup // Taste losgelassen
onmousedown // Maustaste gedrückte
onmouseup //  Maustaste losgelassen
onmousemove // Maus bewegt
onmouseover // Elements überfahren
onmouseout // Elements verlassen
onreset // Formular zurückgesetzt
onresize // Größe des Fensters geändert
onselect // Text selektiert
onsubmit // Formulars abgeschickt
onload // Datei geladen
onerror // im Fehlerfall
onunload // beim Verlassen der Seite

Alle: developer.mozilla.org/…/Reference/Events

  • DOM-Nodes können auch auf Events lauschen und reagieren
  • Beispiel: zufälliges Element inspizieren und per monitorEvents($0) in der Console überwachen

Events

Eventflow

Quelle: w3.org/TR/DOM-Level-3-Events

Events

<!-- automatisch gewrappt -->
<button onClick="this.innerText = 'Nacht'">Tag</button>

<a href="javascript:alert(document.lastModified)">Letztes Update</a>

Events

// ein Listener
element.onclick = function () { this.innerText = 'Nacht'; }

// mehrere Listener
element.addEventListener('click', function (event) {
   this.innerText = 'Nacht';
   event.stopPropagation(); // stop bubbling up
   event.preventDefault(); // bubble but prevent default action
});
  • direkt auf property binden, dann aber nur ein listener
  • mehrere listener über addEventListener, entfernen über removeEventListener
  • event.preventDefault -> z.B. wenn Form in JS behandelt wird, aber ohne JS an Server geschickt werden soll (graceful degradation)

Forms

const input = document.querySelector('input');
if (input.value === 'alter Wert')
   input.value = 'neuer Wert';
else if (input.value === 'anderer Wert')
   input.disabled = true;

URL Search Params

  • Hilfsmethoden um mit dem Query-String einer URL zu arbeiten

hallo.html?vorname=Alice&alter=42

const query = new URLSearchParams(window.location.search);
const vorname = query.get('vorname');
const alter = query.get('alter');

Custom Input Elemente

HTML Formular-Elemente:

  • button
  • input
  • textarea
  • select
  • Checkboxen
  • Radio-Buttons

selber zu entwickeln:

  • Comboboxen / Auto-Complete
  • Tags / Mentions
  • Ratings (z.B. Sterne)
  • Switch (iOS Checkbox)
  • Tri-State-Checkbox
  • Date Picker für Zeiträume
  • Datei-Upload mit Vorschau
  • Standardelemente mit speziellem Styling
  • Tri-State / indeterminate: {an, aus, unentschieden} / {an, aus, teilweise}

DOM Storage

  • sessionStorage und localStorage
  • clientseitiger Speicher – meist 5MB (Achtung: UTF-16)
  • als bessere Cookies gedacht
  • gut für z.B. App-State oder Tokens
  • (ermöglicht auch Inter-Tab-Kommunikation)
localStorage.setItem('username', 'Alice');
const username = localStorage.getItem('username');
alert(`Willkommen zurück ${username}`);
  • Cookies, AppCache, WebStorage, IndexedDB, WebSQL, FileAPI

WebStorage

  • Einzigartig für protokoll://domain:port
  • SuperCookie, synchron, ordentliche API statt Geparse, toll als Input-Cache
  • Immer String, immer UTF-16
  • setItem(), getItem(), key(n), removeItem(key), length(), remaingSpace()
  • LocalStorage
  • zeitlich unbegrenzt, toll für Mails und andere Offline-Sachen, API-Cache (call = cache[url] || ajax(url);)
  • Google und Wikipedia nutzen es als JS-Cache
  • SessionStorage
  • Hält das Leben eines Tabs lang (nicht des Besuchs!)

IndexedDB

  • Object-Store, Key-Value, key meist Zahl, kann aber auch anders sein, asynchron, Transaktionskontrolle (keine rcae conditions)

WebSQL

  • best beschreibender Name, seit 2010 deprecated, aber auf mobile weit verbreitet
  • IndexedDB Nachfolger, aber schlechter verbreitet
  • nicht in Firefox, weil SQL in JS hässlich
  • SQLite SQL
  • Nachteile: feste Größe, festes Schema
  • openDatabase, executeSQL
  • Browser fragen bei Größen von 5, 10, 50, 100, 500MB
  • SQL-Injection

FileSystem API

  • File, FileReader, Filesystem & FileWriter
  • experimentell, sandboxed

Geolocation API

<pre></pre>
canvas { width: 100%; }
var out = document.querySelector('pre');
var success = function (position) {
  var msg = 'latitude: ' + position.coords.latitude + ', longitude: ' + position.coords.longitude;
  out.innerHTML += msg + '<br />';
};

// navigator.geolocation.watchPosition(success);

Battery API

<pre></pre>
var battery = navigator.battery || navigator.webkitBattery || navigator.mozBattery;
var pre = document.querySelector('pre');

function log (message) { pre.innerHTML += message + '<br />'; }

function logBattery (battery) {
   log('Battery level: ' + battery.level);
   log('Battery charging: ' + battery.charging);
   log('Battery discharging time: ', battery.dischargingTime);
   battery.addEventListener('chargingchange', function() {
     log('Battery chargingchange event: ' + battery.charging);
   }, false);
}

if (navigator.getBattery) {
   navigator.getBattery().then(logBattery, function() {
      log('There was an error while getting the battery state.');
   });
}
else if (battery) { logBattery(battery); }
else { log('Shame! The Battery API is not supported on this platform.'); }

Notification API

<input type="text" value="Welt">
<button>Show notification</button>
var button = document.querySelector('button');
var input = document.querySelector('input');

var notify = function() {
  var notification = new Notification('Hallo', { body: input.value });
  notification.onclick = function() { alert('Hihi'); }
};

button.onclick = function(){
  if (Notification.permission === 'granted') notify();
  else if (Notification.permission !== 'denied') {
    Notification.requestPermission(function (permission) {
      if (permission === 'granted') notify();
    });
  }
};

getUserMedia API

<video autoplay></video>
<script>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
</script>
var video = document.querySelector('video');
var constraints = {audio: false, video: true};
var success = function (stream) {
   try {
      video.srcObject = stream;
   } catch (error) {
      video.src = window.URL.createObjectURL(stream);
   }
};

// navigator.getUserMedia(constraints, success, function() { console.log('error'); });

Canvas

<canvas></canvas>
canvas { width: 100%; }
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');

/* Male ein Rechteck */
context.fillStyle='skyblue';
context.fillRect(50, 50, 100, 100);

/* Male einen Kreis */
context.fillStyle='hotpink';
context.beginPath();
context.arc(100, 100, 30, 0, Math.PI*2, true);
context.closePath();
context.fill();