1,282 Matching Annotations
  1. Last 7 days
  2. Sep 2023
    1. Modules do not add anything to the global (window) scope. Modules always are in strict mode. Loading the same module twice in the same file will have no effect, as modules are only executed once. Modules require a server environment.
    1. Did you know you can now use streaming promises in SvelteKit? No need to import anything - it just works out of the box

      Every property of an object returned by the load function can be a promise which itself can return an object that can have a promise as property, and so on.

      Can build a tree of promises based on data delivery priority.

    1. If a site you visit queries the Topics API, it may learn of this interest from Chrome and decide to serve you an advert about bonds or retirement funds. It also means websites can fetch your online interests straight from your browser.

      The Topics API is worst than 3rd-parties cookies, anyone can query a user ad profile:

      ```js // document.browsingTopics() returns an array of BrowsingTopic objects. const topics = await document.browsingTopics();

      // Get data for an ad creative. const response = await fetch('https://ads.example/get-creative', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(topics) });

      // Get the JSON from the response. const creative = await response.json();

      // Display the ad. (or not) ```

  3. Aug 2023
    1. ```js function createPromiseWithData() { let resolveFn;

      const promise = new Promise((resolve, reject) => { resolveFn = resolve; });

      return { promise, resolveFn }; }

      // Usage const { promise, resolveFn } = createPromiseWithData();

      // Later, when you have the data you want to pass const data = 'Future data';

      // Resolve the promise with the data resolveFn(data);

      // Use the promise promise.then((result) => { console.log('Promise resolved with:', result); }); ```

    1. Add aliases to vite.config.ts

      ```js import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import path from 'path';

      // https://vitejs.dev/config/ export default defineConfig({ resolve: { alias: { '@': path.resolve(__dirname, './src'), '@assets': path.resolve(__dirname, './src/assets'), '@components': path.resolve(__dirname, './src/components'), }, }, plugins: [react()] }) ```

      Add aliases to tsconfig.json

      ```js { "compilerOptions": { // ... your other compiler options "baseUrl": ".", "paths": { "@/": ["src/"], "@components/": ["src/components/"], "@assets/": ["src/assets/"] }, }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] } ````

      Use alias

      js import image from `@assets/image.png`

    1. A spec to optimize ad targeting (respectful of privacy, they say... 😂🤣).

      Fuck you Google with your dystopian API:

      ```js // document.browsingTopics() returns an array of BrowsingTopic objects. const topics = await document.browsingTopics();

      // Get data for an ad creative. const response = await fetch('https://ads.example/get-creative', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(topics) });

      // Get the JSON from the response. const creative = await response.json();

      // Display the ad. (or not) ```

    1. ```js // Create a portal with the wikipedia page, and embed it // (like an iframe). You can also use the <portal> tag instead. portal = document.createElement('portal'); portal.src = 'https://en.wikipedia.org/wiki/World_Wide_Web'; portal.style = '...'; document.body.appendChild(portal);

      // When the user touches the preview (embedded portal): // do fancy animation, e.g. expand … // and finish by doing the actual transition. // For the sake of simplicity, this snippet will navigate // on the onload event of the Portals element. portal.addEventListener('load', (evt) => { portal.activate(); });

      // Adding some styles with transitions const style = document.createElement('style'); style.innerHTML = portal { position:fixed; width: 100%; height: 100%; opacity: 0; box-shadow: 0 0 20px 10px #999; transform: scale(0.4); transform-origin: bottom left; bottom: 20px; left: 20px; animation-name: fade-in; animation-duration: 1s; animation-delay: 2s; animation-fill-mode: forwards; } .portal-transition { transition: transform 0.4s; } @media (prefers-reduced-motion: reduce) { .portal-transition { transition: transform 0.001s; } } .portal-reveal { transform: scale(1.0) translateX(-20px) translateY(20px); } @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }; const portal = document.createElement('portal'); // Let's navigate into the WICG Portals spec page portal.src = 'https://wicg.github.io/portals/'; // Add a class that defines the transition. Consider using // prefers-reduced-motion media query to control the animation. // https://developers.google.com/web/updates/2019/03/prefers-reduced-motion portal.classList.add('portal-transition'); portal.addEventListener('click', (evt) => { // Animate the portal once user interacts portal.classList.add('portal-reveal'); }); portal.addEventListener('transitionend', (evt) => { if (evt.propertyName == 'transform') { // Activate the portal once the transition has completed portal.activate(); } }); document.body.append(style, portal); ```

      ```js // Feature detection

      if ('HTMLPortalElement' in window) { // If this is a platform that have Portals... const portal = document.createElement('portal'); ... } ```

      js // Detect whether this page is hosted in a portal if (window.portalHost) { // Customize the UI when being embedded as a portal }

      ```js // Send message to the portal element const portal = document.querySelector('portal'); portal.postMessage({someKey: someValue}, ORIGIN);

      // Receive message via window.portalHost window.portalHost.addEventListener('message', (evt) => { const data = evt.data.someKey; // handle the event }); ```

    1. ```html

      <header>

      Movie website

      <search> <form action="./search/"> <label for="movie">Find a Movie</label> <input type="search" id="movie" name="q" /> <button type="submit">Search</button> </form> </search> </header>

      ```

      ```html <search> <label> Find and filter your query <input type="search" id="query" /> </label> <label> <input type="checkbox" id="exact-only" /> Exact matches only </label>

      <section>

      Results:

      <output id="no-results"> </output> </section>

      </search> ```

    1. ```html

      <body style="visibility: hidden;"> <script>0</script> </body> <noscript> <style>body { visibility: visible; }</style> </noscript>

      ```

  4. Jul 2023
    1. html <meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width"> ... <picture> <!-- serve WebP to Chrome and Opera --> <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w, /image/thing-800.webp 800w, /image/thing-1200.webp 1200w, /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w" type="image/webp"> <source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w, /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w, /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w" type="image/webp"> <!-- serve JPEGXR to Edge --> <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w, /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w, /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w" type="image/vnd.ms-photo"> <source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w, /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w, /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w" type="image/vnd.ms-photo"> <!-- serve JPEG to others --> <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w, /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w, /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w"> <source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w, /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w, /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w"> <!-- fallback for browsers that don't support picture --> <img src="/image/thing.jpg" width="50%"> </picture>

    1. ```js // Log the full user-agent data navigator .userAgentData.getHighEntropyValues( ["architecture", "model", "bitness", "platformVersion", "fullVersionList"]) .then(ua => { console.log(ua) });

      // output { "architecture":"x86", "bitness":"64", "brands":[ { "brand":" Not A;Brand", "version":"99" }, { "brand":"Chromium", "version":"98" }, { "brand":"Google Chrome", "version":"98" } ], "fullVersionList":[ { "brand":" Not A;Brand", "version":"99.0.0.0" }, { "brand":"Chromium", "version":"98.0.4738.0" }, { "brand":"Google Chrome", "version":"98.0.4738.0" } ], "mobile":false, "model":"", "platformVersion":"12.0.1" } ```

    1. ```html

      <script> let counter = 0; let evens = 0; $: { if (counter > 10) { break $; } if (counter % 2 === 0) { evens++; } } </script>

      <button on:click={() => (counter++)}> Increment </button>

      Counter: {counter}, evens before 10: {evens}

      ```

    1. ```js / * twitter-entities.js * This function converts a tweet with "entity" metadata * from plain text to linkified HTML. * * See the documentation here: http://dev.twitter.com/pages/tweet_entities * Basically, add ?include_entities=true to your timeline call * * Copyright 2010, Wade Simmons * Licensed under the MIT license * http://wades.im/mons * * Requires jQuery /

      function escapeHTML(text) { return $('<div/>').text(text).html() }

      function linkify_entities(tweet) { if (!(tweet.entities)) { return escapeHTML(tweet.text) }

      // This is very naive, should find a better way to parse this
      var index_map = {}
      
      $.each(tweet.entities.urls, function(i,entry) {
          index_map[entry.indices[0]] = [entry.indices[1], function(text) {return "<a href='"+escapeHTML(entry.url)+"'>"+escapeHTML(text)+"</a>"}]
      })
      
      $.each(tweet.entities.hashtags, function(i,entry) {
          index_map[entry.indices[0]] = [entry.indices[1], function(text) {return "<a href='http://twitter.com/search?q="+escape("#"+entry.text)+"'>"+escapeHTML(text)+"</a>"}]
      })
      
      $.each(tweet.entities.user_mentions, function(i,entry) {
          index_map[entry.indices[0]] = [entry.indices[1], function(text) {return "<a title='"+escapeHTML(entry.name)+"' href='http://twitter.com/"+escapeHTML(entry.screen_name)+"'>"+escapeHTML(text)+"</a>"}]
      })
      
      var result = ""
      var last_i = 0
      var i = 0
      
      // iterate through the string looking for matches in the index_map
      for (i=0; i < tweet.text.length; ++i) {
          var ind = index_map[i]
          if (ind) {
              var end = ind[0]
              var func = ind[1]
              if (i > last_i) {
                  result += escapeHTML(tweet.text.substring(last_i, i))
              }
              result += func(tweet.text.substring(i, end))
              i = end - 1
              last_i = end
          }
      }
      
      if (i > last_i) {
          result += escapeHTML(tweet.text.substring(last_i, i))
      }
      
      return result
      

      } ```

    1. ```js if (navigator.mediaDevices) { console.log("getUserMedia supported.");

      const constraints = { audio: true }; let chunks = [];

      navigator.mediaDevices .getUserMedia(constraints) .then((stream) => { const mediaRecorder = new MediaRecorder(stream);

        visualize(stream);
      
        record.onclick = () => {
          mediaRecorder.start();
          console.log(mediaRecorder.state);
          console.log("recorder started");
          record.style.background = "red";
          record.style.color = "black";
        };
      
        stop.onclick = () => {
          mediaRecorder.stop();
          console.log(mediaRecorder.state);
          console.log("recorder stopped");
          record.style.background = "";
          record.style.color = "";
        };
      
        mediaRecorder.onstop = (e) => {
          console.log("data available after MediaRecorder.stop() called.");
      
          const clipName = prompt("Enter a name for your sound clip");
      
          const clipContainer = document.createElement("article");
          const clipLabel = document.createElement("p");
          const audio = document.createElement("audio");
          const deleteButton = document.createElement("button");
      
          clipContainer.classList.add("clip");
          audio.setAttribute("controls", "");
          deleteButton.textContent = "Delete";
          clipLabel.textContent = clipName;
      
          clipContainer.appendChild(audio);
          clipContainer.appendChild(clipLabel);
          clipContainer.appendChild(deleteButton);
          soundClips.appendChild(clipContainer);
      
          audio.controls = true;
          const blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
          chunks = [];
          const audioURL = URL.createObjectURL(blob);
          audio.src = audioURL;
          console.log("recorder stopped");
      
          deleteButton.onclick = (e) => {
            const evtTgt = e.target;
            evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
          };
        };
      
        mediaRecorder.ondataavailable = (e) => {
          chunks.push(e.data);
        };
      })
      .catch((err) => {
        console.error(`The following error occurred: ${err}`);
      });
      

      } ```

    1. ```js const canvas = document.querySelector("canvas");

      // Optional frames per second argument. const stream = canvas.captureStream(25); const recordedChunks = [];

      console.log(stream); const options = { mimeType: "video/webm; codecs=vp9" }; const mediaRecorder = new MediaRecorder(stream, options);

      mediaRecorder.ondataavailable = handleDataAvailable; mediaRecorder.start();

      function handleDataAvailable(event) { console.log("data-available"); if (event.data.size > 0) { recordedChunks.push(event.data); console.log(recordedChunks); download(); } else { // … } } function download() { const blob = new Blob(recordedChunks, { type: "video/webm", }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); document.body.appendChild(a); a.style = "display: none"; a.href = url; a.download = "test.webm"; a.click(); window.URL.revokeObjectURL(url); }

      // demo: to download after 9sec setTimeout((event) => { console.log("stopping"); mediaRecorder.stop(); }, 9000); ```

    1. A labeled statement is any statement that is prefixed with an identifier. You can jump to this label using a break or continue statement nested within the labeled statement
      Using a labeled continue with for loops

      ``js // The first for statement is labeled "loop1" loop1: for (let i = 0; i < 3; i++) { // The second for statement is labeled "loop2" loop2: for (let j = 0; j < 3; j++) { if (i === 1 && j === 1) { continue loop1; } console.log(i = ${i}, j = ${j}`); } }

      // Logs: // i = 0, j = 0 // i = 0, j = 1 // i = 0, j = 2 // i = 1, j = 0 // i = 2, j = 0 // i = 2, j = 1 // i = 2, j = 2 ```

      Using a labeled break with for loops

      ```js let i, j;

      // The first for statement is labeled "loop1" loop1: for (i = 0; i < 3; i++) { // The second for statement is labeled "loop2" loop2: for (j = 0; j < 3; j++) { if (i === 1 && j === 1) { break loop1; } console.log(i = ${i}, j = ${j}); } }

      // Logs: // i = 0, j = 0 // i = 0, j = 1 // i = 0, j = 2 // i = 1, j = 0 ```

      Using a labeled continue statement

      ```js // Numbers from 1 to 100 const items = Array.from({ length: 100 }, (_, i) => i + 1)); const tests = [ { pass: (item) => item % 2 === 0 }, { pass: (item) => item % 3 === 0 }, { pass: (item) => item % 5 === 0 }, ]; let itemsPassed = 0;

      itemIteration: for (const item of items) { for (const test of tests) { if (!test.pass(item)) { continue itemIteration; } }

      itemsPassed++; } js // Numbers from 1 to 100 const items = Array.from({ length: 100 }, (_, i) => i + 1)); const tests = [ { pass: (item) => item % 2 === 0 }, { pass: (item) => item % 3 === 0 }, { pass: (item) => item % 5 === 0 }, ]; let itemsPassed = 0;

      for (const item of items) { let passed = true; for (const test of tests) { if (!test.pass(item)) { passed = false; break; } } if (passed) { itemsPassed++; } } ```

      Using a labeled break statement

      ```js // Numbers from 1 to 100 const items = Array.from({ length: 100 }, (_, i) => i + 1)); const tests = [ { pass: (item) => item % 2 === 0 }, { pass: (item) => item % 3 === 0 }, { pass: (item) => item % 5 === 0 }, ]; let allPass = true;

      itemIteration: for (const item of items) { for (const test of tests) { if (!test.pass(item)) { allPass = false; break itemIteration; } } } ```

      Using a labeled block with break

      ```js foo: { console.log("face"); break foo; console.log("this will not be executed"); } console.log("swap");

      // Logs: // "face" // "swap" ```

    1. Adds "previousslide" and "nextslide" actions to the existing Media Session API.

      This will enable developers of video conferencing websites to handle these actions from browser UI. For example, if the user puts their slides presentation into a picture-in-picture window, the browser could display buttons for navigating through slides. When the user clicks those, the website handles them through the Media Session API.

    1. ```js let slideNumber = 1;

      togglePipButton.addEventListener("click", async () => { try { if (video !== document.pictureInPictureElement) await video.requestPictureInPicture(); else await document.exitPictureInPicture(); } catch (error) { log(> Argh! ${error}); } });

      try { navigator.mediaSession.setActionHandler("previousslide", () => { log('> User clicked "Previous Slide" icon.'); if (slideNumber > 1) slideNumber--; updateSlide(); }); } catch (error) { log('Warning! The "previousslide" media session action is not supported.'); }

      try { navigator.mediaSession.setActionHandler("nextslide", () => { log('> User clicked "Next Slide" icon.'); slideNumber++; updateSlide(); }); } catch (error) { log('Warning! The "nextslide" media session action is not supported.'); }

      / Picture-in-Picture canvas /

      const canvas = document.querySelector("canvas"); canvas.width = 1024; canvas.height = 512; updateSlide();

      const video = document.createElement("video"); video.srcObject = canvas.captureStream(); video.muted = true; video.play();

      / Utils /

      function updateSlide() { const ctx = canvas.getContext("2d"); ctx.fillStyle = "grey"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "white"; ctx.font = "100px Google Sans,arial,sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(slide ${slideNumber}, canvas.width / 2, canvas.height / 2, canvas.width); } ```