-(function($){
+(function($) {
+ class Caret {
+ constructor(view) {
+ self = this;
+ self.view = view;
+ self.singleClick = false;
+
+ let caret = this.element = $('<span id="caret"><textarea></textarea></span>');
+
+ // When user writes into caret, add it to the document.
+ $('textarea', caret).on('input', function() {
+ let v = $(this).val();
+ $(this).val('');
+ self.insertChar(v);
+
+ });
+
+ // On click on x-node element, set caret position.
+ self.view.on('click', '*[x-node]', function(e) {
+ if (e.redakcja_caret_inserted) return;
+ e.redakcja_caret_inserted = true;
+
+ if (self.singleClick) {
+ self.singleClick = false;
+ return;
+ }
+
+ self.detach();
+
+ var selection = window.getSelection();
+ if (!selection.isCollapsed) return;
+
+ self.singleClick = true;
+ setTimeout(function() {
+ if (self.singleClick) {
+ self.element.insertBefore(
+ selection.anchorNode.splitText(
+ selection.anchorOffset
+ )
+ )
+ self.focus();
+ }
+ self.singleClick = false;
+ }, 250);
+
+ });
+
+ self.view.on('keydown', function(e) {
+ // TODO:
+ // Enter (split block)
+ // delete selection?
+
+ // cases:
+ // we are in <akap> (no going up)
+ // we are in <wyroznienie> (can go up)
+ // we are next to <wyroznienie> (can go inside)
+
+ switch (e.key) {
+ case "ArrowRight":
+ if (e.shiftKey) {
+ self.detach();
+ return;
+ }
+
+ self.moveRight();
+ break;
+ case "ArrowLeft":
+ if (e.shiftKey) {
+ self.detach();
+ return;
+ }
+
+ self.moveLeft();
+ break;
+ case "ArrowUp":
+ if (e.shiftKey) {
+ self.detach();
+ return;
+ }
+ break;
+ case "ArrowDown":
+ if (e.shiftKey) {
+ self.detach();
+ return;
+ }
+ break;
+ case "Backspace":
+ self.deleteBefore();
+ break;
+ case "Delete":
+ self.deleteAfter();
+ break;
+// default:
+// console.log('key', e.key, e.code);
+ }
+ })
+ }
+
+ get attached() {
+ return this.element.parent().length;
+ }
+
+ detach() {
+ let p;
+ if (this.attached) {
+ p = this.element.parent()[0]
+ this.element.detach();
+ p.normalize()
+ }
+ }
+
+ focus() {
+ $("textarea", self.element).focus();
+ }
+
+ normalize() {
+ this.element.parent()[0].normalize();
+ }
+
+ insertChar(ch) {
+ $(document.createTextNode(ch)).insertBefore(this.element);
+ this.normalize();
+ }
+
+ deleteBefore() {
+ let contents = this.element.parent().contents();
+ // Find the text before caret.
+ let textBefore = contents[contents.index(this.element) - 1];
+
+ // Should be text, but what if not?
+ textBefore.textContent = textBefore.textContent.substr(0, textBefore.textContent.length - 1);
+ this.normalize();
+
+ }
+
+ deleteAfter() {
+ let contents = this.element.parent().contents();
+ // Find the text after caret.
+ let textAfter = contents[contents.index(this.element) + 1];
+ textAfter.textContent = textAfter.textContent.substr(1);
+ }
+
+ moveLeft() {
+ this.move({
+ move: -1,
+ edge: (i, l) => {return !i;},
+ enter: (l) => {return l - 1;},
+ splitTarget: (t) => {return t.splitText(t.length - 1);},
+ noSplitTarget: (t) => {return t.splitText(t.length);},
+ })
+ }
+
+ moveRight() {
+ this.move({
+ move: 1,
+ edge: (i, l) => {return i == l - 1;},
+ enter: (l) => {return 0;},
+ splitTarget: (t) => {return t.splitText(1);},
+ noSplitTarget: (t) => {return t;},
+ })
+ }
+
+ move(opts) {
+ if (!this.attached) return;
+ this.normalize();
+
+ let contents = this.element.parent().contents();
+ let index = contents.index(this.element);
+ let target, moved, oldparent;
+
+ let parent = this.element.parent()[0];
+
+ if (opts.edge(index, contents.length)) {
+ // We're at the end -- what to do?
+ // can we go up?
+
+ if (parent.nodeName == 'EM') {
+ oldparent = parent;
+ parent = parent.parentNode;
+ contents = $(parent).contents();
+ index = contents.index(oldparent);
+ }
+ }
+
+ index += opts.move;
+ target = contents[index];
+ moved = false;
+
+ while (target.nodeType == 1) {
+ // we've encountered a node.
+ // can we go inside?
+
+ if (target.nodeName == 'EM') {
+ // enter
+ parent = $(target);
+ contents = parent.contents();
+ index = opts.enter(contents.length);
+ target = contents[index];
+
+ // what if it has no elements?
+ } else {
+ // skip
+ index += opts.move; // again, what if end?
+ target = contents[index];
+ moved = true;
+ }
+
+ // if editable?
+ // what if editable but empty?
+
+ }
+
+ if (target.nodeType == 3) {
+ if (!moved) {
+ target = opts.splitTarget(target);
+ } else {
+ target = opts.noSplitTarget(target);
+ }
+
+ this.element.insertBefore(target);
+ }
+ this.normalize();
+ this.focus();
+ }
+ }
+
/* Show theme to the user */
function selectTheme(themeId){
-
+
/* Insert theme using current selection */
function addTheme(){
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
});
}
- 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 = $("<div id='specialCharsContainer'><a href='#' id='specialCharsClose'>Zamknij</a><table id='tableSpecialChars' style='width: 600px;'></table></div>");
-
+
var specialChars = [' ', 'Ą','ą','Ć','ć','Ę','ę','Ł','ł','Ń','ń','Ó','ó','Ś','ś','Ż','ż','Ź','ź','Á','á','À','à',
'Â','â','Ä','ä','Å','å','Ā','ā','Ă','ă','Ã','ã',
'Æ','æ','Ç','ç','Č','č','Ċ','ċ','Ď','ď','É','é','È','è',
'„','”','„”','«','»','«»','»«','’','[',']','~','|','−','·',
'×','÷','≈','≠','±','≤','≥','∈'];
var tableContent = "<tr>";
-
+
for(var i in specialChars) {
if(i % 14 == 0 && i > 0) {
tableContent += "</tr><tr>";
- }
- tableContent += "<td><input type='button' class='specialBtn' value='"+specialChars[i]+"'/></td>";
+ }
+ tableContent += "<td><input type='button' class='specialBtn' value='"+specialChars[i]+"'/></td>";
}
-
- tableContent += "</tr>";
+
+ tableContent += "</tr>";
$("body").append(specialCharsContainer);
-
-
+
+
// localStorage for recently used characters - reading
if (typeof(localStorage) != 'undefined') {
if (localStorage.getItem("recentSymbols")) {
var recentArray = recent.split(";");
var recentRow = "";
for(var i in recentArray.reverse()) {
- recentRow += "<td><input type='button' class='specialBtn recentSymbol' value='"+recentArray[i]+"'/></td>";
+ recentRow += "<td><input type='button' class='specialBtn recentSymbol' value='"+recentArray[i]+"'/></td>";
}
- recentRow = "<tr>" + recentRow + "</tr>";
+ recentRow = "<tr>" + recentRow + "</tr>";
}
- }
+ }
$("#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")) {
}
}
$(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){
$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();
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;
}
top: y,
width: w
}).appendTo($box[0].offsetParent || $box.parent()).show();
-
+
if ($origin.is('*[x-edit-no-format]')) {
$('.akap-edit-button').remove();
}
-
+
if ($origin.is('.motyw')) {
$.themes.autocomplete($('textarea', $overlay));
}
} else {
source = $box[0];
}
-
+
html2text({
element: source,
stripOuter: true,
xml = '<' + nodeName + '>' + insertedText + '</' + nodeName + '>';
}
-
+
xml2html({
xml: xml,
success: function(element){
alert('Błąd! ' + text);
}
})
-
+
var msg = $("<div class='saveNotify'><p>Pamiętaj, żeby zapisać swoje zmiany.</p></div>");
$("#base").prepend(msg);
$('#base .saveNotify').fadeOut(3000, function(){
- $(this).remove();
+ $(this).remove();
});
}
addSymbol();
return false;
}
-
- var myField = textAreaOpened;
-
+
+ var myField = textAreaOpened;
+
//IE support
if (document.selection) {
textAreaOpened.focus();
function VisualPerspective(options){
+ perspective = this;
var old_callback = options.callback;
var button = $('<button class="edit-button">Edytuj</button>');
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();
$('#insert-theme-button').click(function(){
addTheme();
return false;
- });
+ });
+
+
+ $(".insert-inline-tag").click(function() {
+ perspective.insertInlineTag($(this).attr('data-tag'));
+ return false;
+ });
+
+ $(".insert-char").click(function() {
+ console.log('perspective', perspective);
+ addSymbol(caret=perspective.caret);
+ return false;
+ });
$(document).on('click', '.edit-button', function(event){
event.preventDefault();
callback();
}
+ perspective = this;
xml2html({
xml: this.doc.text,
base: this.doc.getBase(),
success: function(element){
+
var htmlView = $('#html-view');
htmlView.html(element);
+
+ perspective.caret = new Caret(htmlView);
+
+
+
htmlView.find('*[x-node]').dblclick(function(e) {
if($(e.target).is('textarea'))
return;
});
};
+ VisualPerspective.prototype.insertInlineTag = function(tag) {
+ this.caret.detach();
+
+ let selection = window.getSelection();
+ var n = selection.rangeCount;
+ if (n != 1) {
+ window.alert("Nie zaznaczono obszaru");
+ return false
+ }
+ let range = selection.getRangeAt(0);
+
+ // Make sure that:
+ // Both ends are in the same x-node container.
+ // TODO: That the container is a inline-text container.
+ let node = range.startContainer;
+ if (node.nodeType == node.TEXT_NODE) {
+ node = node.parentNode;
+ }
+ let endNode = range.endContainer;
+ if (endNode.nodeType == endNode.TEXT_NODE) {
+ endNode = endNode.parentNode;
+ }
+ if (node != endNode) {
+ window.alert("Zły obszar.");
+ return false;
+ }
+
+ // We will construct a HTML element with the range selected.
+ let div = $("<span x-pass-thru='true'>");
+
+ contents = $(node).contents();
+ let startChildIndex = node == range.startContainer ? 0 : contents.index(range.startContainer);
+ let endChildIndex = contents.index(range.endContainer);
+
+ current = range.startContainer;
+ if (current.nodeType == current.TEXT_NODE) {
+ current = current.splitText(range.startOffset);
+ }
+ while (current != range.endContainer) {
+ n = current.nextSibling;
+ $(current).appendTo(div);
+ current = n;
+ }
+ if (current.nodeType == current.TEXT_NODE) {
+ end = current.splitText(range.endOffset);
+ }
+ $(current).appendTo(div);
+
+ html2text({
+ element: div[0],
+ success: function(d) {
+ xml2html({
+ xml: d = '<' + tag + '>' + d + '</' + tag + '>',
+ success: function(html) {
+ // What if no end?
+ node.insertBefore($(html)[0], end);
+ }
+ });
+ },
+ error: function(a, b) {
+ console.log(a, b);
+ }
+ });
+ };
+
+
+
$.wiki.VisualPerspective = VisualPerspective;
})(jQuery);