diff --git a/css/style.css b/css/style.css index e9a73a2..c1c9004 100644 --- a/css/style.css +++ b/css/style.css @@ -1,4 +1,7 @@ -* { margin: 0; padding: 0 } +* { + margin: 0; + padding: 0; +} body { overflow: hidden; @@ -16,7 +19,7 @@ iframe { /* The bed of the Machine */ .machine { - background: url('/images/Metal Panel.svg'); + background: url("/images/Metal Panel.svg"); background-repeat: repeat-x; bottom: 0; height: 4rem; @@ -29,10 +32,12 @@ iframe { label { background-color: #202123; - text-shadow: 1px -1px 0px #42464dFF, -1px 1px 0px #ffffff1A; + text-shadow: + 1px -1px 0px #42464dff, + -1px 1px 0px #ffffff1a; color: #eeeeee; display: block; - font: 0.625rem 'Arial Rounded MT Bold'; + font: 0.625rem "Arial Rounded MT Bold"; padding: 0.0625rem 0.3125rem; text-transform: uppercase; transform: rotate(-5deg); @@ -47,7 +52,7 @@ label { top: 0; .grater-bed { - background: url('/images/Grater Bed.svg'); + background: url("/images/Grater Bed.svg"); background-repeat: no-repeat; background-position: bottom; position: absolute; @@ -56,9 +61,9 @@ label { width: 8.5rem; &::before { - background: url('/images/Sausage.svg'); + background: url("/images/Sausage.svg"); background-repeat: no-repeat; - content: ' '; + content: " "; display: block; height: 3em; opacity: 0; @@ -72,7 +77,7 @@ label { } .grater-blade { - background: url('/images/Grater Blade.svg'); + background: url("/images/Grater Blade.svg"); height: 0.625rem; left: var(--graterTravel); position: absolute; @@ -88,7 +93,7 @@ label { width: 6.125rem; .stem { - background: url('/images/Lever Handle.svg'); + background: url("/images/Lever Handle.svg"); height: 3.4375rem; position: absolute; width: 3.0625rem; @@ -107,9 +112,9 @@ label { } &::before { - background: url('/images/Lever Back.svg'); + background: url("/images/Lever Back.svg"); bottom: -0.5rem; - content: ''; + content: ""; height: 1.375rem; left: 2.25rem; position: absolute; @@ -117,9 +122,9 @@ label { } &::after { - background: url('/images/Lever Front.svg'); + background: url("/images/Lever Front.svg"); bottom: -0.5rem; - content: ''; + content: ""; height: 1.0625rem; left: 2.40625rem; position: absolute; @@ -149,22 +154,22 @@ label { } .ready-to-grate { - background: url('/images/Red Unlit Light.svg'); + background: url("/images/Red Unlit Light.svg"); } .ready-to-load { - background: url('/images/Green Unlit Light.svg'); + background: url("/images/Green Unlit Light.svg"); } [data-current-state="readyToGrate"] .ready-to-grate { - background: url('/images/Red Lit Light.svg'); + background: url("/images/Red Lit Light.svg"); } [data-current-state="readyToLoad"] .ready-to-load { - background: url('/images/Green Lit Light.svg'); + background: url("/images/Green Lit Light.svg"); } /* The Link Loader Wheel and Chain Mechanism */ .chain { - background: url('/images/Chain Link.svg'); + background: url("/images/Chain Link.svg"); background-position-y: var(--chainOffset); background-repeat: repeat-y; height: 100vh; @@ -184,7 +189,7 @@ label { width: 6rem; .body { - background: url('/images/Wheel.svg'); + background: url("/images/Wheel.svg"); height: 6rem; left: 0; position: absolute; @@ -212,27 +217,28 @@ label { /* Make a Sausage */ .sausage { - background: url('/images/Sausage.svg'); + align-items: center; + background: url("/images/Sausage.svg"); background-position: top; background-repeat: no-repeat; color: #fff; - display: block; - font: 0.625rem 'Arial Rounded MT Bold'; + display: flex; + font: 0.625rem "Arial Rounded MT Bold"; height: calc(3rem - var(--grateLevel)); + justify-content: center; overflow: hidden; position: absolute; top: var(--grateLevel); left: 0; text-align: center; + text-overflow: ellipsis; text-transform: uppercase; width: 8.125rem; + white-space: nowrap; z-index: 0; - display: flex; - align-items: center; - justify-content: center; } /* Util */ .no-select { - user-select: none + user-select: none; } diff --git a/example.html b/example.html index 07901ff..7bc0f99 100644 --- a/example.html +++ b/example.html @@ -1,1791 +1,15654 @@ - - - - -Machine - Wikipedia - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Jump to content -
-
-
- -
+ +
+
+ -
+ Search + +
+ +
+ - - - + + + +
  • + +
    + 6.3 + Linkages +
    +
    - - - -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
  • +
  • + +
    + 6.4 + Planar mechanism +
    +
    + +
  • +
  • + +
    + 6.5 + Spherical mechanism +
    +
    - - + +
  • +
  • + +
    + 6.6 + Spatial mechanism +
    +
    - - - - -
    -
    -
    -
  • +
  • + +
    + 6.7 + Flexure mechanisms +
    +
    -Toggle the table of contents - -
    + +
  • + + +
  • + +
    + 7 + Machine elements +
    +
    + -
    -
    - - - + +
  • +
  • + +
    + 8 + Controllers +
    +
    -146 languages - -
    + +
  • +
  • + +
    + 9 + Computing machines +
    +
    -
    - - - -
    + +
  • +
  • + +
    + 10 + Molecular machines +
    +
    - - - -
    -
    -
    -
  • +
  • + +
    + 11 + Impact +
    +
    - -
    - - -
    + +
    -
    + +
  • + + +
  • + +
    + 12 + Mechanics +
    +
    - - -
    - - -
  • +
  • + +
    + 13 + Machine design +
    +
    - -
    -
    - Actions -
    - -
    + +
  • +
  • + +
    + 14 + See also +
    +
    -
    -
    - General -
    - -
    + +
  • +
  • + +
    + 15 + References +
    +
    -
    -
    - Print/export -
    - -
    + +
  • +
  • + +
    + 16 + Further reading +
    +
    -
    -
    - In other projects -
    - -
    + +
  • + + + + + + + +
    +
    +
    +
    - + Toggle the table of contents + +
    +
    +
    + + +

    + Machine +

    - - - - -
    -
    - - +
    +
    + -
    - -
    - -
    -
    -
    -
    Page semi-protected
    -
    +
    + +
    + + + +
    +
    +
    + -
    -
    -
    -
    -
    -
    - +
    +
    +
    +
    + -
    - - - -
    - -
    - - - + Add topic + + +
    + +
    + + + +
    + +
    + + + diff --git a/index.html b/index.html index d9620a5..4d1bbf7 100644 --- a/index.html +++ b/index.html @@ -1,23 +1,22 @@ - + - - - - + + + + Internet Machine. - - + + -
    -
    +
    diff --git a/js/machine.js b/js/machine.js index 5c3a289..647923b 100644 --- a/js/machine.js +++ b/js/machine.js @@ -5,90 +5,147 @@ const kDimensions = { sausageHeight: 48, }; const kState = { - waiting: 'waiting', - readyToGrate: 'readyToGrate', - readyToLoad: 'readyToLoad' + waiting: "waiting", + readyToGrate: "readyToGrate", + readyToLoad: "readyToLoad", }; const kAction = { - completeLoading: Symbol('completeLoading'), - startPullingLever: Symbol('startPullingLever'), - stopPullingLever: Symbol('stopPullingLever'), - pullLever: Symbol('pullLever'), - startTurningWheel: Symbol('startTurningWheel'), - stopTurningWheel: Symbol('stopTurningWheel'), - turnWheel: Symbol('turnWheel'), - setIsWaitingForFrame: Symbol('setIsWaitingForFrame'), - createSausage: Symbol('createSausage'), - completeGrating: Symbol('completeGrating'), + completeLoading: Symbol("completeLoading"), + startPullingLever: Symbol("startPullingLever"), + stopPullingLever: Symbol("stopPullingLever"), + pullLever: Symbol("pullLever"), + startTurningWheel: Symbol("startTurningWheel"), + stopTurningWheel: Symbol("stopTurningWheel"), + turnWheel: Symbol("turnWheel"), + setIsWaitingForFrame: Symbol("setIsWaitingForFrame"), + createSausage: Symbol("createSausage"), + completeGrating: Symbol("completeGrating"), }; const kRotationDirection = { - clockwise: Symbol('clockwise'), - counterClockwise: Symbol('counterClockwise'), + clockwise: Symbol("clockwise"), + counterClockwise: Symbol("counterClockwise"), }; const kPullDirection = { - right: Symbol('right'), - left: Symbol('left'), + right: Symbol("right"), + left: Symbol("left"), }; // Configuration /////////////////////////////////////////////////////////////// - const configuration = { - wheelStrength: 1, - maxLoad: 100, - leverTravel: 80.72, - graterTravel: 69, - chainSpeed: 0.5, - grateStrength: 0.01, - defaultUrl: '/example.html' - }; +const configuration = { + wheelStrength: 1, + maxLoad: 100, + leverTravel: 80.72, + graterTravel: 69, + chainSpeed: 0.5, + grateStrength: 0.01, + defaultUrl: "/example.html", +}; // App State /////////////////////////////////////////////////////////////////// - /** - * The main app state - */ - let appState = null; +/** + * The main app state + */ +let appState = null; /** - * Functions to handle side effects - */ - const middleware = [ - function disableSelect(_, action) { - if (action === kAction.startTurningWheel || action === kAction.startPullingLever) { - document.querySelector('.machine')?.classList.add('no-select'); - } - }, - function enableSelect(_, action) { - if (action === kAction.stopTurningWheel || action === kAction.stopPullingLever) { - document.querySelector('.machine')?.classList.remove('no-select'); - } - }, - function completeLoading(state, action) { - if (action === kAction.turnWheel && state.currentState === kState.readyToLoad && parseFloat(state.load) >= configuration.maxLoad) { - send(kAction.completeLoading); - } - }, - function updateIframe(state, action) { - if (action === kAction.turnWheel && state.currentState === kState.readyToLoad && parseFloat(state.load) <= configuration.maxLoad) { - state.currentIframe?.style.setProperty('--loadProgress', `${100 - state.load}vh`); - } - }, - function completeGrating(state, action) { - if (action === kAction.pullLever && state.currentState === kState.readyToGrate && parseFloat(state.grateLevel) >= kDimensions.sausageHeight) { - removeSausages(); - const $iframe = loadIframe(state.currentUrl, 0); - send(kAction.completeGrating, { iframe: $iframe }); - } - }, - function createSausageIfWaiting(state, action, data) { - if (action === kAction.createSausage && state.currentState === kState.waiting) { - createSausage(data.href, data.label); - } - }, - function log(state, action, data) { - //console.log(state.load); + * Functions to handle side effects: Creation or removal of HTML elements, + * actions that occur as a result of a change in state. + */ +const middleware = [ + /** + * Makes text unselectable while we move the lever or wheel. + */ + function disableSelect(_, action) { + if ( + action === kAction.startTurningWheel || + action === kAction.startPullingLever + ) { + document.querySelector(".machine")?.classList.add("no-select"); } - ]; + }, -const $stateContainer = document.querySelector('.machine'); + /** + * Makes text selectable when we're done moving the lever or wheel. + */ + function enableSelect(_, action) { + if ( + action === kAction.stopTurningWheel || + action === kAction.stopPullingLever + ) { + document.querySelector(".machine")?.classList.remove("no-select"); + } + }, + + /** + * Cleans up the old iFrames when we load the new one, and triggers a complete. + */ + function completeLoading(state, action) { + if ( + action === kAction.turnWheel && + state.currentState === kState.readyToLoad && + parseFloat(state.load) >= configuration.maxLoad + ) { + const iframes = $iframeContainer.querySelectorAll("iframe"); + for (const iframe of iframes) { + if (iframe !== appState.currentIframe) { + $iframeContainer.removeChild(iframe); + } + } + send(kAction.completeLoading); + } + }, + + /** + * Sets the individual load state to the current iframe. + */ + function updateIframe(state, action) { + if ( + action === kAction.turnWheel && + state.currentState === kState.readyToLoad && + parseFloat(state.load) <= configuration.maxLoad + ) { + state.currentIframe?.style.setProperty( + "--loadProgress", + `${100 - state.load}vh`, + ); + } + }, + + /** + * Cleans up the sausage and loads the iframe once the grating is complete. + */ + function completeGrating(state, action) { + if ( + action === kAction.pullLever && + state.currentState === kState.readyToGrate && + parseFloat(state.grateLevel) >= kDimensions.sausageHeight + ) { + removeSausages(); + const $iframe = loadIframe(state.currentUrl, 0); + send(kAction.completeGrating, { iframe: $iframe }); + } + }, + + /** + * Creates the sausage element if we are at the right state. + */ + function createSausageIfWaiting(state, action, data) { + if ( + action === kAction.createSausage && + state.currentState === kState.waiting + ) { + createSausage(data.href, data.label); + } + }, +]; + +/** + * We store the state as CSS variables and data attributes in an element + * declared as the $stateContainer. UI updates as a result of this. We + * try to avoid manipulating the elements with JS, except for creating and + * removing elements. + */ +const $stateContainer = document.querySelector(".machine"); const updateState = function updateState(state) { for (const [key, value] of Object.entries(state)) { $stateContainer.style.setProperty(`--${key}`, value); @@ -97,6 +154,9 @@ const updateState = function updateState(state) { appState = state; }; +/** + * We modify a copy of the state and return it. + */ const reduce = function reduce(stateReference, action, data) { let state = Object.assign({}, stateReference); @@ -105,10 +165,18 @@ const reduce = function reduce(stateReference, action, data) { state.wheelRotation = `${data.angle}rad`; if (state.currentState === kState.readyToLoad) { const sign = data.direction === kRotationDirection.clockwise ? 1 : -1; - const load = Math.max(Math.min(state.load - sign * data.magnitude * configuration.wheelStrength, configuration.maxLoad), 0); + const load = Math.max( + Math.min( + state.load - sign * data.magnitude * configuration.wheelStrength, + configuration.maxLoad, + ), + 0, + ); state.load = load; if (load < configuration.maxLoad && load > 0) { - const chainOffset = parseFloat(state.chainOffset) + sign * data.magnitude * configuration.chainSpeed; + const chainOffset = + parseFloat(state.chainOffset) + + sign * data.magnitude * configuration.chainSpeed; state.chainOffset = `${chainOffset}%`; } } @@ -116,18 +184,21 @@ const reduce = function reduce(stateReference, action, data) { case kAction.pullLever: const diff = Math.abs(state.leverTravel - data.magnitude); state.leverTravel = data.magnitude; - const rotation = data.magnitude * configuration.leverTravel / 100; - state.leverRotation = `${rotation}deg` - const gratingTravel = data.magnitude * configuration.graterTravel / 100; - state.graterTravel = `${gratingTravel}px` + const rotation = (data.magnitude * configuration.leverTravel) / 100; + state.leverRotation = `${rotation}deg`; + const gratingTravel = (data.magnitude * configuration.graterTravel) / 100; + state.graterTravel = `${gratingTravel}px`; if (state.currentState === kState.readyToGrate) { - const grateLevel = Math.min(parseFloat(state.grateLevel) + diff * configuration.grateStrength, kDimensions.sausageHeight); + const grateLevel = Math.min( + parseFloat(state.grateLevel) + diff * configuration.grateStrength, + kDimensions.sausageHeight, + ); state.grateLevel = `${grateLevel}px`; } break; case kAction.createSausage: state.currentUrl = data.href; - state.grateLevel = '0%'; + state.grateLevel = "0%"; state.currentState = kState.readyToGrate; break; case kAction.startTurningWheel: @@ -144,12 +215,13 @@ const reduce = function reduce(stateReference, action, data) { break; case kAction.completeLoading: state.currentState = kState.waiting; + state.currentIframe = null; state.load = 0; break; case kAction.completeGrating: state.currentState = kState.readyToLoad; state.currentIframe = data.iframe; - state.grateLevel = '0%'; + state.grateLevel = "0%"; state.load = 0; break; } @@ -158,132 +230,149 @@ const reduce = function reduce(stateReference, action, data) { }; /** - * The main mechanism for view changes to trigger updates. - * It receives an action and its payload. - * It queues the middleware to run after this. - */ - const send = function send(action, data) { - const state = Object.assign({}, appState); - for (const m of middleware) { - setTimeout(() => m(state, action, data), 0); - } - const newState = reduce(state, action, data); - updateState(newState); - }; + * The main mechanism for view changes to trigger updates. + * It receives an action and its payload. + * It queues the middleware to run after this. + */ +const send = function send(action, data) { + const state = Object.assign({}, appState); + for (const m of middleware) { + setTimeout(() => m(state, action, data), 0); + } + const newState = reduce(state, action, data); + updateState(newState); +}; // Initializzation ///////////////////////////////////////////////////////////// - const initialize = function initialize() { - - const state = { - currentState: kState.waiting, - isPullingLever: false, - isTurningWheel: false, - leverTravel: 0, - grateLevel: 0, - leverRotation: '0deg', - graterTravel: '0rem', - wheelRotation: '0deg', - chainOffset: '0%', - load: 0, - }; - updateState(state); - - // Reset interaction with widgets if we lift a mouse button. - document.addEventListener('mouseup', () => { - send(kAction.stopTurningWheel) - send(kAction.stopPullingLever) - }); - - // The lever handle initiates interactions with the lever. - document.querySelector('.lever .handle')?.addEventListener('mousedown', () => { - send(kAction.startPullingLever) - }); - - // The wheel handle initiates interactions with the wheel. - document.querySelector('.wheel .handle')?.addEventListener('mousedown', () => { - send(kAction.startTurningWheel) - }); - - // Rotation is calculated relatively to the whole wheel. - // And travel based no the full arc of the lever - const $wheel = document.querySelector('.wheel'); - const $lever = document.querySelector('.lever'); - document.addEventListener('mousemove', (event) => { - if (appState.isTurningWheel && !appState.waitingForFrame) { - requestAnimationFrame(() => { - const elementPosition = $wheel.getBoundingClientRect(); - const x = event.clientX - elementPosition.left; - const y = event.clientY - elementPosition.top; - const angle = angleFromCenter(x, y, kDimensions.wheelSize, kDimensions.wheelSize) - const oldAngle = parseFloat(appState.wheelRotation); - const { direction, magnitude } = rotationDirection(oldAngle, angle); - send(kAction.turnWheel, { angle, direction, magnitude }); - send(kAction.setIsWaitingForFrame, { state: false }) - }); - send(kAction.setIsWaitingForFrame, { state: true }) - } - if (appState.isPullingLever && !appState.waitingForFrame) { - requestAnimationFrame(() => { - const elementPosition = $lever.getBoundingClientRect(); - const x = event.clientX - elementPosition.left; - const magnitude = Math.max(Math.min(x * 100 / kDimensions.leverWidth, 100), 0); - const direction = magnitude >= appState.leverTravel ? kPullDirection.right : kPullDirection.left; - send(kAction.pullLever, { magnitude, direction }); - send(kAction.setIsWaitingForFrame, { state: false }) - }); - send(kAction.setIsWaitingForFrame, { state: true }) - } - }); - - // The URL Grater is the drop area. - const $grater = document.querySelector('.grater-bed'); - $grater.addEventListener('dragenter', (event) => { - event.preventDefault(); - if (appState.currentState === kState.waiting) { - $grater.classList.add('drag-over'); - } - }); - $grater.addEventListener('dragover', (event) => event.preventDefault()); - $grater.addEventListener('dragleave', (event) => { - if (!$grater.contains(event.relatedTarget)) { - $grater.classList.remove('drag-over'); - } - }); - $grater.addEventListener('drop', (event) => { - event.preventDefault(); - if (appState.currentState !== kState.waiting) { - return; - } - const href = event.dataTransfer.getData('text/uri-list'); - const label = event.dataTransfer.getData('text/plain'); - $grater.classList.remove('drag-over'); - send(kAction.createSausage, { href, label }); - }); - - const params = new URLSearchParams(window.location.search); - const urlFromQuery = params.get("url"); - const url = urlFromQuery ?? configuration.defaultUrl; - loadIframe(url, 100); +/** + * Initializes state and events. + */ +const initialize = function initialize() { + const state = { + currentState: kState.waiting, + isPullingLever: false, + isTurningWheel: false, + leverTravel: 0, + grateLevel: 0, + leverRotation: "0deg", + graterTravel: "0rem", + wheelRotation: "0deg", + chainOffset: "0%", + load: 0, }; + updateState(state); + + // Reset interaction with widgets if we lift a mouse button. + document.addEventListener("mouseup", () => { + send(kAction.stopTurningWheel); + send(kAction.stopPullingLever); + }); + + // The lever handle initiates interactions with the lever. + document + .querySelector(".lever .handle") + ?.addEventListener("mousedown", () => { + send(kAction.startPullingLever); + }); + + // The wheel handle initiates interactions with the wheel. + document + .querySelector(".wheel .handle") + ?.addEventListener("mousedown", () => { + send(kAction.startTurningWheel); + }); + + // Rotation is calculated relatively to the whole wheel. + // And travel based no the full arc of the lever + const $wheel = document.querySelector(".wheel"); + const $lever = document.querySelector(".lever"); + document.addEventListener("mousemove", (event) => { + if (appState.isTurningWheel && !appState.waitingForFrame) { + requestAnimationFrame(() => { + const elementPosition = $wheel.getBoundingClientRect(); + const x = event.clientX - elementPosition.left; + const y = event.clientY - elementPosition.top; + const angle = angleFromCenter( + x, + y, + kDimensions.wheelSize, + kDimensions.wheelSize, + ); + const oldAngle = parseFloat(appState.wheelRotation); + const { direction, magnitude } = rotationDirection(oldAngle, angle); + send(kAction.turnWheel, { angle, direction, magnitude }); + send(kAction.setIsWaitingForFrame, { state: false }); + }); + send(kAction.setIsWaitingForFrame, { state: true }); + } + if (appState.isPullingLever && !appState.waitingForFrame) { + requestAnimationFrame(() => { + const elementPosition = $lever.getBoundingClientRect(); + const x = event.clientX - elementPosition.left; + const magnitude = Math.max( + Math.min((x * 100) / kDimensions.leverWidth, 100), + 0, + ); + const direction = + magnitude >= appState.leverTravel + ? kPullDirection.right + : kPullDirection.left; + send(kAction.pullLever, { magnitude, direction }); + send(kAction.setIsWaitingForFrame, { state: false }); + }); + send(kAction.setIsWaitingForFrame, { state: true }); + } + }); + + // The URL Grater is the drop area. + const $grater = document.querySelector(".grater-bed"); + $grater.addEventListener("dragenter", (event) => { + event.preventDefault(); + if (appState.currentState === kState.waiting) { + $grater.classList.add("drag-over"); + } + }); + $grater.addEventListener("dragover", (event) => event.preventDefault()); + $grater.addEventListener("dragleave", (event) => { + if (!$grater.contains(event.relatedTarget)) { + $grater.classList.remove("drag-over"); + } + }); + $grater.addEventListener("drop", (event) => { + event.preventDefault(); + if (appState.currentState !== kState.waiting) { + return; + } + const href = event.dataTransfer.getData("text/uri-list"); + const label = event.dataTransfer.getData("text/plain"); + $grater.classList.remove("drag-over"); + send(kAction.createSausage, { href, label }); + }); + + const params = new URLSearchParams(window.location.search); + const urlFromQuery = params.get("url"); + const url = urlFromQuery ?? configuration.defaultUrl; + loadIframe(url, 100); +}; // Utility Functions /////////////////////////////////////////////////////////// - /** - * Calculates the angle of a point (x,y) relative to the center of a square - * with dimensions (w, h). The result is in radians. - */ - const angleFromCenter = function angleFromCenter(x, y, w, h) { - const centerX = w / 2; - const centerY = h / 2; - const dx = x - centerX; - const dy = y - centerY; - return Math.atan2(dy, dx); - }; +/** + * Calculates the angle of a point (x,y) relative to the center of a square + * with dimensions (w, h). The result is in radians. + */ +const angleFromCenter = function angleFromCenter(x, y, w, h) { + const centerX = w / 2; + const centerY = h / 2; + const dx = x - centerX; + const dy = y - centerY; + return Math.atan2(dy, dx); +}; - /** - * Given two angles, calculates the direction of the rotation. - */ +/** + * Given two angles, calculates the direction of the rotation. + */ const rotationDirection = function rotationDirection(angle1, angle2) { let diff = angle2 - angle1; @@ -291,46 +380,49 @@ const rotationDirection = function rotationDirection(angle1, angle2) { if (diff < -Math.PI) diff += 2 * Math.PI; const magnitude = Math.abs(diff); - const direction = diff > 0 ? kRotationDirection.counterClockwise : kRotationDirection.clockwise; + const direction = + diff > 0 + ? kRotationDirection.counterClockwise + : kRotationDirection.clockwise; return { direction, - magnitude + magnitude, }; }; - /** - * Loads an iframe and appends it into the body. - */ -const $iframeContainer = document.querySelector('.web-content'); +/** + * Loads an iframe and appends it into the body. + */ +const $iframeContainer = document.querySelector(".web-content"); const loadIframe = function loadIframe(url, loadProgress) { - const $iframe = document.createElement('iframe'); + const $iframe = document.createElement("iframe"); $iframe.src = url; - $iframe.style.setProperty('--loadProgress', `${100 - loadProgress}vh`); + $iframe.style.setProperty("--loadProgress", `${100 - loadProgress}vh`); $iframeContainer.appendChild($iframe); - $iframe.addEventListener('load', () => { + $iframe.addEventListener("load", () => { const iframeDocument = $iframe.contentDocument; - iframeDocument.querySelectorAll('a').forEach(($link) => { - $link.addEventListener('click', (event) => event.preventDefault()); + iframeDocument.querySelectorAll("a").forEach(($link) => { + $link.addEventListener("click", (event) => event.preventDefault()); $link.draggable = true; - $link.addEventListener('dragstart', (event) => { - event.dataTransfer.setData('text/uri-list', $link.href); - event.dataTransfer.setData('text/plain', $link.textContent); + $link.addEventListener("dragstart", (event) => { + event.dataTransfer.setData("text/uri-list", $link.href); + event.dataTransfer.setData("text/plain", $link.textContent.trim()); const ghost = $link.cloneNode(true); - ghost.style.background = 'url(\'/images/Sausage.svg\')'; - ghost.style.backgroundRepeat = 'no-repeat'; - ghost.style.cursor = 'grabbing'; - ghost.style.display = 'block'; - ghost.style.height = '3rem'; - ghost.style.width = '8.125rem'; - ghost.style.color = '#fff'; - ghost.style.textAlign = 'center'; - ghost.style.fontSize = '0.625rem'; - ghost.style.fontFamily = 'sans-serif'; - ghost.style.textTransform = 'uppercase'; - ghost.style.paddingTop = '1rem'; + ghost.style.background = "url('/images/Sausage.svg')"; + ghost.style.backgroundRepeat = "no-repeat"; + ghost.style.cursor = "grabbing"; + ghost.style.display = "block"; + ghost.style.height = "3rem"; + ghost.style.width = "8.125rem"; + ghost.style.color = "#fff"; + ghost.style.textAlign = "center"; + ghost.style.fontSize = "0.625rem"; + ghost.style.fontFamily = "sans-serif"; + ghost.style.textTransform = "uppercase"; + ghost.style.paddingTop = "1rem"; document.body.appendChild(ghost); event.dataTransfer.setDragImage(ghost, 10, 10); @@ -341,21 +433,27 @@ const loadIframe = function loadIframe(url, loadProgress) { return $iframe; }; +/** + * Creates a sausage link for grating. + */ const createSausage = function createSausage(href, label) { - const $sausage = document.createElement('article'); - $sausage.classList.add('sausage'); + const $sausage = document.createElement("article"); + $sausage.classList.add("sausage"); $sausage.dataset.href = href; $sausage.innerText = label; - const $graterBed = document.querySelector('.grater-bed'); + const $graterBed = document.querySelector(".grater-bed"); $graterBed?.appendChild($sausage); }; +/** + * Removes a completely grated sausage link. + */ const removeSausages = function removeSausages() { - const $graterBed = document.querySelector('.grater-bed'); - const $existingSausages = $graterBed.querySelectorAll('.sausage'); + const $graterBed = document.querySelector(".grater-bed"); + const $existingSausages = $graterBed.querySelectorAll(".sausage"); for (const $existingSausage of $existingSausages) { $graterBed?.removeChild($existingSausage); } -} +}; initialize();