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