Within a browser, JavaScript has a permanent access to the
windowobject, which itself points to the DOM:window.document.At loading time, two key events occur: the fact that the DOM (i.e., the HTML “tree of content”) is ready for processing and the fact that the browser window is itself ready (i.e., all resources as images, sounds, videos… are ready for processing). Typically, any
imgDOM element leads to aHTMLImageElementobject (Imageinterface in JavaScript). Accessing this DOM element strictly requires that the DOM has finished loading. However, this image cannot be processed (e.g., grayed) until the browser has not yet finished loading all resources including this image.Example Theo_is_crying.ts.zip
![]()
const Sounds: Array<string> = new Array; // Available sounds... createjs.Sound.on('fileload', (event: { id: string }) => { // This is fired for each sound that is registered... Sounds.push(event.id); }); // No need to wait for either DOM or Window loaded: createjs.Sound.registerSound("./sounds/Baby_crying.mp3", "Baby_crying_sound_ID"); // createjs.Sound.registerSound("./sounds/Baby_laughing.mp3", "Baby_laughing_sound_ID"); let my_image: HTMLImageElement | null = null; window.document.onreadystatechange = function () { // Called *TWO TIMES*: when 'interactive' and later on... when 'complete' if (window.document.readyState === 'interactive') { window.console.log("DOM just loaded..."); my_image = window.document.getElementById("my_image") as HTMLImageElement; my_image.addEventListener('mouseover', function () { if (Sounds.indexOf("Baby_crying_sound_ID") !== -1) { const sound = createjs.Sound.play("Baby_crying_sound_ID"); sound.on('complete', () => window.console.log("Baby_crying_sound_ID" + " just completed...")); } }); } else { if (window.document.readyState === 'complete') { window.console.log("Window just loaded..."); if (my_image === null) { // We missed 'interactive'... my_image = window.document.getElementById("my_image") as HTMLImageElement; my_image.addEventListener('mouseover', function () { if (Sounds.indexOf("Baby_crying_sound_ID") !== -1) { const sound = createjs.Sound.play("Baby_crying_sound_ID"); sound.on('complete', () => window.console.log("Baby_crying_sound_ID" + " just completed...")); } }); } let image = new Image(); image.onload = function () { window.console.log("Image ready for processing? " + image.width, 'x', image.height); }; image.src = my_image.src; // Image load starts... } } };
windowDOM
window.addEventListener('DOMContentLoaded', (event: Event) => { window.console.assert(window.document.readyState === 'interactive'); window.console.log("DOM just loaded..."); // Main_first_part(); // Call 'Main_first_part' program: access DOM resources... });
windowwindow.addEventListener('load', (event: Event) => { window.console.assert(window.document.readyState === 'complete'); window.console.log("Window just loaded..."); // Main_second_part(); // Call 'Main_second_part' program: access *ALL* resources... });
window(alternative)window.onload = (event: Event) => { window.console.assert(window.document.readyState === 'complete'); window.console.log("Window just loaded..."); // Main_second_part(); // Call 'Main_second_part' program: access *ALL* resources... };
The complexity of the DOM as a tree of data items requires powerful querying facilities.
Example Shopping.ts.zip
![]()
<body oncontextmenu="return false;"> <div id="Shopping"></div> <!-- The '<div>' element is a block-level element: --> <div class="info"> Shopping... </div> <p class="info" id="Query">Type '20023966'></p> </body>const div = window.document.querySelector('div'); // Get the first '<div>' element... window.alert(div!.constructor); // 'function HTMLDivElement()...' const div_info = window.document.querySelector('div.info'); // Get the first '<div>' element with class 'info'... window.alert(div_info!.constructor); // 'function HTMLDivElement()...'
The DOM embodies a tree of data items transformable by JavaScript in terms of style (CSS); Other modifications apply on content itself. Beyond, JavaScript may add or remove content items: the switch from static Web to dynamical Web.
const canvas = window.document.createElement('CANVAS') as HTMLCanvasElement; canvas.width = 600; canvas.height = 400; const image_data = canvas.getContext('2d')!.getImageData(0, 0, 600, 400); let pixel_number = 600 * 400; while (--pixel_number >= 0) image_data.data[pixel_number] = buffer[pixel_number]; // Create image content from 'buffer'... canvas.getContext('2d')!.putImageData(image_data, 0, 0); window.document.getElementById("Somewhere_in_the_DOM")!.appendChild(canvas);window.document.getElementById("Somewhere_in_the_DOM")!.insertBefore(something_to_insert, window.document.getElementById("Somewhere_in_the_DOM")!.childNodes[0]);
Example Shopping.ts.zip
![]()
const shopping = window.document.getElementById('Shopping') as HTMLDivElement; window.console.assert(shopping !== null, "'shopping === null', why?"); shopping.style.display = 'grid'; const style: CSSStyleDeclaration = shopping.style; style.gridTemplateColumns = "repeat(" + Shopping._Number_of_columns + ", 1fr)"; style.gridTemplateRows = "fit-content(" + (100 / Shopping._Number_of_rows) + "%)"; style.alignItems = 'center'; /* Value of 'align-self' for children */ style.justifyItems = 'flex-start'; /* Value of 'justify-self' for children */ for (let i = 0; i < Shopping._Number_of_columns * Shopping._Number_of_rows; i++) { let image = new Image; image.style.height = (100 / (Shopping._Number_of_rows)) + "vh"; image.setAttribute("id", "Shopping_image" + i); image.setAttribute("index", i.toString()); // Number is transformed into string! image.style.opacity = "0.5"; image.setAttribute("time-out", "0"); image.style.width = (100 / Shopping._Number_of_columns) + "vw"; image.onload = () => { shopping.appendChild(image); // Images are stored in a random way... }; image.src = './img/Franck.jpg'; }![]()
Check content
Filtering on a CSS style value is impossible in a declarative way using
querySelectororquerySelectorAll; it may be done in an algorithmic way. Beyond, while jQuery has support for, JavaScript puts forward the introduction of a class, which matches the targeted CSS value.// Caution: must wait for all 'shopping.appendChild(image);' finished: window.console.assert(shopping.childNodes.length === Shopping._Number_of_columns * Shopping._Number_of_rows); // Filtering by CSS style value is impossible... // Get all 'HTMLImageElement' objects that have a 'style' attribute: const images = shopping.querySelectorAll('img[style]'); window.console.assert(images.length === Shopping._Number_of_columns * Shopping._Number_of_rows);
Rule(s)
- In JavaScript, the notion of form is embodied by the
FormDatatype: bothXMLHttpRequestandfetchmay processFormDataobjects.- Trickier cases are the use in
FormDataobjects of file objects (FileReadertype) and media objects (Blobtype).Example Form.js.zip
![]()
![]()
<form id="my_form" name="my_form" method="post" action="https://reqres.in/api/users"> <p><label>Name: <input name="name" required></label></p> <p><label>Job: <input name="job" required></label></p> <p><label>Phone: <input type=tel name="phone" pattern="[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}"></label> <small>(format: 12-34-45-67)</small></p> <p><label>E-mail: <input type=email name="e_mail"></label></p> <fieldset> <legend>Humor</legend> <p><label><input type=radio name=good value="good"> Good</label></p> <p><label><input type=radio name=between value="between"> Not so good, not too bad</label></p> <p><label><input type=radio name=bad value="bad"> Bad</label></p> </fieldset> <p><label>Available from: <input type="date" list="my_availabilities" name="availability"></label></p> <p><label>Description: <textarea name="description"></textarea></label></p> </form> <p><button form='my_form'>Send form...</button></p>Example (
FormDatainXMLHttpRequest) Form.js.zip![]()
class ReqRes { static URL() { return 'https://reqres.in'; } static Path() { return '/api/users'; } … static Run2(name = "FranckBarbier", job = "Trainer") { const form_data = new FormData(); // Empty... form_data.append("name", name); form_data.append("job", job); const request = new XMLHttpRequest(); request.onreadystatechange = function () { if (request.readyState === XMLHttpRequest.DONE) { window.console.assert(request.status === 201); // '201' -> Created if (request.responseType === "") // An empty 'responseType' string is treated the same as "text", the default type... window.alert("'ReqRes' ('XMLHttpRequest') RUN2: " + request.responseText); if (request.responseType === "json") window.alert(Object.getOwnPropertyNames(JSON.parse(request)).join(" - ")); } }; request.open('POST', ReqRes.URL() + ReqRes.Path()); request.setRequestHeader('accept', 'application/json; charset=UTF-8'); request.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); // Mandatory to avoid CORS... request.send(form_data); } …Example (
FormDatainfetch) Form.js.zip![]()
class ReqRes { static URL() { return 'https://reqres.in'; } static Path() { return '/api/users'; } … static Run3(name = "FranckBarbier", job = "Trainer") { const my_form = window.document.getElementById('my_form'); // Not empty... const form_data = new FormData(my_form); // Default content type: 'multipart/form-data' window.console.assert(form_data.has("name") && form_data.has("job")); form_data.set("name", name); form_data.set("job", job); fetch(ReqRes.URL() + ReqRes.Path(), { body: form_data, /*new URLSearchParams("name=" + name + "&job=" + job),*/ headers: { 'accept': 'application/json; charset=UTF-8', // -> response 'content-type': /*'application/x-www-form-urlencoded; charset=UTF-8'*/'multipart/form-data; charset=UTF-8' // Mandatory to avoid CORS... }, method: 'POST' }).then(response => { window.console.assert(response.ok && response.status === 201); // '201' -> Created response.json().then(result => { // window.console.assert(result.name === name); // It fails... window.alert("'ReqRes' ('fetch') RUN3: " + JSON.stringify(result)); }); }); } …Example (Form,
submitevent) Form.js.zip![]()
window.document.onreadystatechange = function () { if (window.document.readyState === "interactive") { window.document.forms['my_form'].onsubmit = async(event) => { // Subscription... event.preventDefault(); // window.alert("You just press 'Send form...'"); const body = new URLSearchParams([...new FormData(event.target).entries()]); // <form id="my_form" name="my_form" method="post" action="https://reqres.in/api/users"> const response = await new Response(body).text(); window.alert(response); }; } };