Created
March 17, 2021 14:53
-
-
Save Lucassifoni/e77122b5ce61b3624ab79ff0114351da to your computer and use it in GitHub Desktop.
HTML Juggler
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
| <h2><%= @page.post_title |> Phoenix.HTML.raw %></h2> | |
| <div class="workspace"> | |
| <div class="content_old" style="flex: 0 0 50%; background: #ccc; padding: 1em;"> | |
| <%= @page.post_content |> Phoenix.HTML.raw %> | |
| </div> | |
| <div class="content_highlighter" style="flex: 0 0 50%; background: #f8f8f8; padding: 1em;"> | |
| <%= @page.post_content |> Phoenix.HTML.raw %> | |
| </div> | |
| </div> | |
| <div class="keyboard_shortcuts"> | |
| <ul> | |
| <li><strong>CLIC</strong>Sélectionner</li> | |
| <li><strong>G</strong>Grouper</li> | |
| <li><strong>P</strong>Paragraphe</li> | |
| <li><strong>1</strong>Titre 1</li> | |
| <li><strong>2</strong>Titre 2</li> | |
| <li><strong>3</strong>Titre 3</li> | |
| <li><strong>X</strong>Enlever styles inline</li> | |
| <li><strong>D</strong>Enlever le noeud</li> | |
| <li><strong>U</strong>Déballer d'un niveau</li> | |
| </ul> | |
| <button class="save_button">Enregistrer</button> | |
| </div> | |
| <style> | |
| .keyboard_shortcuts { | |
| position: fixed; | |
| bottom: 2em; | |
| right: 2em; | |
| background: #efefef; | |
| box-shadow: 0 0 10px 0 black; | |
| border-radius: 3px; | |
| border: 1px solid #ddd; | |
| } | |
| main.container { | |
| max-width: 1680px; | |
| } | |
| .keyboard_shortcuts li { | |
| list-style: none; | |
| } | |
| .keyboard_shortcuts strong { | |
| margin-right: 1em; | |
| padding: 4px; | |
| background: beige; | |
| } | |
| .content_highlighter * { | |
| border: 1px solid red; | |
| padding: 4px; | |
| } | |
| .content_old * { | |
| border: 1px solid #ddd; | |
| padding: 4px; | |
| } | |
| .content_highlighter .highlight { | |
| background: lightblue; | |
| } | |
| .content_highlighter .select { | |
| background: goldenrod; | |
| } | |
| .content_highlighter [style] { | |
| position: relative; | |
| } | |
| .content_highlighter [style]::before { | |
| content: "s"; | |
| position: absolute; | |
| border: 1px solid black; | |
| border-radius: 50%; | |
| height: 24px; | |
| width: 24px; | |
| background: green; | |
| left: -1em; | |
| line-height: 24px; | |
| font-size: 18px; | |
| } | |
| .workspace { | |
| width: 100%; | |
| display: flex; | |
| } | |
| </style> | |
| <script> | |
| let hover_target = null; | |
| let click_targets = []; | |
| const CLASSES = "highlight"; | |
| const LISTENERS = {}; | |
| let doing = 0; | |
| function lock() { | |
| doing = 1; | |
| } | |
| function unlock() { | |
| setTimeout(function() { | |
| doing = 0; | |
| }, 300); | |
| } | |
| function lockify(callback) { | |
| return function(...args) { | |
| if (doing) return; | |
| lock(); | |
| console.log("Executing callback"); | |
| callback(...args); | |
| unlock(); | |
| }; | |
| }; | |
| function emit(event, payload = null) { | |
| (LISTENERS[event] || []).forEach(function(callback) { | |
| try { | |
| callback(payload); | |
| } catch(e) { | |
| console.log(e); | |
| console.error("Failed to execute " +event+ " callback for payload " + payload); | |
| } | |
| }); | |
| } | |
| function listen(event, callback) { | |
| if (LISTENERS[event]) { | |
| LISTENERS[event].push(lockify(callback)); | |
| } else { | |
| LISTENERS[event] = [lockify(callback)]; | |
| } | |
| } | |
| function clear_hover_target() { | |
| if (!hover_target) return; | |
| hover_target.classList.remove(CLASSES); | |
| hover_target = null; | |
| }; | |
| function set_hover_target(t) { | |
| hover_target = t; | |
| hover_target.classList.add(CLASSES); | |
| } | |
| function toggle_click_target(t) { | |
| const index = click_targets.indexOf(t); | |
| if (index !== -1) { | |
| click_targets.splice(index, 1); | |
| t.classList.remove('select'); | |
| } else { | |
| click_targets.push(t); | |
| t.classList.add('select'); | |
| } | |
| } | |
| document.querySelector('.content_highlighter').addEventListener('mouseover', function(e) { | |
| clear_hover_target(); | |
| set_hover_target(e.target); | |
| }); | |
| document.querySelector('.content_highlighter').addEventListener('click', function(e){ | |
| toggle_click_target(e.target); | |
| }); | |
| document.addEventListener('keyup', function(k) { | |
| const e = { | |
| 80: 'p', | |
| 97: '1', | |
| 98: '2', | |
| 99: '3', | |
| 88: 'x', | |
| 68: 'd', | |
| 85: 'u', | |
| 71: 'g', | |
| }[k.keyCode]; | |
| if (e) { | |
| emit('keyboard_' + e); | |
| } | |
| }); | |
| listen('keyboard_p', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| const p = document.createElement('p'); | |
| p.innerHTML = t.innerText; | |
| t.parentNode.insertBefore(p, t); | |
| t.parentNode.removeChild(t); | |
| }); | |
| listen('keyboard_1', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| const p = document.createElement('h1'); | |
| p.innerHTML = t.innerText; | |
| t.parentNode.insertBefore(p, t); | |
| t.parentNode.removeChild(t); | |
| }); | |
| listen('keyboard_2', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| const p = document.createElement('h2'); | |
| p.innerHTML = t.innerText; | |
| t.parentNode.insertBefore(p, t); | |
| t.parentNode.removeChild(t); | |
| }); | |
| listen('keyboard_3', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| const p = document.createElement('h3'); | |
| p.innerHTML = t.innerText; | |
| t.parentNode.insertBefore(p, t); | |
| t.parentNode.removeChild(t); | |
| }); | |
| listen('keyboard_x', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| t.removeAttribute('style'); | |
| }); | |
| listen('keyboard_d', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| t.parentNode.removeChild(t); | |
| }); | |
| listen('keyboard_u', function() { | |
| if (!hover_target) return; | |
| const t = hover_target; | |
| const childs = t.childNodes; | |
| Array.from(childs).forEach(function(child) { | |
| t.parentNode.insertBefore(child, t); | |
| }); | |
| t.parentNode.removeChild(t); | |
| }); | |
| listen('keyboard_g', function() { | |
| if (click_targets.length === 0) return; | |
| const group = document.createElement('div'); | |
| const point = click_targets[0]; | |
| point.parentNode.insertBefore(group, point); | |
| click_targets.forEach((c) => { | |
| group.appendChild(c); | |
| }); | |
| }); | |
| document.querySelector('.save_button').addEventListener('click', function() { | |
| const body = new FormData(); | |
| const method = 'PUT'; | |
| const csrfToken = document.head.querySelector("[name~=csrf-token][content]").content; | |
| const headers = new Headers({ | |
| 'x-csrf-token': csrfToken, | |
| }); | |
| body.append("post_content", document.querySelector('.content_highlighter').innerHTML); | |
| fetch(window.location.href, {method, body, headers}).then(() => { | |
| window.location.href = window.location.href + ''; | |
| }); | |
| }); | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment