[SPIP] +spip v3.0.17
[lhc/web/clavette_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.12
4 // Dual licensed under the MIT and GPL licenses.
5 // ----------------------------------------------------------------------------
6 // Copyright (C) 2007-2011 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.12
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 *
53 */
54 ;(function($) {
55 $.fn.markItUp = function(settings, extraSettings) {
56 var options, ctrlKey, shiftKey, altKey;
57 ctrlKey = shiftKey = altKey = false;
58
59 options = { id: '',
60 nameSpace: '',
61 root: '',
62 lang: '',
63 previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes'
64 previewAutoRefresh: true,
65 previewPosition: 'after',
66 previewTemplatePath: '~/templates/preview.html',
67 previewParser: false,
68 previewParserPath: '',
69 previewParserVar: 'data',
70 resizeHandle: true,
71 beforeInsert: '',
72 afterInsert: '',
73 onEnter: {},
74 onShiftEnter: {},
75 onCtrlEnter: {},
76 onTab: {},
77 markupSet: [ { /* set */ } ]
78 };
79 $.extend(options, settings, extraSettings);
80
81 // compute markItUp! path
82 if (!options.root) {
83 $('script').each(function(a, tag) {
84 miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/);
85 if (miuScript !== null) {
86 options.root = miuScript[1];
87 }
88 });
89 }
90
91 return this.each(function() {
92 var $$, textarea, levels, scrollPosition, caretPosition,
93 clicked, hash, header, footer, previewWindow, template, iFrame, abort,
94 before, after;
95 $$ = $(this);
96 textarea = this;
97 levels = [];
98 abort = false;
99 scrollPosition = caretPosition = 0;
100 caretOffset = -1;
101
102 options.previewParserPath = localize(options.previewParserPath);
103 options.previewTemplatePath = localize(options.previewTemplatePath);
104
105 // apply the computed path to ~/
106 function localize(data, inText) {
107 if (inText) {
108 return data.replace(/("|')~\//g, "$1"+options.root);
109 }
110 return data.replace(/^~\//, options.root);
111 }
112
113 // init and build editor
114 function init() {
115 id = ''; nameSpace = '';
116 if (options.id) {
117 id = 'id="'+options.id+'"';
118 } else if ($$.attr("id")) {
119 id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"';
120
121 }
122 if (options.nameSpace) {
123 nameSpace = 'class="'+options.nameSpace+'"';
124 }
125 currentScrollPosition = $$.scrollTop();
126 $$.wrap('<div '+nameSpace+'></div>');
127 $$.wrap('<div '+id+' class="markItUp"></div>');
128 $$.wrap('<div class="markItUpContainer"></div>');
129 $$.addClass("markItUpEditor");
130 $$.scrollTop(currentScrollPosition);
131
132 // add the header before the textarea
133 header = $('<div class="markItUpHeader"></div>').insertBefore($$);
134 $(dropMenus(options.markupSet)).appendTo(header);
135 // remove empty dropMenu
136 $(header).find("li.markItUpDropMenu ul:empty").parent().remove();
137
138 // add the footer after the textarea
139 footer = $('<div class="markItUpFooter"></div>').insertAfter($$);
140
141 // add the resize handle after textarea
142
143 if (options.resizeHandle === true && $.browser.safari !== true) {
144 resizeHandle = $('<div class="markItUpResizeHandle"></div>')
145 .insertAfter($$)
146 .bind("mousedown", function(e) {
147 var h = $$.height(), y = e.clientY, mouseMove, mouseUp;
148 mouseMove = function(e) {
149 $$.css("height", Math.max(20, e.clientY+h-y)+"px");
150 return false;
151 };
152 mouseUp = function(e) {
153 $("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp);
154 return false;
155 };
156 $("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp);
157 });
158 footer.append(resizeHandle);
159 }
160
161 // listen key events
162 $$.keydown(keyPressed).keyup(keyPressed);
163
164 // bind an event to catch external calls
165 $$.bind("insertion", function(e, settings) {
166 if (settings.target !== false) {
167 get();
168 }
169 if (textarea === $.markItUp.focused) {
170 markup(settings);
171 }
172 });
173
174 // remember the last focus
175 $$.focus(function() {
176 $.markItUp.focused = this;
177 });
178 }
179
180 // recursively build header with dropMenus from markupset
181 function dropMenus(markupSet) {
182 var ul = $('<ul></ul>'), i = 0;
183 var lang = ($$.attr('lang')||options.lang);
184
185 $('li:hover > ul', ul).css('display', 'block');
186 $.each(markupSet, function() {
187 var button = this, t = '', title, li, j;
188 // pas de langue ou dans la langue ; et uniquement si langue autorisee
189 if ((!lang || !button.lang || ($.inArray(lang, button.lang) != -1))
190 && (!button.lang_not || ($.inArray(lang, button.lang_not) == -1))) {
191 title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||'');
192 key = (button.key) ? 'accesskey="'+button.key+'"' : '';
193 if (button.separator) {
194 li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul);
195 } else {
196 i++;
197 for (j = levels.length -1; j >= 0; j--) {
198 t += levels[j]+"-";
199 }
200 li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="" '+key+' title="'+title+'"><em>'+(button.name||'')+'</em></a></li>')
201 .bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click
202 return false;
203 }).click(function() {
204 return false;
205 }).bind("focusin", function(){
206 $$.focus();
207 }).mouseup(function() {
208 if (button.call) {
209 eval(button.call)();
210 }
211 setTimeout(function() { markup(button) },1);
212 return false;
213 }).hover(function() {
214 $('> ul', this).show();
215 $(document).one('click', function() { // close dropmenu if click outside
216 $('ul ul', header).hide();
217 }
218 );
219 }, function() {
220 $('> ul', this).hide();
221 }
222 ).appendTo(ul);
223 if (button.dropMenu) {
224 levels.push(i);
225 $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu));
226 }
227 }
228 }
229 });
230 levels.pop();
231 return ul;
232 }
233
234 // markItUp! markups
235 function magicMarkups(string) {
236 if (string) {
237 string = string.toString();
238 string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g,
239 function(x, a) {
240 var b = a.split('|!|');
241 if (altKey === true) {
242 return (b[1] !== undefined) ? b[1] : b[0];
243 } else {
244 return (b[1] === undefined) ? "" : b[0];
245 }
246 }
247 );
248 // [![prompt]!], [![prompt:!:value]!]
249 string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g,
250 function(x, a) {
251 var b = a.split(':!:');
252 if (abort === true) {
253 return false;
254 }
255 value = prompt(b[0], (b[1]) ? b[1] : '');
256 if (value === null) {
257 abort = true;
258 }
259 return value;
260 }
261 );
262 return string;
263 }
264 return "";
265 }
266
267 // prepare action
268 function prepare(action) {
269 if ($.isFunction(action)) {
270 action = action(hash);
271 }
272 return magicMarkups(action);
273 }
274
275 // build block to insert
276 function build(string) {
277 var openWith = prepare(clicked.openWith);
278 var placeHolder = prepare(clicked.placeHolder);
279 var replaceWith = prepare(clicked.replaceWith);
280 var closeWith = prepare(clicked.closeWith);
281 var openBlockWith = prepare(clicked.openBlockWith);
282 var closeBlockWith = prepare(clicked.closeBlockWith);
283 var multiline = clicked.multiline;
284
285 if (replaceWith !== "") {
286 block = openWith + replaceWith + closeWith;
287 } else if (selection === '' && placeHolder !== '') {
288 block = openWith + placeHolder + closeWith;
289 } else if (multiline === true) {
290 string = string || selection;
291
292 var lines = selection.split(/\r?\n/), blocks = [];
293
294 for (var l=0; l < lines.length; l++) {
295 line = lines[l];
296 var trailingSpaces;
297 if (trailingSpaces = line.match(/ *$/)) {
298 blocks.push(openWith + line.replace(/ *$/g, '') + closeWith + trailingSpaces);
299 } else {
300 blocks.push(openWith + line + closeWith);
301 }
302 }
303
304 block = blocks.join("\n");
305 } else {
306 block = openWith + (string || selection) + closeWith;
307 }
308
309 block = openBlockWith + block + closeBlockWith;
310
311 return { block:block,
312 openWith:openWith,
313 replaceWith:replaceWith,
314 placeHolder:placeHolder,
315 closeWith:closeWith
316 };
317 }
318
319
320 function selectWord(){
321 selectionBeforeAfter(/\s|[.,;:!¡?¿()]/);
322 selectionSave();
323 }
324 function selectLine(){
325 selectionBeforeAfter(/\r?\n/);
326 selectionSave();
327 }
328
329 function selectionRemoveLast(pattern){
330 // Remove space by default
331 if (!pattern) pattern = /\s/;
332 last = selection[selection.length-1];
333 if (last && last.match(pattern)) {
334 set(caretPosition, selection.length-1);
335 get();
336 $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } );
337 }
338 }
339
340 function selectionBeforeAfter(pattern) {
341 if (!pattern) pattern = /\s/;
342
343 sautAvantIE = sautApresIE = 0;
344 if ($.browser.msie) {
345 // calcul du nombre reel de caracteres pour le substr()
346 // IE ne compte pas les sauts de lignes pour definir les selections
347 // mais les compte dans la fonction length()
348 lenSelection = selection.length - fixIeBug(selection);
349 // si le caractere avant mon debut est un saut le ligne,
350 // ie ne le prendra pas en compte dans la selection.
351 // il faut pouvoir le connaitre.
352 if (caretPosition) {
353 set(caretPosition - 1, 2);
354 sautAvantIE = fixIeBug(document.selection.createRange().text);
355 }
356 // idem pour le caractere apres la ligne !
357 set(caretPosition, 2);
358 sautApresIE = fixIeBug(document.selection.createRange().text);
359 // selection avant
360 set(0,caretPosition);
361 before = document.selection.createRange().text;
362 // selection apres
363 set(caretPosition + lenSelection, textarea.value.length);
364 after = document.selection.createRange().text;
365 // remettre la veritable selection
366 set(caretPosition, lenSelection);
367 selection = document.selection.createRange().text;
368 } else {
369 before = textarea.value.substring(0, caretPosition);
370 after = textarea.value.substring(caretPosition + selection.length - fixIeBug(selection));
371 }
372
373 before = before.split(pattern);
374 after = after.split(pattern);
375 // ajouter ce fichu saut de ligne pour IE
376 if (sautAvantIE) before.push("");
377 if (sautApresIE) after.unshift("");
378
379 }
380
381 function selectionSave(){
382 nb_before = before ? before[before.length-1].length : 0;
383 nb_after = after ? after[0].length : 0;
384
385 nb = nb_before + selection.length + nb_after - fixIeBug(selection);
386 caretPosition = caretPosition - nb_before;
387
388 set(caretPosition, nb);
389 get();
390 $.extend(hash, { selection:selection, caretPosition:caretPosition, scrollPosition:scrollPosition } );
391 }
392
393 // define markup to insert
394 function markup(button) {
395 var len, j, n, i;
396 hash = clicked = button;
397 get();
398
399 $.extend(hash, { line:"",
400 root:options.root,
401 textarea:textarea,
402 selection:(selection||''),
403 caretPosition:caretPosition,
404 ctrlKey:ctrlKey,
405 shiftKey:shiftKey,
406 altKey:altKey
407 }
408 );
409
410 // corrections des selections pour que
411 // - soit le curseur ne change pas
412 // - soit on prend le mot complet (si pas de selection)
413 // - soit on prend la ligne (avant, apres la selection)
414 if (button.selectionType) {
415
416 if (button.selectionType == "word") {
417 if (!selection) {
418 selectWord();
419 } else {
420 // win/ff add space on double click ? (hum, seems strange)
421 selectionRemoveLast(/\s/);
422 }
423 }
424 if (button.selectionType == "line") {
425 selectLine();
426 }
427 // horrible chose, mais tellement plus pratique
428 // car on ne peut pas de l'exerieur (json) utiliser
429 // les fonctions internes de markitup
430 if (button.selectionType == "return"){
431 // le calcul de before et after sous IE
432 // necessitant de creer des selections
433 // c'est extremement vilain a chaque saut de ligne
434 // des qu'il y a un texte volumineux.
435 // on dit tant pis pour lui.
436 if (!$.browser.msie) {
437 selectionBeforeAfter(/\r?\n/);
438 before_last = before[before.length-1];
439 after = '';
440 // gestion des listes -# et -*
441 if (r = before_last.match(/^-([*#]+) ?(.*)$/)) {
442 if (r[2]) {
443 button.replaceWith = "\n-"+r[1]+' ';
444 before_last = '';
445 } else {
446 // supprime le -* present
447 // (before le fera)
448 button.replaceWith = "\n";
449 }
450 } else {
451 before_last = '';
452 button.replaceWith = "\n";
453 }
454 before[before.length-1] = before_last;
455 selectionSave();
456 }
457 }
458 }
459 // / fin corrections
460
461 // callbacks before insertion
462 prepare(options.beforeInsert);
463 prepare(clicked.beforeInsert);
464 if ((ctrlKey === true && shiftKey === true) || button.multiline === true) {
465 prepare(clicked.beforeMultiInsert);
466 }
467 $.extend(hash, { line:1 });
468
469 if ((ctrlKey === true && shiftKey === true) || button.forceMultiline === true) {
470 lines = selection.split(/\r?\n/);
471 for (j = 0, n = lines.length, i = 0; i < n; i++) {
472 // si une seule ligne, on se fiche de savoir qu'elle est vide,
473 // c'est volontaire si on clique le bouton
474 if (n == 1 || $.trim(lines[i]) !== '') {
475 $.extend(hash, { line:++j, selection:lines[i] } );
476 lines[i] = build(lines[i]).block;
477 } else {
478 lines[i] = "";
479 }
480 }
481 string = { block:lines.join('\n')};
482 start = caretPosition;
483 len = string.block.length + (($.browser.opera) ? n-1 : 0);
484 } else if (ctrlKey === true) {
485 string = build(selection);
486 start = caretPosition + string.openWith.length;
487 len = string.block.length - string.openWith.length - string.closeWith.length;
488 len = len - (string.block.match(/ $/) ? 1 : 0);
489 len -= fixIeBug(string.block);
490 } else if (shiftKey === true) {
491 string = build(selection);
492 start = caretPosition;
493 len = string.block.length;
494 len -= fixIeBug(string.block);
495 } else {
496 string = build(selection);
497 start = caretPosition + string.block.length ;
498 len = 0;
499 start -= fixIeBug(string.block);
500 }
501
502 if ((selection === '' && string.replaceWith === '')) {
503 caretOffset += fixOperaBug(string.block);
504
505 start = caretPosition + string.openWith.length;
506 len = string.block.length - string.openWith.length - string.closeWith.length;
507
508 caretOffset = $$.val().substring(caretPosition, $$.val().length).length;
509 caretOffset -= fixOperaBug($$.val().substring(0, caretPosition));
510 }
511 $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } );
512
513 if (string.block !== selection && abort === false) {
514 insert(string.block);
515 set(start, len);
516 } else {
517 caretOffset = -1;
518 }
519 get();
520
521 $.extend(hash, { line:'', selection:selection });
522
523 // callbacks after insertion
524 if ((ctrlKey === true && shiftKey === true) || button.multiline === true) {
525 prepare(clicked.afterMultiInsert);
526 }
527
528 prepare(clicked.afterInsert);
529 prepare(options.afterInsert);
530
531 // refresh preview if opened
532 if (previewWindow && options.previewAutoRefresh) {
533 refreshPreview();
534 }
535
536 // reinit keyevent
537 shiftKey = altKey = ctrlKey = abort = false;
538
539 }
540
541 // Substract linefeed in Opera
542 function fixOperaBug(string) {
543 if ($.browser.opera) {
544 return string.length - string.replace(/\n*/g, '').length;
545 }
546 return 0;
547 }
548 // Substract linefeed in IE
549 function fixIeBug(string) {
550 if ($.browser.msie) {
551 return string.length - string.replace(/\r*/g, '').length;
552 }
553 return 0;
554 }
555
556 // add markup
557 function insert(block) {
558 if (document.selection) {
559 var newSelection = document.selection.createRange();
560 newSelection.text = block;
561 } else {
562 textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length);
563 }
564 }
565
566 // set a selection
567 function set(start, len) {
568 if (textarea.createTextRange){
569 // quick fix to make it work on Opera 9.5
570 if ($.browser.opera && $.browser.version >= 9.5 && len == 0) {
571 return false;
572 }
573 range = textarea.createTextRange();
574 range.collapse(true);
575 range.moveStart('character', start);
576 range.moveEnd('character', len);
577 range.select();
578 } else if (textarea.setSelectionRange ){
579 textarea.setSelectionRange(start, start + len);
580 }
581 textarea.scrollTop = scrollPosition;
582 textarea.focus();
583 }
584
585 // get the selection
586 function get() {
587 textarea.focus();
588
589 scrollPosition = textarea.scrollTop;
590 if (document.selection) {
591 selection = document.selection.createRange().text;
592 if ($.browser.msie) { // ie
593 var range = document.selection.createRange(), rangeCopy = range.duplicate();
594 rangeCopy.moveToElementText(textarea);
595 caretPosition = -1;
596 while(rangeCopy.inRange(range)) {
597 rangeCopy.moveStart('character');
598 caretPosition ++;
599 }
600 } else { // opera
601 caretPosition = textarea.selectionStart;
602 }
603 } else { // gecko & webkit
604 caretPosition = textarea.selectionStart;
605 selection = textarea.value.substring(caretPosition, textarea.selectionEnd);
606
607 }
608 return selection;
609 }
610
611 // open preview window
612 function preview() {
613 if (!previewWindow || previewWindow.closed) {
614 if (options.previewInWindow) {
615 previewWindow = window.open('', 'preview', options.previewInWindow);
616 $(window).unload(function() {
617 previewWindow.close();
618 });
619 } else {
620 iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>');
621 if (options.previewPosition == 'after') {
622 iFrame.insertAfter(footer);
623 } else {
624 iFrame.insertBefore(header);
625 }
626 previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1];
627 }
628 } else if (altKey === true) {
629 if (iFrame) {
630 iFrame.remove();
631 } else {
632 previewWindow.close();
633 }
634 previewWindow = iFrame = false;
635 }
636 if (!options.previewAutoRefresh) {
637 refreshPreview();
638 }
639 if (options.previewInWindow) {
640 previewWindow.focus();
641 }
642 }
643
644 // refresh Preview window
645 function refreshPreview() {
646 renderPreview();
647 }
648
649 function renderPreview() {
650 var phtml;
651 if (options.previewParser && typeof options.previewParser === 'function') {
652 var data = options.previewParser( $$.val() );
653 writeInPreview( localize(data, 1) );
654 } else if (options.previewParserPath !== '') {
655 $.ajax({
656 type: 'POST',
657 dataType: 'text',
658 global: false,
659 url: options.previewParserPath,
660 data: options.previewParserVar+'='+encodeURIComponent($$.val()),
661 success: function(data) {
662 writeInPreview( localize(data, 1) );
663 }
664 });
665 } else {
666 if (!template) {
667 $.ajax( {
668 url: options.previewTemplatePath,
669 dataType: 'text',
670 global: false,
671 success: function(data) {
672 writeInPreview( localize(data, 1).replace(/<!-- content -->/g, $$.val()) );
673 }
674 });
675 }
676 }
677 return false;
678 }
679
680 function writeInPreview(data) {
681 if (previewWindow.document) {
682 try {
683 sp = previewWindow.document.documentElement.scrollTop
684 } catch(e) {
685 sp = 0;
686 }
687 previewWindow.document.open();
688 previewWindow.document.write(data);
689 previewWindow.document.close();
690 previewWindow.document.documentElement.scrollTop = sp;
691 }
692 }
693
694 // set keys pressed
695 function keyPressed(e) {
696 shiftKey = e.shiftKey;
697 altKey = e.altKey;
698 ctrlKey = (!(e.altKey && e.ctrlKey)) ? (e.ctrlKey || e.metaKey) : false;
699
700 if (e.type === 'keydown') {
701 if (ctrlKey === true) {
702 li = $('a[accesskey="'+String.fromCharCode(e.keyCode)+'"]', header).parent('li');
703 if (li.length !== 0) {
704 ctrlKey = false;
705 setTimeout(function() {
706 li.triggerHandler('mouseup');
707 },1);
708 return false;
709 }
710 }
711
712 // si opera, on s'embete pas, il cree plus de problemes qu'autre chose
713 // car il ne prend pas en compte l'arret de ces evenements
714 if (!$.browser.opera) {
715 if (e.keyCode === 13 || e.keyCode === 10) { // Enter key
716 if (ctrlKey === true) { // Enter + Ctrl
717 ctrlKey = false;
718 markup(options.onCtrlEnter);
719 return options.onCtrlEnter.keepDefault;
720 } else if (shiftKey === true) { // Enter + Shift
721 shiftKey = false;
722 markup(options.onShiftEnter);
723 return options.onShiftEnter.keepDefault;
724 } else { // only Enter
725 markup(options.onEnter);
726 return options.onEnter.keepDefault;
727 }
728 }
729
730 if (e.keyCode === 9) { // Tab key
731 if (shiftKey == true || ctrlKey == true || altKey == true) {
732 // permettre un retour a l'action naturelle
733 // du navigateur via shift+tab
734 return true;
735 }
736 if (caretOffset !== -1) {
737 get();
738 caretOffset = $$.val().length - caretOffset;
739 set(caretOffset, 0);
740 caretOffset = -1;
741 return false;
742 } else {
743 markup(options.onTab);
744 return options.onTab.keepDefault;
745 }
746 }
747 }
748 }
749 }
750
751 init();
752 });
753 };
754
755 $.fn.markItUpRemove = function() {
756 return this.each(function() {
757 var $$ = $(this).unbind().removeClass('markItUpEditor');
758 $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$);
759 }
760 );
761 };
762
763 $.markItUp = function(settings) {
764 var options = { target:false };
765 $.extend(options, settings);
766 if (options.target) {
767 return $(options.target).each(function() {
768 $(this).focus();
769 $(this).trigger('insertion', [options]);
770 });
771 } else {
772 $('textarea').trigger('insertion', [options]);
773 }
774 };
775
776 })(jQuery);