forked from cleditor/cleditor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jquery.cleditor.js
1225 lines (1012 loc) · 41.9 KB
/
jquery.cleditor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*!
CLEditor WYSIWYG HTML Editor v1.4.501
http://premiumsoftware.net/CLEditor
requires jQuery v1.4.2 or later
Copyright 2010, Chris Landowski, Premium Software, LLC
Dual licensed under the MIT or GPL Version 2 licenses.
Smart Toolbar function by franklx (ported from 1.3.1)
*/
(function ($) {
//==============
// jQuery Plugin
//==============
$.cleditor = {
// Define the defaults used for all new cleditor instances
defaultOptions: {
width: 'auto', // width not including margins, borders or padding
height: 250, // height not including margins, borders or padding
controls: // controls to add to the toolbar
"bold italic underline strikethrough subscript superscript | font size " +
"style | color highlight removeformat | bullets numbering | outdent " +
"indent | alignleft center alignright justify | undo redo | " +
"rule image link unlink | cut copy paste pastetext | print source",
colors: // colors in the color popup
"FFF FCC FC9 FF9 FFC 9F9 9FF CFF CCF FCF " +
"CCC F66 F96 FF6 FF3 6F9 3FF 6FF 99F F9F " +
"BBB F00 F90 FC6 FF0 3F3 6CC 3CF 66C C6C " +
"999 C00 F60 FC3 FC0 3C0 0CC 36F 63F C3C " +
"666 900 C60 C93 990 090 399 33F 60C 939 " +
"333 600 930 963 660 060 366 009 339 636 " +
"000 300 630 633 330 030 033 006 309 303",
fonts: // font names in the font popup
"Arial,Arial Black,Comic Sans MS,Courier New,Narrow,Garamond," +
"Georgia,Impact,Sans Serif,Serif,Tahoma,Trebuchet MS,Verdana",
sizes: // sizes in the font size popup
"1,2,3,4,5,6,7",
styles: // styles in the style popup
[["Paragraph", "<p>"], ["Header 1", "<h1>"], ["Header 2", "<h2>"],
["Header 3", "<h3>"], ["Header 4", "<h4>"], ["Header 5", "<h5>"],
["Header 6", "<h6>"]],
useCSS: true, // use CSS to style HTML when possible (not supported in ie)
docType: // Document type contained within the editor
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
docCSSFile: // CSS file used to style the document contained within the editor
"",
bodyStyle: // style to assign to document body contained within the editor
"margin:4px; font:10pt Arial,Verdana; cursor:text",
smartToolbar: true // enable smart-toolbar
},
// Define all usable toolbar buttons - the init string property is
// expanded during initialization back into the buttons object and
// separate object properties are created for each button.
// e.g. buttons.size.title = "Font Size"
buttons: {
// name,title,command,popupName (""=use name)
init:
"bold,,|" +
"italic,,|" +
"underline,,|" +
"strikethrough,,|" +
"subscript,,|" +
"superscript,,|" +
"font,,fontname,|" +
"size,Font Size,fontsize,|" +
"style,,formatblock,|" +
"color,Font Color,forecolor,|" +
"highlight,Text Highlight Color,hilitecolor,color|" +
"removeformat,Remove Formatting,|" +
"bullets,,insertunorderedlist|" +
"numbering,,insertorderedlist|" +
"outdent,,|" +
"indent,,|" +
"alignleft,Align Text Left,justifyleft|" +
"center,,justifycenter|" +
"alignright,Align Text Right,justifyright|" +
"justify,,justifyfull|" +
"undo,,|" +
"redo,,|" +
"rule,Insert Horizontal Rule,inserthorizontalrule|" +
"image,Insert Image,insertimage,url|" +
"link,Insert Hyperlink,createlink,url|" +
"unlink,Remove Hyperlink,|" +
"cut,,|" +
"copy,,|" +
"paste,,|" +
"pastetext,Paste as Text,inserthtml,|" +
"print,,|" +
"source,Show Source"
},
};
// cleditor - creates a new editor for each of the matched textareas
$.fn.cleditor = function (options) {
// Create a new jQuery object to hold the results
var $result = $([]);
// Loop through all matching textareas and create the editors
this.each(function (idx, elem) {
if (elem.tagName.toUpperCase() === "TEXTAREA") {
var data = $.data(elem, CLEDITOR);
if (!data) data = new cleditor(elem, options);
$result = $result.add(data);
}
});
// return the new jQuery object
return $result;
};
//==================
// Private Variables
//==================
var
// Misc constants
BACKGROUND_COLOR = "backgroundColor",
BLURRED = "blurred",
BUTTON = "button",
BUTTON_NAME = "buttonName",
CHANGE = "change",
CLEDITOR = "cleditor",
CLICK = "click",
DISABLED = "disabled",
DIV_TAG = "<div>",
FOCUSED = "focused",
TRANSPARENT = "transparent",
UNSELECTABLE = "unselectable",
// Class name constants
MAIN_CLASS = "cleditorMain", // main containing div
TOOLBAR_CLASS = "cleditorToolbar", // toolbar div inside main div
GROUP_CLASS = "cleditorGroup", // group divs inside the toolbar div
BUTTON_CLASS = "cleditorButton", // button divs inside group div
DISABLED_CLASS = "cleditorDisabled",// disabled button divs
DIVIDER_CLASS = "cleditorDivider", // divider divs inside group div
POPUP_CLASS = "cleditorPopup", // popup divs inside body
LIST_CLASS = "cleditorList", // list popup divs inside body
COLOR_CLASS = "cleditorColor", // color popup div inside body
PROMPT_CLASS = "cleditorPrompt", // prompt popup divs inside body
MSG_CLASS = "cleditorMsg", // message popup div inside body
TOOLIMG_CLASS = "cleditorToolImg", // toolbar image
// Browser detection
ua = navigator.userAgent.toLowerCase(),
ie = /msie/.test(ua),
ie6 = /msie\s6/.test(ua),
iege11 = /(trident)(?:.*rv:([\w.]+))?/.test(ua),
webkit = /webkit/.test(ua),
// Test for iPhone/iTouch/iPad
iOS = /iPhone|iPad|iPod/i.test(ua),
// Popups are created once as needed and shared by all editor instances
popups = {},
// Used to prevent the document click event from being bound more than once
documentClickAssigned,
// Local copy of the buttons object
buttons = $.cleditor.buttons;
//===============
// Initialization
//===============
// Expand the buttons.init string back into the buttons object
// and create seperate object properties for each button.
// e.g. buttons.size.title = "Font Size"
$.each(buttons.init.split("|"), function (idx, button) {
var items = button.split(","), name = items[0];
buttons[name] = {
stripIndex: idx,
name: name,
title: items[1] === "" ? name.charAt(0).toUpperCase() + name.substr(1) : items[1],
command: items[2] === "" ? name : items[2],
popupName: items[3] === "" ? name : items[3]
};
});
delete buttons.init;
//============
// Constructor
//============
// cleditor - creates a new editor for the passed in textarea element
cleditor = function (area, options) {
var editor = this;
// Get the defaults and override with options
editor.options = options = $.extend({}, $.cleditor.defaultOptions, options);
// Hide the textarea and associate it with this editor
var $area = editor.$area = $(area)
.css({ border: "none", margin: 0, padding: 0 }) // Needed for IE6 & 7 (won't work in CSS file)
.hide()
.data(CLEDITOR, editor)
.blur(function () {
// Update the iframe when the textarea loses focus
updateFrame(editor, true);
});
// Create the main container
var $main = editor.$main = $(DIV_TAG)
.addClass(MAIN_CLASS)
.width(options.width)
.height(options.height);
// Create the toolbar
var $toolbar = editor.$toolbar = $(DIV_TAG)
.addClass(TOOLBAR_CLASS)
.appendTo($main);
// Add the first group to the toolbar
var $group = $(DIV_TAG)
.addClass(GROUP_CLASS)
.appendTo($toolbar);
// Trigger form change event on initialization
var $form = $area.parents("form");
if ($form) {
$(this).change(function() {
$form.change();
});
}
editor.$tb_timeout = null;
// Add the buttons to the toolbar
$.each(options.controls.split(" "), function (idx, buttonName) {
if (buttonName === "") return true;
// Divider
if (buttonName === "|") {
// Add a new divider to the group
var $div = $(DIV_TAG)
.addClass(DIVIDER_CLASS)
.appendTo($group);
// Create a new group
$group = $(DIV_TAG)
.addClass(GROUP_CLASS)
.appendTo($toolbar);
}
// Button
else {
// Get the button definition
var button = buttons[buttonName];
// Add a new button to the group
var $buttonDiv = $(DIV_TAG)
.data(BUTTON_NAME, button.name)
.addClass('btn') // bootstrap button class
.addClass(BUTTON_CLASS)
.attr("title", button.title)
.bind(CLICK, $.proxy(buttonClick, editor))
.appendTo($group)
.hover(hoverEnter, hoverLeave);
// Button icon container (bootstrap workaround)
var $buttonSpan = $('<span>')
.addClass(TOOLIMG_CLASS)
.css('backgroundPosition', button.stripIndex * -24)
.appendTo($buttonDiv);
// Add the unselectable attribute for ie
if (ie)
$buttonDiv.attr(UNSELECTABLE, "on");
// Create the popup
if (button.popupName)
createPopup(button.popupName, options, button.popupClass,
button.popupContent, button.popupHover);
}
});
// Add the main div to the DOM and append the textarea
$main.insertBefore($area)
.append($area);
// Bind the document click event handler
if (!documentClickAssigned) {
$(document).click(function (e) {
// Hide toolbars
$.each(popups, function(idx, popup) {
if ($(popup).is(":visible")) {
hideToolbar(editor);
return false;
}
});
// Dismiss all non-prompt popups
var $target = $(e.target);
if (!$target.add($target.parents()).is("." + PROMPT_CLASS))
hidePopups();
});
documentClickAssigned = true;
}
// Bind the window resize event when the width or height is auto or %
if (/auto|%/.test("" + options.width + options.height))
$(window).bind("resize.cleditor", function () { refresh(editor); });
// Create the iframe and resize the controls
refresh(editor);
};
//===============
// Public Methods
//===============
var fn = cleditor.prototype,
// Expose the following private functions as methods on the cleditor object.
// The closure compiler will rename the private functions. However, the
// exposed method names on the cleditor object will remain fixed.
methods = [
["clear", clear],
["disable", disable],
["execCommand", execCommand],
["focus", focus],
["hidePopups", hidePopups],
["sourceMode", sourceMode, true],
["refresh", refresh],
["select", select],
["selectedHTML", selectedHTML, true],
["selectedText", selectedText, true],
["showMessage", showMessage],
["updateFrame", updateFrame],
["updateTextArea", updateTextArea]
];
$.each(methods, function (idx, method) {
fn[method[0]] = function () {
var editor = this, args = [editor];
// using each here would cast booleans into objects!
for (var x = 0; x < arguments.length; x++) { args.push(arguments[x]); }
var result = method[1].apply(editor, args);
if (method[2]) return result;
return editor;
};
});
// blurred - shortcut for .bind("blurred", handler) or .trigger("blurred")
fn.blurred = function (handler) {
var $this = $(this);
return handler ? $this.bind(BLURRED, handler) : $this.trigger(BLURRED);
};
// change - shortcut for .bind("change", handler) or .trigger("change")
fn.change = function change(handler) {
var $this = $(this);
return handler ? $this.bind(CHANGE, handler) : $this.trigger(CHANGE);
};
// focused - shortcut for .bind("focused", handler) or .trigger("focused")
fn.focused = function (handler) {
var $this = $(this);
return handler ? $this.bind(FOCUSED, handler) : $this.trigger(FOCUSED);
};
//===============
// Event Handlers
//===============
// buttonClick - click event handler for toolbar buttons
function buttonClick(e) {
var editor = this,
buttonDiv = e.target.parentNode,
buttonName = $.data(buttonDiv, BUTTON_NAME),
button = buttons[buttonName],
popupName = button.popupName,
popup = popups[popupName];
// Check if disabled
if (editor.disabled || $(buttonDiv).attr(DISABLED) === DISABLED)
return;
// Fire the buttonClick event
var data = {
editor: editor,
button: buttonDiv,
buttonName: buttonName,
popup: popup,
popupName: popupName,
command: button.command,
useCSS: editor.options.useCSS,
smartToolbar: editor.options.smartToolbar
};
if (button.buttonClick && button.buttonClick(e, data) === false)
return false;
// Toggle source
if (buttonName === "source") {
// Show the iframe
if (sourceMode(editor)) {
delete editor.range;
editor.$area.hide();
editor.$frame.show();
buttonDiv.title = button.title;
}
// Show the textarea
else {
editor.$frame.hide();
editor.$area.show();
buttonDiv.title = "Show Rich Text";
}
}
// Check for rich text mode
else if (!sourceMode(editor)) {
// Handle popups
if (popupName) {
var $popup = $(popup);
// URL
if (popupName === "url") {
// Check for selection before showing the link url popup
if (buttonName === "link" && selectedText(editor) === "") {
showMessage(editor, "A selection is required when inserting a link.", buttonDiv);
return false;
}
// Wire up the submit button click event handler
$popup.children(":button")
.unbind(CLICK)
.bind(CLICK, function () {
// Insert the image or link if a url was entered
var $text = $popup.find(":text"),
url = $.trim($text.val());
if (url !== "")
execCommand(editor, data.command, url, null, data.button);
// Reset the text, hide the popup and set focus
$text.val("http://");
hidePopups();
focus(editor);
});
}
// Paste as Text
else if (popupName === "pastetext") {
// Wire up the submit button click event handler
$popup.children(":button")
.unbind(CLICK)
.bind(CLICK, function () {
// Insert the unformatted text replacing new lines with break tags
var $textarea = $popup.find("textarea"),
text = $textarea.val().replace(/\n/g, "<br />");
if (text !== "")
execCommand(editor, data.command, text, null, data.button);
// Reset the text, hide the popup and set focus
$textarea.val("");
hidePopups();
focus(editor);
});
}
// Show the popup if not already showing for this button
if (buttonDiv !== $.data(popup, BUTTON)) {
showPopup(editor, popup, buttonDiv);
return false; // stop propagination to document click
}
// propaginate to document click
return;
}
// Print
else if (buttonName === "print")
editor.$frame[0].contentWindow.print();
// All other buttons
else if (!execCommand(editor, data.command, data.value, data.useCSS, buttonDiv))
return false;
}
// Focus the editor
focus(editor);
}
// hoverEnter - mouseenter event handler for buttons and popup items
function hoverEnter(e) {
var $div = $(e.target).closest("div");
$div.css(BACKGROUND_COLOR, $div.data(BUTTON_NAME) ? "#FFF" : "#FFC");
}
// hoverLeave - mouseleave event handler for buttons and popup items
function hoverLeave(e) {
$(e.target).closest("div").css(BACKGROUND_COLOR, "transparent");
}
// popupClick - click event handler for popup items
function popupClick(e) {
var editor = this,
popup = e.data.popup,
target = e.target;
// Check for message and prompt popups
if (popup === popups.msg || $(popup).hasClass(PROMPT_CLASS))
return;
// Get the button info
var buttonDiv = $.data(popup, BUTTON),
buttonName = $.data(buttonDiv, BUTTON_NAME),
button = buttons[buttonName],
command = button.command,
value,
useCSS = editor.options.useCSS,
smartToolbar = editor.options.smartToolbar;
// Get the command value
if (buttonName === "font")
// Opera returns the fontfamily wrapped in quotes
value = target.style.fontFamily.replace(/"/g, "");
else if (buttonName === "size") {
if (target.tagName.toUpperCase() === "DIV")
target = target.children[0];
value = target.innerHTML;
}
else if (buttonName === "style")
value = "<" + target.tagName + ">";
else if (buttonName === "color")
value = hex(target.style.backgroundColor);
else if (buttonName === "highlight") {
value = hex(target.style.backgroundColor);
if (ie) command = 'backcolor';
else useCSS = true;
}
// Fire the popupClick event
var data = {
editor: editor,
button: buttonDiv,
buttonName: buttonName,
popup: popup,
popupName: button.popupName,
command: command,
value: value,
useCSS: useCSS,
smartToolbar: smartToolbar
};
if (button.popupClick && button.popupClick(e, data) === false)
return;
// Execute the command
if (data.command && !execCommand(editor, data.command, data.value, data.useCSS, buttonDiv))
return false;
// Hide the popup and focus the editor
hidePopups();
focus(editor);
}
//==================
// Private Functions
//==================
// checksum - returns a checksum using the Adler-32 method
function checksum(text) {
var a = 1, b = 0;
for (var index = 0; index < text.length; ++index) {
a = (a + text.charCodeAt(index)) % 65521;
b = (b + a) % 65521;
}
return (b << 16) | a;
}
// clear - clears the contents of the editor
function clear(editor) {
editor.$area.val("");
updateFrame(editor);
}
// createPopup - creates a popup and adds it to the body
function createPopup(popupName, options, popupTypeClass, popupContent, popupHover) {
// Check if popup already exists
if (popups[popupName])
return popups[popupName];
// Create the popup
var $popup = $(DIV_TAG)
.hide()
.addClass(POPUP_CLASS)
.appendTo("body");
// Add the content
// Custom popup
if (popupContent)
$popup.html(popupContent);
// Color
else if (popupName === "color") {
var colors = options.colors.split(" ");
if (colors.length < 10)
$popup.width("auto");
$.each(colors, function (idx, color) {
$(DIV_TAG).appendTo($popup)
.css(BACKGROUND_COLOR, "#" + color);
});
popupTypeClass = COLOR_CLASS;
}
// Font
else if (popupName === "font")
$.each(options.fonts.split(","), function (idx, font) {
$(DIV_TAG).appendTo($popup)
.css("fontFamily", font)
.html(font);
});
// Size
else if (popupName === "size")
$.each(options.sizes.split(","), function (idx, size) {
$(DIV_TAG).appendTo($popup)
.html('<font size="' + size + '">' + size + '</font>');
});
// Style
else if (popupName === "style")
$.each(options.styles, function (idx, style) {
$(DIV_TAG).appendTo($popup)
.html(style[1] + style[0] + style[1].replace("<", "</"));
});
// URL
else if (popupName === "url") {
$popup.html('<label>Enter URL:<br /><input type="text" value="http://" style="width:200px" /></label><br /><input type="button" value="Submit" />');
popupTypeClass = PROMPT_CLASS;
}
// Paste as Text
else if (popupName === "pastetext") {
$popup.html('<label>Paste your content here:<br /><textarea rows="3" style="width:200px"></textarea></label><br /><input type="button" value="Submit" />');
popupTypeClass = PROMPT_CLASS;
}
// Add the popup type class name
if (!popupTypeClass && !popupContent)
popupTypeClass = LIST_CLASS;
$popup.addClass(popupTypeClass);
// Add the unselectable attribute to all items
if (ie) {
$popup.attr(UNSELECTABLE, "on")
.find("div,font,p,h1,h2,h3,h4,h5,h6")
.attr(UNSELECTABLE, "on");
}
// Add the hover effect to all items
if ($popup.hasClass(LIST_CLASS) || popupHover === true)
$popup.children().hover(hoverEnter, hoverLeave);
// Add the popup to the array and return it
popups[popupName] = $popup[0];
return $popup[0];
}
// disable - enables or disables the editor
function disable(editor, disabled) {
// Update the textarea and save the state
if (disabled) {
editor.$area.attr(DISABLED, DISABLED);
editor.disabled = true;
}
else {
editor.$area.removeAttr(DISABLED);
delete editor.disabled;
}
// Switch the iframe into design mode.
// ie6 does not support designMode.
// ie7 & ie8 do not properly support designMode="off".
try {
if (ie) editor.doc.body.contentEditable = !disabled;
else editor.doc.designMode = !disabled ? "on" : "off";
}
// Firefox 1.5 throws an exception that can be ignored
// when toggling designMode from off to on.
catch (err) { }
// Enable or disable the toolbar buttons
refreshButtons(editor);
}
// execCommand - executes a designMode command
function execCommand(editor, command, value, useCSS, button) {
// Restore the current ie selection
restoreRange(editor);
// Set the styling method
if (!ie) {
if (useCSS === undefined || useCSS === null)
useCSS = editor.options.useCSS;
editor.doc.execCommand("styleWithCSS", 0, useCSS.toString());
}
// Execute the command and check for error
var inserthtml = command.toLowerCase() === "inserthtml";
if (ie && inserthtml)
getRange(editor).pasteHTML(value);
else if (iege11 && inserthtml) {
var selection = getSelection(editor),
range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(range.createContextualFragment(value));
selection.removeAllRanges();
selection.addRange(range);
}
else {
var success = true, message;
try { success = editor.doc.execCommand(command, 0, value || null); }
catch (err) { message = err.message; success = false; }
if (!success) {
if ("cutcopypaste".indexOf(command) > -1)
showMessage(editor, "For security reasons, your browser does not support the " +
command + " command. Try using the keyboard shortcut or context menu instead.",
button);
else
showMessage(editor,
(message ? message : "Error executing the " + command + " command."),
button);
}
}
// Enable the buttons and update the textarea
refreshButtons(editor);
updateTextArea(editor, true);
return success;
}
// focus - sets focus to either the textarea or iframe
function focus(editor) {
setTimeout(function () {
if (sourceMode(editor)) editor.$area.focus();
else editor.$frame[0].contentWindow.focus();
refreshButtons(editor);
}, 0);
}
// getRange - gets the current text range object
function getRange(editor) {
if (ie) return getSelection(editor).createRange();
return getSelection(editor).getRangeAt(0);
}
// getSelection - gets the current text range object
function getSelection(editor) {
if (ie) return editor.doc.selection;
return editor.$frame[0].contentWindow.getSelection();
}
// hex - returns the hex value for the passed in color string
function hex(s) {
// hex("rgb(255, 0, 0)") returns #FF0000
var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s);
if (m) {
s = (m[1] << 16 | m[2] << 8 | m[3]).toString(16);
while (s.length < 6)
s = "0" + s;
return "#" + s;
}
// hex("#F00") returns #FF0000
var c = s.split("");
if (s.length === 4)
return "#" + c[1] + c[1] + c[2] + c[2] + c[3] + c[3];
// hex("#FF0000") returns #FF0000
return s;
}
// hidePopups - hides all popups
function hidePopups() {
$.each(popups, function (idx, popup) {
$(popup)
.hide()
.unbind(CLICK)
.removeData(BUTTON);
});
}
// showToolbar - show toolbar with animation
function showToolbar(editor) {
if (!editor.options.smartToolbar) return;
if (editor.$tb_timeout) clearTimeout(editor.$tb_timeout);
if (!editor.$toolbar.is(":visible")) {
var hgt = editor.$frame.height() - editor.$toolbar.outerHeight();
editor.$frame.height(hgt);
editor.$toolbar.slideDown("fast");
}
}
// hideToolbar - hide toolbar with animation
function hideToolbar(editor) {
if (!editor.options.smartToolbar) return;
editor.$tb_timeout = setTimeout(function() {
if (!editor.$frame.is(":focus")) editor.$toolbar.slideUp("fast", function() {
var hgt = editor.$frame.height() + editor.$toolbar.outerHeight();
editor.$frame.height(hgt);
});
}, 1e3);
}
// refresh - creates the iframe and resizes the controls
function refresh(editor) {
var $main = editor.$main,
options = editor.options;
// Remove the old iframe
if (editor.$frame)
editor.$frame.remove();
// Create a new iframe
var $frame = editor.$frame = $('<iframe frameborder="0" src="javascript:true;" />')
.hide()
.appendTo($main);
// Load the iframe document content
var contentWindow = $frame[0].contentWindow,
doc = editor.doc = contentWindow.document,
$doc = $(doc);
doc.open();
doc.write(
options.docType +
'<html>' +
((options.docCSSFile === '') ? '' : '<head><link rel="stylesheet" type="text/css" href="' + options.docCSSFile + '" /></head>') +
'<body style="' + options.bodyStyle + '"></body></html>'
);
doc.close();
// Work around for bug in IE which causes the editor to lose
// focus when clicking below the end of the document.
if (ie || iege11)
$doc.click(function () { focus(editor); });
// Load the content
updateFrame(editor);
// Bind the ie specific iframe event handlers
if (ie || iege11) {
// Save the current user selection. This code is needed since IE will
// reset the selection just after the beforedeactivate event and just
// before the beforeactivate event.
$doc.bind("beforedeactivate beforeactivate selectionchange keypress keyup", function (e) {
// Flag the editor as inactive
if (e.type === "beforedeactivate")
editor.inactive = true;
// Get rid of the bogus selection and flag the editor as active
else if (e.type === "beforeactivate") {
if (!editor.inactive && editor.range && editor.range.length > 1)
editor.range.shift();
delete editor.inactive;
}
// Save the selection when the editor is active
else if (!editor.inactive) {
if (!editor.range)
editor.range = [];
editor.range.unshift(getRange(editor));
// We only need the last 2 selections
while (editor.range.length > 2)
editor.range.pop();
}
});
// Restore the text range and trigger focused event when the iframe gains focus
$frame.focus(function () {
restoreRange(editor);
showToolbar(editor);
$(editor).triggerHandler(FOCUSED);
});
// Trigger blurred event when the iframe looses focus
$frame.blur(function () {
hideToolbar(editor);
$(editor).triggerHandler(BLURRED);
});
}
// Trigger focused and blurred events for all other browsers
else {
$($frame[0].contentWindow)
.focus(function () {
showToolbar(editor);
$(editor).triggerHandler(FOCUSED);
})
.blur(function () {
hideToolbar(editor);
$(editor).triggerHandler(BLURRED);
});
}
// Enable the toolbar buttons and update the textarea as the user types or clicks
$doc.click(hidePopups)
.keydown(function (e) {
// Prevent Internet Explorer from going to prior page when an image
// is selected and the backspace key is pressed.
if (ie && getSelection(editor).type == "Control" && e.keyCode == 8) {
getSelection(editor).clear();
e.preventDefault();
}
})
.bind("keyup mouseup", function () {
refreshButtons(editor);
updateTextArea(editor, true);
});
// Show the textarea for iPhone/iTouch/iPad or
// the iframe when design mode is supported.
if (iOS) editor.$area.show();
else $frame.show();
// Wait for the layout to finish - shortcut for $(document).ready()
$(function () {
var $toolbar = editor.$toolbar,
$group = $toolbar.children("div:last"),
wid = $main.width();
// Resize the toolbar
var hgt = $group.offset().top + $group.outerHeight() - $toolbar.offset().top + 1;
$toolbar.height(hgt);
// Autohide the toolbar
if (editor.options.smartToolbar) {
$toolbar.hide();
hgt = 0;
}
// Resize the iframe
hgt = (/%/.test("" + options.height) ? $main.height() : parseInt(options.height, 10)) - hgt;
$frame.width(wid).height(hgt);
// Resize the textarea. IE6 textareas have a 1px top
// & bottom margin that cannot be removed using css.
editor.$area.width(wid).height(ie6 ? hgt - 2 : hgt);
// Switch the iframe into design mode if enabled
disable(editor, editor.disabled);
// Enable or disable the toolbar buttons
refreshButtons(editor);
});