1// ---------------------------------------------------------------------------- 2// markItUp! Universal MarkUp Engine, JQuery plugin 3// v 1.1.15 ( 77b48ad - 22/10/2018 ) 4// Dual licensed under the MIT and GPL licenses. 5// ---------------------------------------------------------------------------- 6// Copyright (C) 2007-2012 Jay Salvat 7// http://markitup.jaysalvat.com/ 8// ---------------------------------------------------------------------------- 9// Permission is hereby granted, free of charge, to any person obtaining a copy 10// of this software and associated documentation files (the "Software"), to deal 11// in the Software without restriction, including without limitation the rights 12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13// copies of the Software, and to permit persons to whom the Software is 14// furnished to do so, subject to the following conditions: 15// 16// The above copyright notice and this permission notice shall be included in 17// all copies or substantial portions of the Software. 18// 19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25// THE SOFTWARE. 26// ---------------------------------------------------------------------------- 27 28/* 29 * Le code original de markitup 1.1.15 30 * a ete modifie pour prendre en compte 31 * 32 * 1) la langue utilisee dans les textarea : 33 * - si un textarea possede un attribut lang='xx' alors 34 * markitup n'affichera que les icones qui correspondent a cette langue 35 * - on peut passer une valeur de langue par defaut a markitup (le textarea peut ne pas en definir) 36 * .markitup(set_spip,{lang:'fr'}); 37 * - une option supplementaire optionnelle 'lang' est introduite dans les parametres 38 * des boutons (markupset), par exemple : lang:['fr','es','en'] 39 * - si un bouton n'a pas ce parametre, l'icone s'affiche 40 * quelque soit la langue designee dans le textarea ou les parametres de markitup ; 41 * sinon, il faut que la langue soit contenue dedans pour que l'icone s'affiche. 42 43 * 2) gerer des types de selections differentes : 44 * - normales comme dans markitup (rien a faire) 45 * - 'selectionType':'word' : aux mots le plus proche si pas de selection (sinon la selection) 46 * - 'selectionType':'line' : aux lignes les plus proches 47 * - and 'return' : ugly hack to generate list (and so on) on key 'return' press 48 * 49 * 3) eviter a Opera de gerer les evenements apres tabulation ou entree... 50 * il ne sait pas gerer (v11.51) 51 * 52 * 4) ajout d'un <em> supplémentaire sur le html des boutons de la barre d'outil, pour des histoires de sprites 53 */ 54;(function($) { 55 $.fn.markItUp = function(settings, extraSettings) { 56 var method, params, options, ctrlKey, shiftKey, altKey; ctrlKey = shiftKey = altKey = false; 57 markitup_prompt = false; // variable volontairement globale 58 59 if (typeof settings == 'string') { 60 method = settings; 61 params = extraSettings; 62 } 63 64 options = { id: '', 65 nameSpace: '', 66 root: '', 67 lang: '', 68 previewHandler: false, 69 previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes' 70 previewInElement: '', 71 previewAutoRefresh: true, 72 previewPosition: 'after', 73 previewTemplatePath: '~/templates/preview.html', 74 previewParser: false, 75 previewParserPath: '', 76 previewParserVar: 'data', 77 previewParserAjaxType: 'POST', 78 resizeHandle: true, 79 beforeInsert: '', 80 afterInsert: '', 81 onEnter: {}, 82 onShiftEnter: {}, 83 onCtrlEnter: {}, 84 onTab: {}, 85 markupSet: [ { /* set */ } ] 86 }; 87 $.extend(options, settings, extraSettings); 88 89 // compute markItUp! path 90 if (!options.root) { 91 $('script').each(function(a, tag) { 92 var miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/); 93 if (miuScript !== null) { 94 options.root = miuScript[1]; 95 } 96 }); 97 } 98 99 // Quick patch to keep compatibility with jQuery 1.9 100 var uaMatch = function(ua) { 101 ua = ua.toLowerCase(); 102 103 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 104 /(webkit)[ \/]([\w.]+)/.exec(ua) || 105 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 106 /(msie) ([\w.]+)/.exec(ua) || 107 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 108 []; 109 110 return { 111 browser: match[ 1 ] || "", 112 version: match[ 2 ] || "0" 113 }; 114 }; 115 var matched = uaMatch( navigator.userAgent ); 116 var browser = {}; 117 118 if (matched.browser) { 119 browser[matched.browser] = true; 120 browser.version = matched.version; 121 } 122 if (browser.chrome) { 123 browser.webkit = true; 124 } else if (browser.webkit) { 125 browser.safari = true; 126 } 127 128 return this.each(function() { 129 var $$, textarea, levels, scrollPosition, caretPosition, 130 clicked, hash, header, footer, previewWindow, template, iFrame, abort, 131 before, after; 132 $$ = $(this); 133 textarea = this; 134 levels = []; 135 abort = false;
136 scrollPosition = caretPosition = 0; 137 caretOffset = -1; 138 139 options.previewParserPath = localize(options.previewParserPath); 140 options.previewTemplatePath = localize(options.previewTemplatePath); 141 142 if (method) { 143 switch(method) { 144 case 'remove': 145 remove(); 146 break; 147 case 'insert': 148 markup(params); 149 break; 150 default: 151 $.error('Method ' + method + ' does not exist on jQuery.markItUp'); 152 } 153 return; 154 } 155 156 // apply the computed path to ~/ 157 function localize(data, inText) { 158 if (inText) { 159 return data.replace(/("|')~\//g, "$1"+options.root); 160 } 161 return data.replace(/^~\//, options.root); 162 } 163 164 // init and build editor 165 function init() { 166 id = ''; nameSpace = ''; 167 if (options.id) { 168 id = 'id="'+options.id+'"'; 169 } else if ($$.attr("id")) { 170 id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"'; 171 172 } 173 if (options.nameSpace) { 174 nameSpace = 'class="'+options.nameSpace+'"'; 175 } 176 currentScrollPosition = $$.scrollTop(); 177 $$.wrap('<div '+nameSpace+'></div>'); 178 $$.wrap('<div '+id+' class="markItUp"></div>'); 179 $$.wrap('<div class="markItUpContainer"></div>'); 180 $$.addClass("markItUpEditor"); 181 $$.scrollTop(currentScrollPosition); 182 183 // add the header before the textarea 184 header = $('<div class="markItUpHeader"></div>').insertBefore($$); 185 $(dropMenus(options.markupSet)).appendTo(header); 186 // remove empty dropMenu 187 $(header).find("li.markItUpDropMenu ul:empty").parent().remove(); 188 189 // add the footer after the textarea 190 footer = $('<div class="markItUpFooter"></div>').insertAfter($$); 191 192 // add the resize handle after textarea 193 if (options.resizeHandle === true && browser.safari !== true) { 194 resizeHandle = $('<div class="markItUpResizeHandle"></div>') 195 .insertAfter($$) 196 .on("mousedown.markItUp", function(e) { 197 var h = $$.height(), y = e.clientY, mouseMove, mouseUp; 198 mouseMove = function(e) { 199 $$.css("height", Math.max(20, e.clientY+h-y)+"px"); 200 return false; 201 }; 202 mouseUp = function(e) { 203 $("html").off("mousemove.markItUp", mouseMove).off("mouseup.markItUp", mouseUp); 204 return false; 205 }; 206 $("html").on("mousemove.markItUp", mouseMove).on("mouseup.markItUp", mouseUp); 207 }); 208 footer.append(resizeHandle); 209 } 210 211 // listen key events 212 $$.on('keydown.markItUp', keyPressed).on('keyup', keyPressed); 213 214 // bind an event to catch external calls 215 $$.on("insertion.markItUp", function(e, settings) { 216 if (settings.target !== false) { 217 get(); 218 } 219 if (textarea === $.markItUp.focused) { 220 markup(settings); 221 } 222 }); 223 224 // remember the last focus 225 $$.on('focus.markItUp', function() { 226 $.markItUp.focused = this; 227 }); 228 229 if (options.previewInElement) { 230 refreshPreview(); 231 } 232 } 233 234 // recursively build header with dropMenus from markupset 235 function dropMenus(markupSet) { 236 var ul = $('<ul></ul>'), i = 0; 237 var lang = ($$.attr('lang')||options.lang); 238 239 $('li:hover > ul', ul).css('display', 'block'); 240 $.each(markupSet, function() { 241 var button = this, t = '', title, li, j; 242 // pas de langue ou dans la langue ; et uniquement si langue autorisee 243 if ((!lang || !button.lang || ($.inArray(lang, button.lang) != -1)) 244 && (!button.lang_not || ($.inArray(lang, button.lang_not) == -1))) { 245 button.title ? title = (button.key) ? (button.title||'')+' [Ctrl+'+button.key+']' : (button.title||'') : title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||''); 246 key = (button.key) ? 'accesskey="'+button.key+'"' : ''; 247 if (button.separator) { 248 li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul); 249 } else { 250 i++; 251 for (j = levels.length -1; j >= 0; j--) { 252 t += levels[j]+"-"; 253 } 254 li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="#" '+key+' title="'+title+'"><em>'+(button.name||'')+'</em></a></li>') 255 .on("contextmenu.markItUp", function() { // prevent contextmenu on mac and allow ctrl+click 256 return false;
257 }).on('click.markItUp', function(e) { 258 e.preventDefault(); 259 }).on("focusin.markItUp", function(){ 260 setTimeout(function(){ 261 $$.focus(); 262 }, 0); 263 }).on('mouseup', function(e) { 264 if (button.call) { 265 eval(button.call)(e); // Pass the mouseup event to custom delegate 266 } 267 setTimeout(function() { markup(button) },1); 268 return false; 269 }).on('mouseenter.markItUp', function() { 270 $('> a', this).addClass('active'); 271 $('> ul', this).addClass('expanded'); 272 $(document).one('click', function() { // close dropmenu if click outside 273 $('ul a', header).removeClass('active'); 274 $('ul ul', header).removeClass('expanded'); 275 } 276 ); 277 }).on('mouseleave.markItUp', function() { 278 $('> a', this).removeClass('active'); 279 $('> ul', this).removeClass('expanded'); 280 }).appendTo(ul); 281 if (button.dropMenu) { 282 levels.push(i); 283 $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); 284 } 285 } 286 } 287 }); 288 levels.pop(); 289 return ul; 290 } 291 292 // markItUp! markups 293 function magicMarkups(string) { 294 if (string) { 295 string = string.toString(); 296 string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g, 297 function(x, a) { 298 var b = a.split('|!|'); 299 if (altKey === true) { 300 return (b[1] !== undefined) ? b[1] : b[0]; 301 } else { 302 return (b[1] === undefined) ? "" : b[0]; 303 } 304 } 305 ); 306 // [![prompt]!], [![prompt:!:value]!] 307 string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g, 308 function(x, a) { 309 var b = a.split(':!:'); 310 if (abort === true) { 311 return false; 312 } 313 314 // On prévient qu'un prompt s'ouvre 315 markitup_prompt = true; 316 317 value = prompt(b[0], (b[1]) ? b[1] : ''); 318 if (value === null) { 319 abort = true; 320 } 321 322 // On attend un peu avant de dire que le prompt est fermé 323 // pour ne pas que ça soit pris en compte en même temps que la fermeture du prompt 324 setTimeout(function(){markitup_prompt = false;}, 500); 325 326 return value; 327 } 328 ); 329 return string; 330 } 331 return ""; 332 } 333 334 // prepare action 335 function prepare(action) { 336 if ($.isFunction(action)) { 337 action = action(hash); 338 } 339 return magicMarkups(action); 340 } 341 342 // build block to insert 343 function build(string) { 344 var openWith = prepare(clicked.openWith); 345 var placeHolder = prepare(clicked.placeHolder); 346 var replaceWith = prepare(clicked.replaceWith); 347 var closeWith = prepare(clicked.closeWith); 348 var openBlockWith = prepare(clicked.openBlockWith); 349 var closeBlockWith = prepare(clicked.closeBlockWith); 350 var multiline = clicked.multiline; 351 352 if (replaceWith !== "") { 353 block = openWith + replaceWith + closeWith; 354 } else if (selection === '' && placeHolder !== '') { 355 block = openWith + placeHolder + closeWith; 356 } else if (multiline === true) { 357 string = string || selection; 358 359 var lines = [string], blocks = []; 360 361 if (multiline === true) { 362 lines = string.split(/\r?\n/); 363 } 364 365 for (var l = 0; l < lines.length; l++) { 366 line = lines[l]; 367 var trailingSpaces; 368 if (trailingSpaces = line.match(/ *$/)) { 369 blocks.push(openWith + line.replace(/ *$/g, '') + closeWith + trailingSpaces); 370 } else { 371 blocks.push(openWith + line + closeWith); 372 } 373 } 374 375 block = blocks.join("\n"); 376 } else { 377 block = openWith + (string || selection) + closeWith; 378 } 379 380 block = openBlockWith + block + closeBlockWith; 381 382 return { block:block, 383 openBlockWith:openBlockWith, 384 openWith:openWith, 385 replaceWith:replaceWith, 386 placeHolder:placeHolder, 387 closeWith:closeWith, 388 closeBlockWith:closeBlockWith 389 }; 390 } 391 392 393 function selectWord(){ 394 selectionBeforeAfter(/\s|[.,;:!¡?¿()]/); 395 selectionSave(); 396 } 397 function selectLine(){ 398 selectionBeforeAfter(/\r?\n/); 399 selectionSave(); 400 } 401 402 function selectionRemoveLast(pattern){ 403 // Remove space by default 404 if (!pattern) pattern = /\s/; 405 last = selection[selection.length-1]; 406 if (last && last.match(pattern)) { 407 set(caretPosition, selection.length-1); 408 get(); 409 $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); 410 } 411 } 412 413 function selectionBeforeAfter(pattern) { 414 if (!pattern) pattern = /\s/; 415 416 sautAvantIE = sautApresIE = 0; 417 if (browser.msie) { 418 // calcul du nombre reel de caracteres pour le substr() 419 // IE ne compte pas les sauts de lignes pour definir les selections 420 // mais les compte dans la fonction length() 421 lenSelection = selection.length - fixIeBug(selection); 422 // si le caractere avant mon debut est un saut le ligne, 423 // ie ne le prendra pas en compte dans la selection. 424 // il faut pouvoir le connaitre. 425 if (caretPosition) { 426 set(caretPosition - 1, 2); 427 sautAvantIE = fixIeBug(document.selection.createRange().text); 428 } 429 // idem pour le caractere apres la ligne ! 430 set(caretPosition, 2); 431 sautApresIE = fixIeBug(document.selection.createRange().text); 432 // selection avant 433 set(0,caretPosition); 434 before = document.selection.createRange().text;
435 // selection apres 436 set(caretPosition + lenSelection, textarea.value.length); 437 after = document.selection.createRange().text; 438 // remettre la veritable selection 439 set(caretPosition, lenSelection); 440 selection = document.selection.createRange().text; 441 } else { 442 before = textarea.value.substring(0, caretPosition); 443 after = textarea.value.substring(caretPosition + selection.length - fixIeBug(selection)); 444 } 445 446 before = before.split(pattern); 447 after = after.split(pattern); 448 // ajouter ce fichu saut de ligne pour IE 449 if (sautAvantIE) before.push(""); 450 if (sautApresIE) after.unshift(""); 451 452 } 453 454 function selectionSave(){ 455 nb_before = before ? before[before.length-1].length : 0; 456 nb_after = after ? after[0].length : 0; 457 458 nb = nb_before + selection.length + nb_after - fixIeBug(selection); 459 caretPosition = caretPosition - nb_before; 460 461 set(caretPosition, nb); 462 get(); 463 $.extend(hash, { selection:selection, caretPosition:caretPosition, scrollPosition:scrollPosition } ); 464 } 465 466 // define markup to insert 467 function markup(button) { 468 var len, j, n, i; 469 hash = clicked = button; 470 get(); 471 472 $.extend(hash, { line:"", 473 root:options.root, 474 textarea:textarea, 475 selection:(selection||''), 476 caretPosition:caretPosition, 477 ctrlKey:ctrlKey, 478 shiftKey:shiftKey, 479 altKey:altKey 480 } 481 ); 482 483 // corrections des selections pour que 484 // - soit le curseur ne change pas 485 // - soit on prend le mot complet (si pas de selection) 486 // - soit on prend la ligne (avant, apres la selection) 487 if (button.selectionType) { 488 489 if (button.selectionType == "word") { 490 if (!selection) { 491 selectWord(); 492 } else { 493 // win/ff add space on double click ? (hum, seems strange) 494 selectionRemoveLast(/\s/); 495 } 496 } 497 if (button.selectionType == "line") { 498 selectLine(); 499 } 500 // horrible chose, mais tellement plus pratique 501 // car on ne peut pas de l'exerieur (json) utiliser 502 // les fonctions internes de markitup 503 if (button.selectionType == "return"){ 504 // le calcul de before et after sous IE 505 // necessitant de creer des selections 506 // c'est extremement vilain a chaque saut de ligne 507 // des qu'il y a un texte volumineux. 508 // on dit tant pis pour lui. 509 if (!browser.msie) { 510 selectionBeforeAfter(/\r?\n/); 511 before_last = before[before.length-1]; 512 after = ''; 513 // gestion des listes -# et -* 514 if (r = before_last.match(/^-([*#]+) ?(.*)$/)) { 515 if (r[2]) { 516 button.replaceWith = "\n-"+r[1]+' '; 517 before_last = ''; 518 } else { 519 // supprime le -* present 520 // (before le fera) 521 button.replaceWith = "\n"; 522 } 523 } else { 524 before_last = ''; 525 button.replaceWith = "\n"; 526 } 527 before[before.length-1] = before_last; 528 selectionSave(); 529 } 530 } 531 } 532 // / fin corrections 533 534 // callbacks before insertion 535 prepare(options.beforeInsert); 536 prepare(clicked.beforeInsert);
537 if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { 538 prepare(clicked.beforeMultiInsert); 539 } 540 $.extend(hash, { line:1 }); 541 542 if ((ctrlKey === true && shiftKey === true) || button.forceMultiline === true) { 543 lines = selection.split(/\r?\n/); 544 for (j = 0, n = lines.length, i = 0; i < n; i++) { 545 // si une seule ligne, on se fiche de savoir qu'elle est vide, 546 // c'est volontaire si on clique le bouton 547 if (n == 1 || $.trim(lines[i]) !== '') { 548 $.extend(hash, { line:++j, selection:lines[i] } ); 549 lines[i] = build(lines[i]).block; 550 } else { 551 lines[i] = ""; 552 } 553 } 554 555 string = { block:lines.join('\n')}; 556 start = caretPosition; 557 len = string.block.length + ((browser.opera) ? n-1 : 0); 558 } else if (ctrlKey === true) { 559 string = build(selection); 560 start = caretPosition + string.openWith.length; 561 len = string.block.length - string.openWith.length - string.closeWith.length; 562 len = len - (string.block.match(/ $/) ? 1 : 0); 563 len -= fixIeBug(string.block); 564 } else if (shiftKey === true) { 565 string = build(selection); 566 start = caretPosition; 567 len = string.block.length; 568 len -= fixIeBug(string.block); 569 } else { 570 string = build(selection); 571 start = caretPosition + string.block.length ; 572 len = 0; 573 start -= fixIeBug(string.block); 574 } 575 576 if ((selection === '' && string.replaceWith === '')) { 577 caretOffset += fixOperaBug(string.block); 578 579 start = caretPosition + string.openBlockWith.length + string.openWith.length; 580 len = string.block.length - string.openBlockWith.length - string.openWith.length - string.closeWith.length - string.closeBlockWith.length; 581 582 caretOffset = $$.val().substring(caretPosition, $$.val().length).length; 583 caretOffset -= fixOperaBug($$.val().substring(0, caretPosition)); 584 } 585 $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); 586 587 if (string.block !== selection && abort === false) { 588 insert(string.block); 589 set(start, len); 590 } else { 591 caretOffset = -1; 592 } 593 get(); 594 595 $.extend(hash, { line:'', selection:selection }); 596 597 // callbacks after insertion
598 if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { 599 prepare(clicked.afterMultiInsert); 600 } 601 602 prepare(clicked.afterInsert); 603 prepare(options.afterInsert); 604 605 // refresh preview if opened 606 if (previewWindow && options.previewAutoRefresh) { 607 refreshPreview(); 608 } 609 610 // Triggers an input event to allow other scripts to react. 611 textarea.dispatchEvent(new Event('input')); 612 613 // reinit keyevent 614 shiftKey = altKey = ctrlKey = abort = false; 615 } 616 617 // Substract linefeed in Opera 618 function fixOperaBug(string) { 619 if (browser.opera) { 620 return string.length - string.replace(/\n*/g, '').length; 621 } 622 return 0; 623 } 624 // Substract linefeed in IE 625 function fixIeBug(string) { 626 if (browser.msie) { 627 return string.length - string.replace(/\r*/g, '').length; 628 } 629 return 0; 630 } 631 632 // add markup 633 function insert(block) { 634 if (document.selection) { 635 var newSelection = document.selection.createRange(); 636 newSelection.text = block; 637 } else { 638 textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length); 639 } 640 } 641 642 // set a selection 643 function set(start, len) { 644 if (textarea.createTextRange){ 645 // quick fix to make it work on Opera 9.5 646 if (browser.opera && browser.version >= 9.5 && len == 0) { 647 return false; 648 } 649 range = textarea.createTextRange(); 650 range.collapse(true); 651 range.moveStart('character', start); 652 range.moveEnd('character', len); 653 range.select(); 654 } else if (textarea.setSelectionRange ){ 655 textarea.setSelectionRange(start, start + len); 656 } 657 textarea.scrollTop = scrollPosition; 658 textarea.focus(); 659 } 660 661 // get the selection 662 function get() { 663 textarea.focus(); 664 665 scrollPosition = textarea.scrollTop; 666 if (document.selection) { 667 selection = document.selection.createRange().text; 668 if (browser.msie) { // ie 669 var range = document.selection.createRange(), rangeCopy = range.duplicate(); 670 rangeCopy.moveToElementText(textarea); 671 caretPosition = -1; 672 while(rangeCopy.inRange(range)) { 673 rangeCopy.moveStart('character'); 674 caretPosition ++; 675 } 676 } else { // opera 677 caretPosition = textarea.selectionStart; 678 } 679 } else { // gecko & webkit 680 caretPosition = textarea.selectionStart; 681 682 selection = textarea.value.substring(caretPosition, textarea.selectionEnd); 683 } 684 return selection; 685 } 686 687 // open preview window 688 function preview() { 689 if (typeof options.previewHandler === 'function') { 690 previewWindow = true; 691 } else if (options.previewInElement) { 692 previewWindow = $(options.previewInElement); 693 } else if (!previewWindow || previewWindow.closed) { 694 if (options.previewInWindow) { 695 previewWindow = window.open('', 'preview', options.previewInWindow); 696 $(window).unload(function() { 697 previewWindow.close(); 698 }); 699 } else { 700 iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>'); 701 if (options.previewPosition == 'after') { 702 iFrame.insertAfter(footer); 703 } else { 704 iFrame.insertBefore(header); 705 } 706 previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1]; 707 } 708 } else if (altKey === true) { 709 if (iFrame) { 710 iFrame.remove(); 711 } else { 712 previewWindow.close(); 713 } 714 previewWindow = iFrame = false; 715 } 716 if (!options.previewAutoRefresh) { 717 refreshPreview(); 718 } 719 if (options.previewInWindow) { 720 previewWindow.focus(); 721 } 722 } 723 724 // refresh Preview window 725 function refreshPreview() { 726 renderPreview(); 727 } 728 729 function renderPreview() { 730 var phtml; 731 var parsedData = $$.val(); 732 if (options.previewParser && typeof options.previewParser === 'function') { 733 parsedData = options.previewParser(parsedData); 734 } 735 if (options.previewHandler && typeof options.previewHandler === 'function') { 736 options.previewHandler(parsedData); 737 } else if (options.previewParserPath !== '') { 738 $.ajax({ 739 type: options.previewParserAjaxType, 740 dataType: 'text', 741 global: false, 742 url: options.previewParserPath, 743 data: options.previewParserVar+'='+encodeURIComponent(parsedData), 744 success: function(data) { 745 writeInPreview( localize(data, 1) ); 746 } 747 }); 748 } else { 749 if (!template) { 750 $.ajax({ 751 url: options.previewTemplatePath, 752 dataType: 'text', 753 global: false, 754 success: function(data) { 755 writeInPreview( localize(data, 1).replace(/<!-- content -->/g, parsedData) ); 756 } 757 }); 758 } 759 } 760 return false;
761 } 762 763 function writeInPreview(data) { 764 if (options.previewInElement) { 765 $(options.previewInElement).html(data); 766 } else if (previewWindow && previewWindow.document) { 767 try { 768 sp = previewWindow.document.documentElement.scrollTop 769 } catch(e) { 770 sp = 0; 771 } 772 previewWindow.document.open(); 773 previewWindow.document.write(data); 774 previewWindow.document.close(); 775 previewWindow.document.documentElement.scrollTop = sp; 776 } 777 } 778 779 // set keys pressed 780 function keyPressed(e) { 781 shiftKey = e.shiftKey; 782 altKey = e.altKey; 783 ctrlKey = (!(e.altKey && e.ctrlKey)) ? (e.ctrlKey || e.metaKey) : false; 784 785 if (e.type === 'keydown') { 786 if (ctrlKey === true) { 787 li = $('a[accesskey="'+((e.keyCode == 13) ? '\\n' : String.fromCharCode(e.keyCode))+'"]', header).parent('li'); 788 if (li.length !== 0) { 789 ctrlKey = false; 790 setTimeout(function() { 791 li.triggerHandler('mouseup'); 792 },1); 793 return false; 794 } 795 } 796 797 // si opera, on s'embete pas, il cree plus de problemes qu'autre chose 798 // car il ne prend pas en compte l'arret de ces evenements 799 if (!browser.opera) { 800 if (e.keyCode === 13 || e.keyCode === 10) { // Enter key 801 if (ctrlKey === true) { // Enter + Ctrl 802 ctrlKey = false; 803 markup(options.onCtrlEnter); 804 if (!options.onCtrlEnter.keepDefault) { 805 textarea.dispatchEvent(new Event('input')); 806 } 807 return options.onCtrlEnter.keepDefault; 808 } else if (shiftKey === true) { // Enter + Shift 809 shiftKey = false; 810 markup(options.onShiftEnter); 811 if (!options.onShiftEnter.keepDefault) { 812 textarea.dispatchEvent(new Event('input')); 813 } 814 return options.onShiftEnter.keepDefault; 815 } else { // only Enter 816 markup(options.onEnter); 817 if (!options.onEnter.keepDefault) { 818 textarea.dispatchEvent(new Event('input')); 819 } 820 return options.onEnter.keepDefault; 821 } 822 } 823 824 if (e.keyCode === 9) { // Tab key 825 if (shiftKey == true || ctrlKey == true || altKey == true) { 826 // permettre un retour a l'action naturelle 827 // du navigateur via shift+tab 828 return false; 829 } 830 if (caretOffset !== -1) { 831 get(); 832 caretOffset = $$.val().length - caretOffset; 833 set(caretOffset, 0); 834 caretOffset = -1; 835 return false; 836 } else { 837 markup(options.onTab); 838 return options.onTab.keepDefault; 839 } 840 } 841 } 842 } 843 } 844 845 function remove() { 846 $$.off(".markItUp").removeClass('markItUpEditor'); 847 $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); 848 849 var relativeRef = $$.parent('div').parent('div.markItUp').parent('div'); 850 if (relativeRef.length) { 851 relativeRef.replaceWith($$); 852 } 853 854 $$.data('markItUp', null); 855 } 856 857 init(); 858 }); 859 }; 860 861 $.fn.markItUpRemove = function() { 862 return this.each(function() { 863 $(this).markItUp('remove'); 864 } 865 ); 866 }; 867 868 $.markItUp = function(settings) { 869 var options = { target:false }; 870 $.extend(options, settings); 871 if (options.target) { 872 return $(options.target).each(function() { 873 $(this).focus(); 874 $(this).trigger('insertion', [options]); 875 }); 876 } else { 877 $('textarea').trigger('insertion', [options]); 878 } 879 }; 880})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.