X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/83be4d392d94be5d759a5632818b90ebf0afa763..634abe44a671e272552f0016155211ae91be09de:/src/redakcja/static/js/wiki/view_editor_wysiwyg.js diff --git a/src/redakcja/static/js/wiki/view_editor_wysiwyg.js b/src/redakcja/static/js/wiki/view_editor_wysiwyg.js index c1c9f6f1..decc7339 100644 --- a/src/redakcja/static/js/wiki/view_editor_wysiwyg.js +++ b/src/redakcja/static/js/wiki/view_editor_wysiwyg.js @@ -1,4 +1,4 @@ -(function($){ +(function($) { /* Show theme to the user */ function selectTheme(themeId){ @@ -6,8 +6,8 @@ selection.removeAllRanges(); var range = document.createRange(); - var s = $(".motyw[theme-class='" + themeId + "']")[0]; - var e = $(".end[theme-class='" + themeId + "']")[0]; + var s = $("[x-node='motyw'][theme-class='" + themeId + "']")[0]; + var e = $("[x-node='end'][theme-class='" + themeId + "']")[0]; if (s && e) { range.setStartAfter(s); @@ -18,15 +18,21 @@ /* Verify insertion port for annotation or theme */ function verifyTagInsertPoint(node){ - if (node.nodeType == 3) { // Text Node + if (node.nodeType == Node.TEXT_NODE) { node = node.parentNode; } - if (node.nodeType != 1) { + if (node.nodeType != Node.ELEMENT_NODE) { return false; } node = $(node); + if (node.attr('id') == 'caret') { + node = node.parent(); + } + while (node.attr('x-pass-thru')) { + node = node.parent(); + } var xtype = node.attr('x-node'); if (!xtype || (xtype.search(':') >= 0) || @@ -36,6 +42,12 @@ return false; } + return true; + } + + function verifyThemeBoundaryPoint(node) { + if (!verifyTagInsertPoint(node)) return false; + node = $(node); // don't allow themes inside annotations if (node.closest('[x-node="pe"]').length > 0) return false; @@ -50,10 +62,10 @@ var text = ""; $(fragment.childNodes).each(function(){ - if (this.nodeType == 3) // textNode + if (this.nodeType == Node.TEXT_NODE) text += this.nodeValue; else { - if (this.nodeType == 1 && + if (this.nodeType == Node.ELEMENT_NODE && $.inArray($(this).attr('x-node'), ANNOT_FORBIDDEN) == -1) { text += html2plainText(this); } @@ -69,76 +81,32 @@ var selection = window.getSelection(); var n = selection.rangeCount; - if (n == 0) { + if (selection.isCollapsed) { window.alert("Nie zaznaczono żadnego obszaru"); return false; } - // for now allow only 1 range - if (n > 1) { - window.alert("Zaznacz jeden obszar"); - return false; - } - - // remember the selected range - var range = selection.getRangeAt(0); + var range = selection.getRangeAt(n - 1); if (!verifyTagInsertPoint(range.endContainer)) { window.alert("Nie można wstawić w to miejsce przypisu."); return false; } - // BUG #273 - selected text can contain themes, which should be omitted from - // defining term - var text = html2plainText(range.cloneContents()); - var tag = $(''); - range.collapse(false); - range.insertNode(tag[0]); - - xml2html({ - xml: '' + text + ' --- ', - success: function(text){ - var t = $(text); - tag.replaceWith(t); - openForEdit(t); - }, - error: function(){ - tag.remove(); - alert('Błąd przy dodawaniu przypisu:' + errors); + text = ''; + for (let i = 0; i < n; ++ i) { + let rangeI = selection.getRangeAt(i); + if (verifyTagInsertPoint(rangeI.startContainer) && + verifyTagInsertPoint(rangeI.endContainer)) { + text += html2plainText(rangeI.cloneContents()); } - }) - } - - - function addReference(){ - var selection = window.getSelection(); - var n = selection.rangeCount; - - if (n == 0) { - window.alert("Nie zaznaczono żadnego obszaru"); - return false; - } - - // for now allow only 1 range - if (n > 1) { - window.alert("Zaznacz jeden obszar"); - return false; } - - // remember the selected range - var range = selection.getRangeAt(0); - - if (!verifyTagInsertPoint(range.endContainer)) { - window.alert("Nie można wstawić w to miejsce przypisu."); - return false; - } - var tag = $(''); range.collapse(false); range.insertNode(tag[0]); xml2html({ - xml: '', + xml: '' + text + ' --- ', success: function(text){ var t = $(text); tag.replaceWith(t); @@ -146,14 +114,13 @@ }, error: function(){ tag.remove(); - alert('Błąd przy dodawaniu referncji:' + errors); + alert('Błąd przy dodawaniu przypisu:' + errors); } }) } - /* Insert theme using current selection */ function addTheme(){ @@ -171,11 +138,9 @@ return false; } - // remember the selected range var range = selection.getRangeAt(0); - if ($(range.startContainer).is('.html-editarea') || $(range.endContainer).is('.html-editarea')) { window.alert("Motywy można oznaczać tylko na tekście nie otwartym do edycji. \n Zamknij edytowany fragment i spróbuj ponownie."); @@ -185,12 +150,12 @@ // verify if the start/end points make even sense - // they must be inside a x-node (otherwise they will be discarded) // and the x-node must be a main text - if (!verifyTagInsertPoint(range.startContainer)) { + if (!verifyThemeBoundaryPoint(range.startContainer)) { window.alert("Motyw nie może się zaczynać w tym miejscu."); return false; } - if (!verifyTagInsertPoint(range.endContainer)) { + if (!verifyThemeBoundaryPoint(range.endContainer)) { window.alert("Motyw nie może się kończyć w tym miejscu."); return false; } @@ -210,10 +175,10 @@ point.setStart(container, offset); return point; } - + var spoint = createPoint(range.startContainer, range.startOffset); var epoint = createPoint(range.endContainer, range.endOffset); - + var mtag, btag, etag, errors; // insert theme-ref @@ -237,7 +202,7 @@ spoint.insertNode(btag[0]) btag.replaceWith(text); selection.removeAllRanges(); - openForEdit($('.motyw[theme-class="' + id + '"]')); + openForEdit($('[x-node="motyw"][theme-class="' + id + '"]')); } }); } @@ -246,10 +211,18 @@ }); } - function addSymbol() { - if($('div.html-editarea textarea')[0]) { + function addSymbol(caret) { + let editArea; + + if (caret) { + editArea = $("textarea", caret.element)[0]; + } else { + editArea = $('div.html-editarea textarea')[0]; + } + + if(editArea) { var specialCharsContainer = $("
Zamknij
"); - + var specialChars = [' ', 'Ą','ą','Ć','ć','Ę','ę','Ł','ł','Ń','ń','Ó','ó','Ś','ś','Ż','ż','Ź','ź','Á','á','À','à', 'Â','â','Ä','ä','Å','å','Ā','ā','Ă','ă','Ã','ã', 'Æ','æ','Ç','ç','Č','č','Ċ','ċ','Ď','ď','É','é','È','è', @@ -274,18 +247,18 @@ '„','”','„”','«','»','«»','»«','’','[',']','~','|','−','·', '×','÷','≈','≠','±','≤','≥','∈']; var tableContent = ""; - + for(var i in specialChars) { if(i % 14 == 0 && i > 0) { tableContent += ""; - } - tableContent += ""; + } + tableContent += ""; } - - tableContent += ""; + + tableContent += ""; $("body").append(specialCharsContainer); - - + + // localStorage for recently used characters - reading if (typeof(localStorage) != 'undefined') { if (localStorage.getItem("recentSymbols")) { @@ -293,45 +266,48 @@ var recentArray = recent.split(";"); var recentRow = ""; for(var i in recentArray.reverse()) { - recentRow += ""; + recentRow += ""; } - recentRow = "" + recentRow + ""; + recentRow = "" + recentRow + ""; } - } + } $("#tableSpecialChars").append(recentRow); $("#tableSpecialChars").append(tableContent); - + /* events */ - + $('.specialBtn').click(function(){ - var editArea = $('div.html-editarea textarea')[0]; var insertVal = $(this).val(); - + // if we want to surround text with quotes // not sure if just check if value has length == 2 - - if (insertVal.length == 2) { - var startTag = insertVal[0]; - var endTag = insertVal[1]; - var textAreaOpened = editArea; - //IE support - if (document.selection) { - textAreaOpened.focus(); - sel = document.selection.createRange(); - sel.text = startTag + sel.text + endTag; - } - //MOZILLA/NETSCAPE support - else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') { - var startPos = textAreaOpened.selectionStart; - var endPos = textAreaOpened.selectionEnd; - textAreaOpened.value = textAreaOpened.value.substring(0, startPos) - + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length); - } + + if (caret) { + caret.insertChar(insertVal); + caret.focus(); } else { - // if we just want to insert single symbol - insertAtCaret(editArea, insertVal); + if (insertVal.length == 2) { + var startTag = insertVal[0]; + var endTag = insertVal[1]; + var textAreaOpened = editArea; + //IE support + if (document.selection) { + textAreaOpened.focus(); + sel = document.selection.createRange(); + sel.text = startTag + sel.text + endTag; + } + //MOZILLA/NETSCAPE support + else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') { + var startPos = textAreaOpened.selectionStart; + var endPos = textAreaOpened.selectionEnd; + textAreaOpened.value = textAreaOpened.value.substring(0, startPos) + + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length); + } + } else { + insertAtCaret(editArea, insertVal); + } } - + // localStorage for recently used characters - saving if (typeof(localStorage) != 'undefined') { if (localStorage.getItem("recentSymbols")) { @@ -360,49 +336,49 @@ } } $(specialCharsContainer).remove(); - }); + }); $('#specialCharsClose').click(function(){ $(specialCharsContainer).remove(); - }); - + }); + } else { window.alert('Najedź na fragment tekstu, wybierz "Edytuj" i ustaw kursor na miejscu gdzie chcesz wstawić symbol.'); } } - function insertAtCaret(txtarea,text) { + function insertAtCaret(txtarea,text) { /* http://www.scottklarr.com/topic/425/how-to-insert-text-into-a-textarea-where-the-cursor-is/ */ - var scrollPos = txtarea.scrollTop; - var strPos = 0; + var scrollPos = txtarea.scrollTop; + var strPos = 0; var backStart = 0; var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false ) ); - if (br == "ie") { + if (br == "ie") { txtarea.focus(); - var range = document.selection.createRange(); - range.moveStart ('character', -txtarea.value.length); - strPos = backStart = range.text.length; + var range = document.selection.createRange(); + range.moveStart ('character', -txtarea.value.length); + strPos = backStart = range.text.length; } else if (br == "ff") { - strPos = txtarea.selectionStart; + strPos = txtarea.selectionStart; backStart = txtarea.selectionEnd; } - var front = (txtarea.value).substring(0,strPos); - var back = (txtarea.value).substring(backStart,txtarea.value.length); - txtarea.value=front+text+back; - strPos = strPos + text.length; - if (br == "ie") { - txtarea.focus(); - var range = document.selection.createRange(); - range.moveStart ('character', -txtarea.value.length); - range.moveStart ('character', strPos); - range.moveEnd ('character', 0); - range.select(); - } else if (br == "ff") { - txtarea.selectionStart = strPos; - txtarea.selectionEnd = strPos; - txtarea.focus(); - } - txtarea.scrollTop = scrollPos; - } + var front = (txtarea.value).substring(0,strPos); + var back = (txtarea.value).substring(backStart,txtarea.value.length); + txtarea.value=front+text+back; + strPos = strPos + text.length; + if (br == "ie") { + txtarea.focus(); + var range = document.selection.createRange(); + range.moveStart ('character', -txtarea.value.length); + range.moveStart ('character', strPos); + range.moveEnd ('character', 0); + range.select(); + } else if (br == "ff") { + txtarea.selectionStart = strPos; + txtarea.selectionEnd = strPos; + txtarea.focus(); + } + txtarea.scrollTop = scrollPos; + } /* open edition window for selected fragment */ function openForEdit($origin){ @@ -416,20 +392,29 @@ $box = $origin; } var x = $box[0].offsetLeft; - var y = $box[0].offsetTop; - + var y = $box[0].offsetTop; + var w = $box.outerWidth(); var h = $box.innerHeight(); - if ($origin.is(".annotation-inline-box") | $origin.is('*[x-edit-no-format]')) { + if ($origin.is(".annotation-inline-box")) { w = Math.max(w, 400); h = Math.max(h, 60); if($('.htmlview div').offset().left + $('.htmlview div').width() > ($('.vsplitbar').offset().left - 480)){ - x = -(Math.max($origin.offset().left, $origin.width())); + x = -(Math.max($origin.offset().left, $origin.width())); } else { x = 100; } } + if ($origin.is('.reference-inline-box')) { + w = 400; + h = 32; + y -= 32; + x = Math.min( + x, + $('.htmlview div').offset().left + $('.htmlview div').width() - 400 + ); + } // start edition on this node var $overlay = $('
').css({ @@ -439,17 +424,17 @@ top: y, width: w }).appendTo($box[0].offsetParent || $box.parent()).show(); - + if ($origin.is('*[x-edit-no-format]')) { - $('.akap-edit-button').remove(); + $('.akap-edit-button').remove(); } - - if ($origin.is('.motyw')) { + + if ($origin.is('[x-node="motyw"]')) { $.themes.autocomplete($('textarea', $overlay)); } - if ($origin.is('.motyw')){ + if ($origin.is('[x-node="motyw"]')){ $('.delete-button', $overlay).click(function(){ if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten motyw?")) { $('[theme-class="' + $origin.attr('theme-class') + '"]').remove(); @@ -459,9 +444,20 @@ }; }); } - else if($box.is('*[x-annotation-box]') || $origin.is('*[x-edit-attribute]')) { + else if($box.is('*[x-annotation-box]') || $origin.is('*[x-edit-attribute]') || $origin.is('*[x-node="uwaga"]')) { + let q; + switch ($origin.attr('x-node')) { + case 'uwaga': + q = 'tę uwagę'; + break; + case 'ref': + q = 'tę referencję'; + break + default: + q = 'ten przypis'; + } $('.delete-button', $overlay).click(function(){ - if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten przypis?")) { + if (window.confirm("Czy jesteś pewien, że chcesz usunąć " + q + "?")) { $origin.remove(); $overlay.remove(); $(document).unbind('click.blur-overlay'); @@ -485,12 +481,12 @@ if($box.attr("x-edit-attribute")) { source = $(''); - source.text($box.attr("data-wlf-" + $box.attr("x-edit-attribute"))); + source.text($box.attr("x-a-wl-" + $box.attr("x-edit-attribute"))); source = source[0]; } else { source = $box[0]; } - + html2text({ element: source, stripOuter: true, @@ -505,7 +501,7 @@ var nodeName = $box.attr('x-node') || 'pe'; var insertedText = $('textarea', $overlay).val(); - if ($origin.is('.motyw')) { + if ($origin.is('[x-node="motyw"]')) { insertedText = insertedText.replace(/,\s*$/, ''); } @@ -515,7 +511,6 @@ xml = '<' + nodeName + '>' + insertedText + ''; } - xml2html({ xml: xml, success: function(element){ @@ -531,55 +526,56 @@ $origin.html($(element).html()); } $overlay.remove(); + $.wiki.activePerspective().flush(); }, error: function(text){ alert('Błąd! ' + text); } }) - + var msg = $("

Pamiętaj, żeby zapisać swoje zmiany.

"); $("#base").prepend(msg); $('#base .saveNotify').fadeOut(3000, function(){ - $(this).remove(); + $(this).remove(); }); } - $('.akap-edit-button', $overlay).click(function(){ - var textAreaOpened = $('textarea', $overlay)[0]; - var startTag = ""; - var endTag = ""; - var buttonName = this.innerHTML; - - if(buttonName == "słowo obce") { - startTag = ""; - endTag = ""; - } else if (buttonName == "wyróżnienie") { - startTag = ""; - endTag = ""; - } else if (buttonName == "tytuł dzieła") { - startTag = ""; - endTag = ""; - } else if(buttonName == "znak spec."){ - addSymbol(); - return false; - } - - var myField = textAreaOpened; - - //IE support - if (document.selection) { - textAreaOpened.focus(); - sel = document.selection.createRange(); - sel.text = startTag + sel.text + endTag; - } - //MOZILLA/NETSCAPE support - else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') { - var startPos = textAreaOpened.selectionStart; - var endPos = textAreaOpened.selectionEnd; - textAreaOpened.value = textAreaOpened.value.substring(0, startPos) - + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length); - } - }); + $('.akap-edit-button', $overlay).click(function(){ + var textAreaOpened = $('textarea', $overlay)[0]; + var startTag = ""; + var endTag = ""; + var buttonName = this.innerHTML; + + if(buttonName == "słowo obce") { + startTag = ""; + endTag = ""; + } else if (buttonName == "wyróżnienie") { + startTag = ""; + endTag = ""; + } else if (buttonName == "tytuł dzieła") { + startTag = ""; + endTag = ""; + } else if(buttonName == "znak spec."){ + addSymbol(); + return false; + } + + var myField = textAreaOpened; + + //IE support + if (document.selection) { + textAreaOpened.focus(); + sel = document.selection.createRange(); + sel.text = startTag + sel.text + endTag; + } + //MOZILLA/NETSCAPE support + else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') { + var startPos = textAreaOpened.selectionStart; + var endPos = textAreaOpened.selectionEnd; + textAreaOpened.value = textAreaOpened.value.substring(0, startPos) + + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length); + } + }); $('.accept-button', $overlay).click(function(){ save(); @@ -601,140 +597,307 @@ }); } + function createUwagaBefore(before) { + xml2html({ + xml: '', + success: function(element){ + let $element = $(element); + $element.insertBefore(before); + openForEdit($element); + } + }); + } - function VisualPerspective(options){ - - var old_callback = options.callback; - - options.callback = function(){ + class VisualPerspective extends $.wiki.Perspective { + constructor(options) { + super(options); + let self = this; var element = $("#html-view"); - var button = $(''); + var button = $(''); + var uwagaButton = $(''); if (!CurrentDocument.readonly) { + $('#html-view').bind('mousemove', function(event){ var editable = $(event.target).closest('*[x-editable]'); - $('.active', element).not(editable).removeClass('active').children('.edit-button').remove(); + $('.active', element).not(editable).removeClass('active').children('.active-block-button').remove(); if (!editable.hasClass('active')) { editable.addClass('active').append(button); + if (!editable.is('[x-edit-attribute]') && + !editable.is('.annotation-inline-box') && + !editable.is('[x-edit-no-format]') + ) { + editable.append(uwagaButton); + } } if (editable.is('.annotation-inline-box')) { $('*[x-annotation-box]', editable).css({ - position: 'absolute', - left: event.clientX - editable.offset().left + 5, - top: event.clientY - editable.offset().top + 5 }).show(); } - else { - $('*[x-annotation-box]').hide(); - } }); + self.caret = new Caret(element); + $('#insert-reference-button').click(function(){ - addReference(); + self.flush(); + self.addReference(); return false; }); $('#insert-annotation-button').click(function(){ + self.flush(); addAnnotation(); return false; }); $('#insert-theme-button').click(function(){ + self.flush(); addTheme(); return false; - }); + }); + + $(".insert-inline-tag").click(function() { + self.flush(); + self.insertInlineTag($(this).attr('data-tag')); + return false; + }); + + $(".insert-char").click(function() { + self.flush(); + addSymbol(caret=self.caret); + return false; + }); $(document).on('click', '.edit-button', function(event){ + self.flush(); event.preventDefault(); openForEdit($(this).parent()); }); + $(document).on('click', '.uwaga-button', function(event){ + self.flush(); + event.preventDefault(); + createUwagaBefore($(this).parent()); + }); } - $(document).on('click', '.motyw', function(){ + $(document).on('click', '[x-node="motyw"]', function(){ selectTheme($(this).attr('theme-class')); }); - old_callback.call(this); - }; + element.on('click', '.annotation', function(event) { + self.flush(); + event.preventDefault(); + event.redakcja_caret_ignore = true; + $('[x-annotation-box]', $(this).parent()).toggleClass('editing'); + self.caret.detach(); + }); + } - $.wiki.Perspective.call(this, options); - }; + onEnter(success, failure) { + super.onEnter(); - VisualPerspective.prototype = new $.wiki.Perspective(); + $.blockUI({ + message: 'Uaktualnianie widoku...' + }); - VisualPerspective.prototype.freezeState = function(){ + function _finalize(callback){ + $.unblockUI(); + if (callback) + callback(); + } - }; + xml2html({ + xml: this.doc.text, + base: this.doc.getBase(), + success: function(element){ + + var htmlView = $('#html-view'); + htmlView.html(element); + if ('PropertiesPerspective' in $.wiki.perspectives) + $.wiki.perspectives.PropertiesPerspective.enable(); + + _finalize(success); + }, + error: function(text, source){ + let err = '

Wystąpił błąd:

'+text+'

'; + if (source) + err += '
'+source.replace(/&/g, '&').replace(/'
+                    $('#html-view').html(err);
+                    _finalize(failure);
+                }
+            });
+        }
 
-    VisualPerspective.prototype.onEnter = function(success, failure){
-        $.wiki.Perspective.prototype.onEnter.call(this);
+        flush() {
+            let self = this;
+            return new Promise((resolve, reject) => {
+                if ($('#html-view .error').length > 0) {
+                    reject()
+                } else {
+                    //return _finalize(failure);
+                    html2text({
+                        element: $('#html-view').get(0),
+                        stripOuter: true,
+                        success: (text) => {
+                            self.doc.setText(text);
+                            resolve();
+                        },
+                        error: (text) => {
+                            reject(text);
+                            //$('#source-editor').html('

Wystąpił błąd:

' + text + '
'); + } + }); + } + }); + } - $.blockUI({ - message: 'Uaktualnianie widoku...' - }); + onExit(success, failure) { + var self = this; - function _finalize(callback){ - $.unblockUI(); - if (callback) - callback(); - } + self.caret.detach(); - xml2html({ - xml: this.doc.text, - success: function(element){ - var htmlView = $('#html-view'); - htmlView.html(element); - htmlView.find('*[x-node]').dblclick(function(e) { - if($(e.target).is('textarea')) - return; - var selection = window.getSelection(); - selection.collapseToStart(); - selection.modify('extend', 'forward', 'word'); - e.stopPropagation(); - }); - _finalize(success); - }, - error: function(text, source){ - err = '

Wystąpił błąd:

'+text+'

'; - if (source) - err += '
'+source.replace(/&/g, '&').replace(/'
-                $('#html-view').html(err);
-                _finalize(failure);
+            if ('PropertiesPerspective' in $.wiki.perspectives)
+                $.wiki.perspectives.PropertiesPerspective.disable();
+
+            self.flush().then(() => {
+                success && success();
+            }).catch((e) => {
+                // TODO report
+                console.log('REJECTED!', e);
+                failure && failure();
+            });
+        };
+
+        insertInlineTag(tag) {
+            this.caret.detach();
+            let self = this;
+
+            let selection = window.getSelection();
+            var n = selection.rangeCount;
+            if (n != 1 || selection.isCollapsed) {
+                window.alert("Nie zaznaczono obszaru");
+                return false
             }
-        });
-    };
+            let range = selection.getRangeAt(0);
 
-    VisualPerspective.prototype.onExit = function(success, failure){
-        var self = this;
+            // Make sure that:
+            // Both ends are in the same x-node container.
+            // Both ends are set to text nodes.
+            // TODO: That the container is a inline-text container.
+            let commonNode = range.endContainer;
 
-        $.blockUI({
-            message: 'Zapisywanie widoku...'
-        });
+            if (commonNode.nodeType == Node.TEXT_NODE) {
+                commonNode = commonNode.parentNode;
+            }
+            let node = range.startContainer;
+            if (node.nodeType == Node.TEXT_NODE) {
+                node = node.parentNode;
+            }
+            if (node != commonNode) {
+                window.alert("Zły obszar.");
+                return false;
+            }
+
+            let end;
+            if (range.endContainer.nodeType == Node.TEXT_NODE) {
+                end = range.endContainer.splitText(range.endOffset);
+            } else {
+                end = document.createTextNode('');
+                let cont = $(range.endContainer).contents();
+                if (range.endOffset < cont.length) {
+                    range.endContainer.insertBefore(end, cont[range.endOffset])
+                } else {
+                    range.endContainer.append(end);
+                }
+            }
 
-        function _finalize(callback){
-            $.unblockUI();
-            if (callback)
-                callback();
+            let current;
+            if (range.startContainer.nodeType == Node.TEXT_NODE) {
+                current = range.startContainer.splitText(range.startOffset);
+            } else {
+                current = document.createTextNode('');
+                let cont = $(range.startContainer).contents();
+                if (range.startOffset < cont.length) {
+                    range.startContainer.insertBefore(current, cont[range.startOffset])
+                } else {
+                    startNode.append(current);
+                }
+            }
+
+            // We will construct a HTML element with the range selected.
+            let div = $("");
+            while (current != end) {
+                n = current.nextSibling;
+                $(current).appendTo(div);
+                current = n;
+            }
+
+            html2text({
+                element: div[0],
+                success: function(d) {
+                    xml2html({
+                        xml: d = '<' + tag + '>' + d + '',
+                        success: function(html) {
+                            // What if no end?
+                            node.insertBefore($(html)[0], end);
+                            self.flush();
+                        }
+                    });
+                },
+                error: function(a, b) {
+                    console.log(a, b);
+                }
+            });
         }
 
-        if ($('#html-view .error').length > 0)
-            return _finalize(failure);
+        insertAtRange(range, elem) {
+            let self = this;
+            let $end = $(range.endContainer);
+            if ($end.attr('id') == 'caret') {
+                self.caret.insert(elem);
+            } else {
+                range.insertNode(elem[0]);
+            }
+        }
 
-        html2text({
-            element: $('#html-view').get(0),
-            stripOuter: true,
-            success: function(text){
-                self.doc.setText(text);
-                _finalize(success);
-            },
-            error: function(text){
-                $('#source-editor').html('

Wystąpił błąd:

' + text + '
'); - _finalize(failure); + addReference() { + let self = this; + var selection = window.getSelection(); + var n = selection.rangeCount; + + // TODO: if no selection, take caret position.. + if (n == 0) { + window.alert("Nie zaznaczono żadnego obszaru"); + return false; } - }); - }; + + var range = selection.getRangeAt(n - 1); + if (!verifyTagInsertPoint(range.endContainer)) { + window.alert("Nie można wstawić w to miejsce referencji."); + return false; + } + + var tag = $(''); + + range.collapse(false); + self.insertAtRange(range, tag); + + xml2html({ + xml: '', + success: function(text){ + var t = $(text); + tag.replaceWith(t); + openForEdit(t); + }, + error: function(){ + tag.remove(); + alert('Błąd przy dodawaniu referncji:' + errors); + } + }) + } + } $.wiki.VisualPerspective = VisualPerspective;