1// ---------------------------------------------------------------------------- 2// markItUp! Universal MarkUp Engine, JQuery plugin 3// v 1.1.15 ( e147ca3 - 16/08/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 $('> ul', this).show(); 271 $(document).one('click', function() { // close dropmenu if click outside 272 $('ul ul', header).hide(); 273 } 274 ); 275 }).on('mouseleave.markItUp', function() { 276 $('> ul', this).hide(); 277 }).appendTo(ul); 278 if (button.dropMenu) { 279 levels.push(i); 280 $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); 281 } 282 } 283 } 284 }); 285 levels.pop(); 286 return ul; 287 } 288 289 // markItUp! markups 290 function magicMarkups(string) { 291 if (string) { 292 string = string.toString(); 293 string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g, 294 function(x, a) { 295 var b = a.split('|!|'); 296 if (altKey === true) { 297 return (b[1] !== undefined) ? b[1] : b[0]; 298 } else { 299 return (b[1] === undefined) ? "" : b[0]; 300 } 301 } 302 ); 303 // [![prompt]!], [![prompt:!:value]!] 304 string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g, 305 function(x, a) { 306 var b = a.split(':!:'); 307 if (abort === true) { 308 return false; 309 } 310 311 // On prévient qu'un prompt s'ouvre 312 markitup_prompt = true; 313 314 value = prompt(b[0], (b[1]) ? b[1] : ''); 315 if (value === null) { 316 abort = true; 317 } 318 319 // On attend un peu avant de dire que le prompt est fermé 320 // pour ne pas que ça soit pris en compte en même temps que la fermeture du prompt 321 setTimeout(function(){markitup_prompt = false;}, 500); 322 323 return value; 324 } 325 ); 326 return string; 327 } 328 return ""; 329 } 330 331 // prepare action 332 function prepare(action) { 333 if ($.isFunction(action)) { 334 action = action(hash); 335 } 336 return magicMarkups(action); 337 } 338 339 // build block to insert 340 function build(string) { 341 var openWith = prepare(clicked.openWith); 342 var placeHolder = prepare(clicked.placeHolder); 343 var replaceWith = prepare(clicked.replaceWith); 344 var closeWith = prepare(clicked.closeWith); 345 var openBlockWith = prepare(clicked.openBlockWith); 346 var closeBlockWith = prepare(clicked.closeBlockWith); 347 var multiline = clicked.multiline; 348 349 if (replaceWith !== "") { 350 block = openWith + replaceWith + closeWith; 351 } else if (selection === '' && placeHolder !== '') { 352 block = openWith + placeHolder + closeWith; 353 } else if (multiline === true) { 354 string = string || selection; 355 356 var lines = [string], blocks = []; 357 358 if (multiline === true) { 359 lines = string.split(/\r?\n/); 360 } 361 362 for (var l = 0; l < lines.length; l++) { 363 line = lines[l]; 364 var trailingSpaces; 365 if (trailingSpaces = line.match(/ *$/)) { 366 blocks.push(openWith + line.replace(/ *$/g, '') + closeWith + trailingSpaces); 367 } else { 368 blocks.push(openWith + line + closeWith); 369 } 370 } 371 372 block = blocks.join("\n"); 373 } else { 374 block = openWith + (string || selection) + closeWith; 375 } 376 377 block = openBlockWith + block + closeBlockWith; 378 379 return { block:block, 380 openBlockWith:openBlockWith, 381 openWith:openWith, 382 replaceWith:replaceWith, 383 placeHolder:placeHolder, 384 closeWith:closeWith, 385 closeBlockWith:closeBlockWith 386 }; 387 } 388 389 390 function selectWord(){ 391 selectionBeforeAfter(/\s|[.,;:!¡?¿()]/); 392 selectionSave(); 393 } 394 function selectLine(){ 395 selectionBeforeAfter(/\r?\n/); 396 selectionSave(); 397 } 398 399 function selectionRemoveLast(pattern){ 400 // Remove space by default 401 if (!pattern) pattern = /\s/; 402 last = selection[selection.length-1]; 403 if (last && last.match(pattern)) { 404 set(caretPosition, selection.length-1); 405 get(); 406 $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); 407 } 408 } 409 410 function selectionBeforeAfter(pattern) { 411 if (!pattern) pattern = /\s/; 412 413 sautAvantIE = sautApresIE = 0; 414 if (browser.msie) { 415 // calcul du nombre reel de caracteres pour le substr() 416 // IE ne compte pas les sauts de lignes pour definir les selections 417 // mais les compte dans la fonction length() 418 lenSelection = selection.length - fixIeBug(selection); 419 // si le caractere avant mon debut est un saut le ligne, 420 // ie ne le prendra pas en compte dans la selection. 421 // il faut pouvoir le connaitre. 422 if (caretPosition) { 423 set(caretPosition - 1, 2); 424 sautAvantIE = fixIeBug(document.selection.createRange().text); 425 } 426 // idem pour le caractere apres la ligne ! 427 set(caretPosition, 2); 428 sautApresIE = fixIeBug(document.selection.createRange().text); 429 // selection avant 430 set(0,caretPosition); 431 before = document.selection.createRange().text;
432 // selection apres 433 set(caretPosition + lenSelection, textarea.value.length); 434 after = document.selection.createRange().text; 435 // remettre la veritable selection 436 set(caretPosition, lenSelection); 437 selection = document.selection.createRange().text; 438 } else { 439 before = textarea.value.substring(0, caretPosition); 440 after = textarea.value.substring(caretPosition + selection.length - fixIeBug(selection)); 441 } 442 443 before = before.split(pattern); 444 after = after.split(pattern); 445 // ajouter ce fichu saut de ligne pour IE 446 if (sautAvantIE) before.push(""); 447 if (sautApresIE) after.unshift(""); 448 449 } 450 451 function selectionSave(){ 452 nb_before = before ? before[before.length-1].length : 0; 453 nb_after = after ? after[0].length : 0; 454 455 nb = nb_before + selection.length + nb_after - fixIeBug(selection); 456 caretPosition = caretPosition - nb_before; 457 458 set(caretPosition, nb); 459 get(); 460 $.extend(hash, { selection:selection, caretPosition:caretPosition, scrollPosition:scrollPosition } ); 461 } 462 463 // define markup to insert 464 function markup(button) { 465 var len, j, n, i; 466 hash = clicked = button; 467 get(); 468 469 $.extend(hash, { line:"", 470 root:options.root, 471 textarea:textarea, 472 selection:(selection||''), 473 caretPosition:caretPosition, 474 ctrlKey:ctrlKey, 475 shiftKey:shiftKey, 476 altKey:altKey 477 } 478 ); 479 480 // corrections des selections pour que 481 // - soit le curseur ne change pas 482 // - soit on prend le mot complet (si pas de selection) 483 // - soit on prend la ligne (avant, apres la selection) 484 if (button.selectionType) { 485 486 if (button.selectionType == "word") { 487 if (!selection) { 488 selectWord(); 489 } else { 490 // win/ff add space on double click ? (hum, seems strange) 491 selectionRemoveLast(/\s/); 492 } 493 } 494 if (button.selectionType == "line") { 495 selectLine(); 496 } 497 // horrible chose, mais tellement plus pratique 498 // car on ne peut pas de l'exerieur (json) utiliser 499 // les fonctions internes de markitup 500 if (button.selectionType == "return"){ 501 // le calcul de before et after sous IE 502 // necessitant de creer des selections 503 // c'est extremement vilain a chaque saut de ligne 504 // des qu'il y a un texte volumineux. 505 // on dit tant pis pour lui. 506 if (!browser.msie) { 507 selectionBeforeAfter(/\r?\n/); 508 before_last = before[before.length-1]; 509 after = ''; 510 // gestion des listes -# et -* 511 if (r = before_last.match(/^-([*#]+) ?(.*)$/)) { 512 if (r[2]) { 513 button.replaceWith = "\n-"+r[1]+' '; 514 before_last = ''; 515 } else { 516 // supprime le -* present 517 // (before le fera) 518 button.replaceWith = "\n"; 519 } 520 } else { 521 before_last = ''; 522 button.replaceWith = "\n"; 523 } 524 before[before.length-1] = before_last; 525 selectionSave(); 526 } 527 } 528 } 529 // / fin corrections 530 531 // callbacks before insertion 532 prepare(options.beforeInsert); 533 prepare(clicked.beforeInsert);
534 if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { 535 prepare(clicked.beforeMultiInsert); 536 } 537 $.extend(hash, { line:1 }); 538 539 if ((ctrlKey === true && shiftKey === true) || button.forceMultiline === true) { 540 lines = selection.split(/\r?\n/); 541 for (j = 0, n = lines.length, i = 0; i < n; i++) { 542 // si une seule ligne, on se fiche de savoir qu'elle est vide, 543 // c'est volontaire si on clique le bouton 544 if (n == 1 || $.trim(lines[i]) !== '') { 545 $.extend(hash, { line:++j, selection:lines[i] } ); 546 lines[i] = build(lines[i]).block; 547 } else { 548 lines[i] = ""; 549 } 550 } 551 552 string = { block:lines.join('\n')}; 553 start = caretPosition; 554 len = string.block.length + ((browser.opera) ? n-1 : 0); 555 } else if (ctrlKey === true) { 556 string = build(selection); 557 start = caretPosition + string.openWith.length; 558 len = string.block.length - string.openWith.length - string.closeWith.length; 559 len = len - (string.block.match(/ $/) ? 1 : 0); 560 len -= fixIeBug(string.block); 561 } else if (shiftKey === true) { 562 string = build(selection); 563 start = caretPosition; 564 len = string.block.length; 565 len -= fixIeBug(string.block); 566 } else { 567 string = build(selection); 568 start = caretPosition + string.block.length ; 569 len = 0; 570 start -= fixIeBug(string.block); 571 } 572 573 if ((selection === '' && string.replaceWith === '')) { 574 caretOffset += fixOperaBug(string.block); 575 576 start = caretPosition + string.openBlockWith.length + string.openWith.length; 577 len = string.block.length - string.openBlockWith.length - string.openWith.length - string.closeWith.length - string.closeBlockWith.length; 578 579 caretOffset = $$.val().substring(caretPosition, $$.val().length).length; 580 caretOffset -= fixOperaBug($$.val().substring(0, caretPosition)); 581 } 582 $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); 583 584 if (string.block !== selection && abort === false) { 585 insert(string.block); 586 set(start, len); 587 } else { 588 caretOffset = -1; 589 } 590 get(); 591 592 $.extend(hash, { line:'', selection:selection }); 593 594 // callbacks after insertion
595 if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { 596 prepare(clicked.afterMultiInsert); 597 } 598 599 prepare(clicked.afterInsert); 600 prepare(options.afterInsert); 601 602 // refresh preview if opened 603 if (previewWindow && options.previewAutoRefresh) { 604 refreshPreview(); 605 } 606 607 // reinit keyevent 608 shiftKey = altKey = ctrlKey = abort = false; 609 } 610 611 // Substract linefeed in Opera 612 function fixOperaBug(string) { 613 if (browser.opera) { 614 return string.length - string.replace(/\n*/g, '').length; 615 } 616 return 0; 617 } 618 // Substract linefeed in IE 619 function fixIeBug(string) { 620 if (browser.msie) { 621 return string.length - string.replace(/\r*/g, '').length; 622 } 623 return 0; 624 } 625 626 // add markup 627 function insert(block) { 628 if (document.selection) { 629 var newSelection = document.selection.createRange(); 630 newSelection.text = block; 631 } else { 632 textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length); 633 } 634 } 635 636 // set a selection 637 function set(start, len) { 638 if (textarea.createTextRange){ 639 // quick fix to make it work on Opera 9.5 640 if (browser.opera && browser.version >= 9.5 && len == 0) { 641 return false; 642 } 643 range = textarea.createTextRange(); 644 range.collapse(true); 645 range.moveStart('character', start); 646 range.moveEnd('character', len); 647 range.select(); 648 } else if (textarea.setSelectionRange ){ 649 textarea.setSelectionRange(start, start + len); 650 } 651 textarea.scrollTop = scrollPosition; 652 textarea.focus(); 653 } 654 655 // get the selection 656 function get() { 657 textarea.focus(); 658 659 scrollPosition = textarea.scrollTop; 660 if (document.selection) { 661 selection = document.selection.createRange().text; 662 if (browser.msie) { // ie 663 var range = document.selection.createRange(), rangeCopy = range.duplicate(); 664 rangeCopy.moveToElementText(textarea); 665 caretPosition = -1; 666 while(rangeCopy.inRange(range)) { 667 rangeCopy.moveStart('character'); 668 caretPosition ++; 669 } 670 } else { // opera 671 caretPosition = textarea.selectionStart; 672 } 673 } else { // gecko & webkit 674 caretPosition = textarea.selectionStart; 675 676 selection = textarea.value.substring(caretPosition, textarea.selectionEnd); 677 } 678 return selection; 679 } 680 681 // open preview window 682 function preview() { 683 if (typeof options.previewHandler === 'function') { 684 previewWindow = true; 685 } else if (options.previewInElement) { 686 previewWindow = $(options.previewInElement); 687 } else if (!previewWindow || previewWindow.closed) { 688 if (options.previewInWindow) { 689 previewWindow = window.open('', 'preview', options.previewInWindow); 690 $(window).unload(function() { 691 previewWindow.close(); 692 }); 693 } else { 694 iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>'); 695 if (options.previewPosition == 'after') { 696 iFrame.insertAfter(footer); 697 } else { 698 iFrame.insertBefore(header); 699 } 700 previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1]; 701 } 702 } else if (altKey === true) { 703 if (iFrame) { 704 iFrame.remove(); 705 } else { 706 previewWindow.close(); 707 } 708 previewWindow = iFrame = false; 709 } 710 if (!options.previewAutoRefresh) { 711 refreshPreview(); 712 } 713 if (options.previewInWindow) { 714 previewWindow.focus(); 715 } 716 } 717 718 // refresh Preview window 719 function refreshPreview() { 720 renderPreview(); 721 } 722 723 function renderPreview() { 724 var phtml; 725 var parsedData = $$.val(); 726 if (options.previewParser && typeof options.previewParser === 'function') { 727 parsedData = options.previewParser(parsedData); 728 } 729 if (options.previewHandler && typeof options.previewHandler === 'function') { 730 options.previewHandler(parsedData); 731 } else if (options.previewParserPath !== '') { 732 $.ajax({ 733 type: options.previewParserAjaxType, 734 dataType: 'text', 735 global: false, 736 url: options.previewParserPath, 737 data: options.previewParserVar+'='+encodeURIComponent(parsedData), 738 success: function(data) { 739 writeInPreview( localize(data, 1) ); 740 } 741 }); 742 } else { 743 if (!template) { 744 $.ajax({ 745 url: options.previewTemplatePath, 746 dataType: 'text', 747 global: false, 748 success: function(data) { 749 writeInPreview( localize(data, 1).replace(/<!-- content -->/g, $$.val()) ); 750 } 751 }); 752 } 753 } 754 return false;
755 } 756 757 function writeInPreview(data) { 758 if (options.previewInElement) { 759 $(options.previewInElement).html(data); 760 } else if (previewWindow && previewWindow.document) { 761 try { 762 sp = previewWindow.document.documentElement.scrollTop 763 } catch(e) { 764 sp = 0; 765 } 766 previewWindow.document.open(); 767 previewWindow.document.write(data); 768 previewWindow.document.close(); 769 previewWindow.document.documentElement.scrollTop = sp; 770 } 771 } 772 773 // set keys pressed 774 function keyPressed(e) { 775 shiftKey = e.shiftKey; 776 altKey = e.altKey; 777 ctrlKey = (!(e.altKey && e.ctrlKey)) ? (e.ctrlKey || e.metaKey) : false; 778 779 if (e.type === 'keydown') { 780 if (ctrlKey === true) { 781 li = $('a[accesskey="'+((e.keyCode == 13) ? '\\n' : String.fromCharCode(e.keyCode))+'"]', header).parent('li'); 782 if (li.length !== 0) { 783 ctrlKey = false; 784 setTimeout(function() { 785 li.triggerHandler('mouseup'); 786 },1); 787 return false; 788 } 789 } 790 791 // si opera, on s'embete pas, il cree plus de problemes qu'autre chose 792 // car il ne prend pas en compte l'arret de ces evenements 793 if (!browser.opera) { 794 if (e.keyCode === 13 || e.keyCode === 10) { // Enter key 795 if (ctrlKey === true) { // Enter + Ctrl 796 ctrlKey = false; 797 markup(options.onCtrlEnter); 798 return options.onCtrlEnter.keepDefault; 799 } else if (shiftKey === true) { // Enter + Shift 800 shiftKey = false; 801 markup(options.onShiftEnter); 802 return options.onShiftEnter.keepDefault; 803 } else { // only Enter 804 markup(options.onEnter); 805 return options.onEnter.keepDefault; 806 } 807 } 808 809 if (e.keyCode === 9) { // Tab key 810 if (shiftKey == true || ctrlKey == true || altKey == true) { 811 // permettre un retour a l'action naturelle 812 // du navigateur via shift+tab 813 return false; 814 } 815 if (caretOffset !== -1) { 816 get(); 817 caretOffset = $$.val().length - caretOffset; 818 set(caretOffset, 0); 819 caretOffset = -1; 820 return false; 821 } else { 822 markup(options.onTab); 823 return options.onTab.keepDefault; 824 } 825 } 826 } 827 } 828 } 829 830 function remove() { 831 $$.off(".markItUp").removeClass('markItUpEditor'); 832 $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); 833 834 var relativeRef = $$.parent('div').parent('div.markItUp').parent('div'); 835 if (relativeRef.length) { 836 relativeRef.replaceWith($$); 837 } 838 839 $$.data('markItUp', null); 840 } 841 842 init(); 843 }); 844 }; 845 846 $.fn.markItUpRemove = function() { 847 return this.each(function() { 848 $(this).markItUp('remove'); 849 } 850 ); 851 }; 852 853 $.markItUp = function(settings) { 854 var options = { target:false }; 855 $.extend(options, settings); 856 if (options.target) { 857 return $(options.target).each(function() { 858 $(this).focus(); 859 $(this).trigger('insertion', [options]); 860 }); 861 } else { 862 $('textarea').trigger('insertion', [options]); 863 } 864 }; 865})(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.