-
-
Save ochafik/93bc9ea68f19e654882cbab8eab22f74 to your computer and use it in GitHub Desktop.
dom abduction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html> | |
| <head> | |
| <script> | |
| class Container { | |
| constructor(div) { | |
| this.div = div; | |
| this.content = null; | |
| } | |
| setContent(content) { | |
| if (content.parentElement != this.div) { | |
| if (content.parentElement != null) throw new Error('Content already has a parent'); | |
| this.div.appendChild(content); | |
| } | |
| this.content = content; | |
| } | |
| ensureSizeOf(e) { | |
| // TODO: import more styles from content. | |
| const p = document.createElement('div'); | |
| p.style.width = e.clientWidth + 'px'; | |
| p.style.height = e.clientHeight + 'px'; | |
| if (this.sizer != null) { | |
| this.sizer.replaceWith(p); | |
| } else { | |
| this.div.appendChild(p); | |
| } | |
| this.sizer = p; | |
| } | |
| removeSizer() { | |
| if (this.sizer == null) { | |
| return; | |
| } | |
| this.div.removeChild(this.sizer); | |
| this.sizer = null; | |
| } | |
| borrowContentOf(container) { | |
| if (container.content == null) throw new Error('Container has no content'); | |
| if (this.content == container.content) throw new Error('Already owns the other container\'s content'); | |
| if (this.content != null) throw new Error('Container already has content'); | |
| if (container.content.parentElement == this.div) throw new Error('Content is already a child'); | |
| const content = container.content; | |
| const width = content.clientWidth; | |
| const height = content.clientHeight; | |
| this.ensureSizeOf(content); | |
| setTimeout(() => { | |
| const originRect = content.getBoundingClientRect(); | |
| const destinationRect = this.sizer.getBoundingClientRect(); | |
| container.ensureSizeOf(content); | |
| container.div.removeChild(content); | |
| container.content = null; | |
| this.removeSizer(); | |
| this.setContent(content); | |
| const originScale = originRect.width / width; | |
| const destinationScale = destinationRect.width / width; | |
| content.style.position = 'relative'; | |
| content.className += ' animated'; | |
| const restoredScale = originScale / destinationScale; | |
| const deltaLeft = (originRect.left - destinationRect.left) | |
| + (originScale - 1) * width / 2 | |
| - (destinationScale - 1) * width / 2 | |
| ; | |
| const deltaTop = (originRect.top - destinationRect.top) | |
| + (originScale - 1) * height / 2 | |
| - (destinationScale - 1) * height / 2 | |
| ; | |
| content.style.left = deltaLeft / destinationScale; | |
| content.style.top = deltaTop / destinationScale; | |
| if (originScale != destinationScale) { | |
| content.style.transform = `scale(${restoredScale})`; | |
| } | |
| // if (false) | |
| setTimeout(() => { | |
| content.style.left = 0; | |
| content.style.top = 0; | |
| content.style.transform = null; | |
| }, 100); | |
| }); | |
| } | |
| } | |
| var app; | |
| class App { | |
| constructor() { | |
| this.payload = document.getElementById('payload'); | |
| this.container1 = new Container(document.getElementById('container1')); | |
| this.container1.setContent(this.payload); | |
| this.container2 = new Container(document.getElementById('container2')); | |
| setTimeout(() => app.abduct(), 1000); | |
| } | |
| abduct() { | |
| app.container2.borrowContentOf(app.container1); | |
| } | |
| release() { | |
| app.container1.borrowContentOf(app.container2); | |
| } | |
| } | |
| </script> | |
| <style> | |
| #app { | |
| position: relative; | |
| height: 100%; | |
| } | |
| .animated { | |
| -webkit-transition: .54s ease-in-out; | |
| -moz-transition: .54s ease-in-out; | |
| -o-transition: .54s ease-in-out; | |
| transition: .54s ease-in-out; | |
| } | |
| #payload { | |
| background-color: blue; | |
| width: 100px; | |
| height: 100px; | |
| } | |
| #container1 { | |
| padding: 10px; | |
| position: absolute; | |
| left: 0; | |
| background-color: #aaffaa; /* green-ish */ | |
| transform: scale(0.4); | |
| } | |
| #container2 { | |
| padding: 10px; | |
| right: 0; | |
| bottom: 0; | |
| position: absolute; | |
| background-color: #ffaaaa; /* red-ish */ | |
| width: 150px; | |
| height: 150px; | |
| /*transform: scale(2);*/ | |
| } | |
| </style> | |
| </head> | |
| <body onload="app = new App()"> | |
| <div id="app"> | |
| <button onclick="app.abduct()">Abduct</button> | |
| <button onclick="app.release()">Release</button> | |
| <div id="container1"> | |
| Container 1 | |
| <div id="payload"> | |
| </div> | |
| </div> | |
| <div id="container2"> | |
| Container 2 | |
| </div> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment