trumbowyg2-rails 2.1.0 → 2.1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. metadata +3 -43
  3. data/README.md +0 -43
  4. data/VERSION +0 -1
  5. data/lib/trumbowyg2-rails.rb +0 -4
  6. data/trumbowyg2-rails.gemspec +0 -19
  7. data/vendor/assets/images/trumbowyg/images/icons.svg +0 -1
  8. data/vendor/assets/javascripts/trumbowyg/langs/ar.js +0 -56
  9. data/vendor/assets/javascripts/trumbowyg/langs/ca.js +0 -57
  10. data/vendor/assets/javascripts/trumbowyg/langs/cs.js +0 -54
  11. data/vendor/assets/javascripts/trumbowyg/langs/da.js +0 -55
  12. data/vendor/assets/javascripts/trumbowyg/langs/de.js +0 -55
  13. data/vendor/assets/javascripts/trumbowyg/langs/el.js +0 -58
  14. data/vendor/assets/javascripts/trumbowyg/langs/en.js +0 -14
  15. data/vendor/assets/javascripts/trumbowyg/langs/es.js +0 -55
  16. data/vendor/assets/javascripts/trumbowyg/langs/es_ar.js +0 -56
  17. data/vendor/assets/javascripts/trumbowyg/langs/fa.js +0 -56
  18. data/vendor/assets/javascripts/trumbowyg/langs/fi.js +0 -55
  19. data/vendor/assets/javascripts/trumbowyg/langs/fr.js +0 -63
  20. data/vendor/assets/javascripts/trumbowyg/langs/he.js +0 -57
  21. data/vendor/assets/javascripts/trumbowyg/langs/hu.js +0 -58
  22. data/vendor/assets/javascripts/trumbowyg/langs/id.js +0 -57
  23. data/vendor/assets/javascripts/trumbowyg/langs/it.js +0 -54
  24. data/vendor/assets/javascripts/trumbowyg/langs/ja.js +0 -56
  25. data/vendor/assets/javascripts/trumbowyg/langs/ko.js +0 -56
  26. data/vendor/assets/javascripts/trumbowyg/langs/my.js +0 -54
  27. data/vendor/assets/javascripts/trumbowyg/langs/nl.js +0 -56
  28. data/vendor/assets/javascripts/trumbowyg/langs/pl.js +0 -55
  29. data/vendor/assets/javascripts/trumbowyg/langs/pt.js +0 -57
  30. data/vendor/assets/javascripts/trumbowyg/langs/ro.js +0 -58
  31. data/vendor/assets/javascripts/trumbowyg/langs/rs.js +0 -53
  32. data/vendor/assets/javascripts/trumbowyg/langs/rs_latin.js +0 -54
  33. data/vendor/assets/javascripts/trumbowyg/langs/ru.js +0 -54
  34. data/vendor/assets/javascripts/trumbowyg/langs/sk.js +0 -54
  35. data/vendor/assets/javascripts/trumbowyg/langs/sv.js +0 -55
  36. data/vendor/assets/javascripts/trumbowyg/langs/tr.js +0 -55
  37. data/vendor/assets/javascripts/trumbowyg/langs/ua.js +0 -54
  38. data/vendor/assets/javascripts/trumbowyg/langs/vi.js +0 -55
  39. data/vendor/assets/javascripts/trumbowyg/langs/zh_cn.js +0 -57
  40. data/vendor/assets/javascripts/trumbowyg/langs/zh_tw.js +0 -57
  41. data/vendor/assets/javascripts/trumbowyg/trumbowyg.js +0 -1522
  42. data/vendor/assets/stylesheets/trumbowyg/trumbowyg.scss +0 -758
@@ -1,1522 +0,0 @@
1
- jQuery.trumbowyg = {
2
- langs: {
3
- en: {
4
- viewHTML: 'View HTML',
5
-
6
- undo: 'Undo',
7
- redo: 'Redo',
8
-
9
- formatting: 'Formatting',
10
- p: 'Paragraph',
11
- blockquote: 'Quote',
12
- code: 'Code',
13
- header: 'Header',
14
-
15
- bold: 'Bold',
16
- italic: 'Italic',
17
- strikethrough: 'Stroke',
18
- underline: 'Underline',
19
-
20
- strong: 'Strong',
21
- em: 'Emphasis',
22
- del: 'Deleted',
23
-
24
- superscript: 'Superscript',
25
- subscript: 'Subscript',
26
-
27
- unorderedList: 'Unordered list',
28
- orderedList: 'Ordered list',
29
-
30
- insertImage: 'Insert Image',
31
- link: 'Link',
32
- createLink: 'Insert link',
33
- unlink: 'Remove link',
34
-
35
- justifyLeft: 'Align Left',
36
- justifyCenter: 'Align Center',
37
- justifyRight: 'Align Right',
38
- justifyFull: 'Align Justify',
39
-
40
- horizontalRule: 'Insert horizontal rule',
41
- removeformat: 'Remove format',
42
-
43
- fullscreen: 'Fullscreen',
44
-
45
- close: 'Close',
46
-
47
- submit: 'Confirm',
48
- reset: 'Cancel',
49
-
50
- required: 'Required',
51
- description: 'Description',
52
- title: 'Title',
53
- text: 'Text',
54
- target: 'Target'
55
- }
56
- },
57
-
58
- // Plugins
59
- plugins: {},
60
-
61
- // SVG Path globally
62
- svgPath: null
63
- };
64
-
65
-
66
- (function (navigator, window, document, $) {
67
- 'use strict';
68
-
69
- $.fn.trumbowyg = function (options, params) {
70
- var trumbowygDataName = 'trumbowyg';
71
- if (options === Object(options) || !options) {
72
- return this.each(function () {
73
- if (!$(this).data(trumbowygDataName)) {
74
- $(this).data(trumbowygDataName, new Trumbowyg(this, options));
75
- }
76
- });
77
- }
78
- if (this.length === 1) {
79
- try {
80
- var t = $(this).data(trumbowygDataName);
81
- switch (options) {
82
- // Exec command
83
- case 'execCmd':
84
- return t.execCmd(params.cmd, params.param, params.forceCss);
85
-
86
- // Modal box
87
- case 'openModal':
88
- return t.openModal(params.title, params.content);
89
- case 'closeModal':
90
- return t.closeModal();
91
- case 'openModalInsert':
92
- return t.openModalInsert(params.title, params.fields, params.callback);
93
-
94
- // Range
95
- case 'saveRange':
96
- return t.saveRange();
97
- case 'getRange':
98
- return t.range;
99
- case 'getRangeText':
100
- return t.getRangeText();
101
- case 'restoreRange':
102
- return t.restoreRange();
103
-
104
- // Enable/disable
105
- case 'enable':
106
- return t.toggleDisable(false);
107
- case 'disable':
108
- return t.toggleDisable(true);
109
-
110
- // Destroy
111
- case 'destroy':
112
- return t.destroy();
113
-
114
- // Empty
115
- case 'empty':
116
- return t.empty();
117
-
118
- // HTML
119
- case 'html':
120
- return t.html(params);
121
- }
122
- } catch (c) {
123
- }
124
- }
125
-
126
- return false;
127
- };
128
-
129
- // @param: editorElem is the DOM element
130
- var Trumbowyg = function (editorElem, options) {
131
- var t = this,
132
- trumbowygIconsId = 'trumbowyg-icons';
133
-
134
- // Get the document of the element. It use to makes the plugin
135
- // compatible on iframes.
136
- t.doc = editorElem.ownerDocument || document;
137
-
138
- // jQuery object of the editor
139
- t.$ta = $(editorElem); // $ta : Textarea
140
- t.$c = $(editorElem); // $c : creator
141
-
142
- options = options || {};
143
-
144
- // Localization management
145
- if (options.lang != null || $.trumbowyg.langs[options.lang] != null) {
146
- t.lang = $.extend(true, {}, $.trumbowyg.langs.en, $.trumbowyg.langs[options.lang]);
147
- } else {
148
- t.lang = $.trumbowyg.langs.en;
149
- }
150
-
151
- // SVG path
152
- var svgPathOption = $.trumbowyg.svgPath != null ? $.trumbowyg.svgPath : options.svgPath;
153
- t.hasSvg = svgPathOption !== false;
154
- t.svgPath = !!t.doc.querySelector('base') ? window.location : '';
155
- if ($('#' + trumbowygIconsId, t.doc).length === 0 && svgPathOption !== false) {
156
- if (svgPathOption == null) {
157
- try {
158
- throw new Error();
159
- } catch (e) {
160
- var stackLines = e.stack.split('\n');
161
-
162
- for (var i in stackLines) {
163
- if (!stackLines[i].match(/http[s]?:\/\//)) {
164
- continue;
165
- }
166
- svgPathOption = stackLines[Number(i)].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/)[1].split('/');
167
- svgPathOption.pop();
168
- svgPathOption = svgPathOption.join('/') + '/ui/icons.svg';
169
- break;
170
- }
171
- }
172
- }
173
-
174
- var div = t.doc.createElement('div');
175
- div.id = trumbowygIconsId;
176
- t.doc.body.insertBefore(div, t.doc.body.childNodes[0]);
177
- $.get(svgPathOption, function (data) {
178
- div.innerHTML = new XMLSerializer().serializeToString(data.documentElement);
179
- });
180
- }
181
-
182
-
183
- /**
184
- * When the button is associated to a empty object
185
- * fn and title attributs are defined from the button key value
186
- *
187
- * For example
188
- * foo: {}
189
- * is equivalent to :
190
- * foo: {
191
- * fn: 'foo',
192
- * title: this.lang.foo
193
- * }
194
- */
195
- var h = t.lang.header, // Header translation
196
- isBlinkFunction = function () {
197
- return (window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window;
198
- };
199
- t.btnsDef = {
200
- viewHTML: {
201
- fn: 'toggle'
202
- },
203
-
204
- undo: {
205
- isSupported: isBlinkFunction,
206
- key: 'Z'
207
- },
208
- redo: {
209
- isSupported: isBlinkFunction,
210
- key: 'Y'
211
- },
212
-
213
- p: {
214
- fn: 'formatBlock'
215
- },
216
- blockquote: {
217
- fn: 'formatBlock'
218
- },
219
- h1: {
220
- fn: 'formatBlock',
221
- title: h + ' 1'
222
- },
223
- h2: {
224
- fn: 'formatBlock',
225
- title: h + ' 2'
226
- },
227
- h3: {
228
- fn: 'formatBlock',
229
- title: h + ' 3'
230
- },
231
- h4: {
232
- fn: 'formatBlock',
233
- title: h + ' 4'
234
- },
235
- subscript: {
236
- tag: 'sub'
237
- },
238
- superscript: {
239
- tag: 'sup'
240
- },
241
-
242
- bold: {
243
- key: 'B'
244
- },
245
- italic: {
246
- key: 'I'
247
- },
248
- underline: {
249
- tag: 'u'
250
- },
251
- strikethrough: {
252
- tag: 'strike'
253
- },
254
-
255
- strong: {
256
- fn: 'bold',
257
- key: 'B'
258
- },
259
- em: {
260
- fn: 'italic',
261
- key: 'I'
262
- },
263
- del: {
264
- fn: 'strikethrough'
265
- },
266
-
267
- createLink: {
268
- key: 'K',
269
- tag: 'a'
270
- },
271
- unlink: {},
272
-
273
- insertImage: {},
274
-
275
- justifyLeft: {
276
- tag: 'left',
277
- forceCss: true
278
- },
279
- justifyCenter: {
280
- tag: 'center',
281
- forceCss: true
282
- },
283
- justifyRight: {
284
- tag: 'right',
285
- forceCss: true
286
- },
287
- justifyFull: {
288
- tag: 'justify',
289
- forceCss: true
290
- },
291
-
292
- unorderedList: {
293
- fn: 'insertUnorderedList',
294
- tag: 'ul'
295
- },
296
- orderedList: {
297
- fn: 'insertOrderedList',
298
- tag: 'ol'
299
- },
300
-
301
- horizontalRule: {
302
- fn: 'insertHorizontalRule'
303
- },
304
-
305
- removeformat: {},
306
-
307
- fullscreen: {
308
- class: 'trumbowyg-not-disable'
309
- },
310
- close: {
311
- fn: 'destroy',
312
- class: 'trumbowyg-not-disable'
313
- },
314
-
315
- // Dropdowns
316
- formatting: {
317
- dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4'],
318
- ico: 'p'
319
- },
320
- link: {
321
- dropdown: ['createLink', 'unlink']
322
- }
323
- };
324
-
325
- // Defaults Options
326
- t.o = $.extend(true, {}, {
327
- lang: 'en',
328
-
329
- fixedBtnPane: false,
330
- fixedFullWidth: false,
331
- autogrow: false,
332
-
333
- prefix: 'trumbowyg-',
334
-
335
- semantic: true,
336
- resetCss: false,
337
- removeformatPasted: false,
338
- tagsToRemove: [],
339
-
340
- btnsGrps: {
341
- design: ['bold', 'italic', 'underline', 'strikethrough'],
342
- semantic: ['strong', 'em', 'del'],
343
- justify: ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
344
- lists: ['unorderedList', 'orderedList']
345
- },
346
- btns: [
347
- ['viewHTML'],
348
- ['undo', 'redo'],
349
- ['formatting'],
350
- 'btnGrp-semantic',
351
- ['superscript', 'subscript'],
352
- ['link'],
353
- ['insertImage'],
354
- 'btnGrp-justify',
355
- 'btnGrp-lists',
356
- ['horizontalRule'],
357
- ['removeformat'],
358
- ['fullscreen']
359
- ],
360
- // For custom button definitions
361
- btnsDef: {},
362
-
363
- inlineElementsSelector: 'a,abbr,acronym,b,caption,cite,code,col,dfn,dir,dt,dd,em,font,hr,i,kbd,li,q,span,strikeout,strong,sub,sup,u',
364
-
365
- pasteHandlers: [],
366
-
367
- imgDblClickHandler: function () {
368
- var $img = $(this),
369
- src = $img.attr('src'),
370
- base64 = '(Base64)';
371
-
372
- if (src.indexOf('data:image') === 0) {
373
- src = base64;
374
- }
375
-
376
- t.openModalInsert(t.lang.insertImage, {
377
- url: {
378
- label: 'URL',
379
- value: src,
380
- required: true
381
- },
382
- alt: {
383
- label: t.lang.description,
384
- value: $img.attr('alt')
385
- }
386
- }, function (v) {
387
- if (v.src !== base64) {
388
- $img.attr({
389
- src: v.src
390
- });
391
- }
392
- $img.attr({
393
- alt: v.alt
394
- });
395
- return true;
396
- });
397
- return false;
398
- },
399
-
400
- plugins: {}
401
- }, options);
402
-
403
- t.disabled = t.o.disabled || (editorElem.nodeName === 'TEXTAREA' && editorElem.disabled);
404
-
405
- if (options.btns) {
406
- t.o.btns = options.btns;
407
- } else if (!t.o.semantic) {
408
- t.o.btns[4] = 'btnGrp-design';
409
- }
410
-
411
- $.each(t.o.btnsDef, function (btnName, btnDef) {
412
- t.addBtnDef(btnName, btnDef);
413
- });
414
-
415
- // Keyboard shortcuts are load in this array
416
- t.keys = [];
417
-
418
- // Tag to button dynamically hydrated
419
- t.tagToButton = {};
420
- t.tagHandlers = [];
421
-
422
- // Admit multiple paste handlers
423
- t.pasteHandlers = [].concat(t.o.pasteHandlers);
424
-
425
- t.init();
426
- };
427
-
428
- Trumbowyg.prototype = {
429
- init: function () {
430
- var t = this;
431
- t.height = t.$ta.height();
432
-
433
- t.initPlugins();
434
-
435
- // Disable image resize in Firefox
436
- t.doc.execCommand('enableObjectResizing', false, false);
437
- t.doc.execCommand('defaultParagraphSeparator', false, 'p');
438
-
439
- t.buildEditor();
440
- t.buildBtnPane();
441
-
442
- t.fixedBtnPaneEvents();
443
-
444
- t.buildOverlay();
445
-
446
- setTimeout(function () {
447
- if (t.disabled) {
448
- t.toggleDisable(true);
449
- }
450
- t.$c.trigger('tbwinit');
451
- });
452
- },
453
-
454
- addBtnDef: function (btnName, btnDef) {
455
- this.btnsDef[btnName] = btnDef;
456
- },
457
-
458
- buildEditor: function () {
459
- var t = this,
460
- prefix = t.o.prefix,
461
- html = '';
462
-
463
- t.$box = $('<div/>', {
464
- class: prefix + 'box ' + prefix + 'editor-visible ' + prefix + t.o.lang + ' trumbowyg'
465
- });
466
-
467
- // $ta = Textarea
468
- // $ed = Editor
469
- t.isTextarea = t.$ta.is('textarea');
470
- if (t.isTextarea) {
471
- html = t.$ta.val();
472
- t.$ed = $('<div/>');
473
- t.$box
474
- .insertAfter(t.$ta)
475
- .append(t.$ed, t.$ta);
476
- } else {
477
- t.$ed = t.$ta;
478
- html = t.$ed.html();
479
-
480
- t.$ta = $('<textarea/>', {
481
- name: t.$ta.attr('id'),
482
- height: t.height
483
- }).val(html);
484
-
485
- t.$box
486
- .insertAfter(t.$ed)
487
- .append(t.$ta, t.$ed);
488
- t.syncCode();
489
- }
490
-
491
- t.$ta
492
- .addClass(prefix + 'textarea')
493
- .attr('tabindex', -1)
494
- ;
495
-
496
- t.$ed
497
- .addClass(prefix + 'editor')
498
- .attr({
499
- contenteditable: true,
500
- dir: t.lang._dir || 'ltr'
501
- })
502
- .html(html)
503
- ;
504
-
505
- if (t.o.tabindex) {
506
- t.$ed.attr('tabindex', t.o.tabindex);
507
- }
508
-
509
- if (t.$c.is('[placeholder]')) {
510
- t.$ed.attr('placeholder', t.$c.attr('placeholder'));
511
- }
512
-
513
- if (t.o.resetCss) {
514
- t.$ed.addClass(prefix + 'reset-css');
515
- }
516
-
517
- if (!t.o.autogrow) {
518
- t.$ta.add(t.$ed).css({
519
- height: t.height
520
- });
521
- }
522
-
523
- t.semanticCode();
524
-
525
-
526
- t._ctrl = false;
527
- t.$ed
528
- .on('dblclick', 'img', t.o.imgDblClickHandler)
529
- .on('keydown', function (e) {
530
- t._composition = (e.which === 229);
531
-
532
- if (e.ctrlKey) {
533
- t._ctrl = true;
534
- var k = t.keys[String.fromCharCode(e.which).toUpperCase()];
535
-
536
- try {
537
- t.execCmd(k.fn, k.param);
538
- return false;
539
- } catch (c) {
540
- }
541
- }
542
- })
543
- .on('keyup', function (e) {
544
- if (e.which >= 37 && e.which <= 40) {
545
- return;
546
- }
547
-
548
- if (e.ctrlKey && (e.which === 89 || e.which === 90)) {
549
- t.$c.trigger('tbwchange');
550
- } else if (!t._ctrl && e.which !== 17 && !t._composition) {
551
- t.semanticCode(false, e.which === 13);
552
- t.$c.trigger('tbwchange');
553
- }
554
-
555
- setTimeout(function () {
556
- t._ctrl = false;
557
- }, 200);
558
- })
559
- .on('mouseup keydown keyup', function () {
560
- t.updateButtonPaneStatus();
561
- })
562
- .on('focus blur', function (e) {
563
- t.$c.trigger('tbw' + e.type);
564
- if (e.type === 'blur') {
565
- $('.' + prefix + 'active-button', t.$btnPane).removeClass(prefix + 'active-button ' + prefix + 'active');
566
- }
567
- })
568
- .on('cut', function () {
569
- t.$c.trigger('tbwchange');
570
- })
571
- .on('paste', function (e) {
572
- if (t.o.removeformatPasted) {
573
- e.preventDefault();
574
-
575
- try {
576
- // IE
577
- var text = window.clipboardData.getData('Text');
578
-
579
- try {
580
- // <= IE10
581
- t.doc.selection.createRange().pasteHTML(text);
582
- } catch (c) {
583
- // IE 11
584
- t.doc.getSelection().getRangeAt(0).insertNode(t.doc.createTextNode(text));
585
- }
586
- } catch (d) {
587
- // Not IE
588
- t.execCmd('insertText', (e.originalEvent || e).clipboardData.getData('text/plain'));
589
- }
590
- }
591
-
592
- // Call pasteHandlers
593
- $.each(t.pasteHandlers, function (i, pasteHandler) {
594
- pasteHandler(e);
595
- });
596
-
597
- setTimeout(function () {
598
- if (t.o.semantic) {
599
- t.semanticCode(false, true);
600
- } else {
601
- t.syncCode();
602
- }
603
- t.$c.trigger('tbwpaste', e);
604
- }, 0);
605
- });
606
- t.$ta.on('keyup paste', function () {
607
- t.$c.trigger('tbwchange');
608
- });
609
-
610
- $(t.doc).on('keydown', function (e) {
611
- if (e.which === 27) {
612
- t.closeModal();
613
- return false;
614
- }
615
- });
616
- },
617
-
618
-
619
- // Build button pane, use o.btns option
620
- buildBtnPane: function () {
621
- var t = this,
622
- prefix = t.o.prefix;
623
-
624
- var $btnPane = t.$btnPane = $('<div/>', {
625
- class: prefix + 'button-pane'
626
- });
627
-
628
- $.each(t.o.btns, function (i, btnGrps) {
629
- // Managment of group of buttons
630
- try {
631
- var b = btnGrps.split('btnGrp-');
632
- if (b[1] != null) {
633
- btnGrps = t.o.btnsGrps[b[1]];
634
- }
635
- } catch (c) {
636
- }
637
-
638
- if (!$.isArray(btnGrps)) {
639
- btnGrps = [btnGrps];
640
- }
641
-
642
- var $btnGroup = $('<div/>', {
643
- class: prefix + 'button-group ' + ((btnGrps.indexOf('fullscreen') >= 0) ? prefix + 'right' : '')
644
- });
645
- $.each(btnGrps, function (i, btn) {
646
- try { // Prevent buildBtn error
647
- var $item;
648
-
649
- if (t.isSupportedBtn(btn)) { // It's a supported button
650
- $item = t.buildBtn(btn);
651
- }
652
-
653
- $btnGroup.append($item);
654
- } catch (c) {
655
- }
656
- });
657
- $btnPane.append($btnGroup);
658
- });
659
-
660
- t.$box.prepend($btnPane);
661
- },
662
-
663
-
664
- // Build a button and his action
665
- buildBtn: function (btnName) { // btnName is name of the button
666
- var t = this,
667
- prefix = t.o.prefix,
668
- btn = t.btnsDef[btnName],
669
- isDropdown = btn.dropdown,
670
- textDef = t.lang[btnName] || btnName,
671
-
672
- $btn = $('<button/>', {
673
- type: 'button',
674
- class: prefix + btnName + '-button ' + (btn.class || ''),
675
- html: t.hasSvg ? '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' : '',
676
- title: (btn.title || btn.text || textDef) + ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : ''),
677
- tabindex: -1,
678
- mousedown: function () {
679
- if (!isDropdown || $('.' + btnName + '-' + prefix + 'dropdown', t.$box).is(':hidden')) {
680
- $('body', t.doc).trigger('mousedown');
681
- }
682
-
683
- if (t.$btnPane.hasClass(prefix + 'disable') && !$(this).hasClass(prefix + 'active') && !$(this).hasClass(prefix + 'not-disable')) {
684
- return false;
685
- }
686
-
687
- t.execCmd((isDropdown ? 'dropdown' : false) || btn.fn || btnName, btn.param || btnName, btn.forceCss || false);
688
-
689
- return false;
690
- }
691
- });
692
-
693
- if (isDropdown) {
694
- $btn.addClass(prefix + 'open-dropdown');
695
- var dropdownPrefix = prefix + 'dropdown',
696
- $dropdown = $('<div/>', { // the dropdown
697
- class: dropdownPrefix + '-' + btnName + ' ' + dropdownPrefix + ' ' + prefix + 'fixed-top',
698
- 'data-dropdown': btnName
699
- });
700
- $.each(isDropdown, function (i, def) {
701
- if (t.btnsDef[def] && t.isSupportedBtn(def)) {
702
- $dropdown.append(t.buildSubBtn(def));
703
- }
704
- });
705
- t.$box.append($dropdown.hide());
706
- } else if (btn.key) {
707
- t.keys[btn.key] = {
708
- fn: btn.fn || btnName,
709
- param: btn.param || btnName
710
- };
711
- }
712
-
713
- if (!isDropdown) {
714
- t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName;
715
- }
716
-
717
- return $btn;
718
- },
719
- // Build a button for dropdown menu
720
- // @param n : name of the subbutton
721
- buildSubBtn: function (btnName) {
722
- var t = this,
723
- prefix = t.o.prefix,
724
- btn = t.btnsDef[btnName];
725
-
726
- if (btn.key) {
727
- t.keys[btn.key] = {
728
- fn: btn.fn || btnName,
729
- param: btn.param || btnName
730
- };
731
- }
732
-
733
- t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName;
734
-
735
- return $('<button/>', {
736
- type: 'button',
737
- class: prefix + btnName + '-dropdown-button' + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''),
738
- html: t.hasSvg ? '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' + (btn.text || btn.title || t.lang[btnName] || btnName) : '',
739
- title: ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : null),
740
- style: btn.style || null,
741
- mousedown: function () {
742
- $('body', t.doc).trigger('mousedown');
743
-
744
- t.execCmd(btn.fn || btnName, btn.param || btnName, btn.forceCss || false);
745
-
746
- return false;
747
- }
748
- });
749
- },
750
- // Check if button is supported
751
- isSupportedBtn: function (b) {
752
- try {
753
- return this.btnsDef[b].isSupported();
754
- } catch (c) {
755
- }
756
- return true;
757
- },
758
-
759
- // Build overlay for modal box
760
- buildOverlay: function () {
761
- var t = this;
762
- t.$overlay = $('<div/>', {
763
- class: t.o.prefix + 'overlay'
764
- }).css({
765
- top: t.$btnPane.outerHeight(),
766
- height: (t.$ed.outerHeight() + 1) + 'px'
767
- }).appendTo(t.$box);
768
- return t.$overlay;
769
- },
770
- showOverlay: function () {
771
- var t = this;
772
- $(window).trigger('scroll');
773
- t.$overlay.fadeIn(200);
774
- t.$box.addClass(t.o.prefix + 'box-blur');
775
- },
776
- hideOverlay: function () {
777
- var t = this;
778
- t.$overlay.fadeOut(50);
779
- t.$box.removeClass(t.o.prefix + 'box-blur');
780
- },
781
-
782
- // Management of fixed button pane
783
- fixedBtnPaneEvents: function () {
784
- var t = this,
785
- fixedFullWidth = t.o.fixedFullWidth,
786
- $box = t.$box;
787
-
788
- if (!t.o.fixedBtnPane) {
789
- return;
790
- }
791
-
792
- t.isFixed = false;
793
-
794
- $(window)
795
- .on('scroll resize', function () {
796
- if (!$box) {
797
- return;
798
- }
799
-
800
- t.syncCode();
801
-
802
- var scrollTop = $(window).scrollTop(),
803
- offset = $box.offset().top + 1,
804
- bp = t.$btnPane,
805
- oh = bp.outerHeight() - 2;
806
-
807
- if ((scrollTop - offset > 0) && ((scrollTop - offset - t.height) < 0)) {
808
- if (!t.isFixed) {
809
- t.isFixed = true;
810
- bp.css({
811
- position: 'fixed',
812
- top: 0,
813
- left: fixedFullWidth ? '0' : 'auto',
814
- zIndex: 7
815
- });
816
- $([t.$ta, t.$ed]).css({marginTop: bp.height()});
817
- }
818
- bp.css({
819
- width: fixedFullWidth ? '100%' : (($box.width() - 1) + 'px')
820
- });
821
-
822
- $('.' + t.o.prefix + 'fixed-top', $box).css({
823
- position: fixedFullWidth ? 'fixed' : 'absolute',
824
- top: fixedFullWidth ? oh : oh + (scrollTop - offset) + 'px',
825
- zIndex: 15
826
- });
827
- } else if (t.isFixed) {
828
- t.isFixed = false;
829
- bp.removeAttr('style');
830
- $([t.$ta, t.$ed]).css({marginTop: 0});
831
- $('.' + t.o.prefix + 'fixed-top', $box).css({
832
- position: 'absolute',
833
- top: oh
834
- });
835
- }
836
- });
837
- },
838
-
839
- // Disable editor
840
- toggleDisable: function (disable) {
841
- var t = this,
842
- prefix = t.o.prefix;
843
-
844
- t.disabled = disable;
845
-
846
- if (disable) {
847
- t.$ta.attr('disabled', true);
848
- } else {
849
- t.$ta.removeAttr('disabled');
850
- }
851
- t.$box.toggleClass(prefix + 'disabled', disable);
852
- t.$ed.attr('contenteditable', !disable);
853
- },
854
-
855
- // Destroy the editor
856
- destroy: function () {
857
- var t = this,
858
- prefix = t.o.prefix,
859
- height = t.height;
860
-
861
- if (t.isTextarea) {
862
- t.$box.after(
863
- t.$ta
864
- .css({height: height})
865
- .val(t.html())
866
- .removeClass(prefix + 'textarea')
867
- .show()
868
- );
869
- } else {
870
- t.$box.after(
871
- t.$ed
872
- .css({height: height})
873
- .removeClass(prefix + 'editor')
874
- .removeAttr('contenteditable')
875
- .html(t.html())
876
- .show()
877
- );
878
- }
879
-
880
- t.$ed.off('dblclick', 'img');
881
-
882
- t.destroyPlugins();
883
-
884
- t.$box.remove();
885
- t.$c.removeData('trumbowyg');
886
- $('body').removeClass(prefix + 'body-fullscreen');
887
- },
888
-
889
-
890
- // Empty the editor
891
- empty: function () {
892
- this.$ta.val('');
893
- this.syncCode(true);
894
- },
895
-
896
-
897
- // Function call when click on viewHTML button
898
- toggle: function () {
899
- var t = this,
900
- prefix = t.o.prefix;
901
- t.semanticCode(false, true);
902
- setTimeout(function () {
903
- t.doc.activeElement.blur();
904
- t.$box.toggleClass(prefix + 'editor-hidden ' + prefix + 'editor-visible');
905
- t.$btnPane.toggleClass(prefix + 'disable');
906
- $('.' + prefix + 'viewHTML-button', t.$btnPane).toggleClass(prefix + 'active');
907
- if (t.$box.hasClass(prefix + 'editor-visible')) {
908
- t.$ta.attr('tabindex', -1);
909
- } else {
910
- t.$ta.removeAttr('tabindex');
911
- }
912
- }, 0);
913
- },
914
-
915
- // Open dropdown when click on a button which open that
916
- dropdown: function (name) {
917
- var t = this,
918
- d = t.doc,
919
- prefix = t.o.prefix,
920
- $dropdown = $('[data-dropdown=' + name + ']', t.$box),
921
- $btn = $('.' + prefix + name + '-button', t.$btnPane),
922
- show = $dropdown.is(':hidden');
923
-
924
- $('body', d).trigger('mousedown');
925
-
926
- if (show) {
927
- var o = $btn.offset().left;
928
- $btn.addClass(prefix + 'active');
929
-
930
- $dropdown.css({
931
- position: 'absolute',
932
- top: $btn.offset().top - t.$btnPane.offset().top + $btn.outerHeight(),
933
- left: (t.o.fixedFullWidth && t.isFixed) ? o + 'px' : (o - t.$btnPane.offset().left) + 'px'
934
- }).show();
935
-
936
- $(window).trigger('scroll');
937
-
938
- $('body', d).on('mousedown', function () {
939
- $('.' + prefix + 'dropdown', d).hide();
940
- $('.' + prefix + 'active', d).removeClass(prefix + 'active');
941
- $('body', d).off('mousedown');
942
- });
943
- }
944
- },
945
-
946
-
947
- // HTML Code management
948
- html: function (html) {
949
- var t = this;
950
- if (html != null) {
951
- t.$ta.val(html);
952
- t.syncCode(true);
953
- return t;
954
- }
955
- return t.$ta.val();
956
- },
957
- syncTextarea: function () {
958
- var t = this;
959
- t.$ta.val(t.$ed.text().trim().length > 0 || t.$ed.find('hr,img,embed,input').length > 0 ? t.$ed.html() : '');
960
- },
961
- syncCode: function (force) {
962
- var t = this;
963
- if (!force && t.$ed.is(':visible')) {
964
- t.syncTextarea();
965
- } else {
966
- t.$ed.html(t.$ta.val());
967
- }
968
-
969
- if (t.o.autogrow) {
970
- t.height = t.$ed.height();
971
- if (t.height !== t.$ta.css('height')) {
972
- t.$ta.css({height: t.height});
973
- t.$c.trigger('tbwresize');
974
- }
975
- }
976
- },
977
-
978
- // Analyse and update to semantic code
979
- // @param force : force to sync code from textarea
980
- // @param full : wrap text nodes in <p>
981
- semanticCode: function (force, full) {
982
- var t = this;
983
- t.saveRange();
984
- t.syncCode(force);
985
-
986
- $(t.o.tagsToRemove.join(','), t.$ed).remove();
987
-
988
- if (t.o.semantic) {
989
- t.semanticTag('b', 'strong');
990
- t.semanticTag('i', 'em');
991
- t.semanticTag('strike', 'del');
992
-
993
- if (full) {
994
- var inlineElementsSelector = t.o.inlineElementsSelector,
995
- blockElementsSelector = ':not(' + inlineElementsSelector + ')';
996
-
997
- // Wrap text nodes in span for easier processing
998
- t.$ed.contents().filter(function () {
999
- return this.nodeType === 3 && this.nodeValue.trim().length > 0;
1000
- }).wrap('<span data-tbw/>');
1001
-
1002
- // Wrap groups of inline elements in paragraphs (recursive)
1003
- var wrapInlinesInParagraphsFrom = function ($from) {
1004
- if ($from.length !== 0) {
1005
- var $finalParagraph = $from.nextUntil(blockElementsSelector).andSelf().wrapAll('<p/>').parent(),
1006
- $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first();
1007
- $finalParagraph.next('br').remove();
1008
- wrapInlinesInParagraphsFrom($nextElement);
1009
- }
1010
- };
1011
- wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first());
1012
-
1013
- t.semanticTag('div', 'p', true);
1014
-
1015
- // Unwrap paragraphs content, containing nothing usefull
1016
- t.$ed.find('p').filter(function () {
1017
- // Don't remove currently being edited element
1018
- if (t.range && this === t.range.startContainer) {
1019
- return false;
1020
- }
1021
- return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0;
1022
- }).contents().unwrap();
1023
-
1024
- // Get rid of temporial span's
1025
- $('[data-tbw]', t.$ed).contents().unwrap();
1026
-
1027
- // Remove empty <p>
1028
- t.$ed.find('p:empty').remove();
1029
- }
1030
-
1031
- t.restoreRange();
1032
-
1033
- t.syncTextarea();
1034
- }
1035
- },
1036
-
1037
- semanticTag: function (oldTag, newTag, copyAttributes) {
1038
- $(oldTag, this.$ed).each(function () {
1039
- var $oldTag = $(this);
1040
- $oldTag.wrap('<' + newTag + '/>');
1041
- if (copyAttributes) {
1042
- $.each($oldTag.prop('attributes'), function () {
1043
- $oldTag.parent().attr(this.name, this.value);
1044
- });
1045
- }
1046
- $oldTag.contents().unwrap();
1047
- });
1048
- },
1049
-
1050
- // Function call when user click on "Insert Link"
1051
- createLink: function () {
1052
- var t = this,
1053
- documentSelection = t.doc.getSelection(),
1054
- node = documentSelection.focusNode,
1055
- url,
1056
- title,
1057
- target;
1058
-
1059
- while (['A', 'DIV'].indexOf(node.nodeName) < 0) {
1060
- node = node.parentNode;
1061
- }
1062
-
1063
- if (node && node.nodeName === 'A') {
1064
- var $a = $(node);
1065
- url = $a.attr('href');
1066
- title = $a.attr('title');
1067
- target = $a.attr('target');
1068
- var range = t.doc.createRange();
1069
- range.selectNode(node);
1070
- documentSelection.addRange(range);
1071
- }
1072
-
1073
- t.saveRange();
1074
-
1075
- t.openModalInsert(t.lang.createLink, {
1076
- url: {
1077
- label: 'URL',
1078
- required: true,
1079
- value: url
1080
- },
1081
- title: {
1082
- label: t.lang.title,
1083
- value: title
1084
- },
1085
- text: {
1086
- label: t.lang.text,
1087
- value: t.getRangeText()
1088
- },
1089
- target: {
1090
- label: t.lang.target,
1091
- value: target
1092
- }
1093
- }, function (v) { // v is value
1094
- var link = $(['<a href="', v.url, '">', v.text, '</a>'].join(''));
1095
- if (v.title.length > 0) {
1096
- link.attr('title', v.title);
1097
- }
1098
- if (v.target.length > 0) {
1099
- link.attr('target', v.target);
1100
- }
1101
- t.range.deleteContents();
1102
- t.range.insertNode(link[0]);
1103
- return true;
1104
- });
1105
- },
1106
- unlink: function () {
1107
- var t = this,
1108
- documentSelection = t.doc.getSelection(),
1109
- node = documentSelection.focusNode;
1110
-
1111
- if (documentSelection.isCollapsed) {
1112
- while (['A', 'DIV'].indexOf(node.nodeName) < 0) {
1113
- node = node.parentNode;
1114
- }
1115
-
1116
- if (node && node.nodeName === 'A') {
1117
- var range = t.doc.createRange();
1118
- range.selectNode(node);
1119
- documentSelection.addRange(range);
1120
- }
1121
- }
1122
- t.execCmd('unlink', undefined, undefined, true);
1123
- },
1124
- insertImage: function () {
1125
- var t = this;
1126
- t.saveRange();
1127
- t.openModalInsert(t.lang.insertImage, {
1128
- url: {
1129
- label: 'URL',
1130
- required: true
1131
- },
1132
- alt: {
1133
- label: t.lang.description,
1134
- value: t.getRangeText()
1135
- }
1136
- }, function (v) { // v are values
1137
- t.execCmd('insertImage', v.url);
1138
- $('img[src="' + v.url + '"]:not([alt])', t.$box).attr('alt', v.alt);
1139
- return true;
1140
- });
1141
- },
1142
- fullscreen: function () {
1143
- var t = this,
1144
- prefix = t.o.prefix,
1145
- fullscreenCssClass = prefix + 'fullscreen',
1146
- isFullscreen;
1147
-
1148
- t.$box.toggleClass(fullscreenCssClass);
1149
- isFullscreen = t.$box.hasClass(fullscreenCssClass);
1150
- $('body').toggleClass(prefix + 'body-fullscreen', isFullscreen);
1151
- $(window).trigger('scroll');
1152
- t.$c.trigger('tbw' + (isFullscreen ? 'open' : 'close') + 'fullscreen');
1153
- },
1154
-
1155
-
1156
- /*
1157
- * Call method of trumbowyg if exist
1158
- * else try to call anonymous function
1159
- * and finaly native execCommand
1160
- */
1161
- execCmd: function (cmd, param, forceCss, skipTrumbowyg) {
1162
- var t = this;
1163
- skipTrumbowyg = !!skipTrumbowyg || '';
1164
-
1165
- if (cmd !== 'dropdown') {
1166
- t.$ed.focus();
1167
- }
1168
-
1169
- t.doc.execCommand('styleWithCSS', false, forceCss || false);
1170
-
1171
- try {
1172
- t[cmd + skipTrumbowyg](param);
1173
- } catch (c) {
1174
- try {
1175
- cmd(param);
1176
- } catch (e2) {
1177
- if (cmd === 'insertHorizontalRule') {
1178
- param = undefined;
1179
- } else if (cmd === 'formatBlock' && (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') !== -1)) {
1180
- param = '<' + param + '>';
1181
- }
1182
-
1183
- t.doc.execCommand(cmd, false, param);
1184
-
1185
- t.syncCode();
1186
- t.semanticCode(false, true);
1187
- }
1188
-
1189
- if (cmd !== 'dropdown') {
1190
- t.updateButtonPaneStatus();
1191
- t.$c.trigger('tbwchange');
1192
- }
1193
- }
1194
- },
1195
-
1196
-
1197
- // Open a modal box
1198
- openModal: function (title, content) {
1199
- var t = this,
1200
- prefix = t.o.prefix;
1201
-
1202
- // No open a modal box when exist other modal box
1203
- if ($('.' + prefix + 'modal-box', t.$box).length > 0) {
1204
- return false;
1205
- }
1206
-
1207
- t.saveRange();
1208
- t.showOverlay();
1209
-
1210
- // Disable all btnPane btns
1211
- t.$btnPane.addClass(prefix + 'disable');
1212
-
1213
- // Build out of ModalBox, it's the mask for animations
1214
- var $modal = $('<div/>', {
1215
- class: prefix + 'modal ' + prefix + 'fixed-top'
1216
- }).css({
1217
- top: t.$btnPane.height()
1218
- }).appendTo(t.$box);
1219
-
1220
- // Click on overlay close modal by cancelling them
1221
- t.$overlay.one('click', function () {
1222
- $modal.trigger('tbwcancel');
1223
- return false;
1224
- });
1225
-
1226
- // Build the form
1227
- var $form = $('<form/>', {
1228
- action: '',
1229
- html: content
1230
- })
1231
- .on('submit', function () {
1232
- $modal.trigger('tbwconfirm');
1233
- return false;
1234
- })
1235
- .on('reset', function () {
1236
- $modal.trigger('tbwcancel');
1237
- return false;
1238
- });
1239
-
1240
-
1241
- // Build ModalBox and animate to show them
1242
- var $box = $('<div/>', {
1243
- class: prefix + 'modal-box',
1244
- html: $form
1245
- })
1246
- .css({
1247
- top: '-' + t.$btnPane.outerHeight() + 'px',
1248
- opacity: 0
1249
- })
1250
- .appendTo($modal)
1251
- .animate({
1252
- top: 0,
1253
- opacity: 1
1254
- }, 100);
1255
-
1256
-
1257
- // Append title
1258
- $('<span/>', {
1259
- text: title,
1260
- class: prefix + 'modal-title'
1261
- }).prependTo($box);
1262
-
1263
- $modal.height($box.outerHeight() + 10);
1264
-
1265
-
1266
- // Focus in modal box
1267
- $('input:first', $box).focus();
1268
-
1269
-
1270
- // Append Confirm and Cancel buttons
1271
- t.buildModalBtn('submit', $box);
1272
- t.buildModalBtn('reset', $box);
1273
-
1274
-
1275
- $(window).trigger('scroll');
1276
-
1277
- return $modal;
1278
- },
1279
- // @param n is name of modal
1280
- buildModalBtn: function (n, $modal) {
1281
- var t = this,
1282
- prefix = t.o.prefix;
1283
-
1284
- return $('<button/>', {
1285
- class: prefix + 'modal-button ' + prefix + 'modal-' + n,
1286
- type: n,
1287
- text: t.lang[n] || n
1288
- }).appendTo($('form', $modal));
1289
- },
1290
- // close current modal box
1291
- closeModal: function () {
1292
- var t = this,
1293
- prefix = t.o.prefix;
1294
-
1295
- t.$btnPane.removeClass(prefix + 'disable');
1296
- t.$overlay.off();
1297
-
1298
- // Find the modal box
1299
- var $mb = $('.' + prefix + 'modal-box', t.$box);
1300
-
1301
- $mb.animate({
1302
- top: '-' + $mb.height()
1303
- }, 100, function () {
1304
- $mb.parent().remove();
1305
- t.hideOverlay();
1306
- });
1307
-
1308
- t.restoreRange();
1309
- },
1310
- // Preformated build and management modal
1311
- openModalInsert: function (title, fields, cmd) {
1312
- var t = this,
1313
- prefix = t.o.prefix,
1314
- lg = t.lang,
1315
- html = '',
1316
- CONFIRM_EVENT = 'tbwconfirm';
1317
-
1318
- $.each(fields, function (fieldName, field) {
1319
- var l = field.label,
1320
- n = field.name || fieldName;
1321
-
1322
- html += '<label><input type="' + (field.type || 'text') + '" name="' + n + '" value="' + (field.value || '').replace(/"/g, '&quot;') + '"><span class="' + prefix + 'input-infos"><span>' +
1323
- ((!l) ? (lg[fieldName] ? lg[fieldName] : fieldName) : (lg[l] ? lg[l] : l)) +
1324
- '</span></span></label>';
1325
- });
1326
-
1327
- return t.openModal(title, html)
1328
- .on(CONFIRM_EVENT, function () {
1329
- var $form = $('form', $(this)),
1330
- valid = true,
1331
- values = {};
1332
-
1333
- $.each(fields, function (fieldName, field) {
1334
- var $field = $('input[name="' + fieldName + '"]', $form);
1335
-
1336
- values[fieldName] = $.trim($field.val());
1337
-
1338
- // Validate value
1339
- if (field.required && values[fieldName] === '') {
1340
- valid = false;
1341
- t.addErrorOnModalField($field, t.lang.required);
1342
- } else if (field.pattern && !field.pattern.test(values[fieldName])) {
1343
- valid = false;
1344
- t.addErrorOnModalField($field, field.patternError);
1345
- }
1346
- });
1347
-
1348
- if (valid) {
1349
- t.restoreRange();
1350
-
1351
- if (cmd(values, fields)) {
1352
- t.syncCode();
1353
- t.$c.trigger('tbwchange');
1354
- t.closeModal();
1355
- $(this).off(CONFIRM_EVENT);
1356
- }
1357
- }
1358
- })
1359
- .one('tbwcancel', function () {
1360
- $(this).off(CONFIRM_EVENT);
1361
- t.closeModal();
1362
- });
1363
- },
1364
- addErrorOnModalField: function ($field, err) {
1365
- var prefix = this.o.prefix,
1366
- $label = $field.parent();
1367
-
1368
- $field
1369
- .on('change keyup', function () {
1370
- $label.removeClass(prefix + 'input-error');
1371
- });
1372
-
1373
- $label
1374
- .addClass(prefix + 'input-error')
1375
- .find('input+span')
1376
- .append(
1377
- $('<span/>', {
1378
- class: prefix + 'msg-error',
1379
- text: err
1380
- })
1381
- );
1382
- },
1383
-
1384
-
1385
- // Range management
1386
- saveRange: function () {
1387
- var t = this,
1388
- documentSelection = t.doc.getSelection();
1389
-
1390
- t.range = null;
1391
-
1392
- if (documentSelection.rangeCount) {
1393
- var savedRange = t.range = documentSelection.getRangeAt(0),
1394
- range = t.doc.createRange(),
1395
- rangeStart;
1396
- range.selectNodeContents(t.$ed[0]);
1397
- range.setEnd(savedRange.startContainer, savedRange.startOffset);
1398
- rangeStart = (range + '').length;
1399
- t.metaRange = {
1400
- start: rangeStart,
1401
- end: rangeStart + (savedRange + '').length
1402
- };
1403
- }
1404
- },
1405
- restoreRange: function () {
1406
- var t = this,
1407
- metaRange = t.metaRange,
1408
- savedRange = t.range,
1409
- documentSelection = t.doc.getSelection(),
1410
- range;
1411
-
1412
- if (!savedRange) {
1413
- return;
1414
- }
1415
-
1416
- if (metaRange && metaRange.start !== metaRange.end) { // Algorithm from http://jsfiddle.net/WeWy7/3/
1417
- var charIndex = 0,
1418
- nodeStack = [t.$ed[0]],
1419
- node,
1420
- foundStart = false,
1421
- stop = false;
1422
-
1423
- range = t.doc.createRange();
1424
-
1425
- while (!stop && (node = nodeStack.pop())) {
1426
- if (node.nodeType === 3) {
1427
- var nextCharIndex = charIndex + node.length;
1428
- if (!foundStart && metaRange.start >= charIndex && metaRange.start <= nextCharIndex) {
1429
- range.setStart(node, metaRange.start - charIndex);
1430
- foundStart = true;
1431
- }
1432
- if (foundStart && metaRange.end >= charIndex && metaRange.end <= nextCharIndex) {
1433
- range.setEnd(node, metaRange.end - charIndex);
1434
- stop = true;
1435
- }
1436
- charIndex = nextCharIndex;
1437
- } else {
1438
- var cn = node.childNodes,
1439
- i = cn.length;
1440
-
1441
- while (i > 0) {
1442
- i -= 1;
1443
- nodeStack.push(cn[i]);
1444
- }
1445
- }
1446
- }
1447
- }
1448
-
1449
- documentSelection.removeAllRanges();
1450
- documentSelection.addRange(range || savedRange);
1451
- },
1452
- getRangeText: function () {
1453
- return this.range + '';
1454
- },
1455
-
1456
- updateButtonPaneStatus: function () {
1457
- var t = this,
1458
- prefix = t.o.prefix,
1459
- tags = t.getTagsRecursive(t.doc.getSelection().focusNode.parentNode),
1460
- activeClasses = prefix + 'active-button ' + prefix + 'active';
1461
-
1462
- $('.' + prefix + 'active-button', t.$btnPane).removeClass(activeClasses);
1463
- $.each(tags, function (i, tag) {
1464
- var btnName = t.tagToButton[tag.toLowerCase()],
1465
- $btn = $('.' + prefix + btnName + '-button', t.$btnPane);
1466
-
1467
- if ($btn.length > 0) {
1468
- $btn.addClass(activeClasses);
1469
- } else {
1470
- try {
1471
- $btn = $('.' + prefix + 'dropdown .' + prefix + btnName + '-dropdown-button', t.$box);
1472
- var dropdownBtnName = $btn.parent().data('dropdown');
1473
- $('.' + prefix + dropdownBtnName + '-button', t.$box).addClass(activeClasses);
1474
- } catch (e) {
1475
- }
1476
- }
1477
- });
1478
- },
1479
- getTagsRecursive: function (element, tags) {
1480
- var t = this;
1481
- tags = tags || [];
1482
-
1483
- var tag = element.tagName;
1484
- if (tag === 'DIV') {
1485
- return tags;
1486
- }
1487
- if (tag === 'P' && element.style.textAlign !== '') {
1488
- tags.push(element.style.textAlign);
1489
- }
1490
-
1491
- $.each(t.tagHandlers, function (i, tagHandler) {
1492
- tags = tags.concat(tagHandler(element, t));
1493
- });
1494
-
1495
- tags.push(tag);
1496
-
1497
- return t.getTagsRecursive(element.parentNode, tags);
1498
- },
1499
-
1500
- // Plugins
1501
- initPlugins: function () {
1502
- var t = this;
1503
- t.loadedPlugins = [];
1504
- $.each($.trumbowyg.plugins, function (name, plugin) {
1505
- if (!plugin.shouldInit || plugin.shouldInit(t)) {
1506
- plugin.init(t);
1507
- if (plugin.tagHandler) {
1508
- t.tagHandlers.push(plugin.tagHandler);
1509
- }
1510
- t.loadedPlugins.push(plugin);
1511
- }
1512
- });
1513
- },
1514
- destroyPlugins: function () {
1515
- $.each(this.loadedPlugins, function (i, plugin) {
1516
- if (plugin.destroy) {
1517
- plugin.destroy();
1518
- }
1519
- });
1520
- }
1521
- };
1522
- })(navigator, window, document, jQuery);