/ Gists / JavaScript

Gists - JavaScript

On gists

Resize Observer : only as many images what i need in limited container

JavaScript

ResizeObserver.html #

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>

        <style>
            .container {
                display: flex;
                width: 100%; /* This can be changed via the buttons. */
                height: 200px;
                padding: 8px;
                background: #eaeaea;
            }

            /* Image Wrappers */
            .container > div {
                height: 200px;
                min-width: 100px;
                max-width: 200px;
                flex: 1;
                background-size: cover;
                background-repeat: no-repeat;
            }

            /* The rest is just setup. */

            #app {
                display: flex;
                flex-direction: column;
                align-items: center;
                font-family: sans-serif;
                padding: 16px;
            }

            p {
                margin-top: 32px;
                text-align: center;
                color: #4c11f7;
                text-transform: uppercase;
                font-weight: 600;
                font-size: 14px;
                letter-spacing: 0.5px;
            }

            .change-size {
                display: flex;
                align-items: center;
                justify-content: center;
                flex-wrap: wrap;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div class="container"></div>

            <p>Container Size</p>
            <div class="change-size">
                <button value="100%">100%</button>
                <button value="1400px">1400px</button>
                <button value="640px">640px</button>
                <button value="200px">200px</button>
            </div>
        </div>

        <script>
            /* Attach ResizeObserver to the container. */
            const resizeObserver = new ResizeObserver(onResize);
            resizeObserver.observe(document.querySelector('.container'));

            const IMAGE_MAX_WIDTH = 200;
            const IMAGE_MIN_WIDTH = 100;

            function onResize(entries) {
                const entry = entries[0];
                const container = entry.target;
                /* Calculate how many images can fit in the container. */
                const imagesNeeded = Math.ceil(entry.contentRect.width / IMAGE_MAX_WIDTH);
                let images = container.children;

                console.log(images);

                /* Remove images as needed. */
                while (images.length > imagesNeeded) {
                    images[images.length - 1].remove();
                }
                /* Add images as needed. */
                while (images.length < imagesNeeded) {
                    let seed = Math.random().toString().replace('.', '');
                    const newImage = document.createElement('div');
                    const imageUrl = `https://picsum.photos/seed/${seed}/${IMAGE_MAX_WIDTH}`;
                    newImage.style.backgroundImage = `url(${imageUrl})`;
                    container.append(newImage);
                }
            }

            /* The rest is for the container size buttons. */
            function changeSize(e) {
                if (!e.target.value) return;
                const container = document.querySelector('.container');
                container.style.width = e.target.value;
            }

            const changeSizeButtons = document.querySelector('.change-size');
            changeSizeButtons.addEventListener('click', changeSize);
        </script>
    </body>
</html>

On gists

CSS Clamp builder (responsive fluid typography)

JavaScript CSS CSS trick

clampBuilder.js #

// https://css-tricks.com/linearly-scale-font-size-with-css-clamp-based-on-the-viewport/#for-those-who-dont-mind-that-edge-case
// https://royalfig.github.io/fluid-typography-calculator/
// https://fluid-typography.netlify.app/

function clampBuilder( minWidthPx, maxWidthPx, minFontSize, maxFontSize ) {
  const root = document.querySelector( "html" );
  const pixelsPerRem = Number( getComputedStyle( root ).fontSize.slice( 0,-2 ) );

  const minWidth = minWidthPx / pixelsPerRem;
  const maxWidth = maxWidthPx / pixelsPerRem;

  const slope = ( maxFontSize - minFontSize ) / ( maxWidth - minWidth );
  const yAxisIntersection = -minWidth * slope + minFontSize

  return `clamp( ${ minFontSize }rem, ${ yAxisIntersection }rem + ${ slope * 100 }vw, ${ maxFontSize }rem )`;
}


console.log(clampBuilder(320, 1920, 1, 3)); // "clamp( 1rem, 0.6rem + 2vw, 3rem )"

On gists

Fast fill array

JavaScript JS oneliners

fast-fill.js #

const newData = Array(20)
      .fill(0)
      .map((_, index) =>  index++);

On gists

Intersection observer (infinity scroll)

JavaScript Web Api

demo.js #

// https://levelup.gitconnected.com/what-is-intersection-observer-api-and-how-is-it-useful-1e91a14579df
// https://codepen.io/ohdylan/pen/ZExqKzx



let secondLastChild = document.querySelectorAll('.box:nth-last-child(2)')[0];
let boxes = document.querySelector('.boxes')
const mockFetchMoreBoxes = () => {
    const startIndex = parseInt(secondLastChild.textContent.replace('Test Element', '')) + 2
    for(let i = startIndex; i < startIndex + 20; i++) {
        const newBox = document.createElement('div')
        newBox.textContent = `Test Element ${i}`
        newBox.classList.add('box')
        boxes.append(newBox)
        if(i == startIndex + 18) {
            observer.unobserve(secondLastChild)
            secondLastChild = newBox
            observer.observe(secondLastChild);
        }
    }
}

let observer = new IntersectionObserver((entries) => {
    console.log(entries[0])
    const secondLastChild = entries[0]
    if(secondLastChild.isIntersecting){
        return mockFetchMoreBoxes()
    }
}, {})

observer.observe(secondLastChild);

On gists

JS Doc

JavaScript DOC Vue.js

example.js #

  data() {
    return {
      // https://medium.com/@trukrs/type-safe-javascript-with-jsdoc-7a2a63209b76
      // https://devhints.io/jsdoc
      // better suggestion ... eg:  this.overlay?. + tab

      /**
       * @type {boolean}
       */
      delaySet: false, // je nastaveny delay?

      /**
       * @type {?number}
       */
      timeout: null, // timeout delay

      /**
       * @type {number}
       */
      ttlIn: 400, // delka prodlevy najeti

      /**
       * @type {number}
       */
      ttlOut: 300, // delka prodlevy pri odjeti

      /**
       * @type {HTMLElement}
       */
      overlay: null, // HTML prvek zacileneho overlaySelector-u

      /**
       * @type {Array}
       */
      listChildren: [] // LI-cka pod zacilenym UL-kem
    }
  },

On gists

Web component

JavaScript Web components

calendar.js #

class AmbiCalendar extends HTMLElement
{
    constructor()
    {
      super();
      this.shadow = this.attachShadow({ mode: "open"});
    }

    connectedCallback()
    {
      this.render(true, []);

      fetch('/api/v1/dk_workshop_date?filters[dk_voucher_id]=' + this.getAttribute('voucherId'))
      .then((response) => {
        if (response.ok) {
          return response.json();
        } else {
          return Promise.reject(response);
        }

      }).then((data) => {
        this.render(false, data);
      }).catch(function (err) {
        // There was an error
        console.warn('Something went wrong.', err);
      });
    }

    render(loading, data)
    {
      let body = '';

      if (loading) {
        body = '<div>loading...</div>';
      } else {
        data.map((item) => {
          body += `<li>${item.date_from} - ${item.date_to}</li>`;
        });
      }

      this.shadow.innerHTML = `
        <h1>Ambi calendar</h1>
        <lu>
            ${body}
        </lu>
      `;
    }
}

customElements.define('ambi-calendar', AmbiCalendar);

On gists

JS Parallax

JavaScript

parallax.js #

// https://github.com/yablko/responzivny-web-kurz/blob/crave-game-verzia-z-kurzu/index.html

		const headerEl = document.querySelector('header')
		const logoEl = document.querySelector('.crave-logo img')
		const setTranslate = (xPos, yPos, el) => {
			el.style.transform = `translate3d(${xPos}, ${yPos}px, 0)`;
		}
		let xScrollPosition;
		let yScrollPosition;
		const scrollLoop = () => {
			xScrollPosition = window.scrollX;
			yScrollPosition = window.scrollY;
			setTranslate(0, yScrollPosition * 0.75, headerEl);
			setTranslate(0, yScrollPosition * -0.25, logoEl);
			requestAnimationFrame(scrollLoop);
		}
		window.addEventListener('DOMContentLoaded', scrollLoop, false);

On gists

Iframe autoheight

JavaScript

index.html #

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <iframe id="frame" src="long.html" width="100%" height="0" frameborder="0"></iframe>

        <script>
            let f = document.getElementById('frame');
            f.onload = () => {
                console.log('nacteno');
                console.dir(f.contentDocument.documentElement);

                var obsah = f.contentDocument || f.contentWindow.document;
                f.style.height = obsah.documentElement.scrollHeight + 'px';
            };
        </script>
    </body>
</html>

On gists

JS objects copies, shallow, deep, lodash etc ...

JavaScript

copies.js #

/*
All ways 
===========
https://code.tutsplus.com/articles/the-best-way-to-deep-copy-an-object-in-javascript--cms-39655 

*/


let a = {
	user: 'A',
	age: 99,
	hobbies: {
		sport: ['soccer', 'hockey'],
		others: ['sleeping']
	}
}

// only shallow copy
let b = {...a}

b.age = 50
b.user = 'B'
b.hobbies.sport = ['ping-pong']
b.hobbies.others = ['eating hamburgers']


// deep copy with nested
let c = JSON.parse(JSON.stringify(a));


c.age = 20
c.user = 'C'
c.hobbies.sport = ['swimming']
c.hobbies.others = ['tv & music']

console.log(a)
console.log(b)
console.log(c)

On gists

Detect outside click

JavaScript

outsideclick.js #

const elem = document.querySelector('div');
elem.addEventListener('click', (e) => {
 const outsideClick = !elem.contains(e.target);
  
 console.log(outsideClick); //returns true or fasle
});