<!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>
// 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 )"
const newData = Array(20)
.fill(0)
.map((_, index) => index++);
// 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);
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
}
},
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);
// 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);
<!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>
/*
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)
const elem = document.querySelector('div');
elem.addEventListener('click', (e) => {
const outsideClick = !elem.contains(e.target);
console.log(outsideClick); //returns true or fasle
});