[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / plugins-dist / porte_plume / javascript / jquery.markitup_pour_spip.js
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 .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 $$.focus();
261 }).on('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 }).on('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 }).on('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 $$.off(".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);