X-Git-Url: https://git.0d.be/?p=chloro.git;a=blobdiff_plain;f=chloro%2Fphyll%2Fstatic%2Fjs%2Fchloro.js;h=10f91e252e2dddc45052a9b19324fd5cabd1d834;hp=4b0ffea80cc354a6f7df8a98ab155c2cb9445e2d;hb=HEAD;hpb=50d1936b8b4654c3a8ea0d607232b2ed670a4f15 diff --git a/chloro/phyll/static/js/chloro.js b/chloro/phyll/static/js/chloro.js index 4b0ffea..ecc6c97 100644 --- a/chloro/phyll/static/js/chloro.js +++ b/chloro/phyll/static/js/chloro.js @@ -1,32 +1,161 @@ -$(function() { - var BLOCKS = [ +// from django/contrib/admin/static/admin/js/urlify.js +var LATIN_MAP = { + 'Ã': 'A', 'Ã': 'A', 'Ã': 'A', 'Ã': 'A', 'Ã': 'A', 'à ': 'A', 'Ã': 'AE', + 'Ã': 'C', 'Ã': 'E', 'Ã': 'E', 'Ã': 'E', 'Ã': 'E', 'Ã': 'I', 'Ã': 'I', + 'Ã': 'I', 'Ã': 'I', 'Ã': 'D', 'Ã': 'N', 'Ã': 'O', 'Ã': 'O', 'Ã': 'O', + 'Ã': 'O', 'Ã': 'O', 'Å': 'O', 'Ã': 'O', 'Ã': 'U', 'Ã': 'U', 'Ã': 'U', + 'Ã': 'U', 'Å°': 'U', 'Ã': 'Y', 'Ã': 'TH', 'Ÿ': 'Y', 'Ã': 'ss', 'à ': 'a', + 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'Ã¥': 'a', 'æ': 'ae', 'ç': 'c', + 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'Ã': 'i', 'î': 'i', + 'ï': 'i', 'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', + 'ö': 'o', 'Å': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', + 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y' +}; + +function downcode(string) { + return string.toLowerCase().replace(/[^A-Za-z0-9\[\] ]/g,function(a){ return LATIN_MAP[a]||a }).replace(/[^-\w\s]/g, '').replace(/^\s+|\s+$/g, '').replace(/[-\s]+/g, '-'); +}; + +function remove_auto_anchors() { + $('article .wiki-anchor-auto').each(function(idx, anchor) { + $(anchor).parent().removeAttr('id'); + $(anchor).remove(); + }); +} + +function auto_anchors() { + $('article h2, article h3, article h4').each(function(idx, elem) { + var $elem = $(elem); + if ($elem.attr('id')) return; + if ($elem.find('.wiki-anchor').length) return; + $elem.attr('id', downcode($elem.text())); + $('¶').appendTo($elem); + }); +} + +function create_toc() { + $('#toc').remove(); + if ($('article h2').length == 0) return; + $div_toc = $('
+ 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) {
@@ -35,26 +164,194 @@ $(function() {
title.textContent = title.textContent.slice(4);
prev_p.replaceWith(title);
}
+ return true;
+ },
+
+ init: function() {
+ $(document).on('selectionchange', function(event) {
+ if ($('input[name=link-target].shown').length) {
+ return;
+ }
+ var sel = window.getSelection();
+ if ($(sel.anchorNode).parents('div[contenteditable]').length && sel.toString()) {
+ show_inline_style_toolbar(sel);
+ } else if (inline_style_toolbar) {
+ $(inline_style_toolbar).hide();
+ }
+ if ($(sel.anchorNode).is('div.figure') && $(sel.anchorNode).find('img').length) {
+ show_figure_toolbar(sel);
+ } else if ($(sel.anchorNode).parents('.figure-toolbar').length == 0) {
+ $(figure_toolbar).hide();
+ }
+ });
+ var $image_upload = $('');
+ $image_upload.on('change', upload_image);
+ $image_upload.appendTo(document.body);
+
+ var $document_upload = $('');
+ $document_upload.on('change', upload_document);
+ $document_upload.appendTo(document.body);
+
+ document.execCommand('defaultParagraphSeparator', false, 'p');
+ $(document).on('click', 'div.figure span.empty', function() {
+ window.active_figure = this.parentNode;
+ $('#image-upload').trigger('click');
+ return true;
+ });
+ $(document).on('click', 'div.document span.empty', function() {
+ window.active_document = this.parentNode;
+ $('#document-upload').trigger('click');
+ return true;
+ });
+ },
+
+ off: function() {
+ $('#image-upload').remove();
+ $('#document-upload').remove();
+ if (block_style_toolbar) { block_style_toolbar.hide(); }
+ if (inline_style_toolbar) { inline_style_toolbar.hide(); }
+ $(document).off('selectionchange');
+ },
+
+ window_keypress: function(ev) {
+ if (inline_style_toolbar && inline_style_toolbar.is(':visible')) {
+ if (event.ctrlKey || event.metaKey) {
+ var key = String.fromCharCode(event.which).toLowerCase();
+ var button = inline_style_toolbar.find('[data-accel="' + key + '"]').first();
+ if (button.length) {
+ button.trigger('click');
+ ev.preventDefault();
+ }
+ }
+ }
+ },
+
+ bind_events: function(elem) {
+ $(elem).on('input', Phylly.input_event);
+ $(elem).on('keyup click', update_block_style_toolbar);
+ $(window).on('keydown', this.window_keypress);
+ },
+
+ unbind_events: function(elem) {
+ $(elem).off('input');
+ $(elem).off('keyup click');
+ $(window).off('keydown', this.window_keypress);
+ },
+
+ }
+ window.Phylly = Phylly;
+
+ function upload_image() {
+ if ($(this).prop('files').length > 0) {
+ var file = $(this).prop('files')[0];
+ var params = new FormData();
+ params.append('upload', file);
+ $.post({url: '/ajax/upload/', processData: false, data: params, contentType: false}).done(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);
+ });
}
- return true;
- });
- $('div[contenteditable]').on('keyup click', update_block_style_popup);
-
- $('#save').on('click', function() {
- var text = $('div[contenteditable]')[0].innerHTML;
- var csrf = $('[name=csrfmiddlewaretoken]').val();
- $.post('api-save/',
- { text: text, csrfmiddlewaretoken: csrf}
- ).fail(function() {
- $('#save').css('background', 'red');
- });
- return false;
- });
+ }
+
+ function upload_document() {
+ if ($(this).prop('files').length > 0) {
+ var file = $(this).prop('files')[0];
+ var params = new FormData();
+ params.append('upload', file);
+ $.post({url: '/ajax/upload/', processData: false, data: params, contentType: false}).done(function(data) {
+ var doc_link = document.createElement('A');
+ doc_link.className = 'button';
+ doc_link.textContent = 'Télécharger ' + data.filename;
+ doc_link.href = data.url;
+ $(window.active_document).empty().append(doc_link);
+ });
+ }
+ }
+
+ 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;
+ for (const block of Phylly.BLOCKS) {
+ if (main_node.tagName === block.tag && main_node.classList.contains(block.klass))
+ return block;
+ }
+ 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 = '
', {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('/ajax/newpage/', params).done(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 selected_link = get_parent(sel.anchorNode, 'A');
+ if (sel.anchorNode.nodeType == Node.TEXT_NODE) {
+ if (sel.anchorNode.length == sel.anchorOffset && sel.anchorNode.nextSibling.nodeName == 'A') {
+ selected_link = sel.anchorNode.nextSibling;
+ }
+ }
var $input = $('input[name=link-target]');
$input[0]._range = sel.getRangeAt(0);
- if (sel.anchorNode instanceof Element) {
- var elem = sel.anchorNode.childNodes[sel.anchorOffset];
- if (elem.tagName == 'A') {
- $input.val(elem.href);
- }
+ if (selected_link) {
+ $input[0]._selected_link = selected_link;
+ $input.val(selected_link.href);
}
$input.addClass('shown');
$input.focus();
@@ -154,13 +469,25 @@ $(function() {
$input.removeClass('shown');
var sel = window.getSelection();
sel.addRange(this._range);
+ var selected_link = $input[0]._selected_link;
if (url) {
- document.execCommand('createLink', false, url);
+ if (selected_link) {
+ selected_link.href = url;
+ } else {
+ var $new_link = $('', {text: sel.toString(), href: url});
+ this._range.deleteContents();
+ this._range.insertNode($new_link[0]);
+ sel.empty();
+ sel.collapse($new_link[0]);
+ sel.empty();
+ }
} else {
- document.execCommand('unlink', false, null);
+ if (selected_link) {
+ selected_link.replaceWith(document.createTextNode(selected_link.textContent));
+ }
}
- sel.empty();
$input.val('');
+ $input[0]._selected_link = null;
}
}
function focusout_link(ev) {
@@ -171,36 +498,109 @@ $(function() {
sel.addRange(this._range);
}
- function show_style_popup(sel) {
- if (style_popup === null) {
- style_popup = $('