jwysiwyg_rails 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -0,0 +1,2454 @@
1
+ /**
2
+ * WYSIWYG - jQuery plugin 0.97
3
+ * (0.97.2 - From infinity)
4
+ *
5
+ * Copyright (c) 2008-2009 Juan M Martinez, 2010-2011 Akzhan Abdulin and all contributors
6
+ * https://github.com/akzhan/jwysiwyg
7
+ *
8
+ * Dual licensed under the MIT and GPL licenses:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ * http://www.gnu.org/licenses/gpl.html
11
+ *
12
+ */
13
+
14
+ /*jslint browser: true, forin: true */
15
+
16
+ (function ($) {
17
+ "use strict";
18
+ /* Wysiwyg namespace: private properties and methods */
19
+
20
+ var console = window.console ? window.console : {
21
+ log: $.noop,
22
+ error: function (msg) {
23
+ $.error(msg);
24
+ }
25
+ };
26
+ var supportsProp = (('prop' in $.fn) && ('removeProp' in $.fn));
27
+
28
+ function Wysiwyg() {
29
+ // - the item is added by this.ui.appendControls and then appendItem
30
+ // - click triggers this.triggerControl
31
+ // cmd or[key] - designMode exec function name
32
+ // tags - activates control for these tags (@see checkTargets)
33
+ // css - activates control if one of css is applied
34
+ this.controls = {
35
+ bold: {
36
+ groupIndex: 0,
37
+ visible: true,
38
+ tags: ["b", "strong"],
39
+ css: {
40
+ fontWeight: "bold"
41
+ },
42
+ tooltip: "Bold",
43
+ hotkey: {"ctrl": 1, "key": 66}
44
+ },
45
+
46
+ copy: {
47
+ groupIndex: 8,
48
+ visible: false,
49
+ tooltip: "Copy"
50
+ },
51
+
52
+ createLink: {
53
+ groupIndex: 6,
54
+ visible: true,
55
+ exec: function () {
56
+ var self = this;
57
+ if ($.wysiwyg.controls && $.wysiwyg.controls.link) {
58
+ $.wysiwyg.controls.link.init(this);
59
+ } else if ($.wysiwyg.autoload) {
60
+ $.wysiwyg.autoload.control("wysiwyg.link.js", function () {
61
+ self.controls.createLink.exec.apply(self);
62
+ });
63
+ } else {
64
+ console.error("$.wysiwyg.controls.link not defined. You need to include wysiwyg.link.js file");
65
+ }
66
+ },
67
+ tags: ["a"],
68
+ tooltip: "Create link"
69
+ },
70
+
71
+ cut: {
72
+ groupIndex: 8,
73
+ visible: false,
74
+ tooltip: "Cut"
75
+ },
76
+
77
+ decreaseFontSize: {
78
+ groupIndex: 9,
79
+ visible: false,
80
+ tags: ["small"],
81
+ tooltip: "Decrease font size",
82
+ exec: function () {
83
+ this.decreaseFontSize();
84
+ }
85
+ },
86
+
87
+ h1: {
88
+ groupIndex: 7,
89
+ visible: true,
90
+ className: "h1",
91
+ command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
92
+ "arguments": ($.browser.msie || $.browser.safari) ? "<h1>" : "h1",
93
+ tags: ["h1"],
94
+ tooltip: "Header 1"
95
+ },
96
+
97
+ h2: {
98
+ groupIndex: 7,
99
+ visible: true,
100
+ className: "h2",
101
+ command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
102
+ "arguments": ($.browser.msie || $.browser.safari) ? "<h2>" : "h2",
103
+ tags: ["h2"],
104
+ tooltip: "Header 2"
105
+ },
106
+
107
+ h3: {
108
+ groupIndex: 7,
109
+ visible: true,
110
+ className: "h3",
111
+ command: ($.browser.msie || $.browser.safari) ? "FormatBlock" : "heading",
112
+ "arguments": ($.browser.msie || $.browser.safari) ? "<h3>" : "h3",
113
+ tags: ["h3"],
114
+ tooltip: "Header 3"
115
+ },
116
+
117
+ highlight: {
118
+ tooltip: "Highlight",
119
+ className: "highlight",
120
+ groupIndex: 1,
121
+ visible: false,
122
+ css: {
123
+ backgroundColor: "rgb(255, 255, 102)"
124
+ },
125
+ exec: function () {
126
+ var command, node, selection, args;
127
+
128
+ if ($.browser.msie || $.browser.safari) {
129
+ command = "backcolor";
130
+ } else {
131
+ command = "hilitecolor";
132
+ }
133
+
134
+ if ($.browser.msie) {
135
+ node = this.getInternalRange().parentElement();
136
+ } else {
137
+ selection = this.getInternalSelection();
138
+ node = selection.extentNode || selection.focusNode;
139
+
140
+ while (node.style === undefined) {
141
+ node = node.parentNode;
142
+ if (node.tagName && node.tagName.toLowerCase() === "body") {
143
+ return;
144
+ }
145
+ }
146
+ }
147
+
148
+ if (node.style.backgroundColor === "rgb(255, 255, 102)" ||
149
+ node.style.backgroundColor === "#ffff66") {
150
+ args = "#ffffff";
151
+ } else {
152
+ args = "#ffff66";
153
+ }
154
+
155
+ this.editorDoc.execCommand(command, false, args);
156
+ }
157
+ },
158
+
159
+ html: {
160
+ groupIndex: 10,
161
+ visible: false,
162
+ exec: function () {
163
+ var elementHeight;
164
+
165
+ if (this.options.resizeOptions && $.fn.resizable) {
166
+ elementHeight = this.element.height();
167
+ }
168
+
169
+ if (this.viewHTML) { //textarea is shown
170
+ this.setContent(this.original.value);
171
+
172
+ $(this.original).hide();
173
+ this.editor.show();
174
+
175
+ if (this.options.resizeOptions && $.fn.resizable) {
176
+ // if element.height still the same after frame was shown
177
+ if (elementHeight === this.element.height()) {
178
+ this.element.height(elementHeight + this.editor.height());
179
+ }
180
+
181
+ this.element.resizable($.extend(true, {
182
+ alsoResize: this.editor
183
+ }, this.options.resizeOptions));
184
+ }
185
+
186
+ this.ui.toolbar.find("li").each(function () {
187
+ var li = $(this);
188
+
189
+ if (li.hasClass("html")) {
190
+ li.removeClass("active");
191
+ } else {
192
+ li.removeClass('disabled');
193
+ }
194
+ });
195
+ } else { //wysiwyg is shown
196
+ this.saveContent();
197
+
198
+ $(this.original).css({
199
+ width: this.element.outerWidth() - 6,
200
+ height: this.element.height() - this.ui.toolbar.height() - 6,
201
+ resize: "none"
202
+ }).show();
203
+ this.editor.hide();
204
+
205
+ if (this.options.resizeOptions && $.fn.resizable) {
206
+ // if element.height still the same after frame was hidden
207
+ if (elementHeight === this.element.height()) {
208
+ this.element.height(this.ui.toolbar.height());
209
+ }
210
+
211
+ this.element.resizable("destroy");
212
+ }
213
+
214
+ this.ui.toolbar.find("li").each(function () {
215
+ var li = $(this);
216
+
217
+ if (li.hasClass("html")) {
218
+ li.addClass("active");
219
+ } else {
220
+ if (false === li.hasClass("fullscreen")) {
221
+ li.removeClass("active").addClass('disabled');
222
+ }
223
+ }
224
+ });
225
+ }
226
+
227
+ this.viewHTML = !(this.viewHTML);
228
+ },
229
+ tooltip: "View source code"
230
+ },
231
+
232
+ increaseFontSize: {
233
+ groupIndex: 9,
234
+ visible: false,
235
+ tags: ["big"],
236
+ tooltip: "Increase font size",
237
+ exec: function () {
238
+ this.increaseFontSize();
239
+ }
240
+ },
241
+
242
+ indent: {
243
+ groupIndex: 2,
244
+ visible: true,
245
+ tooltip: "Indent"
246
+ },
247
+
248
+ insertHorizontalRule: {
249
+ groupIndex: 6,
250
+ visible: true,
251
+ tags: ["hr"],
252
+ tooltip: "Insert Horizontal Rule"
253
+ },
254
+
255
+ insertImage: {
256
+ groupIndex: 6,
257
+ visible: true,
258
+ exec: function () {
259
+ var self = this;
260
+
261
+ if ($.wysiwyg.controls && $.wysiwyg.controls.image) {
262
+ $.wysiwyg.controls.image.init(this);
263
+ } else if ($.wysiwyg.autoload) {
264
+ $.wysiwyg.autoload.control("wysiwyg.image.js", function () {
265
+ self.controls.insertImage.exec.apply(self);
266
+ });
267
+ } else {
268
+ console.error("$.wysiwyg.controls.image not defined. You need to include wysiwyg.image.js file");
269
+ }
270
+ },
271
+ tags: ["img"],
272
+ tooltip: "Insert image"
273
+ },
274
+
275
+ insertOrderedList: {
276
+ groupIndex: 5,
277
+ visible: true,
278
+ tags: ["ol"],
279
+ tooltip: "Insert Ordered List"
280
+ },
281
+
282
+ insertTable: {
283
+ groupIndex: 6,
284
+ visible: true,
285
+ exec: function () {
286
+ var self = this;
287
+
288
+ if ($.wysiwyg.controls && $.wysiwyg.controls.table) {
289
+ $.wysiwyg.controls.table(this);
290
+ } else if ($.wysiwyg.autoload) {
291
+ $.wysiwyg.autoload.control("wysiwyg.table.js", function () {
292
+ self.controls.insertTable.exec.apply(self);
293
+ });
294
+ } else {
295
+ console.error("$.wysiwyg.controls.table not defined. You need to include wysiwyg.table.js file");
296
+ }
297
+ },
298
+ tags: ["table"],
299
+ tooltip: "Insert table"
300
+ },
301
+
302
+ insertUnorderedList: {
303
+ groupIndex: 5,
304
+ visible: true,
305
+ tags: ["ul"],
306
+ tooltip: "Insert Unordered List"
307
+ },
308
+
309
+ italic: {
310
+ groupIndex: 0,
311
+ visible: true,
312
+ tags: ["i", "em"],
313
+ css: {
314
+ fontStyle: "italic"
315
+ },
316
+ tooltip: "Italic",
317
+ hotkey: {"ctrl": 1, "key": 73}
318
+ },
319
+
320
+ justifyCenter: {
321
+ groupIndex: 1,
322
+ visible: true,
323
+ tags: ["center"],
324
+ css: {
325
+ textAlign: "center"
326
+ },
327
+ tooltip: "Justify Center"
328
+ },
329
+
330
+ justifyFull: {
331
+ groupIndex: 1,
332
+ visible: true,
333
+ css: {
334
+ textAlign: "justify"
335
+ },
336
+ tooltip: "Justify Full"
337
+ },
338
+
339
+ justifyLeft: {
340
+ visible: true,
341
+ groupIndex: 1,
342
+ css: {
343
+ textAlign: "left"
344
+ },
345
+ tooltip: "Justify Left"
346
+ },
347
+
348
+ justifyRight: {
349
+ groupIndex: 1,
350
+ visible: true,
351
+ css: {
352
+ textAlign: "right"
353
+ },
354
+ tooltip: "Justify Right"
355
+ },
356
+
357
+ ltr: {
358
+ groupIndex: 10,
359
+ visible: false,
360
+ exec: function () {
361
+ var p = this.dom.getElement("p");
362
+
363
+ if (!p) {
364
+ return false;
365
+ }
366
+
367
+ $(p).attr("dir", "ltr");
368
+ return true;
369
+ },
370
+ tooltip : "Left to Right"
371
+ },
372
+
373
+ outdent: {
374
+ groupIndex: 2,
375
+ visible: true,
376
+ tooltip: "Outdent"
377
+ },
378
+
379
+ paragraph: {
380
+ groupIndex: 7,
381
+ visible: false,
382
+ className: "paragraph",
383
+ command: "FormatBlock",
384
+ "arguments": ($.browser.msie || $.browser.safari) ? "<p>" : "p",
385
+ tags: ["p"],
386
+ tooltip: "Paragraph"
387
+ },
388
+
389
+ paste: {
390
+ groupIndex: 8,
391
+ visible: false,
392
+ tooltip: "Paste"
393
+ },
394
+
395
+ redo: {
396
+ groupIndex: 4,
397
+ visible: true,
398
+ tooltip: "Redo"
399
+ },
400
+
401
+ removeFormat: {
402
+ groupIndex: 10,
403
+ visible: true,
404
+ exec: function () {
405
+ this.removeFormat();
406
+ },
407
+ tooltip: "Remove formatting"
408
+ },
409
+
410
+ rtl: {
411
+ groupIndex: 10,
412
+ visible: false,
413
+ exec: function () {
414
+ var p = this.dom.getElement("p");
415
+
416
+ if (!p) {
417
+ return false;
418
+ }
419
+
420
+ $(p).attr("dir", "rtl");
421
+ return true;
422
+ },
423
+ tooltip : "Right to Left"
424
+ },
425
+
426
+ strikeThrough: {
427
+ groupIndex: 0,
428
+ visible: true,
429
+ tags: ["s", "strike"],
430
+ css: {
431
+ textDecoration: "line-through"
432
+ },
433
+ tooltip: "Strike-through"
434
+ },
435
+
436
+ subscript: {
437
+ groupIndex: 3,
438
+ visible: true,
439
+ tags: ["sub"],
440
+ tooltip: "Subscript"
441
+ },
442
+
443
+ superscript: {
444
+ groupIndex: 3,
445
+ visible: true,
446
+ tags: ["sup"],
447
+ tooltip: "Superscript"
448
+ },
449
+
450
+ underline: {
451
+ groupIndex: 0,
452
+ visible: true,
453
+ tags: ["u"],
454
+ css: {
455
+ textDecoration: "underline"
456
+ },
457
+ tooltip: "Underline",
458
+ hotkey: {"ctrl": 1, "key": 85}
459
+ },
460
+
461
+ undo: {
462
+ groupIndex: 4,
463
+ visible: true,
464
+ tooltip: "Undo"
465
+ },
466
+
467
+ code: {
468
+ visible : true,
469
+ groupIndex: 6,
470
+ tooltip: "Code snippet",
471
+ exec: function () {
472
+ var range = this.getInternalRange(),
473
+ common = $(range.commonAncestorContainer),
474
+ $nodeName = range.commonAncestorContainer.nodeName.toLowerCase();
475
+ if (common.parent("code").length) {
476
+ common.unwrap();
477
+ } else {
478
+ if ($nodeName !== "body") {
479
+ common.wrap("<code/>");
480
+ }
481
+ }
482
+ }
483
+ },
484
+
485
+ cssWrap: {
486
+ visible : false,
487
+ groupIndex: 6,
488
+ tooltip: "CSS Wrapper",
489
+ exec: function () {
490
+ $.wysiwyg.controls.cssWrap.init(this);
491
+ }
492
+ }
493
+
494
+ };
495
+
496
+ this.defaults = {
497
+ html: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" style="margin:0"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body style="margin:0;">INITIAL_CONTENT</body></html>',
498
+ debug: false,
499
+ controls: {},
500
+ css: {},
501
+ events: {},
502
+ autoGrow: false,
503
+ autoSave: true,
504
+ brIE: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=15
505
+ formHeight: 270,
506
+ formWidth: 440,
507
+ iFrameClass: null,
508
+ initialContent: "<p>Initial content</p>",
509
+ maxHeight: 10000, // see autoGrow
510
+ maxLength: 0,
511
+ messages: {
512
+ nonSelection: "Select the text you wish to link"
513
+ },
514
+ toolbarHtml: '<ul role="menu" class="toolbar"></ul>',
515
+ removeHeadings: false,
516
+ replaceDivWithP: false,
517
+ resizeOptions: false,
518
+ rmUnusedControls: false, // https://github.com/akzhan/jwysiwyg/issues/52
519
+ rmUnwantedBr: true, // http://code.google.com/p/jwysiwyg/issues/detail?id=11
520
+ tableFiller: "Lorem ipsum",
521
+ initialMinHeight: null,
522
+
523
+ controlImage: {
524
+ forceRelativeUrls: false
525
+ },
526
+
527
+ controlLink: {
528
+ forceRelativeUrls: false
529
+ },
530
+
531
+ plugins: { // placeholder for plugins settings
532
+ autoload: false,
533
+ i18n: false,
534
+ rmFormat: {
535
+ rmMsWordMarkup: false
536
+ }
537
+ },
538
+
539
+ dialog : "default"
540
+ };
541
+
542
+ //these properties are set from control hashes
543
+ this.availableControlProperties = [
544
+ "arguments",
545
+ "callback",
546
+ "className",
547
+ "command",
548
+ "css",
549
+ "custom",
550
+ "exec",
551
+ "groupIndex",
552
+ "hotkey",
553
+ "icon",
554
+ "tags",
555
+ "tooltip",
556
+ "visible"
557
+ ];
558
+
559
+ this.editor = null; //jquery iframe holder
560
+ this.editorDoc = null;
561
+ this.element = null;
562
+ this.options = {};
563
+ this.original = null;
564
+ this.savedRange = null;
565
+ this.timers = [];
566
+ this.validKeyCodes = [8, 9, 13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46];
567
+
568
+ this.isDestroyed = false;
569
+
570
+ this.dom = { // DOM related properties and methods
571
+ ie: {
572
+ parent: null // link to dom
573
+ },
574
+ w3c: {
575
+ parent: null // link to dom
576
+ }
577
+ };
578
+ this.dom.parent = this;
579
+ this.dom.ie.parent = this.dom;
580
+ this.dom.w3c.parent = this.dom;
581
+
582
+ this.ui = {}; // UI related properties and methods
583
+ this.ui.self = this;
584
+ this.ui.toolbar = null;
585
+ this.ui.initialHeight = null; // ui.grow
586
+
587
+ this.dom.getAncestor = function (element, filterTagName) {
588
+ filterTagName = filterTagName.toLowerCase();
589
+
590
+ while (element && typeof element.tagName != "undefined" && "body" !== element.tagName.toLowerCase()) {
591
+ if (filterTagName === element.tagName.toLowerCase()) {
592
+ return element;
593
+ }
594
+
595
+ element = element.parentNode;
596
+ }
597
+ if(!element.tagName && (element.previousSibling || element.nextSibling)) {
598
+ if(element.previousSibling) {
599
+ if(element.previousSibling.tagName.toLowerCase() == filterTagName) {
600
+ return element.previousSibling;
601
+ }
602
+ }
603
+ if(element.nextSibling) {
604
+ if(element.nextSibling.tagName.toLowerCase() == filterTagName) {
605
+ return element.nextSibling;
606
+ }
607
+ }
608
+ }
609
+
610
+ return null;
611
+ };
612
+
613
+ this.dom.getElement = function (filterTagName) {
614
+ var dom = this;
615
+
616
+ filterTagName = filterTagName.toLowerCase();
617
+
618
+ if (window.getSelection) {
619
+ return dom.w3c.getElement(filterTagName);
620
+ } else {
621
+ return dom.ie.getElement(filterTagName);
622
+ }
623
+ };
624
+
625
+ this.dom.ie.getElement = function (filterTagName) {
626
+ var dom = this.parent,
627
+ selection = dom.parent.getInternalSelection(),
628
+ range = selection.createRange(),
629
+ element;
630
+
631
+ if ("Control" === selection.type) {
632
+ // control selection
633
+ if (1 === range.length) {
634
+ element = range.item(0);
635
+ } else {
636
+ // multiple control selection
637
+ return null;
638
+ }
639
+ } else {
640
+ element = range.parentElement();
641
+ }
642
+
643
+ return dom.getAncestor(element, filterTagName);
644
+ };
645
+
646
+ this.dom.w3c.getElement = function (filterTagName) {
647
+ var dom = this.parent,
648
+ range = dom.parent.getInternalRange(),
649
+ element;
650
+
651
+ if (!range) {
652
+ return null;
653
+ }
654
+
655
+ element = range.commonAncestorContainer;
656
+
657
+ if (3 === element.nodeType) {
658
+ element = element.parentNode;
659
+ }
660
+
661
+ // if startContainer not Text, Comment, or CDATASection element then
662
+ // startOffset is the number of child nodes between the start of the
663
+ // startContainer and the boundary point of the Range
664
+ if (element === range.startContainer) {
665
+ element = element.childNodes[range.startOffset];
666
+ }
667
+
668
+ if(!element.tagName && (element.previousSibiling || element.nextSibling)) {
669
+ if(element.previousSibiling) {
670
+ if(element.previousSibiling.tagName.toLowerCase() == filterTagName) {
671
+ return element.previousSibiling;
672
+ }
673
+ }
674
+ if(element.nextSibling) {
675
+ if(element.nextSibling.tagName.toLowerCase() == filterTagName) {
676
+ return element.nextSibling;
677
+ }
678
+ }
679
+ }
680
+
681
+ return dom.getAncestor(element, filterTagName);
682
+ };
683
+
684
+ this.ui.addHoverClass = function () {
685
+ $(this).addClass("wysiwyg-button-hover");
686
+ };
687
+
688
+ this.ui.appendControls = function () {
689
+ var ui = this,
690
+ self = this.self,
691
+ controls = self.parseControls(),
692
+ hasVisibleControls = true, // to prevent separator before first item
693
+ groups = [],
694
+ controlsByGroup = {},
695
+ i,
696
+ currentGroupIndex, // jslint wants all vars at top of function
697
+ iterateGroup = function (controlName, control) { //called for every group when adding
698
+ if (control.groupIndex && currentGroupIndex !== control.groupIndex) {
699
+ currentGroupIndex = control.groupIndex;
700
+ hasVisibleControls = false;
701
+ }
702
+
703
+ if (!control.visible) {
704
+ return;
705
+ }
706
+
707
+ if (!hasVisibleControls) {
708
+ ui.appendItemSeparator();
709
+ hasVisibleControls = true;
710
+ }
711
+
712
+ if (control.custom) {
713
+ ui.appendItemCustom(controlName, control);
714
+ } else {
715
+ ui.appendItem(controlName, control);
716
+ }
717
+ };
718
+
719
+ $.each(controls, function (name, c) { //sort by groupIndex
720
+ var index = "empty";
721
+
722
+ if (undefined !== c.groupIndex) {
723
+ if ("" === c.groupIndex) {
724
+ index = "empty";
725
+ } else {
726
+ index = c.groupIndex;
727
+ }
728
+ }
729
+
730
+ if (undefined === controlsByGroup[index]) {
731
+ groups.push(index);
732
+ controlsByGroup[index] = {};
733
+ }
734
+ controlsByGroup[index][name] = c;
735
+ });
736
+
737
+ groups.sort(function (a, b) { //just sort group indexes by
738
+ if ("number" === typeof (a) && typeof (a) === typeof (b)) {
739
+ return (a - b);
740
+ } else {
741
+ a = a.toString();
742
+ b = b.toString();
743
+
744
+ if (a > b) {
745
+ return 1;
746
+ }
747
+
748
+ if (a === b) {
749
+ return 0;
750
+ }
751
+
752
+ return -1;
753
+ }
754
+ });
755
+
756
+ if (0 < groups.length) {
757
+ // set to first index in groups to proper placement of separator
758
+ currentGroupIndex = groups[0];
759
+ }
760
+
761
+ for (i = 0; i < groups.length; i += 1) {
762
+ $.each(controlsByGroup[groups[i]], iterateGroup);
763
+ }
764
+ };
765
+
766
+ this.ui.appendItem = function (name, control) {
767
+ var self = this.self,
768
+ className = control.className || control.command || name || "empty",
769
+ tooltip = control.tooltip || control.command || name || "";
770
+
771
+ return $('<li role="menuitem" unselectable="on">' + (className) + "</li>")
772
+ .addClass(className)
773
+ .attr("title", tooltip)
774
+ .hover(this.addHoverClass, this.removeHoverClass)
775
+ .click(function (event) {
776
+ if ($(this).hasClass("disabled")) {
777
+ return false;
778
+ }
779
+
780
+ self.triggerControl.apply(self, [name, control]);
781
+
782
+ /**
783
+ * @link https://github.com/akzhan/jwysiwyg/issues/219
784
+ */
785
+ var $target = $(event.target);
786
+ for (var controlName in self.controls) {
787
+ if ($target.hasClass(controlName)) {
788
+ self.ui.toolbar.find("." + controlName).toggleClass("active");
789
+ self.editorDoc.rememberCommand = true;
790
+ break;
791
+ }
792
+ }
793
+
794
+ this.blur();
795
+ self.ui.returnRange();
796
+ self.ui.focus();
797
+ return true;
798
+ })
799
+ .appendTo(self.ui.toolbar);
800
+ };
801
+
802
+ this.ui.appendItemCustom = function (name, control) {
803
+ var self = this.self,
804
+ tooltip = control.tooltip || control.command || name || "";
805
+
806
+ if (control.callback) {
807
+ $(window).bind("trigger-" + name + ".wysiwyg", control.callback);
808
+ }
809
+
810
+ return $('<li role="menuitem" unselectable="on" style="background: url(\'' + control.icon + '\') no-repeat;"></li>')
811
+ .addClass("custom-command-" + name)
812
+ .addClass("wysiwyg-custom-command")
813
+ .addClass(name)
814
+ .attr("title", tooltip)
815
+ .hover(this.addHoverClass, this.removeHoverClass)
816
+ .click(function () {
817
+ if ($(this).hasClass("disabled")) {
818
+ return false;
819
+ }
820
+
821
+ self.triggerControl.apply(self, [name, control]);
822
+
823
+ this.blur();
824
+ self.ui.returnRange();
825
+ self.ui.focus();
826
+
827
+ self.triggerControlCallback(name);
828
+ return true;
829
+ })
830
+ .appendTo(self.ui.toolbar);
831
+ };
832
+
833
+ this.ui.appendItemSeparator = function () {
834
+ var self = this.self;
835
+ return $('<li role="separator" class="separator"></li>').appendTo(self.ui.toolbar);
836
+ };
837
+
838
+ this.autoSaveFunction = function () {
839
+ this.saveContent();
840
+ };
841
+
842
+ //called after click in wysiwyg "textarea"
843
+ this.ui.checkTargets = function (element) {
844
+ var self = this.self;
845
+
846
+ //activate controls
847
+ $.each(self.options.controls, function (name, control) {
848
+ var className = control.className || control.command || name || "empty",
849
+ tags,
850
+ elm,
851
+ css,
852
+ el,
853
+ checkActiveStatus = function (cssProperty, cssValue) {
854
+ var handler;
855
+
856
+ if ("function" === typeof (cssValue)) {
857
+ handler = cssValue;
858
+ if (handler(el.css(cssProperty).toString().toLowerCase(), self)) {
859
+ self.ui.toolbar.find("." + className).addClass("active");
860
+ }
861
+ } else {
862
+ if (el.css(cssProperty).toString().toLowerCase() === cssValue) {
863
+ self.ui.toolbar.find("." + className).addClass("active");
864
+ }
865
+ }
866
+ };
867
+
868
+ if ("fullscreen" !== className) {
869
+ self.ui.toolbar.find("." + className).removeClass("active");
870
+ }
871
+
872
+ //activate by allowed tags
873
+ if (control.tags || (control.options && control.options.tags)) {
874
+ tags = control.tags || (control.options && control.options.tags);
875
+
876
+ elm = element;
877
+ while (elm) {
878
+ if (elm.nodeType !== 1) {
879
+ break;
880
+ }
881
+
882
+ if ($.inArray(elm.tagName.toLowerCase(), tags) !== -1) {
883
+ self.ui.toolbar.find("." + className).addClass("active");
884
+ }
885
+
886
+ elm = elm.parentNode;
887
+ }
888
+ }
889
+
890
+ //activate by supposed css
891
+ if (control.css || (control.options && control.options.css)) {
892
+ css = control.css || (control.options && control.options.css);
893
+ el = $(element);
894
+
895
+ while (el) {
896
+ if (el[0].nodeType !== 1) {
897
+ break;
898
+ }
899
+ $.each(css, checkActiveStatus);
900
+
901
+ el = el.parent();
902
+ }
903
+ }
904
+ });
905
+ };
906
+
907
+ this.ui.designMode = function () {
908
+ var attempts = 3,
909
+ self = this.self,
910
+ runner;
911
+ runner = function (attempts) {
912
+ if ("on" === self.editorDoc.designMode) {
913
+ if (self.timers.designMode) {
914
+ window.clearTimeout(self.timers.designMode);
915
+ }
916
+
917
+ // IE needs to reget the document element (this.editorDoc) after designMode was set
918
+ if (self.innerDocument() !== self.editorDoc) {
919
+ self.ui.initFrame();
920
+ }
921
+
922
+ return;
923
+ }
924
+
925
+ try {
926
+ self.editorDoc.designMode = "on";
927
+ } catch (e) {
928
+ }
929
+
930
+ attempts -= 1;
931
+ if (attempts > 0) {
932
+ self.timers.designMode = window.setTimeout(function () { runner(attempts); }, 100);
933
+ }
934
+ };
935
+
936
+ runner(attempts);
937
+ };
938
+
939
+ this.destroy = function () {
940
+ this.isDestroyed = true;
941
+
942
+ var i, $form = this.element.closest("form");
943
+
944
+ for (i = 0; i < this.timers.length; i += 1) {
945
+ window.clearTimeout(this.timers[i]);
946
+ }
947
+
948
+ // Remove bindings
949
+ $form.unbind(".wysiwyg");
950
+ this.element.remove();
951
+ $.removeData(this.original, "wysiwyg");
952
+ $(this.original).show();
953
+ return this;
954
+ };
955
+
956
+ this.getRangeText = function () {
957
+ var r = this.getInternalRange();
958
+
959
+ if (r.toString) {
960
+ r = r.toString();
961
+ } else if (r.text) { // IE
962
+ r = r.text;
963
+ }
964
+
965
+ return r;
966
+ };
967
+ //not used?
968
+ this.execute = function (command, arg) {
969
+ if (typeof (arg) === "undefined") {
970
+ arg = null;
971
+ }
972
+ this.editorDoc.execCommand(command, false, arg);
973
+ };
974
+
975
+ this.extendOptions = function (options) {
976
+ var controls = {};
977
+
978
+ /**
979
+ * If the user set custom controls, we catch it, and merge with the
980
+ * defaults controls later.
981
+ */
982
+ if ("object" === typeof options.controls) {
983
+ controls = options.controls;
984
+ delete options.controls;
985
+ }
986
+
987
+ options = $.extend(true, {}, this.defaults, options);
988
+ options.controls = $.extend(true, {}, controls, this.controls, controls);
989
+
990
+ if (options.rmUnusedControls) {
991
+ $.each(options.controls, function (controlName) {
992
+ if (!controls[controlName]) {
993
+ delete options.controls[controlName];
994
+ }
995
+ });
996
+ }
997
+
998
+ return options;
999
+ };
1000
+
1001
+ this.ui.focus = function () {
1002
+ var self = this.self;
1003
+
1004
+ self.editor.get(0).contentWindow.focus();
1005
+ return self;
1006
+ };
1007
+
1008
+ this.ui.returnRange = function () {
1009
+ var self = this.self, sel;
1010
+
1011
+ if (self.savedRange !== null) {
1012
+ if (window.getSelection) { //non IE and there is already a selection
1013
+ sel = window.getSelection();
1014
+ if (sel.rangeCount > 0) {
1015
+ sel.removeAllRanges();
1016
+ }
1017
+ try {
1018
+ sel.addRange(self.savedRange);
1019
+ } catch (e) {
1020
+ console.error(e);
1021
+ }
1022
+ } else if (window.document.createRange) { // non IE and no selection
1023
+ window.getSelection().addRange(self.savedRange);
1024
+ } else if (window.document.selection) { //IE
1025
+ self.savedRange.select();
1026
+ }
1027
+
1028
+ self.savedRange = null;
1029
+ }
1030
+ };
1031
+
1032
+ this.increaseFontSize = function () {
1033
+ if ($.browser.mozilla || $.browser.opera) {
1034
+ this.editorDoc.execCommand("increaseFontSize", false, null);
1035
+ } else if ($.browser.safari) {
1036
+ var Range = this.getInternalRange(),
1037
+ Selection = this.getInternalSelection(),
1038
+ newNode = this.editorDoc.createElement("big");
1039
+
1040
+ // If cursor placed on text node
1041
+ if (true === Range.collapsed && 3 === Range.commonAncestorContainer.nodeType) {
1042
+ var text = Range.commonAncestorContainer.nodeValue.toString(),
1043
+ start = text.lastIndexOf(" ", Range.startOffset) + 1,
1044
+ end = (-1 === text.indexOf(" ", Range.startOffset)) ? text : text.indexOf(" ", Range.startOffset);
1045
+
1046
+ Range.setStart(Range.commonAncestorContainer, start);
1047
+ Range.setEnd(Range.commonAncestorContainer, end);
1048
+
1049
+ Range.surroundContents(newNode);
1050
+ Selection.addRange(Range);
1051
+ } else {
1052
+ Range.surroundContents(newNode);
1053
+ Selection.removeAllRanges();
1054
+ Selection.addRange(Range);
1055
+ }
1056
+ } else {
1057
+ console.error("Internet Explorer?");
1058
+ }
1059
+ };
1060
+
1061
+ this.decreaseFontSize = function () {
1062
+ if ($.browser.mozilla || $.browser.opera) {
1063
+ this.editorDoc.execCommand("decreaseFontSize", false, null);
1064
+ } else if ($.browser.safari) {
1065
+ var Range = this.getInternalRange(),
1066
+ Selection = this.getInternalSelection(),
1067
+ newNode = this.editorDoc.createElement("small");
1068
+
1069
+ // If cursor placed on text node
1070
+ if (true === Range.collapsed && 3 === Range.commonAncestorContainer.nodeType) {
1071
+ var text = Range.commonAncestorContainer.nodeValue.toString(),
1072
+ start = text.lastIndexOf(" ", Range.startOffset) + 1,
1073
+ end = (-1 === text.indexOf(" ", Range.startOffset)) ? text : text.indexOf(" ", Range.startOffset);
1074
+
1075
+ Range.setStart(Range.commonAncestorContainer, start);
1076
+ Range.setEnd(Range.commonAncestorContainer, end);
1077
+
1078
+ Range.surroundContents(newNode);
1079
+ Selection.addRange(Range);
1080
+ } else {
1081
+ Range.surroundContents(newNode);
1082
+ Selection.removeAllRanges();
1083
+ Selection.addRange(Range);
1084
+ }
1085
+ } else {
1086
+ console.error("Internet Explorer?");
1087
+ }
1088
+ };
1089
+
1090
+ this.getContent = function () {
1091
+ if (this.viewHTML) {
1092
+ this.setContent(this.original.value);
1093
+ }
1094
+ return this.events.filter('getContent', this.editorDoc.body.innerHTML);
1095
+ };
1096
+
1097
+ /**
1098
+ * A jWysiwyg specific event system.
1099
+ *
1100
+ * Example:
1101
+ *
1102
+ * $("#editor").getWysiwyg().events.bind("getContent", function (orig) {
1103
+ * return "<div id='content'>"+orgi+"</div>";
1104
+ * });
1105
+ *
1106
+ * This makes it so that when ever getContent is called, it is wrapped in a div#content.
1107
+ */
1108
+ this.events = {
1109
+ _events : {},
1110
+
1111
+ /**
1112
+ * Similar to jQuery's bind, but for jWysiwyg only.
1113
+ */
1114
+ bind : function (eventName, callback) {
1115
+ if (typeof (this._events.eventName) !== "object") {
1116
+ this._events[eventName] = [];
1117
+ }
1118
+ this._events[eventName].push(callback);
1119
+ },
1120
+
1121
+ /**
1122
+ * Similar to jQuery's trigger, but for jWysiwyg only.
1123
+ */
1124
+ trigger : function (eventName, args) {
1125
+ if (typeof (this._events.eventName) === "object") {
1126
+ var editor = this.editor;
1127
+ $.each(this._events[eventName], function (k, v) {
1128
+ if (typeof (v) === "function") {
1129
+ v.apply(editor, args);
1130
+ }
1131
+ });
1132
+ }
1133
+ },
1134
+
1135
+ /**
1136
+ * This "filters" `originalText` by passing it as the first argument to every callback
1137
+ * with the name `eventName` and taking the return value and passing it to the next function.
1138
+ *
1139
+ * This function returns the result after all the callbacks have been applied to `originalText`.
1140
+ */
1141
+ filter : function (eventName, originalText) {
1142
+ if (typeof (this._events[eventName]) === "object") {
1143
+ var editor = this.editor,
1144
+ args = Array.prototype.slice.call(arguments, 1);
1145
+
1146
+ $.each(this._events[eventName], function (k, v) {
1147
+ if (typeof (v) === "function") {
1148
+ originalText = v.apply(editor, args);
1149
+ }
1150
+ });
1151
+ }
1152
+ return originalText;
1153
+ }
1154
+ };
1155
+
1156
+ this.getElementByAttributeValue = function (tagName, attributeName, attributeValue) {
1157
+ var i, value, elements = this.editorDoc.getElementsByTagName(tagName);
1158
+
1159
+ for (i = 0; i < elements.length; i += 1) {
1160
+ value = elements[i].getAttribute(attributeName);
1161
+
1162
+ if ($.browser.msie) {
1163
+ /** IE add full path, so I check by the last chars. */
1164
+ value = value.substr(value.length - attributeValue.length);
1165
+ }
1166
+
1167
+ if (value === attributeValue) {
1168
+ return elements[i];
1169
+ }
1170
+ }
1171
+
1172
+ return false;
1173
+ };
1174
+
1175
+ this.getInternalRange = function () {
1176
+ var selection = this.getInternalSelection();
1177
+
1178
+ if (!selection) {
1179
+ return null;
1180
+ }
1181
+
1182
+ if (selection.rangeCount && selection.rangeCount > 0) { // w3c
1183
+ return selection.getRangeAt(0);
1184
+ } else if (selection.createRange) { // ie
1185
+ return selection.createRange();
1186
+ }
1187
+
1188
+ return null;
1189
+ };
1190
+
1191
+ this.getInternalSelection = function () {
1192
+ // firefox: document.getSelection is deprecated
1193
+ if (this.editor.get(0).contentWindow) {
1194
+ if (this.editor.get(0).contentWindow.getSelection) {
1195
+ return this.editor.get(0).contentWindow.getSelection();
1196
+ }
1197
+ if (this.editor.get(0).contentWindow.selection) {
1198
+ return this.editor.get(0).contentWindow.selection;
1199
+ }
1200
+ }
1201
+ if (this.editorDoc.getSelection) {
1202
+ return this.editorDoc.getSelection();
1203
+ }
1204
+ if (this.editorDoc.selection) {
1205
+ return this.editorDoc.selection;
1206
+ }
1207
+
1208
+ return null;
1209
+ };
1210
+
1211
+ this.getRange = function () {
1212
+ var selection = this.getSelection();
1213
+
1214
+ if (!selection) {
1215
+ return null;
1216
+ }
1217
+
1218
+ if (selection.rangeCount && selection.rangeCount > 0) { // w3c
1219
+ selection.getRangeAt(0);
1220
+ } else if (selection.createRange) { // ie
1221
+ return selection.createRange();
1222
+ }
1223
+
1224
+ return null;
1225
+ };
1226
+
1227
+ this.getSelection = function () {
1228
+ return (window.getSelection) ? window.getSelection() : window.document.selection;
1229
+ };
1230
+
1231
+ // :TODO: you can type long string and letters will be hidden because of overflow
1232
+ this.ui.grow = function () {
1233
+ var self = this.self,
1234
+ innerBody = $(self.editorDoc.body),
1235
+ innerHeight = $.browser.msie ? innerBody[0].scrollHeight : innerBody.height() + 2 + 20, // 2 - borders, 20 - to prevent content jumping on grow
1236
+ minHeight = self.ui.initialHeight,
1237
+ height = Math.max(innerHeight, minHeight);
1238
+
1239
+ height = Math.min(height, self.options.maxHeight);
1240
+
1241
+ self.editor.attr("scrolling", height < self.options.maxHeight ? "no" : "auto"); // hide scrollbar firefox
1242
+ innerBody.css("overflow", height < self.options.maxHeight ? "hidden" : ""); // hide scrollbar chrome
1243
+
1244
+ self.editor.get(0).height = height;
1245
+
1246
+ return self;
1247
+ };
1248
+
1249
+ this.init = function (element, options) {
1250
+ var self = this,
1251
+ $form = $(element).closest("form"),
1252
+ newX = (element.width || element.clientWidth || 0),
1253
+ newY = (element.height || element.clientHeight || 0)
1254
+ ;
1255
+
1256
+ this.options = this.extendOptions(options);
1257
+ this.original = element;
1258
+ this.ui.toolbar = $(this.options.toolbarHtml);
1259
+
1260
+ if ($.browser.msie && parseInt($.browser.version, 10) < 8) {
1261
+ this.options.autoGrow = false;
1262
+ }
1263
+
1264
+ if (newX === 0 && element.cols) {
1265
+ newX = (element.cols * 8) + 21;
1266
+ }
1267
+ if (newY === 0 && element.rows) {
1268
+ newY = (element.rows * 16) + 16;
1269
+ }
1270
+
1271
+ this.editor = $(window.location.protocol === "https:" ? '<iframe src="javascript:false;"></iframe>' : "<iframe></iframe>").attr("frameborder", "0");
1272
+
1273
+ if (this.options.iFrameClass) {
1274
+ this.editor.addClass(this.options.iFrameClass);
1275
+ } else {
1276
+ this.editor.css({
1277
+ minHeight: (newY - 6).toString() + "px",
1278
+ // fix for issue 12 ( http://github.com/akzhan/jwysiwyg/issues/issue/12 )
1279
+ width: (newX > 50) ? (newX - 8).toString() + "px" : ""
1280
+ });
1281
+ if ($.browser.msie && parseInt($.browser.version, 10) < 7) {
1282
+ this.editor.css("height", newY.toString() + "px");
1283
+ }
1284
+ }
1285
+ /**
1286
+ * Automagically add id to iframe if textarea has its own when possible
1287
+ * ( http://github.com/akzhan/jwysiwyg/issues/245 )
1288
+ */
1289
+ if (element.id) {
1290
+ var proposedId = element.id + '-wysiwyg-iframe';
1291
+ if (! document.getElementById(proposedId)) {
1292
+ this.editor.attr('id', proposedId);
1293
+ }
1294
+ }
1295
+
1296
+ /**
1297
+ * http://code.google.com/p/jwysiwyg/issues/detail?id=96
1298
+ */
1299
+ this.editor.attr("tabindex", $(element).attr("tabindex"));
1300
+
1301
+ this.element = $("<div/>").addClass("wysiwyg");
1302
+
1303
+ if (!this.options.iFrameClass) {
1304
+ this.element.css({
1305
+ width: (newX > 0) ? newX.toString() + "px" : "100%"
1306
+ });
1307
+ }
1308
+
1309
+ $(element).hide().before(this.element);
1310
+
1311
+ this.viewHTML = false;
1312
+
1313
+ /**
1314
+ * @link http://code.google.com/p/jwysiwyg/issues/detail?id=52
1315
+ */
1316
+ this.initialContent = $(element).val();
1317
+ this.ui.initFrame();
1318
+
1319
+ if (this.options.resizeOptions && $.fn.resizable) {
1320
+ this.element.resizable($.extend(true, {
1321
+ alsoResize: this.editor
1322
+ }, this.options.resizeOptions));
1323
+ }
1324
+
1325
+ if (this.options.autoSave) {
1326
+ $form.bind("submit.wysiwyg", function () { self.autoSaveFunction(); });
1327
+ }
1328
+
1329
+ $form.bind("reset.wysiwyg", function () { self.resetFunction(); });
1330
+ };
1331
+
1332
+ this.ui.initFrame = function () {
1333
+ var self = this.self,
1334
+ stylesheet,
1335
+ growHandler,
1336
+ saveHandler;
1337
+
1338
+ self.ui.appendControls();
1339
+ self.element.append(self.ui.toolbar)
1340
+ .append($("<div><!-- --></div>")
1341
+ .css({
1342
+ clear: "both"
1343
+ }))
1344
+ .append(self.editor);
1345
+
1346
+ self.editorDoc = self.innerDocument();
1347
+
1348
+ if (self.isDestroyed) {
1349
+ return null;
1350
+ }
1351
+
1352
+ self.ui.designMode();
1353
+ self.editorDoc.open();
1354
+ self.editorDoc.write(
1355
+ self.options.html
1356
+ /**
1357
+ * @link http://code.google.com/p/jwysiwyg/issues/detail?id=144
1358
+ */
1359
+ .replace(/INITIAL_CONTENT/, function () { return self.wrapInitialContent(); })
1360
+ );
1361
+ self.editorDoc.close();
1362
+
1363
+ $.wysiwyg.plugin.bind(self);
1364
+
1365
+ $(self.editorDoc).trigger("initFrame.wysiwyg");
1366
+
1367
+ $(self.editorDoc).bind("click.wysiwyg", function (event) {
1368
+ self.ui.checkTargets(event.target ? event.target : event.srcElement);
1369
+ });
1370
+
1371
+ /**
1372
+ * @link https://github.com/akzhan/jwysiwyg/issues/251
1373
+ */
1374
+ setInterval(function () {
1375
+ var offset = null;
1376
+
1377
+ try {
1378
+ var range = self.getInternalRange();
1379
+ if (range) {
1380
+ offset = {
1381
+ range: range,
1382
+ parent: $.browser.msie ? range.parentElement() : range.endContainer.parentNode,
1383
+ width: ($.browser.msie ? range.boundingWidth : range.startOffset - range.endOffset) || 0
1384
+ };
1385
+ }
1386
+ }
1387
+ catch (e) { console.error(e); }
1388
+
1389
+ if (offset && offset.width == 0 && !self.editorDoc.rememberCommand) {
1390
+ self.ui.checkTargets(offset.parent);
1391
+ }
1392
+ }, 400);
1393
+
1394
+ /**
1395
+ * @link http://code.google.com/p/jwysiwyg/issues/detail?id=20
1396
+ */
1397
+ $(self.original).focus(function () {
1398
+ if ($(this).filter(":visible").length === 0) {
1399
+ return;
1400
+ }
1401
+ self.ui.focus();
1402
+ });
1403
+
1404
+ $(self.editorDoc).keydown(function (event) {
1405
+ var emptyContentRegex;
1406
+ if (event.keyCode === 8) { // backspace
1407
+ emptyContentRegex = /^<([\w]+)[^>]*>(<br\/?>)?<\/\1>$/;
1408
+ if (emptyContentRegex.test(self.getContent())) { // if content is empty
1409
+ event.stopPropagation(); // prevent remove single empty tag
1410
+ return false;
1411
+ }
1412
+ }
1413
+
1414
+ self.editorDoc.rememberCommand = false;
1415
+ return true;
1416
+ });
1417
+
1418
+ if (!$.browser.msie) {
1419
+ $(self.editorDoc).keydown(function (event) {
1420
+ var controlName;
1421
+
1422
+ /* Meta for Macs. tom@punkave.com */
1423
+ if (event.ctrlKey || event.metaKey) {
1424
+ for (controlName in self.controls) {
1425
+ if (self.controls[controlName].hotkey && self.controls[controlName].hotkey.ctrl) {
1426
+ if (event.keyCode === self.controls[controlName].hotkey.key) {
1427
+ self.triggerControl.apply(self, [controlName, self.controls[controlName]]);
1428
+
1429
+ return false;
1430
+ }
1431
+ }
1432
+ }
1433
+ }
1434
+
1435
+ return true;
1436
+ });
1437
+ } else if (self.options.brIE) {
1438
+ $(self.editorDoc).keydown(function (event) {
1439
+ if (event.keyCode === 13) {
1440
+ var rng = self.getRange();
1441
+ rng.pasteHTML("<br/>");
1442
+ rng.collapse(false);
1443
+ rng.select();
1444
+
1445
+ return false;
1446
+ }
1447
+
1448
+ return true;
1449
+ });
1450
+ }
1451
+
1452
+ if (self.options.plugins.rmFormat.rmMsWordMarkup) {
1453
+ $(self.editorDoc).bind("keyup.wysiwyg", function (event) {
1454
+ if (event.ctrlKey || event.metaKey) {
1455
+ // CTRL + V (paste)
1456
+ if (86 === event.keyCode) {
1457
+ if ($.wysiwyg.rmFormat) {
1458
+ if ("object" === typeof (self.options.plugins.rmFormat.rmMsWordMarkup)) {
1459
+ $.wysiwyg.rmFormat.run(self, {rules: { msWordMarkup: self.options.plugins.rmFormat.rmMsWordMarkup }});
1460
+ } else {
1461
+ $.wysiwyg.rmFormat.run(self, {rules: { msWordMarkup: { enabled: true }}});
1462
+ }
1463
+ }
1464
+ }
1465
+ }
1466
+ });
1467
+ }
1468
+
1469
+ if (self.options.autoSave) {
1470
+ $(self.editorDoc).keydown(function () { self.autoSaveFunction(); })
1471
+ .keyup(function () { self.autoSaveFunction(); })
1472
+ .mousedown(function () { self.autoSaveFunction(); })
1473
+ .bind($.support.noCloneEvent ? "input.wysiwyg" : "paste.wysiwyg", function () { self.autoSaveFunction(); });
1474
+ }
1475
+
1476
+ if (self.options.autoGrow) {
1477
+ if (self.options.initialMinHeight !== null) {
1478
+ self.ui.initialHeight = self.options.initialMinHeight;
1479
+ } else {
1480
+ self.ui.initialHeight = $(self.editorDoc).height();
1481
+ }
1482
+ $(self.editorDoc.body).css("border", "1px solid white"); // cancel margin collapsing
1483
+
1484
+ growHandler = function () {
1485
+ self.ui.grow();
1486
+ };
1487
+
1488
+ $(self.editorDoc).keyup(growHandler);
1489
+ $(self.editorDoc).bind("editorRefresh.wysiwyg", growHandler);
1490
+
1491
+ // fix when content height > textarea height
1492
+ self.ui.grow();
1493
+ }
1494
+
1495
+ if (self.options.css) {
1496
+ if (String === self.options.css.constructor) {
1497
+ if ($.browser.msie) {
1498
+ stylesheet = self.editorDoc.createStyleSheet(self.options.css);
1499
+ $(stylesheet).attr({
1500
+ "media": "all"
1501
+ });
1502
+ } else {
1503
+ stylesheet = $("<link/>").attr({
1504
+ "href": self.options.css,
1505
+ "media": "all",
1506
+ "rel": "stylesheet",
1507
+ "type": "text/css"
1508
+ });
1509
+
1510
+ $(self.editorDoc).find("head").append(stylesheet);
1511
+ }
1512
+ } else {
1513
+ self.timers.initFrame_Css = window.setTimeout(function () {
1514
+ $(self.editorDoc.body).css(self.options.css);
1515
+ }, 0);
1516
+ }
1517
+ }
1518
+
1519
+ if (self.initialContent.length === 0) {
1520
+ if ("function" === typeof (self.options.initialContent)) {
1521
+ self.setContent(self.options.initialContent());
1522
+ } else {
1523
+ self.setContent(self.options.initialContent);
1524
+ }
1525
+ }
1526
+
1527
+ if (self.options.maxLength > 0) {
1528
+ $(self.editorDoc).keydown(function (event) {
1529
+ if ($(self.editorDoc).text().length >= self.options.maxLength && $.inArray(event.which, self.validKeyCodes) === -1) {
1530
+ event.preventDefault();
1531
+ }
1532
+ });
1533
+ }
1534
+
1535
+ // Support event callbacks
1536
+ $.each(self.options.events, function (key, handler) {
1537
+ $(self.editorDoc).bind(key + ".wysiwyg", function (event) {
1538
+ // Trigger event handler, providing the event and api to
1539
+ // support additional functionality.
1540
+ handler.apply(self.editorDoc, [event, self]);
1541
+ });
1542
+ });
1543
+
1544
+ // restores selection properly on focus
1545
+ if ($.browser.msie) {
1546
+ // Event chain: beforedeactivate => focusout => blur.
1547
+ // Focusout & blur fired too late to handle internalRange() in dialogs.
1548
+ // When clicked on input boxes both got range = null
1549
+ $(self.editorDoc).bind("beforedeactivate.wysiwyg", function () {
1550
+ self.savedRange = self.getInternalRange();
1551
+ });
1552
+ } else {
1553
+ $(self.editorDoc).bind("blur.wysiwyg", function () {
1554
+ self.savedRange = self.getInternalRange();
1555
+ });
1556
+ }
1557
+
1558
+ $(self.editorDoc.body).addClass("wysiwyg");
1559
+ if (self.options.events && self.options.events.save) {
1560
+ saveHandler = self.options.events.save;
1561
+
1562
+ $(self.editorDoc).bind("keyup.wysiwyg", saveHandler);
1563
+ $(self.editorDoc).bind("change.wysiwyg", saveHandler);
1564
+
1565
+ if ($.support.noCloneEvent) {
1566
+ $(self.editorDoc).bind("input.wysiwyg", saveHandler);
1567
+ } else {
1568
+ $(self.editorDoc).bind("paste.wysiwyg", saveHandler);
1569
+ $(self.editorDoc).bind("cut.wysiwyg", saveHandler);
1570
+ }
1571
+ }
1572
+
1573
+ /**
1574
+ * XHTML5 {@link https://github.com/akzhan/jwysiwyg/issues/152}
1575
+ */
1576
+ if (self.options.xhtml5 && self.options.unicode) {
1577
+ var replacements = {ne:8800,le:8804,para:182,xi:958,darr:8595,nu:957,oacute:243,Uacute:218,omega:969,prime:8242,pound:163,igrave:236,thorn:254,forall:8704,emsp:8195,lowast:8727,brvbar:166,alefsym:8501,nbsp:160,delta:948,clubs:9827,lArr:8656,Omega:937,Auml:196,cedil:184,and:8743,plusmn:177,ge:8805,raquo:187,uml:168,equiv:8801,laquo:171,rdquo:8221,Epsilon:917,divide:247,fnof:402,chi:967,Dagger:8225,iacute:237,rceil:8969,sigma:963,Oslash:216,acute:180,frac34:190,lrm:8206,upsih:978,Scaron:352,part:8706,exist:8707,nabla:8711,image:8465,prop:8733,zwj:8205,omicron:959,aacute:225,Yuml:376,Yacute:221,weierp:8472,rsquo:8217,otimes:8855,kappa:954,thetasym:977,harr:8596,Ouml:214,Iota:921,ograve:242,sdot:8901,copy:169,oplus:8853,acirc:226,sup:8835,zeta:950,Iacute:205,Oacute:211,crarr:8629,Nu:925,bdquo:8222,lsquo:8216,apos:39,Beta:914,eacute:233,egrave:232,lceil:8968,Kappa:922,piv:982,Ccedil:199,ldquo:8220,Xi:926,cent:162,uarr:8593,hellip:8230,Aacute:193,ensp:8194,sect:167,Ugrave:217,aelig:230,ordf:170,curren:164,sbquo:8218,macr:175,Phi:934,Eta:919,rho:961,Omicron:927,sup2:178,euro:8364,aring:229,Theta:920,mdash:8212,uuml:252,otilde:245,eta:951,uacute:250,rArr:8658,nsub:8836,agrave:224,notin:8713,ndash:8211,Psi:936,Ocirc:212,sube:8838,szlig:223,micro:181,not:172,sup1:185,middot:183,iota:953,ecirc:234,lsaquo:8249,thinsp:8201,sum:8721,ntilde:241,scaron:353,cap:8745,atilde:227,lang:10216,__replacement:65533,isin:8712,gamma:947,Euml:203,ang:8736,upsilon:965,Ntilde:209,hearts:9829,Alpha:913,Tau:932,spades:9824,dagger:8224,THORN:222,"int":8747,lambda:955,Eacute:201,Uuml:220,infin:8734,rlm:8207,Aring:197,ugrave:249,Egrave:200,Acirc:194,rsaquo:8250,ETH:208,oslash:248,alpha:945,Ograve:210,Prime:8243,mu:956,ni:8715,real:8476,bull:8226,beta:946,icirc:238,eth:240,prod:8719,larr:8592,ordm:186,perp:8869,Gamma:915,reg:174,ucirc:251,Pi:928,psi:968,tilde:732,asymp:8776,zwnj:8204,Agrave:192,deg:176,AElig:198,times:215,Delta:916,sim:8764,Otilde:213,Mu:924,uArr:8657,circ:710,theta:952,Rho:929,sup3:179,diams:9830,tau:964,Chi:935,frac14:188,oelig:339,shy:173,or:8744,dArr:8659,phi:966,iuml:239,Lambda:923,rfloor:8971,iexcl:161,cong:8773,ccedil:231,Icirc:206,frac12:189,loz:9674,rarr:8594,cup:8746,radic:8730,frasl:8260,euml:235,OElig:338,hArr:8660,Atilde:195,Upsilon:933,there4:8756,ouml:246,oline:8254,Ecirc:202,yacute:253,auml:228,permil:8240,sigmaf:962,iquest:191,empty:8709,pi:960,Ucirc:219,supe:8839,Igrave:204,yen:165,rang:10217,trade:8482,lfloor:8970,minus:8722,Zeta:918,sub:8834,epsilon:949,yuml:255,Sigma:931,Iuml:207,ocirc:244};
1578
+ self.events.bind("getContent", function (text) {
1579
+ return text.replace(/&(?:amp;)?(?!amp|lt|gt|quot)([a-z][a-z0-9]*);/gi, function (str, p1) {
1580
+ if (!replacements[p1]) {
1581
+ p1 = p1.toLowerCase();
1582
+ if (!replacements[p1]) {
1583
+ p1 = "__replacement";
1584
+ }
1585
+ }
1586
+
1587
+ var num = replacements[p1];
1588
+ /* Numeric return if ever wanted: return replacements[p1] ? "&#"+num+";" : ""; */
1589
+ return String.fromCharCode(num);
1590
+ });
1591
+ });
1592
+ }
1593
+ $(self.original).trigger('ready.jwysiwyg', [self.editorDoc, self]);
1594
+ };
1595
+
1596
+ this.innerDocument = function () {
1597
+ var element = this.editor.get(0);
1598
+
1599
+ if (element.nodeName.toLowerCase() === "iframe") {
1600
+ if (element.contentDocument) { // Gecko
1601
+ return element.contentDocument;
1602
+ } else if (element.contentWindow) { // IE
1603
+ return element.contentWindow.document;
1604
+ }
1605
+
1606
+ if (this.isDestroyed) {
1607
+ return null;
1608
+ }
1609
+
1610
+ console.error("Unexpected error in innerDocument");
1611
+
1612
+ /*
1613
+ return ( $.browser.msie )
1614
+ ? document.frames[element.id].document
1615
+ : element.contentWindow.document // contentDocument;
1616
+ */
1617
+ }
1618
+
1619
+ return element;
1620
+ };
1621
+
1622
+ this.insertHtml = function (szHTML) {
1623
+ var img, range;
1624
+
1625
+ if (!szHTML || szHTML.length === 0) {
1626
+ return this;
1627
+ }
1628
+
1629
+ if ($.browser.msie) {
1630
+ this.ui.focus();
1631
+ this.editorDoc.execCommand("insertImage", false, "#jwysiwyg#");
1632
+ img = this.getElementByAttributeValue("img", "src", "#jwysiwyg#");
1633
+ if (img) {
1634
+ $(img).replaceWith(szHTML);
1635
+ }
1636
+ } else {
1637
+ if ($.browser.mozilla) { // @link https://github.com/akzhan/jwysiwyg/issues/50
1638
+ if (1 === $(szHTML).length) {
1639
+ range = this.getInternalRange();
1640
+ range.deleteContents();
1641
+ range.insertNode($(szHTML).get(0));
1642
+ } else {
1643
+ this.editorDoc.execCommand("insertHTML", false, szHTML);
1644
+ }
1645
+ } else {
1646
+ if (!this.editorDoc.execCommand("insertHTML", false, szHTML)) {
1647
+ this.editor.focus();
1648
+ /* :TODO: place caret at the end
1649
+ if (window.getSelection) {
1650
+ } else {
1651
+ }
1652
+ this.editor.focus();
1653
+ */
1654
+ this.editorDoc.execCommand("insertHTML", false, szHTML);
1655
+ }
1656
+ }
1657
+ }
1658
+
1659
+ this.saveContent();
1660
+
1661
+ return this;
1662
+ };
1663
+
1664
+ //check allowed properties
1665
+ this.parseControls = function () {
1666
+ var self = this;
1667
+
1668
+ $.each(this.options.controls, function (controlName, control) {
1669
+ $.each(control, function (propertyName) {
1670
+ if (-1 === $.inArray(propertyName, self.availableControlProperties)) {
1671
+ throw controlName + '["' + propertyName + '"]: property "' + propertyName + '" not exists in Wysiwyg.availableControlProperties';
1672
+ }
1673
+ });
1674
+ });
1675
+
1676
+ if (this.options.parseControls) { //user callback
1677
+ return this.options.parseControls.call(this);
1678
+ }
1679
+
1680
+ return this.options.controls;
1681
+ };
1682
+
1683
+ this.removeFormat = function () {
1684
+ if ($.browser.msie) {
1685
+ this.ui.focus();
1686
+ }
1687
+
1688
+ if (this.options.removeHeadings) {
1689
+ this.editorDoc.execCommand("formatBlock", false, "<p>"); // remove headings
1690
+ }
1691
+
1692
+ this.editorDoc.execCommand("removeFormat", false, null);
1693
+ this.editorDoc.execCommand("unlink", false, null);
1694
+
1695
+ if ($.wysiwyg.rmFormat && $.wysiwyg.rmFormat.enabled) {
1696
+ if ("object" === typeof (this.options.plugins.rmFormat.rmMsWordMarkup)) {
1697
+ $.wysiwyg.rmFormat.run(this, {rules: { msWordMarkup: this.options.plugins.rmFormat.rmMsWordMarkup }});
1698
+ } else {
1699
+ $.wysiwyg.rmFormat.run(this, {rules: { msWordMarkup: { enabled: true }}});
1700
+ }
1701
+ }
1702
+
1703
+ return this;
1704
+ };
1705
+
1706
+ this.ui.removeHoverClass = function () {
1707
+ $(this).removeClass("wysiwyg-button-hover");
1708
+ };
1709
+
1710
+ this.resetFunction = function () {
1711
+ this.setContent(this.initialContent);
1712
+ };
1713
+
1714
+ this.saveContent = function () {
1715
+ if (this.viewHTML)
1716
+ {
1717
+ return; // no need
1718
+ }
1719
+ if (this.original) {
1720
+ var content, newContent;
1721
+
1722
+ content = this.getContent();
1723
+
1724
+ if (this.options.rmUnwantedBr) {
1725
+ content = content.replace(/<br\/?>$/, "");
1726
+ }
1727
+
1728
+ if (this.options.replaceDivWithP) {
1729
+ newContent = $("<div/>").addClass("temp").append(content);
1730
+
1731
+ newContent.children("div").each(function () {
1732
+ var element = $(this), p = element.find("p"), i;
1733
+
1734
+ if (0 === p.length) {
1735
+ p = $("<p></p>");
1736
+
1737
+ if (this.attributes.length > 0) {
1738
+ for (i = 0; i < this.attributes.length; i += 1) {
1739
+ p.attr(this.attributes[i].name, element.attr(this.attributes[i].name));
1740
+ }
1741
+ }
1742
+
1743
+ p.append(element.html());
1744
+
1745
+ element.replaceWith(p);
1746
+ }
1747
+ });
1748
+
1749
+ content = newContent.html();
1750
+ }
1751
+
1752
+ $(this.original).val(content);
1753
+
1754
+ if (this.options.events && this.options.events.save) {
1755
+ this.options.events.save.call(this);
1756
+ }
1757
+ }
1758
+
1759
+ return this;
1760
+ };
1761
+
1762
+ this.setContent = function (newContent) {
1763
+ this.editorDoc.body.innerHTML = newContent;
1764
+ this.saveContent();
1765
+
1766
+ return this;
1767
+ };
1768
+
1769
+ this.triggerControl = function (name, control) {
1770
+ var cmd = control.command || name, //command directly for designMode=on iframe (this.editorDoc)
1771
+ args = control["arguments"] || [];
1772
+
1773
+ if (control.exec) {
1774
+ control.exec.apply(this); //custom exec function in control, allows DOM changing
1775
+ } else {
1776
+ this.ui.focus();
1777
+ this.ui.withoutCss(); //disable style="" attr inserting in mozzila's designMode
1778
+ // when click <Cut>, <Copy> or <Paste> got "Access to XPConnect service denied" code: "1011"
1779
+ // in Firefox untrusted JavaScript is not allowed to access the clipboard
1780
+ try {
1781
+ this.editorDoc.execCommand(cmd, false, args);
1782
+ } catch (e) {
1783
+ console.error(e);
1784
+ }
1785
+ }
1786
+
1787
+ if (this.options.autoSave) {
1788
+ this.autoSaveFunction();
1789
+ }
1790
+ };
1791
+
1792
+ this.triggerControlCallback = function (name) {
1793
+ $(window).trigger("trigger-" + name + ".wysiwyg", [this]);
1794
+ };
1795
+
1796
+ this.ui.withoutCss = function () {
1797
+ var self = this.self;
1798
+
1799
+ if ($.browser.mozilla) {
1800
+ try {
1801
+ self.editorDoc.execCommand("styleWithCSS", false, false);
1802
+ } catch (e) {
1803
+ try {
1804
+ self.editorDoc.execCommand("useCSS", false, true);
1805
+ } catch (e2) {
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+ return self;
1811
+ };
1812
+
1813
+ this.wrapInitialContent = function () {
1814
+ var content = this.initialContent,
1815
+ found = content.match(/<\/?p>/gi);
1816
+
1817
+ if (!found) {
1818
+ return "<p>" + content + "</p>";
1819
+ } else {
1820
+ // :TODO: checking/replacing
1821
+ }
1822
+
1823
+ return content;
1824
+ };
1825
+ }
1826
+
1827
+ /*
1828
+ * Wysiwyg namespace: public properties and methods
1829
+ */
1830
+ $.wysiwyg = {
1831
+ messages: {
1832
+ noObject: "Something goes wrong, check object"
1833
+ },
1834
+
1835
+ /**
1836
+ * Custom control support by Alec Gorge ( http://github.com/alecgorge )
1837
+ */
1838
+ addControl: function (object, name, settings) {
1839
+ return object.each(function () {
1840
+ var oWysiwyg = $(this).data("wysiwyg"),
1841
+ customControl = {},
1842
+ toolbar;
1843
+
1844
+ if (!oWysiwyg) {
1845
+ return this;
1846
+ }
1847
+
1848
+ customControl[name] = $.extend(true, {visible: true, custom: true}, settings);
1849
+ $.extend(true, oWysiwyg.options.controls, customControl);
1850
+
1851
+ // render new toolbar
1852
+ toolbar = $(oWysiwyg.options.toolbarHtml);
1853
+ oWysiwyg.ui.toolbar.replaceWith(toolbar);
1854
+ oWysiwyg.ui.toolbar = toolbar;
1855
+ oWysiwyg.ui.appendControls();
1856
+ });
1857
+ },
1858
+
1859
+ clear: function (object) {
1860
+ return object.each(function () {
1861
+ var oWysiwyg = $(this).data("wysiwyg");
1862
+
1863
+ if (!oWysiwyg) {
1864
+ return this;
1865
+ }
1866
+
1867
+ oWysiwyg.setContent("");
1868
+ });
1869
+ },
1870
+
1871
+ console: console, // let our console be available for extensions
1872
+
1873
+ destroy: function (object) {
1874
+ return object.each(function () {
1875
+ var oWysiwyg = $(this).data("wysiwyg");
1876
+
1877
+ if (!oWysiwyg) {
1878
+ return this;
1879
+ }
1880
+
1881
+ oWysiwyg.destroy();
1882
+ });
1883
+ },
1884
+
1885
+ "document": function (object) {
1886
+ // no chains because of return
1887
+ var oWysiwyg = object.data("wysiwyg");
1888
+
1889
+ if (!oWysiwyg) {
1890
+ return undefined;
1891
+ }
1892
+
1893
+ return $(oWysiwyg.editorDoc);
1894
+ },
1895
+
1896
+ getContent: function (object) {
1897
+ // no chains because of return
1898
+ var oWysiwyg = object.data("wysiwyg");
1899
+
1900
+ if (!oWysiwyg) {
1901
+ return undefined;
1902
+ }
1903
+
1904
+ return oWysiwyg.getContent();
1905
+ },
1906
+
1907
+ init: function (object, options) {
1908
+ return object.each(function () {
1909
+ var opts = $.extend(true, {}, options),
1910
+ obj;
1911
+
1912
+ // :4fun:
1913
+ // remove this textarea validation and change line in this.saveContent function
1914
+ // $(this.original).val(content); to $(this.original).html(content);
1915
+ // now you can make WYSIWYG editor on h1, p, and many more tags
1916
+ if (("textarea" !== this.nodeName.toLowerCase()) || $(this).data("wysiwyg")) {
1917
+ return;
1918
+ }
1919
+
1920
+ obj = new Wysiwyg();
1921
+ obj.init(this, opts);
1922
+ $.data(this, "wysiwyg", obj);
1923
+
1924
+ $(obj.editorDoc).trigger("afterInit.wysiwyg");
1925
+ });
1926
+ },
1927
+
1928
+ insertHtml: function (object, szHTML) {
1929
+ return object.each(function () {
1930
+ var oWysiwyg = $(this).data("wysiwyg");
1931
+
1932
+ if (!oWysiwyg) {
1933
+ return this;
1934
+ }
1935
+
1936
+ oWysiwyg.insertHtml(szHTML);
1937
+ });
1938
+ },
1939
+
1940
+ plugin: {
1941
+ listeners: {},
1942
+
1943
+ bind: function (Wysiwyg) {
1944
+ var self = this;
1945
+
1946
+ $.each(this.listeners, function (action, handlers) {
1947
+ var i, plugin;
1948
+
1949
+ for (i = 0; i < handlers.length; i += 1) {
1950
+ plugin = self.parseName(handlers[i]);
1951
+
1952
+ $(Wysiwyg.editorDoc).bind(action + ".wysiwyg", {plugin: plugin}, function (event) {
1953
+ $.wysiwyg[event.data.plugin.name][event.data.plugin.method].apply($.wysiwyg[event.data.plugin.name], [Wysiwyg]);
1954
+ });
1955
+ }
1956
+ });
1957
+ },
1958
+
1959
+ exists: function (name) {
1960
+ var plugin;
1961
+
1962
+ if ("string" !== typeof (name)) {
1963
+ return false;
1964
+ }
1965
+
1966
+ plugin = this.parseName(name);
1967
+
1968
+ if (!$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method]) {
1969
+ return false;
1970
+ }
1971
+
1972
+ return true;
1973
+ },
1974
+
1975
+ listen: function (action, handler) {
1976
+ var plugin;
1977
+
1978
+ plugin = this.parseName(handler);
1979
+
1980
+ if (!$.wysiwyg[plugin.name] || !$.wysiwyg[plugin.name][plugin.method]) {
1981
+ return false;
1982
+ }
1983
+
1984
+ if (!this.listeners[action]) {
1985
+ this.listeners[action] = [];
1986
+ }
1987
+
1988
+ this.listeners[action].push(handler);
1989
+
1990
+ return true;
1991
+ },
1992
+
1993
+ parseName: function (name) {
1994
+ var elements;
1995
+
1996
+ if ("string" !== typeof (name)) {
1997
+ return false;
1998
+ }
1999
+
2000
+ elements = name.split(".");
2001
+
2002
+ if (2 > elements.length) {
2003
+ return false;
2004
+ }
2005
+
2006
+ return {name: elements[0], method: elements[1]};
2007
+ },
2008
+
2009
+ register: function (data) {
2010
+ if (!data.name) {
2011
+ console.error("Plugin name missing");
2012
+ }
2013
+
2014
+ $.each($.wysiwyg, function (pluginName) {
2015
+ if (pluginName === data.name) {
2016
+ console.error("Plugin with name '" + data.name + "' was already registered");
2017
+ }
2018
+ });
2019
+
2020
+ $.wysiwyg[data.name] = data;
2021
+
2022
+ return true;
2023
+ }
2024
+ },
2025
+
2026
+ removeFormat: function (object) {
2027
+ return object.each(function () {
2028
+ var oWysiwyg = $(this).data("wysiwyg");
2029
+
2030
+ if (!oWysiwyg) {
2031
+ return this;
2032
+ }
2033
+
2034
+ oWysiwyg.removeFormat();
2035
+ });
2036
+ },
2037
+
2038
+ save: function (object) {
2039
+ return object.each(function () {
2040
+ var oWysiwyg = $(this).data("wysiwyg");
2041
+
2042
+ if (!oWysiwyg) {
2043
+ return this;
2044
+ }
2045
+
2046
+ oWysiwyg.saveContent();
2047
+ });
2048
+ },
2049
+
2050
+ selectAll: function (object) {
2051
+ var oWysiwyg = object.data("wysiwyg"), oBody, oRange, selection;
2052
+
2053
+ if (!oWysiwyg) {
2054
+ return this;
2055
+ }
2056
+
2057
+ oBody = oWysiwyg.editorDoc.body;
2058
+ if (window.getSelection) {
2059
+ selection = oWysiwyg.getInternalSelection();
2060
+ selection.selectAllChildren(oBody);
2061
+ } else {
2062
+ oRange = oBody.createTextRange();
2063
+ oRange.moveToElementText(oBody);
2064
+ oRange.select();
2065
+ }
2066
+ },
2067
+
2068
+ setContent: function (object, newContent) {
2069
+ return object.each(function () {
2070
+ var oWysiwyg = $(this).data("wysiwyg");
2071
+
2072
+ if (!oWysiwyg) {
2073
+ return this;
2074
+ }
2075
+
2076
+ oWysiwyg.setContent(newContent);
2077
+ });
2078
+ },
2079
+
2080
+ triggerControl: function (object, controlName) {
2081
+ return object.each(function () {
2082
+ var oWysiwyg = $(this).data("wysiwyg");
2083
+
2084
+ if (!oWysiwyg) {
2085
+ return this;
2086
+ }
2087
+
2088
+ if (!oWysiwyg.controls[controlName]) {
2089
+ console.error("Control '" + controlName + "' not exists");
2090
+ }
2091
+
2092
+ oWysiwyg.triggerControl.apply(oWysiwyg, [controlName, oWysiwyg.controls[controlName]]);
2093
+ });
2094
+ },
2095
+
2096
+ support: {
2097
+ prop: supportsProp
2098
+ },
2099
+
2100
+ utils: {
2101
+ extraSafeEntities: [["<", ">", "'", '"', " "], [32]],
2102
+
2103
+ encodeEntities: function (str) {
2104
+ var self = this, aStr, aRet = [];
2105
+
2106
+ if (this.extraSafeEntities[1].length === 0) {
2107
+ $.each(this.extraSafeEntities[0], function (i, ch) {
2108
+ self.extraSafeEntities[1].push(ch.charCodeAt(0));
2109
+ });
2110
+ }
2111
+ aStr = str.split("");
2112
+ $.each(aStr, function (i) {
2113
+ var iC = aStr[i].charCodeAt(0);
2114
+ if ($.inArray(iC, self.extraSafeEntities[1]) && (iC < 65 || iC > 127 || (iC > 90 && iC < 97))) {
2115
+ aRet.push('&#' + iC + ';');
2116
+ } else {
2117
+ aRet.push(aStr[i]);
2118
+ }
2119
+ });
2120
+
2121
+ return aRet.join('');
2122
+ }
2123
+ }
2124
+ };
2125
+
2126
+ /**
2127
+ * Unifies dialog methods to allow custom implementations
2128
+ *
2129
+ * Events:
2130
+ * * afterOpen
2131
+ * * beforeShow
2132
+ * * afterShow
2133
+ * * beforeHide
2134
+ * * afterHide
2135
+ * * beforeClose
2136
+ * * afterClose
2137
+ *
2138
+ * Example:
2139
+ * var dialog = new ($.wysiwyg.dialog)($('#idToTextArea').data('wysiwyg'), {"title": "Test", "content": "form data, etc."});
2140
+ *
2141
+ * dialog.bind("afterOpen", function () { alert('you should see a dialog behind this one!'); });
2142
+ *
2143
+ * dialog.open();
2144
+ *
2145
+ *
2146
+ */
2147
+ $.wysiwyg.dialog = function (jWysiwyg, opts) {
2148
+
2149
+ var theme = (jWysiwyg && jWysiwyg.options && jWysiwyg.options.dialog) ? jWysiwyg.options.dialog : (opts.theme ? opts.theme : "default"),
2150
+ obj = new $.wysiwyg.dialog.createDialog(theme),
2151
+ that = this,
2152
+ $that = $(that);
2153
+
2154
+ this.options = {
2155
+ "modal": true,
2156
+ "draggable": true,
2157
+ "title": "Title",
2158
+ "content": "Content",
2159
+ "width": "auto",
2160
+ "height": "auto",
2161
+ "zIndex": 2000,
2162
+ "open": false,
2163
+ "close": false
2164
+ };
2165
+
2166
+ this.isOpen = false;
2167
+
2168
+ $.extend(this.options, opts);
2169
+
2170
+ this.object = obj;
2171
+
2172
+ // Opens a dialog with the specified content
2173
+ this.open = function () {
2174
+ this.isOpen = true;
2175
+
2176
+ obj.init.apply(that, []);
2177
+ var $dialog = obj.show.apply(that, []);
2178
+
2179
+ $that.trigger("afterOpen", [$dialog]);
2180
+
2181
+ };
2182
+
2183
+ this.show = function () {
2184
+ this.isOpen = true;
2185
+
2186
+ $that.trigger("beforeShow");
2187
+
2188
+ var $dialog = obj.show.apply(that, []);
2189
+
2190
+ $that.trigger("afterShow");
2191
+ };
2192
+
2193
+ this.hide = function () {
2194
+ this.isOpen = false;
2195
+
2196
+ $that.trigger("beforeHide");
2197
+
2198
+ var $dialog = obj.hide.apply(that, []);
2199
+
2200
+ $that.trigger("afterHide", [$dialog]);
2201
+ };
2202
+
2203
+ // Closes the dialog window.
2204
+ this.close = function () {
2205
+ this.isOpen = false;
2206
+
2207
+ var $dialog = obj.hide.apply(that, []);
2208
+
2209
+ $that.trigger("beforeClose", [$dialog]);
2210
+
2211
+ obj.destroy.apply(that, []);
2212
+
2213
+ $that.trigger("afterClose", [$dialog]);
2214
+
2215
+ };
2216
+
2217
+ if (this.options.open) {
2218
+ $that.bind("afterOpen", this.options.open);
2219
+ }
2220
+ if (this.options.close) {
2221
+ $that.bind("afterClose", this.options.close);
2222
+ }
2223
+
2224
+ return this;
2225
+ };
2226
+
2227
+ // "Static" Dialog methods.
2228
+ $.extend(true, $.wysiwyg.dialog, {
2229
+ _themes : {}, // sample {"Theme Name": object}
2230
+ _theme : "", // the current theme
2231
+
2232
+ register : function(name, obj) {
2233
+ $.wysiwyg.dialog._themes[name] = obj;
2234
+ },
2235
+
2236
+ deregister : function (name) {
2237
+ delete $.wysiwyg.dialog._themes[name];
2238
+ },
2239
+
2240
+ createDialog : function (name) {
2241
+ return new ($.wysiwyg.dialog._themes[name]);
2242
+ },
2243
+
2244
+ getDimensions : function () {
2245
+ var width = document.body.scrollWidth,
2246
+ height = document.body.scrollHeight;
2247
+
2248
+ if ($.browser.opera) {
2249
+ height = Math.max(
2250
+ $(document).height(),
2251
+ $(window).height(),
2252
+ document.documentElement.clientHeight);
2253
+ }
2254
+
2255
+ return [width, height];
2256
+ }
2257
+ });
2258
+
2259
+ $(function () { // need access to jQuery UI stuff.
2260
+ if (jQuery.ui) {
2261
+ $.wysiwyg.dialog.register("jqueryui", function () {
2262
+ var that = this;
2263
+
2264
+ this._$dialog = null;
2265
+
2266
+ this.init = function() {
2267
+ var abstractDialog = this,
2268
+ content = this.options.content;
2269
+
2270
+ if (typeof content === 'object') {
2271
+ if (typeof content.html === 'function') {
2272
+ content = content.html();
2273
+ } else if(typeof content.toString === 'function') {
2274
+ content = content.toString();
2275
+ }
2276
+ }
2277
+
2278
+ that._$dialog = $('<div></div>').attr('title', this.options.title).html(content);
2279
+
2280
+ var dialogHeight = this.options.height == 'auto' ? 300 : this.options.height,
2281
+ dialogWidth = this.options.width == 'auto' ? 450 : this.options.width;
2282
+
2283
+ // console.log(that._$dialog);
2284
+
2285
+ that._$dialog.dialog({
2286
+ modal: this.options.modal,
2287
+ draggable: this.options.draggable,
2288
+ height: dialogHeight,
2289
+ width: dialogWidth
2290
+ });
2291
+
2292
+ return that._$dialog;
2293
+ };
2294
+
2295
+ this.show = function () {
2296
+ that._$dialog.dialog("open");
2297
+ return that._$dialog;
2298
+ };
2299
+
2300
+ this.hide = function () {
2301
+ that._$dialog.dialog("close");
2302
+ return that._$dialog;
2303
+ };
2304
+
2305
+ this.destroy = function() {
2306
+ that._$dialog.dialog("destroy");
2307
+ return that._$dialog;
2308
+ };
2309
+ });
2310
+ }
2311
+
2312
+ $.wysiwyg.dialog.register("default", function () {
2313
+ var that = this;
2314
+
2315
+ this._$dialog = null;
2316
+
2317
+ this.init = function() {
2318
+ var abstractDialog = this,
2319
+ content = this.options.content;
2320
+
2321
+ if (typeof content === 'object') {
2322
+ if(typeof content.html === 'function') {
2323
+ content = content.html();
2324
+ }
2325
+ else if(typeof content.toString === 'function') {
2326
+ content = content.toString();
2327
+ }
2328
+ }
2329
+
2330
+ that._$dialog = $('<div class="wysiwyg-dialog"></div>').css({"z-index": this.options.zIndex});
2331
+
2332
+ var $topbar = $('<div class="wysiwyg-dialog-topbar"><div class="wysiwyg-dialog-close-wrapper"></div><div class="wysiwyg-dialog-title">'+this.options.title+'</div></div>');
2333
+ var $link = $('<a href="#" class="wysiwyg-dialog-close-button">X</a>');
2334
+
2335
+ $link.click(function () {
2336
+ abstractDialog.close(); // this is important it makes sure that is close from the abstract $.wysiwyg.dialog instace, not just locally
2337
+ });
2338
+
2339
+ $topbar.find('.wysiwyg-dialog-close-wrapper').prepend($link);
2340
+
2341
+ var $dcontent = $('<div class="wysiwyg-dialog-content">'+content+'</div>');
2342
+
2343
+ that._$dialog.append($topbar).append($dcontent);
2344
+
2345
+ // Set dialog's height & width, and position it correctly:
2346
+ var dialogHeight = this.options.height == 'auto' ? 300 : this.options.height,
2347
+ dialogWidth = this.options.width == 'auto' ? 450 : this.options.width;
2348
+ that._$dialog.hide().css({
2349
+ "width": dialogWidth,
2350
+ "height": dialogHeight,
2351
+ "left": (($(window).width() - dialogWidth) / 2),
2352
+ "top": (($(window).height() - dialogHeight) / 3)
2353
+ });
2354
+
2355
+ $("body").append(that._$dialog);
2356
+
2357
+ return that._$dialog;
2358
+ };
2359
+
2360
+ this.show = function () {
2361
+
2362
+ // Modal feature:
2363
+ if (this.options.modal) {
2364
+ var dimensions = $.wysiwyg.dialog.getDimensions(),
2365
+ wrapper = $('<div class="wysiwyg-dialog-modal-div"></div>')
2366
+ .css({"width": dimensions[0], "height": dimensions[1]});
2367
+ that._$dialog.wrap(wrapper);
2368
+ }
2369
+
2370
+ // Draggable feature:
2371
+ if (this.options.draggable) {
2372
+
2373
+ var mouseDown = false;
2374
+
2375
+ that._$dialog.find("div.wysiwyg-dialog-topbar").bind("mousedown", function (e) {
2376
+ e.preventDefault();
2377
+ $(this).css({ "cursor": "move" });
2378
+ var $topbar = $(this),
2379
+ _dialog = $(this).parents(".wysiwyg-dialog"),
2380
+ offsetX = (e.pageX - parseInt(_dialog.css("left"), 10)),
2381
+ offsetY = (e.pageY - parseInt(_dialog.css("top"), 10));
2382
+ mouseDown = true;
2383
+ $(this).css({ "cursor": "move" });
2384
+
2385
+ $(document).bind("mousemove", function (e) {
2386
+ e.preventDefault();
2387
+ if (mouseDown) {
2388
+ _dialog.css({
2389
+ "top": (e.pageY - offsetY),
2390
+ "left": (e.pageX - offsetX)
2391
+ });
2392
+ }
2393
+ }).bind("mouseup", function (e) {
2394
+ e.preventDefault();
2395
+ mouseDown = false;
2396
+ $topbar.css({ "cursor": "auto" });
2397
+ $(document).unbind("mousemove").unbind("mouseup");
2398
+ });
2399
+
2400
+ });
2401
+ }
2402
+
2403
+ that._$dialog.show();
2404
+ return that._$dialog;
2405
+
2406
+ };
2407
+
2408
+ this.hide = function () {
2409
+ that._$dialog.hide();
2410
+ return that._$dialog;
2411
+ };
2412
+
2413
+ this.destroy = function() {
2414
+
2415
+ // Modal feature:
2416
+ if (this.options.modal) {
2417
+ that._$dialog.unwrap();
2418
+ }
2419
+
2420
+ // Draggable feature:
2421
+ if (this.options.draggable) {
2422
+ that._$dialog.find("div.wysiwyg-dialog-topbar").unbind("mousedown");
2423
+ }
2424
+
2425
+ that._$dialog.remove();
2426
+ return that._$dialog;
2427
+ };
2428
+ });
2429
+ });
2430
+ // end Dialog
2431
+
2432
+ $.fn.wysiwyg = function (method) {
2433
+ var args = arguments, plugin;
2434
+
2435
+ if ("undefined" !== typeof $.wysiwyg[method]) {
2436
+ // set argument object to undefined
2437
+ args = Array.prototype.concat.call([args[0]], [this], Array.prototype.slice.call(args, 1));
2438
+ return $.wysiwyg[method].apply($.wysiwyg, Array.prototype.slice.call(args, 1));
2439
+ } else if ("object" === typeof method || !method) {
2440
+ Array.prototype.unshift.call(args, this);
2441
+ return $.wysiwyg.init.apply($.wysiwyg, args);
2442
+ } else if ($.wysiwyg.plugin.exists(method)) {
2443
+ plugin = $.wysiwyg.plugin.parseName(method);
2444
+ args = Array.prototype.concat.call([args[0]], [this], Array.prototype.slice.call(args, 1));
2445
+ return $.wysiwyg[plugin.name][plugin.method].apply($.wysiwyg[plugin.name], Array.prototype.slice.call(args, 1));
2446
+ } else {
2447
+ console.error("Method '" + method + "' does not exist on jQuery.wysiwyg.\nTry to include some extra controls or plugins");
2448
+ }
2449
+ };
2450
+
2451
+ $.fn.getWysiwyg = function () {
2452
+ return this.data("wysiwyg");
2453
+ };
2454
+ })(jQuery);