From 1684cf04e518914a3266d7e57d48b68d6020d1b6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sat, 20 Jun 2020 14:21:43 +0200 Subject: [PATCH] sync live edit js from panikdb --- chloro/phyll/static/js/chloro.js | 145 ++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/chloro/phyll/static/js/chloro.js b/chloro/phyll/static/js/chloro.js index e7b3f1d..6b831ac 100644 --- a/chloro/phyll/static/js/chloro.js +++ b/chloro/phyll/static/js/chloro.js @@ -2,17 +2,58 @@ var Phylly = { BLOCKS: [ {name: 'code', tag: 'PRE', klass: 'screen'}, - {name: 'figure', tag: 'DIV', subtag: true, klass: 'figure'}, + {name: 'figure', special: 'img', tag: 'DIV', subtag: true, klass: 'figure'}, {name: 'note', tag: 'DIV', subtag: true, klass: 'note'}, ], input_event: function(event) { - if (event.originalEvent.inputType != "insertParagraph") return true; var sel = document.getSelection(); var anchorNode = sel.anchorNode; + if (sel.anchorNode.contentEditable === 'true' && ( + sel.anchorNode.innerHTML == '
' || !sel.anchorNode.innerHTML)) { + // when everything has been removed, add back


+ var empty_p = document.createElement('P'); + empty_p.appendChild(document.createElement('BR')); + if (anchorNode.childNodes.length) { // lone
+ anchorNode.removeChild(anchorNode.childNodes[0]); + } + anchorNode.appendChild(empty_p); + var range = document.createRange(); + range.setStart(empty_p, 0); + sel.removeAllRanges(); + sel.addRange(range); + return; + } + if (event.originalEvent.inputType != "insertParagraph") return true; + if (sel.anchorNode.tagName == "DIV" && sel.anchorNode.innerHTML == "
") { + // new empty div got inserted, replace it with a

+ var empty_p = document.createElement('P'); + empty_p.appendChild(document.createElement('BR')); + var empty_div = sel.anchorNode; + empty_div.replaceWith(empty_p); + var range = document.createRange(); + range.setStart(empty_p, 0); + sel.removeAllRanges(); + sel.addRange(range); + } + if (sel.anchorNode.tagName == "LI" && sel.anchorNode.innerHTML == "
") { + // new empty li got inserted, insert a

within + var empty_p = document.createElement('P'); + empty_p.appendChild(document.createElement('BR')); + var empty_li = anchorNode; + if (empty_li.childNodes.length) { // lone
+ empty_li.removeChild(empty_li.childNodes[0]); + } + empty_li.appendChild(empty_p); + var range = document.createRange(); + range.setStart(empty_p, 0); + sel.removeAllRanges(); + sel.addRange(range); + } var prev_p = sel.anchorNode.previousSibling; if (! prev_p) return; if (prev_p.tagName != 'P') { prev_p = $(prev_p).parents('p')[0]; + if (! prev_p || prev_p.tagName != 'P') return; } var title_match = prev_p.innerText.match(/^(h[1-6]). /); if (title_match) { @@ -36,6 +77,22 @@ $(inline_style_toolbar).hide(); } }); + var $image_upload = $(''); + $image_upload.on('change', upload_image); + $image_upload.appendTo(document.body); + + $(document).on('click', 'div.figure span.empty', function() { + window.active_figure = this.parentNode; + $('#image-upload').trigger('click'); + return true; + }); + }, + + off: function() { + $('#image-upload').remove(); + if (block_style_toolbar) { block_style_toolbar.hide(); } + if (inline_style_toolbar) { inline_style_toolbar.hide(); } + $(document).off('selectionchange'); }, bind_events: function(elem) { @@ -43,14 +100,41 @@ $(elem).on('keyup click', update_block_style_toolbar); }, + unbind_events: function(elem) { + $(elem).off('input'); + $(elem).off('keyup click'); + }, + } window.Phylly = Phylly; + function upload_image() { + if ($(this).prop('files').length > 0) { + var file = $(this).prop('files')[0]; + var params = new FormData(); + params.append('image', file); + $.post({url: '/wiki/ajax/image/', processData: false, data: params, contentType: false}).success(function(data) { + var img = document.createElement('IMG'); + img.src = data.url; + if (data.orig_url) { + img.setAttribute('data-orig-url', data.orig_url); + } + $(window.active_figure).empty().append(img); + }); + } + } + function get_contenteditable_subnode(node) { if (node === null) return null; + if (node.contentEditable === 'true') return node; // but we shouldn't arrive at root if (node.parentNode.contentEditable === 'true') return node; return get_contenteditable_subnode(node.parentNode); } + function get_parent(node, type) { + if (node === null) return null; + if (node.tagName == type) return node; + return get_parent(node.parentNode, type); + } function get_active_block(node) { var main_node = get_contenteditable_subnode(node); if (main_node === null) return null; @@ -65,6 +149,49 @@ function block_style() { var sel = window.getSelection(); var current_anchor = sel.anchorNode; + if (this.action_block.special == 'img') { + action = 'insertHTML'; + param = '

'; + document.execCommand(action, false, param); + current_anchor = $('#new-p')[0]; + $(current_anchor).attr('id', null); + var range = document.createRange(); + range.setStart(current_anchor, 0); + sel.removeAllRanges(); + sel.addRange(range); + update_block_style_toolbar(); + + return; + } + if (this.action_block.special == 'list') { + if (this.classList.contains('on')) { // toggle off + var main_node = get_contenteditable_subnode(sel.anchorNode); + var li = get_parent(sel.anchorNode, 'LI'); + for (var i=li.childNodes.length; i>0; i--) { + var child = li.childNodes[i-1]; + main_node.insertAdjacentElement('afterend', child); + var range = document.createRange(); + range.setStart(child, 0); + sel.removeAllRanges(); + sel.addRange(range); + } + li.remove(); + update_block_style_toolbar(); + } else { + var current_node = sel.anchorNode; + var ul = document.createElement('UL'); + ul.className = 'list'; + var li = document.createElement('LI'); + ul.appendChild(li); + sel.anchorNode.parentNode.insertBefore(ul, current_node); + li.appendChild(current_node); + var range = document.createRange(); + range.setStart(current_node, 0); + sel.removeAllRanges(); + sel.addRange(range); + } + return; + } if (this.classList.contains('on')) { // toggle off if (this.action_block.subtag) { // unwrap @@ -139,6 +266,20 @@ action = 'insertHTML'; param = $('', {text: window.getSelection().toString()})[0].outerHTML; } + if (action == 'wiki') { + action = 'insertHTML'; + var text = window.getSelection().toString(); + var $new_link = $('', {text: text, href: '#tbd'}); + var request_id = Math.floor(Math.random() * 10000); + $new_link.attr('data-request-id', request_id); + var params = {}; + params.title = text; + params.request_id = request_id; + $.post('/wiki/ajax/newpage/', params).success(function(data) { + $('a[data-request-id=' + data.request_id + ']').attr('href', data.url).removeAttr('data-request-id'); + }); + param = $new_link[0].outerHTML; + } if (action == 'createLink') { var sel = window.getSelection(); var $input = $('input[name=link-target]'); -- 2.39.2