X-Git-Url: https://git.0d.be/?p=chloro.git;a=blobdiff_plain;f=chloro%2Fphyll%2Fstatic%2Fjs%2Fchloro.js;h=6b831ac2588c7f92e10609c2a5b643512a0659a7;hp=781836f0c50aea826a670179da9340b3cdfff047;hb=1684cf04e518914a3266d7e57d48b68d6020d1b6;hpb=0bbf07b426024de46e5fb2a8c893f2422507f62a diff --git a/chloro/phyll/static/js/chloro.js b/chloro/phyll/static/js/chloro.js index 781836f..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) { @@ -31,26 +72,69 @@ } var sel = window.getSelection(); if ($(sel.anchorNode).parents('div[contenteditable]').length && sel.toString()) { - show_style_popup(sel); - } else if (style_popup) { - $(style_popup).hide(); + show_inline_style_toolbar(sel); + } else if (inline_style_toolbar) { + $(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) { $(elem).on('input', Phylly.input_event); - $(elem).on('keyup click', update_block_style_popup); + $(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; @@ -61,10 +145,53 @@ return null; } - var block_style_popup = null; + var block_style_toolbar = null; 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 @@ -91,47 +218,47 @@ range.setStart(current_anchor, 0); sel.removeAllRanges(); sel.addRange(range); - update_block_style_popup(); + update_block_style_toolbar(); } - function update_block_style_popup() { + function update_block_style_toolbar() { var sel = window.getSelection(); if (! ((sel.anchorNode instanceof Element && (sel.anchorOffset == 0 && sel.isCollapsed)) || get_active_block(sel.anchorNode))) { - if (block_style_popup) { - $(block_style_popup).hide(); + if (block_style_toolbar) { + $(block_style_toolbar).hide(); } return true; } - if (block_style_popup === null) { - block_style_popup = $('
'); + if (block_style_toolbar === null) { + block_style_toolbar = $('
'); for (const block of Phylly.BLOCKS) { var button = document.createElement('button'); button.action_block = block; button.dataset.action = block.name; button.textContent = block.name; - block_style_popup.append(button); + block_style_toolbar.append(button); } - block_style_popup.hide(); - block_style_popup.insertAfter(document.body); - block_style_popup.find('button').on('click', block_style); + block_style_toolbar.hide(); + block_style_toolbar.insertAfter(document.body); + block_style_toolbar.find('button').on('click', block_style); } - block_style_popup.css('position', 'absolute'); + block_style_toolbar.css('position', 'absolute'); var block = get_active_block(sel.anchorNode); - block_style_popup.find('button').removeClass('on'); + block_style_toolbar.find('button').removeClass('on'); if (block) { - block_style_popup.find('[data-action=' + block.name + ']').addClass('on'); - block_style_popup.addClass('selected'); + block_style_toolbar.find('[data-action=' + block.name + ']').addClass('on'); + block_style_toolbar.addClass('selected'); } else { - block_style_popup.removeClass('selected'); + block_style_toolbar.removeClass('selected'); } var anchor = get_contenteditable_subnode(sel.anchorNode); var pos = $(anchor).offset(); - block_style_popup.css('top', pos.top - 33); - block_style_popup.css('left', pos.left); - block_style_popup.show(); + block_style_toolbar.css('top', pos.top - 33); + block_style_toolbar.css('left', pos.left); + block_style_toolbar.show(); return true; } - var style_popup = null; + var inline_style_toolbar = null; function update_style() { var action = $(this).data('action'); var param = null; @@ -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]'); @@ -181,9 +322,9 @@ sel.addRange(this._range); } - function show_style_popup(sel) { - if (style_popup === null) { - style_popup = $('
' + + function show_inline_style_toolbar(sel) { + if (inline_style_toolbar === null) { + inline_style_toolbar = $('
' + '' + '' + '' + @@ -191,16 +332,16 @@ '' + '' + '
'); - style_popup.hide(); - style_popup.insertAfter($('.actions')); - style_popup.find('button').on('click', update_style); - style_popup.find('[name=link-target]').on('keypress', validate_link).on('focusout', focusout_link); + inline_style_toolbar.hide(); + inline_style_toolbar.insertAfter(document.body); + inline_style_toolbar.find('button').on('click', update_style); + inline_style_toolbar.find('[name=link-target]').on('keypress', validate_link).on('focusout', focusout_link); } - style_popup.css('position', 'absolute'); + inline_style_toolbar.css('position', 'absolute'); var pos = sel.getRangeAt(0).getClientRects()[0]; - style_popup.css('top', pos.top + window.scrollY - 33); - style_popup.css('left', pos.left + window.scrollX); - style_popup.show(); + inline_style_toolbar.css('top', pos.top + window.scrollY - 33); + inline_style_toolbar.css('left', pos.left + window.scrollX); + inline_style_toolbar.show(); }; }(window, document));