3     /* Show theme to the user */
 
   4     function selectTheme(themeId){
 
   5         var selection = window.getSelection();
 
   6         selection.removeAllRanges();
 
   8         var range = document.createRange();
 
   9         var s = $(".motyw[theme-class='" + themeId + "']")[0];
 
  10         var e = $(".end[theme-class='" + themeId + "']")[0];
 
  13             range.setStartAfter(s);
 
  14             range.setEndBefore(e);
 
  15             selection.addRange(range);
 
  19     /* Verify insertion port for annotation or theme */
 
  20     function verifyTagInsertPoint(node){
 
  21         if (node.nodeType == 3) { // Text Node
 
  22             node = node.parentNode;
 
  25         if (node.nodeType != 1) {
 
  30         var xtype = node.attr('x-node');
 
  32         if (!xtype || (xtype.search(':') >= 0) ||
 
  39         // don't allow themes inside annotations
 
  40         if (node.is('*[x-annotation-box] *'))
 
  46     /* Convert HTML fragment to plaintext */
 
  47     var ANNOT_FORBIDDEN = ['pt', 'pa', 'pr', 'pe', 'begin', 'end', 'motyw'];
 
  49     function html2plainText(fragment){
 
  52         $(fragment.childNodes).each(function(){
 
  53             if (this.nodeType == 3) // textNode
 
  54                 text += this.nodeValue;
 
  56                 if (this.nodeType == 1 &&
 
  57                         $.inArray($(this).attr('x-node'), ANNOT_FORBIDDEN) == -1) {
 
  58                     text += html2plainText(this);
 
  67     /* Insert annotation using current selection */
 
  68     function addAnnotation(){
 
  69         var selection = window.getSelection();
 
  70         var n = selection.rangeCount;
 
  73             window.alert("Nie zaznaczono żadnego obszaru");
 
  77         // for now allow only 1 range
 
  79             window.alert("Zaznacz jeden obszar");
 
  83         // remember the selected range
 
  84         var range = selection.getRangeAt(0);
 
  86         if (!verifyTagInsertPoint(range.endContainer)) {
 
  87             window.alert("Nie można wstawić w to miejsce przypisu.");
 
  91         // BUG #273 - selected text can contain themes, which should be omitted from
 
  93         var text = html2plainText(range.cloneContents());
 
  94         var tag = $('<span></span>');
 
  95         range.collapse(false);
 
  96         range.insertNode(tag[0]);
 
  99             xml: '<pe><slowo_obce>' + text + '</slowo_obce> --- </pe>',
 
 100             success: function(text){
 
 107                 alert('Błąd przy dodawaniu przypisu:' + errors);
 
 113     /* Insert theme using current selection */
 
 116         var selection = window.getSelection();
 
 117         var n = selection.rangeCount;
 
 120             window.alert("Nie zaznaczono żadnego obszaru");
 
 124         // for now allow only 1 range
 
 126             window.alert("Zaznacz jeden obszar.");
 
 131         // remember the selected range
 
 132         var range = selection.getRangeAt(0);
 
 135         if ($(range.startContainer).is('.html-editarea') ||
 
 136         $(range.endContainer).is('.html-editarea')) {
 
 137             window.alert("Motywy można oznaczać tylko na tekście nie otwartym do edycji. \n Zamknij edytowany fragment i spróbuj ponownie.");
 
 141         // verify if the start/end points make even sense -
 
 142         // they must be inside a x-node (otherwise they will be discarded)
 
 143         // and the x-node must be a main text
 
 144         if (!verifyTagInsertPoint(range.startContainer)) {
 
 145             window.alert("Motyw nie może się zaczynać w tym miejscu.");
 
 149         if (!verifyTagInsertPoint(range.endContainer)) {
 
 150             window.alert("Motyw nie może się kończyć w tym miejscu.");
 
 154         var date = (new Date()).getTime();
 
 155         var random = Math.floor(4000000000 * Math.random());
 
 156         var id = ('' + date) + '-' + ('' + random);
 
 158         var spoint = document.createRange();
 
 159         var epoint = document.createRange();
 
 161         spoint.setStart(range.startContainer, range.startOffset);
 
 162         epoint.setStart(range.endContainer, range.endOffset);
 
 164         var mtag, btag, etag, errors;
 
 169             xml: '<end id="e' + id + '" />',
 
 170             success: function(text){
 
 171                 etag = $('<span></span>');
 
 172                 epoint.insertNode(etag[0]);
 
 173                 etag.replaceWith(text);
 
 175                     xml: '<motyw id="m' + id + '"></motyw>',
 
 176                     success: function(text){
 
 177                         mtag = $('<span></span>');
 
 178                         spoint.insertNode(mtag[0]);
 
 179                         mtag.replaceWith(text);
 
 181                             xml: '<begin id="b' + id + '" />',
 
 182                             success: function(text){
 
 183                                 btag = $('<span></span>');
 
 184                                 spoint.insertNode(btag[0])
 
 185                                 btag.replaceWith(text);
 
 186                                 selection.removeAllRanges();
 
 187                                 openForEdit($('.motyw[theme-class=' + id + ']'));
 
 196     function addSymbol() {
 
 197         if($('div.html-editarea textarea')[0]) {
 
 198             var specialCharsContainer = $("<div id='specialCharsContainer'><a href='#' id='specialCharsClose'>Zamknij</a><table id='tableSpecialChars' style='width: 600px;'></table></div>");
 
 200             var specialChars = ['Ą','ą','Ć','ć','Ę','ę','Ł','ł','Ń','ń','Ó','ó','Ś','ś','Ż','ż','Ź','ź','Á','á','À','à',
 
 201             'Â','â','Ä','ä','Å','å','Ā','ā','Ă','ă','Ã','ã',
 
 202             'Æ','æ','Ç','ç','Č','č','Ċ','ċ','Ď','ď','É','é','È','è',
 
 203             'Ê','ê','Ë','ë','Ē','ē','Ě','ě','Ġ','ġ','Ħ','ħ','Í','í','Î','î',
 
 204             'Ī','ī','Ĭ','ĭ','Ľ','ľ','Ñ','ñ','Ň','ň','Ó','ó','Ö','ö',
 
 205             'Ô','ô','Ō','ō','Ǒ','ǒ','Œ','œ','Ø','ø','Ř','ř','Š',
 
 206             'š','Ş','ş','Ť','ť','Ţ','ţ','Ű','ű','Ú','ú','Ù','ù',
 
 207             'Ü','ü','Ů','ů','Ū','ū','Û','û','Ŭ','ŭ',
 
 208             'Ý','ý','Ž','ž','ß','Ð','ð','Þ','þ','А','а','Б',
 
 209             'б','В','в','Г','г','Д','д','Е','е','Ё','ё','Ж',
 
 210             'ж','З','з','И','и','Й','й','К','к','Л','л','М',
 
 211             'м','Н','н','О','о','П','п','Р','р','С','с',
 
 212             'Т','т','У','у','Ф','ф','Х','х','Ц','ц','Ч',
 
 213             'ч','Ш','ш','Щ','щ','Ъ','ъ','Ы','ы','Ь','ь','Э',
 
 214             'э','Ю','ю','Я','я','ѓ','є','і','ї','ј','љ','њ',
 
 215             'Ґ','ґ','Α','α','Β','β','Γ','γ','Δ','δ','Ε','ε',
 
 216             'Ζ','ζ','Η','η','Θ','θ','Ι','ι','Κ','κ','Λ','λ','Μ',
 
 217             'μ','Ν','ν','Ξ','ξ','Ο','ο','Π','π','Ρ','ρ','Σ','ς','σ',
 
 218             'Τ','τ','Υ','υ','Φ','φ','Χ','χ','Ψ','ψ','Ω','ω','–',
 
 219             '—','¡','¿','$','¢','£','€','©','®','°','¹','²','³',
 
 220             '¼','½','¾','†','§','‰','•','←','↑','→','↓',
 
 221             '„','”','„”','«','»','«»','»«','’','[',']','~','|','−','·',
 
 222             '×','÷','≈','≠','±','≤','≥','∈'];
 
 223             var tableContent = "<tr>";
 
 225             for(var i in specialChars) {
 
 226                 if(i % 14 == 0 && i > 0) {
 
 227                     tableContent += "</tr><tr>";
 
 229                 tableContent += "<td><input type='button' class='specialBtn' value='"+specialChars[i]+"'/></td>";              
 
 232             tableContent += "</tr>";                                   
 
 233             $("#content").append(specialCharsContainer);
 
 236              // localStorage for recently used characters - reading
 
 237              if (typeof(localStorage) != 'undefined') {
 
 238                  if (localStorage.getItem("recentSymbols")) {
 
 239                      var recent = localStorage.getItem("recentSymbols");
 
 240                      var recentArray = recent.split(";");
 
 242                      for(var i in recentArray.reverse()) {
 
 243                         recentRow += "<td><input type='button' class='specialBtn recentSymbol' value='"+recentArray[i]+"'/></td>";              
 
 245                      recentRow = "<tr>" + recentRow + "</tr>";                              
 
 248             $("#tableSpecialChars").append(recentRow);
 
 249             $("#tableSpecialChars").append(tableContent);
 
 253             $('.specialBtn').click(function(){
 
 254                 var editArea = $('div.html-editarea textarea')[0];
 
 255                 var insertVal = $(this).val();
 
 257                 // if we want to surround text with quotes
 
 258                 // not sure if just check if value has length == 2
 
 260                 if (insertVal.length == 2) {
 
 261                     var startTag = insertVal[0];
 
 262                     var endTag = insertVal[1];
 
 263                                 var textAreaOpened = editArea;                                                  
 
 265                                 if (document.selection) {
 
 266                                     textAreaOpened.focus();
 
 267                                     sel = document.selection.createRange();
 
 268                                     sel.text = startTag + sel.text + endTag;
 
 270                                 //MOZILLA/NETSCAPE support
 
 271                                 else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') {
 
 272                                     var startPos = textAreaOpened.selectionStart;
 
 273                                     var endPos = textAreaOpened.selectionEnd;
 
 274                                     textAreaOpened.value = textAreaOpened.value.substring(0, startPos)
 
 275                                           + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length);
 
 278                     // if we just want to insert single symbol
 
 279                     insertAtCaret(editArea, insertVal);
 
 282                 // localStorage for recently used characters - saving
 
 283                 if (typeof(localStorage) != 'undefined') {
 
 284                     if (localStorage.getItem("recentSymbols")) {
 
 285                         var recent = localStorage.getItem("recentSymbols");
 
 286                         var recentArray = recent.split(";");
 
 287                         var valIndex = $.inArray(insertVal, recentArray);
 
 290                             // value not present in array yet
 
 291                             if(recentArray.length > 13){
 
 293                                 recentArray.push(insertVal);
 
 295                                 recentArray.push(insertVal);
 
 298                             // value already in the array
 
 299                             for(var i = valIndex; i < recentArray.length; i++){
 
 300                                 recentArray[i] = recentArray[i+1];
 
 302                             recentArray[recentArray.length-1] = insertVal;
 
 304                         localStorage.setItem("recentSymbols", recentArray.join(";"));
 
 306                         localStorage.setItem("recentSymbols", insertVal);
 
 310                 $(specialCharsContainer).remove();
 
 312             $('#specialCharsClose').click(function(){
 
 313                 $(specialCharsContainer).remove();
 
 317             window.alert('Najedź na fragment tekstu, wybierz "Edytuj" i ustaw kursor na miejscu gdzie chcesz wstawić symbol.');
 
 321     function insertAtCaret(txtarea,text) { 
 
 322         /* http://www.scottklarr.com/topic/425/how-to-insert-text-into-a-textarea-where-the-cursor-is/ */
 
 323         var scrollPos = txtarea.scrollTop; 
 
 325         var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false ) );
 
 328             var range = document.selection.createRange(); 
 
 329             range.moveStart ('character', -txtarea.value.length); 
 
 330             strPos = range.text.length; 
 
 331         } else if (br == "ff") strPos = txtarea.selectionStart; 
 
 332         var front = (txtarea.value).substring(0,strPos); 
 
 333         var back = (txtarea.value).substring(strPos,txtarea.value.length); 
 
 334         txtarea.value=front+text+back; 
 
 335         strPos = strPos + text.length; 
 
 338             var range = document.selection.createRange(); 
 
 339             range.moveStart ('character', -txtarea.value.length); 
 
 340             range.moveStart ('character', strPos); 
 
 341             range.moveEnd ('character', 0); 
 
 343         } else if (br == "ff") { 
 
 344             txtarea.selectionStart = strPos; 
 
 345             txtarea.selectionEnd = strPos; 
 
 348         txtarea.scrollTop = scrollPos; 
 
 351     function getXNodeAttributes(node) {
 
 353         $.map(node.attributes, function(attrNode) {
 
 354             if (attrNode.nodeName.indexOf('data-wlf-') === 0) {
 
 355                 var n = attrNode.nodeName.substr(9);
 
 356                 var v = attrNode.nodeValue;
 
 363     function setXNodeAttributes(node, attrs) {
 
 364         $.map(node.attributes, function(attrNode) {
 
 365             var xName = attrNode.nodeName.substr(9);
 
 366             if (attrNode.nodeName.indexOf('data-wlf-') === 0
 
 368                 attrNode.nodeValue = attrs[xName];
 
 370             if (attrNode.nodeName.indexOf('x-attr-name-') === 0
 
 371                 && attrNode.nodeValue in attrs) {
 
 372                 node.setAttribute('x-attr-value-' + attrNode.nodeName.substr("x-attr-name-".length),
 
 373                                   attrs[attrNode.nodeValue]);
 
 378     /* open edition window for selected fragment */
 
 379     function openForEdit($origin){
 
 382         // annotations overlay their sub box - not their own box //
 
 383         if ($origin.is(".annotation-inline-box")) {
 
 384             $box = $("*[x-annotation-box]", $origin);
 
 389         var x = $box[0].offsetLeft;
 
 390         var y = $box[0].offsetTop;        
 
 392         var w = $box.outerWidth();
 
 393         var h = $box.innerHeight();
 
 395         if ($origin.is(".annotation-inline-box")) {
 
 396             w = Math.max(w, 400);
 
 398             if($('.htmlview div').offset().left + $('.htmlview div').width() > ($('.vsplitbar').offset().left - 480)){
 
 399                 x = -(Math.max($origin.offset().left, $origin.width())); 
 
 405         // start edition on this node
 
 406         var $overlay = $('<div class="html-editarea"><button class="accept-button">Zapisz</button><button class="delete-button">Usuń</button><button class="tytul-button akap-edit-button">tytuł dzieła</button><button class="wyroznienie-button akap-edit-button">wyróżnienie</button><button class="slowo-button akap-edit-button">słowo obce</button><button class="znak-button akap-edit-button">znak spec.</button><button class="luka-button akap-edit-button">luka</button><button class="zastap-button akap-edit-button">zastąp</button><textarea></textarea></div>');
 
 408         $attributes = $('<div class="html-editarea-attributes"></div>')
 
 410         $.map(getXNodeAttributes($origin.get(0)),
 
 412                 $attributes.append('<span><label for="attr-'+n+'">'+n+'</label><input type="text" name="'+n+'" id="attr-'+n+'" value="'+v+'"/></span>');
 
 414         $overlay.append($attributes);
 
 417             position: 'absolute',
 
 422         }).appendTo($box[0].offsetParent || $box.parent()).show();
 
 425         if ($origin.is('.motyw')) {
 
 426             $('.akap-edit-button').remove();
 
 427             withThemes(function(canonThemes){
 
 428                 $('textarea', $overlay).autocomplete(canonThemes, {
 
 437         if ($origin.is('.motyw')){
 
 438             $('.delete-button', $overlay).click(function(){
 
 439                 if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten motyw ?")) {
 
 440                     $('[theme-class=' + $origin.attr('theme-class') + ']').remove();
 
 442                     $(document).unbind('click.blur-overlay');
 
 447         else if($box.is('*[x-annotation-box]')) {
 
 448             $('.delete-button', $overlay).click(function(){
 
 449                 if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten przypis?")) {
 
 452                     $(document).unbind('click.blur-overlay');
 
 458             $('.delete-button', $overlay).html("Anuluj");
 
 459             $('.delete-button', $overlay).click(function(){
 
 460                 if (window.confirm("Czy jesteś pewien, że chcesz anulować zmiany?")) {
 
 462                     $(document).unbind('click.blur-overlay');
 
 469         var serializer = new XMLSerializer();
 
 474             success: function(text){
 
 475                 $('textarea', $overlay).val($.trim(text));
 
 477                 setTimeout(function(){
 
 478                     $('textarea', $overlay).elastic().focus();
 
 481                 function save(argument){
 
 482                     var nodeName = $box.attr('x-node') || 'pe';
 
 483                     var insertedText = $('textarea', $overlay).val();
 
 485                     if ($origin.is('.motyw')) {
 
 486                         insertedText = insertedText.replace(/,\s*$/, '');
 
 490                         xml: '<' + nodeName + '>' + insertedText + '</' + nodeName + '>',
 
 491                         success: function(element){
 
 492                             if (nodeName == 'out-of-flow-text') {
 
 493                                 $(element).children().insertAfter($origin);
 
 497                                 $origin.html($(element).html());
 
 499                             /* Set attributres back to the node */
 
 501                             $(".html-editarea-attributes [name]")
 
 502                                 .each(function(i, textField) {
 
 503                                     attrs[textField.name] = textField.value;
 
 505                             setXNodeAttributes($origin.get(0), attrs);
 
 509                         error: function(text){
 
 511                             alert('Błąd! ' + text);
 
 515                     var msg = $("<div class='saveNotify'><p>Pamiętaj, żeby zapisać swoje zmiany.</p></div>");
 
 516                     $("#base").prepend(msg);
 
 517                     $('#base .saveNotify').fadeOut(3000, function(){
 
 522                 $('.akap-edit-button', $overlay).click(function(){
 
 523                         var textAreaOpened = $('textarea', $overlay)[0];
 
 526                         var buttonName = this.innerHTML;
 
 528                         if(buttonName == "słowo obce") {
 
 529                                 startTag = "<slowo_obce>";
 
 530                                 endTag = "</slowo_obce>";
 
 531                         } else if (buttonName == "wyróżnienie") {
 
 532                                 startTag = "<wyroznienie>";
 
 533                                 endTag = "</wyroznienie>";
 
 534                         } else if (buttonName == "tytuł dzieła") {
 
 535                                 startTag = "<tytul_dziela>";
 
 536                                 endTag = "</tytul_dziela>";
 
 537                         } else if(buttonName == "znak spec."){
 
 540                         } else if (buttonName == "luka") {
 
 543                         } else if (buttonName == "zastąp") {
 
 544                                 startTag = "<zastap rozw=\"\">";
 
 545                                 endTag = "</zastap>";
 
 548                         var myField = textAreaOpened;                   
 
 551                         if (document.selection) {
 
 552                             textAreaOpened.focus();
 
 553                             sel = document.selection.createRange();
 
 554                             sel.text = startTag + sel.text + endTag;
 
 556                         //MOZILLA/NETSCAPE support
 
 557                         else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') {
 
 558                             var startPos = textAreaOpened.selectionStart;
 
 559                             var endPos = textAreaOpened.selectionEnd;
 
 560                             textAreaOpened.value = textAreaOpened.value.substring(0, startPos)
 
 561                                   + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length);
 
 565                 $('.accept-button', $overlay).click(function(){
 
 569                 $(document).bind('click.blur-overlay', function(event){
 
 570                     if ($(event.target).parents('.html-editarea').length > 0) {
 
 574                     $(document).unbind('click.blur-overlay');
 
 578             error: function(text){
 
 579                 alert('Błąd! ' + text);
 
 584     function VisualPerspective(options){
 
 586         var old_callback = options.callback;
 
 588         options.callback = function(){
 
 589             var element = $("#html-view");
 
 590             var button = $('<button class="edit-button">Edytuj</button>');
 
 592             if (!CurrentDocument.readonly) {
 
 593                 $('#html-view').bind('mousemove', function(event){
 
 594                     var editable = $(event.target).closest('*[x-editable]');
 
 595                     $('.active', element).not(editable).removeClass('active').children('.edit-button').remove();
 
 597                     if (!editable.hasClass('active')) {
 
 598                         editable.addClass('active').append(button);
 
 600                     if (editable.is('.annotation-inline-box')) {
 
 601                         $('*[x-annotation-box]', editable).css({
 
 602                             position: 'absolute',
 
 603                             left: event.clientX - editable.offset().left + 5,
 
 604                             top: event.clientY - editable.offset().top + 5
 
 608                         $('*[x-annotation-box]').hide();
 
 612                 $('#insert-annotation-button').click(function(){
 
 617                 $('#insert-theme-button').click(function(){
 
 622                 $('.edit-button').live('click', function(event){
 
 623                     event.preventDefault();
 
 624                     openForEdit($(this).parent());
 
 629             $('.motyw').live('click', function(){
 
 630                 selectTheme($(this).attr('theme-class'));
 
 633             old_callback.call(this);
 
 636         $.wiki.Perspective.call(this, options);
 
 639     VisualPerspective.prototype = new $.wiki.Perspective();
 
 641     VisualPerspective.prototype.freezeState = function(){
 
 645     VisualPerspective.prototype.onEnter = function(success, failure){
 
 646         $.wiki.Perspective.prototype.onEnter.call(this);
 
 649             message: 'Uaktualnianie widoku...'
 
 652         function _finalize(callback){
 
 660             success: function(element){
 
 661                 $('#html-view').html(element);
 
 664             error: function(text, source){
 
 665                 err = '<p class="error">Wystąpił błąd:</p><p>'+text+'</p>';
 
 667                     err += '<pre>'+source.replace(/&/g, '&').replace(/</g, '<')+'</pre>'
 
 668                 $('#html-view').html(err);
 
 674     VisualPerspective.prototype.onExit = function(success, failure){
 
 678             message: 'Zapisywanie widoku...'
 
 681         function _finalize(callback){
 
 687         if ($('#html-view .error').length > 0)
 
 688             return _finalize(failure);
 
 691             element: $('#html-view').get(0),
 
 693             success: function(text){
 
 694                 self.doc.setText(text);
 
 697             error: function(text){
 
 698                 $('#source-editor').html('<p>Wystąpił błąd:</p><pre>' + text + '</pre>');
 
 704     $.wiki.VisualPerspective = VisualPerspective;