Merge lp:~openerp-dev/openerp-web/trunk-mail-ie-chm into lp:openerp-web

Proposed by Christophe Matthieu (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openerp-web/trunk-mail-ie-chm
Merge into: lp:openerp-web
Diff against target: 1326 lines (+378/-341)
2 files modified
addons/web/static/lib/cleditor/jquery.cleditor.js (+374/-336)
addons/web/static/src/js/view_form.js (+4/-5)
To merge this branch: bzr merge lp:~openerp-dev/openerp-web/trunk-mail-ie-chm
Reviewer Review Type Date Requested Status
OpenERP R&D Web Team Pending
Review via email: mp+139924@code.launchpad.net
To post a comment you must log in.
3613. By Christophe Matthieu (OpenERP)

[FIX] web cleditor: bind and trigger event change inside cleditor

3614. By Christophe Matthieu (OpenERP)

[IMP] cleditor: rewrite braces, spaces, ponctuation

3615. By Christophe Matthieu (OpenERP)

[IMP] web form: fieldtexthtml

3616. By Christophe Matthieu (OpenERP)

[IMP] cleditor: remove spaces

3617. By Christophe Matthieu (OpenERP)

[MERGE] from trunk

Unmerged revisions

3617. By Christophe Matthieu (OpenERP)

[MERGE] from trunk

3616. By Christophe Matthieu (OpenERP)

[IMP] cleditor: remove spaces

3615. By Christophe Matthieu (OpenERP)

[IMP] web form: fieldtexthtml

3614. By Christophe Matthieu (OpenERP)

[IMP] cleditor: rewrite braces, spaces, ponctuation

3613. By Christophe Matthieu (OpenERP)

[FIX] web cleditor: bind and trigger event change inside cleditor

3612. By Christophe Matthieu (OpenERP)

[IMP] web form: change for cleditor field html

3611. By Christophe Matthieu (OpenERP)

[IMP] view_form: add console in cleditor for ie debugging

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'addons/web/static/lib/cleditor/jquery.cleditor.js'
--- addons/web/static/lib/cleditor/jquery.cleditor.js 2012-10-29 14:35:27 +0000
+++ addons/web/static/lib/cleditor/jquery.cleditor.js 2012-12-21 17:26:22 +0000
@@ -12,7 +12,8 @@
12// @output_file_name jquery.cleditor.min.js12// @output_file_name jquery.cleditor.min.js
13// ==/ClosureCompiler==13// ==/ClosureCompiler==
1414
15(function($) {15(function ($) {
16 'use strict';
1617
17 //==============18 //==============
18 // jQuery Plugin19 // jQuery Plugin
@@ -25,93 +26,91 @@
25 width: 500, // width not including margins, borders or padding26 width: 500, // width not including margins, borders or padding
26 height: 250, // height not including margins, borders or padding27 height: 250, // height not including margins, borders or padding
27 controls: // controls to add to the toolbar28 controls: // controls to add to the toolbar
28 "bold italic underline strikethrough subscript superscript | font size " +29 'bold italic underline strikethrough subscript superscript | font size ' +
29 "style | color highlight removeformat | bullets numbering | outdent " +30 'style | color highlight removeformat | bullets numbering | outdent ' +
30 "indent | alignleft center alignright justify | undo redo | " +31 'indent | alignleft center alignright justify | undo redo | ' +
31 "rule image link unlink | cut copy paste pastetext | print source",32 'rule image link unlink | cut copy paste pastetext | print source',
32 colors: // colors in the color popup33 colors: // colors in the color popup
33 "FFF FCC FC9 FF9 FFC 9F9 9FF CFF CCF FCF " +34 'FFF FCC FC9 FF9 FFC 9F9 9FF CFF CCF FCF ' +
34 "CCC F66 F96 FF6 FF3 6F9 3FF 6FF 99F F9F " +35 'CCC F66 F96 FF6 FF3 6F9 3FF 6FF 99F F9F ' +
35 "BBB F00 F90 FC6 FF0 3F3 6CC 3CF 66C C6C " +36 'BBB F00 F90 FC6 FF0 3F3 6CC 3CF 66C C6C ' +
36 "999 C00 F60 FC3 FC0 3C0 0CC 36F 63F C3C " +37 '999 C00 F60 FC3 FC0 3C0 0CC 36F 63F C3C ' +
37 "666 900 C60 C93 990 090 399 33F 60C 939 " +38 '666 900 C60 C93 990 090 399 33F 60C 939 ' +
38 "333 600 930 963 660 060 366 009 339 636 " +39 '333 600 930 963 660 060 366 009 339 636 ' +
39 "000 300 630 633 330 030 033 006 309 303", 40 '000 300 630 633 330 030 033 006 309 303',
40 fonts: // font names in the font popup41 fonts: // font names in the font popup
41 "Arial,Arial Black,Comic Sans MS,Courier New,Narrow,Garamond," +42 'Arial, Arial Black, Comic Sans MS, Courier New, Narrow, Garamond, ' +
42 "Georgia,Impact,Sans Serif,Serif,Tahoma,Trebuchet MS,Verdana",43 'Georgia, Impact, Sans Serif, Serif, Tahoma, Trebuchet MS, Verdana',
43 sizes: // sizes in the font size popup44 sizes: // sizes in the font size popup
44 "1,2,3,4,5,6,7",45 '1, 2, 3, 4, 5, 6, 7',
45 styles: // styles in the style popup46 styles: // styles in the style popup
46 [["Paragraph", "<p>"], ["Header 1", "<h1>"], ["Header 2", "<h2>"],47 [['Paragraph', '<p>'], ['Header 1', '<h1>'], ['Header 2', '<h2>'],
47 ["Header 3", "<h3>"], ["Header 4","<h4>"], ["Header 5","<h5>"],48 ['Header 3', '<h3>'], ['Header 4', '<h4>'], ['Header 5', '<h5>'],
48 ["Header 6","<h6>"]],49 ['Header 6', '<h6>']],
49 useCSS: false, // use CSS to style HTML when possible (not supported in ie)50 useCSS: false, // use CSS to style HTML when possible (not supported in ie)
50 docType: // Document type contained within the editor51 docType: // Document type contained within the editor
51 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',52 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
52 docCSSFile: // CSS file used to style the document contained within the editor53 docCSSFile: // CSS file used to style the document contained within the editor
53 "", 54 '',
54 bodyStyle: // style to assign to document body contained within the editor55 bodyStyle: // style to assign to document body contained within the editor
55 "margin:4px; font:10pt Arial,Verdana; cursor:text"56 'margin:4px; font:10pt Arial, Verdana; cursor:text'
56 },57 },
57
58 // Define all usable toolbar buttons - the init string property is 58 // Define all usable toolbar buttons - the init string property is
59 // expanded during initialization back into the buttons object and 59 // expanded during initialization back into the buttons object and
60 // seperate object properties are created for each button.60 // seperate object properties are created for each button.
61 // e.g. buttons.size.title = "Font Size"61 // e.g. buttons.size.title = 'Font Size'
62 buttons: {62 buttons: {
63 // name,title,command,popupName (""=use name)63 // name, title, command, popupName (''=use name)
64 init:64 init:
65 "bold,,|" +65 'bold,,|' +
66 "italic,,|" +66 'italic,,|' +
67 "underline,,|" +67 'underline,,|' +
68 "strikethrough,,|" +68 'strikethrough,,|' +
69 "subscript,,|" +69 'subscript,,|' +
70 "superscript,,|" +70 'superscript,,|' +
71 "font,,fontname,|" +71 'font,,fontname,|' +
72 "size,Font Size,fontsize,|" +72 'size,Font Size,fontsize,|' +
73 "style,,formatblock,|" +73 'style,,formatblock,|' +
74 "color,Font Color,forecolor,|" +74 'color,Font Color,forecolor,|' +
75 "highlight,Text Highlight Color,hilitecolor,color|" +75 'highlight,Text Highlight Color,hilitecolor,color|' +
76 "removeformat,Remove Formatting,|" +76 'removeformat,Remove Formatting,|' +
77 "bullets,,insertunorderedlist|" +77 'bullets,,insertunorderedlist|' +
78 "numbering,,insertorderedlist|" +78 'numbering,,insertorderedlist|' +
79 "outdent,,|" +79 'outdent,,|' +
80 "indent,,|" +80 'indent,,|' +
81 "alignleft,Align Text Left,justifyleft|" +81 'alignleft,Align Text Left,justifyleft|' +
82 "center,,justifycenter|" +82 'center,,justifycenter|' +
83 "alignright,Align Text Right,justifyright|" +83 'alignright,Align Text Right,justifyright|' +
84 "justify,,justifyfull|" +84 'justify,,justifyfull|' +
85 "undo,,|" +85 'undo,,|' +
86 "redo,,|" +86 'redo,,|' +
87 "rule,Insert Horizontal Rule,inserthorizontalrule|" +87 'rule,Insert Horizontal Rule,inserthorizontalrule|' +
88 "image,Insert Image,insertimage,url|" +88 'image,Insert Image,insertimage,url|' +
89 "link,Insert Hyperlink,createlink,url|" +89 'link,Insert Hyperlink,createlink,url|' +
90 "unlink,Remove Hyperlink,|" +90 'unlink,Remove Hyperlink,|' +
91 "cut,,|" +91 'cut,,|' +
92 "copy,,|" +92 'copy,,|' +
93 "paste,,|" +93 'paste,,|' +
94 "pastetext,Paste as Text,inserthtml,|" +94 'pastetext,Paste as Text,inserthtml,|' +
95 "print,,|" +95 'print,,|' +
96 "source,Show Source"96 'source,Show Source'
97 },97 },
98
99 // imagesPath - returns the path to the images folder98 // imagesPath - returns the path to the images folder
100 imagesPath: function() { return imagesPath(); }99 imagesPath: function () { return imagesPath(); }
101100
102 };101 };
103102
104 // cleditor - creates a new editor for each of the matched textareas103 // cleditor - creates a new editor for each of the matched textareas
105 $.fn.cleditor = function(options) {104 $.fn.cleditor = function (options) {
106105
107 // Create a new jQuery object to hold the results106 // Create a new jQuery object to hold the results
108 var $result = $([]);107 var $result = $([]);
109108
110 // Loop through all matching textareas and create the editors109 // Loop through all matching textareas and create the editors
111 this.each(function(idx, elem) {110 this.each(function (idx, elem) {
112 if (elem.tagName == "TEXTAREA") {111 if (elem.tagName === 'TEXTAREA') {
113 var data = $.data(elem, CLEDITOR);112 var data = $.data(elem, CLEDITOR);
114 if (!data) data = new cleditor(elem, options);113 if (!data) {data = new cleditor(elem, options);}
115 $result = $result.add(data);114 $result = $result.add(data);
116 }115 }
117 });116 });
@@ -128,45 +127,40 @@
128 var127 var
129128
130 // Misc constants129 // Misc constants
131 BACKGROUND_COLOR = "backgroundColor",130 BACKGROUND_COLOR = 'backgroundColor',
132 BUTTON = "button",131 BUTTON = 'button',
133 BUTTON_NAME = "buttonName",132 BUTTON_NAME = 'buttonName',
134 CHANGE = "change",133 CHANGE = 'change',
135 CLEDITOR = "cleditor",134 CLEDITOR = 'cleditor',
136 CLICK = "click",135 CLICK = 'click',
137 DISABLED = "disabled",136 DISABLED = 'disabled',
138 DIV_TAG = "<div>",137 DIV_TAG = '<div>',
139 TRANSPARENT = "transparent",138 TRANSPARENT = 'transparent',
140 UNSELECTABLE = "unselectable",139 UNSELECTABLE = 'unselectable',
141140 // Class name constants
142 // Class name constants141 MAIN_CLASS = 'cleditorMain', // main containing div
143 MAIN_CLASS = "cleditorMain", // main containing div142 TOOLBAR_CLASS = 'cleditorToolbar', // toolbar div inside main div
144 TOOLBAR_CLASS = "cleditorToolbar", // toolbar div inside main div143 GROUP_CLASS = 'cleditorGroup', // group divs inside the toolbar div
145 GROUP_CLASS = "cleditorGroup", // group divs inside the toolbar div144 BUTTON_CLASS = 'cleditorButton', // button divs inside group div
146 BUTTON_CLASS = "cleditorButton", // button divs inside group div145 DISABLED_CLASS = 'cleditorDisabled', // disabled button divs
147 DISABLED_CLASS = "cleditorDisabled",// disabled button divs146 DIVIDER_CLASS = 'cleditorDivider', // divider divs inside group div
148 DIVIDER_CLASS = "cleditorDivider", // divider divs inside group div147 POPUP_CLASS = 'cleditorPopup', // popup divs inside body
149 POPUP_CLASS = "cleditorPopup", // popup divs inside body148 LIST_CLASS = 'cleditorList', // list popup divs inside body
150 LIST_CLASS = "cleditorList", // list popup divs inside body149 COLOR_CLASS = 'cleditorColor', // color popup div inside body
151 COLOR_CLASS = "cleditorColor", // color popup div inside body150 PROMPT_CLASS = 'cleditorPrompt', // prompt popup divs inside body
152 PROMPT_CLASS = "cleditorPrompt", // prompt popup divs inside body151 MSG_CLASS = 'cleditorMsg', // message popup div inside body
153 MSG_CLASS = "cleditorMsg", // message popup div inside body152
154153 // Test for ie
155 // Test for ie154 ie = $.browser.msie,
156 ie = $.browser.msie,155 ie6 = /msie\s6/i.test(navigator.userAgent),
157 ie6 = /msie\s6/i.test(navigator.userAgent),156 // Test for iPhone/iTouch/iPad
158157 iOS = /iphone|ipad|ipod/i.test(navigator.userAgent),
159 // Test for iPhone/iTouch/iPad158 // Popups are created once as needed and shared by all editor instances
160 iOS = /iphone|ipad|ipod/i.test(navigator.userAgent),159 popups = {},
161160 // Used to prevent the document click event from being bound more than once
162 // Popups are created once as needed and shared by all editor instances161 documentClickAssigned,
163 popups = {},162 // Local copy of the buttons object
164163 buttons = $.cleditor.buttons;
165 // Used to prevent the document click event from being bound more than once
166 documentClickAssigned,
167
168 // Local copy of the buttons object
169 buttons = $.cleditor.buttons;
170164
171 //===============165 //===============
172 // Initialization166 // Initialization
@@ -174,15 +168,15 @@
174168
175 // Expand the buttons.init string back into the buttons object169 // Expand the buttons.init string back into the buttons object
176 // and create seperate object properties for each button.170 // and create seperate object properties for each button.
177 // e.g. buttons.size.title = "Font Size"171 // e.g. buttons.size.title = 'Font Size'
178 $.each(buttons.init.split("|"), function(idx, button) {172 $.each(buttons.init.split('|'), function (idx, button) {
179 var items = button.split(","), name = items[0];173 var items = button.split(','), name = items[0];
180 buttons[name] = {174 buttons[name] = {
181 stripIndex: idx,175 stripIndex: idx,
182 name: name,176 name: name,
183 title: items[1] === "" ? name.charAt(0).toUpperCase() + name.substr(1) : items[1],177 title: items[1] === '' ? name.charAt(0).toUpperCase() + name.substr(1) : items[1],
184 command: items[2] === "" ? name : items[2],178 command: items[2] === '' ? name : items[2],
185 popupName: items[3] === "" ? name : items[3]179 popupName: items[3] === '' ? name : items[3]
186 };180 };
187 });181 });
188 delete buttons.init;182 delete buttons.init;
@@ -192,7 +186,7 @@
192 //============186 //============
193187
194 // cleditor - creates a new editor for the passed in textarea element188 // cleditor - creates a new editor for the passed in textarea element
195 cleditor = function(area, options) {189 var cleditor = function (area, options) {
196190
197 var editor = this;191 var editor = this;
198192
@@ -203,7 +197,7 @@
203 var $area = editor.$area = $(area)197 var $area = editor.$area = $(area)
204 .hide()198 .hide()
205 .data(CLEDITOR, editor)199 .data(CLEDITOR, editor)
206 .blur(function() {200 .blur(function () {
207 // Update the iframe when the textarea loses focus201 // Update the iframe when the textarea loses focus
208 updateFrame(editor, true);202 updateFrame(editor, true);
209 });203 });
@@ -225,11 +219,11 @@
225 .appendTo($toolbar);219 .appendTo($toolbar);
226 220
227 // Add the buttons to the toolbar221 // Add the buttons to the toolbar
228 $.each(options.controls.split(" "), function(idx, buttonName) {222 $.each(options.controls.split(' '), function (idx, buttonName) {
229 if (buttonName === "") return true;223 if (buttonName === '') {return true;}
230224
231 // Divider225 // Divider
232 if (buttonName == "|") {226 if (buttonName === '|') {
233227
234 // Add a new divider to the group228 // Add a new divider to the group
235 var $div = $(DIV_TAG)229 var $div = $(DIV_TAG)
@@ -253,27 +247,28 @@
253 var $buttonDiv = $(DIV_TAG)247 var $buttonDiv = $(DIV_TAG)
254 .data(BUTTON_NAME, button.name)248 .data(BUTTON_NAME, button.name)
255 .addClass(BUTTON_CLASS)249 .addClass(BUTTON_CLASS)
256 .attr("title", button.title)250 .attr('title', button.title)
257 .bind(CLICK, $.proxy(buttonClick, editor))251 .bind(CLICK, $.proxy(buttonClick, editor))
258 .appendTo($group)252 .appendTo($group)
259 .hover(hoverEnter, hoverLeave);253 .hover(hoverEnter, hoverLeave);
260254
261 // Prepare the button image255 // Prepare the button image
262 var map = {};256 var map = {};
263 if (button.css) map = button.css;257 if (button.css) {map = button.css;}
264 else if (button.image) map.backgroundImage = imageUrl(button.image);258 else if (button.image) {map.backgroundImage = imageUrl(button.image);}
265 if (button.stripIndex) map.backgroundPosition = button.stripIndex * -24;259 if (button.stripIndex) {map.backgroundPosition = button.stripIndex * -24;}
266 $buttonDiv.css(map);260 $buttonDiv.css(map);
267261
268 // Add the unselectable attribute for ie262 // Add the unselectable attribute for ie
269 if (ie)263 if (ie) {
270 $buttonDiv.attr(UNSELECTABLE, "on");264 $buttonDiv.attr(UNSELECTABLE, 'on');
265 }
271266
272 // Create the popup267 // Create the popup
273 if (button.popupName)268 if (button.popupName) {
274 createPopup(button.popupName, options, button.popupClass,269 createPopup(button.popupName, options, button.popupClass,
275 button.popupContent, button.popupHover);270 button.popupContent, button.popupHover);
276 271 }
277 }272 }
278273
279 });274 });
@@ -284,23 +279,25 @@
284279
285 // Bind the document click event handler280 // Bind the document click event handler
286 if (!documentClickAssigned) {281 if (!documentClickAssigned) {
287 $(document).click(function(e) {282 $(document).click(function (e) {
288 // Dismiss all non-prompt popups283 // Dismiss all non-prompt popups
289 var $target = $(e.target);284 var $target = $(e.target);
290 if (!$target.add($target.parents()).is("." + PROMPT_CLASS))285 if (!$target.add($target.parents()).is('.' + PROMPT_CLASS)) {
291 hidePopups();286 hidePopups();
287 }
292 });288 });
293 documentClickAssigned = true;289 documentClickAssigned = true;
294 }290 }
295291
296 // Bind the window resize event when the width or height is auto or %292 // Bind the window resize event when the width or height is auto or %
297 if (/auto|%/.test("" + options.width + options.height))293 if (/auto|%/.test('' + options.width + options.height)) {
298 $(window).resize(function() {294 $(window).resize(function () {
299 // CHM Note MonkeyPatch: if the DOM is not remove, refresh the cleditor295 // CHM Note MonkeyPatch: if the DOM is not remove, refresh the cleditor
300 if(editor.$main.parent().parent().size()) {296 if(editor.$main.parent().parent().size()) {
301 refresh(editor);297 refresh(editor);
302 }298 }
303 });299 });
300 }
304301
305 // Create the iframe and resize the controls302 // Create the iframe and resize the controls
306 refresh(editor);303 refresh(editor);
@@ -311,40 +308,39 @@
311 // Public Methods308 // Public Methods
312 //===============309 //===============
313310
314 var fn = cleditor.prototype,311 var fn = cleditor.prototype,
315
316 // Expose the following private functions as methods on the cleditor object.312 // Expose the following private functions as methods on the cleditor object.
317 // The closure compiler will rename the private functions. However, the313 // The closure compiler will rename the private functions. However, the
318 // exposed method names on the cleditor object will remain fixed.314 // exposed method names on the cleditor object will remain fixed.
319 methods = [315 methods = [
320 ["clear", clear],316 ['clear', clear],
321 ["disable", disable],317 ['disable', disable],
322 ["execCommand", execCommand],318 ['execCommand', execCommand],
323 ["focus", focus],319 ['focus', focus],
324 ["hidePopups", hidePopups],320 ['hidePopups', hidePopups],
325 ["sourceMode", sourceMode, true],321 ['sourceMode', sourceMode, true],
326 ["refresh", refresh],322 ['refresh', refresh],
327 ["select", select],323 ['select', select],
328 ["selectedHTML", selectedHTML, true],324 ['selectedHTML', selectedHTML, true],
329 ["selectedText", selectedText, true],325 ['selectedText', selectedText, true],
330 ["showMessage", showMessage],326 ['showMessage', showMessage],
331 ["updateFrame", updateFrame],327 ['updateFrame', updateFrame],
332 ["updateTextArea", updateTextArea]328 ['updateTextArea', updateTextArea]
333 ];329 ];
334330
335 $.each(methods, function(idx, method) {331 $.each(methods, function (idx, method) {
336 fn[method[0]] = function() {332 fn[method[0]] = function () {
337 var editor = this, args = [editor];333 var editor = this, args = [editor];
338 // using each here would cast booleans into objects!334 // using each here would cast booleans into objects!
339 for(var x = 0; x < arguments.length; x++) {args.push(arguments[x]);}335 for(var x = 0; x < arguments.length; x++) {args.push(arguments[x]);}
340 var result = method[1].apply(editor, args);336 var result = method[1].apply(editor, args);
341 if (method[2]) return result;337 if (method[2]) {return result;}
342 return editor;338 return editor;
343 };339 };
344 });340 });
345341
346 // change - shortcut for .bind("change", handler) or .trigger("change")342 // change - shortcut for .bind('change', handler) or .trigger('change')
347 fn.change = function(handler) {343 fn.change = function (handler) {
348 var $this = $(this);344 var $this = $(this);
349 return handler ? $this.bind(CHANGE, handler) : $this.trigger(CHANGE);345 return handler ? $this.bind(CHANGE, handler) : $this.trigger(CHANGE);
350 };346 };
@@ -356,33 +352,35 @@
356 // buttonClick - click event handler for toolbar buttons352 // buttonClick - click event handler for toolbar buttons
357 function buttonClick(e) {353 function buttonClick(e) {
358354
359 var editor = this,355 var editor = this,
360 buttonDiv = e.target,356 buttonDiv = e.target,
361 buttonName = $.data(buttonDiv, BUTTON_NAME),357 buttonName = $.data(buttonDiv, BUTTON_NAME),
362 button = buttons[buttonName],358 button = buttons[buttonName],
363 popupName = button.popupName,359 popupName = button.popupName,
364 popup = popups[popupName];360 popup = popups[popupName];
365361
366 // Check if disabled362 // Check if disabled
367 if (editor.disabled || $(buttonDiv).attr(DISABLED) == DISABLED)363 if (editor.disabled || $(buttonDiv).attr(DISABLED) === DISABLED) {
368 return;364 return;
365 }
369366
370 // Fire the buttonClick event367 // Fire the buttonClick event
371 var data = {368 var data = {
372 editor: editor,369 editor: editor,
373 button: buttonDiv,370 button: buttonDiv,
374 buttonName: buttonName,371 buttonName: buttonName,
375 popup: popup,372 popup: popup,
376 popupName: popupName,373 popupName: popupName,
377 command: button.command,374 command: button.command,
378 useCSS: editor.options.useCSS375 useCSS: editor.options.useCSS
379 };376 };
380377
381 if (button.buttonClick && button.buttonClick(e, data) === false)378 if (button.buttonClick && button.buttonClick(e, data) === false) {
382 return false;379 return false;
380 }
383381
384 // Toggle source382 // Toggle source
385 if (buttonName == "source") {383 if (buttonName === 'source') {
386384
387 // Show the iframe385 // Show the iframe
388 if (sourceMode(editor)) {386 if (sourceMode(editor)) {
@@ -396,12 +394,12 @@
396 else {394 else {
397 editor.$frame.hide();395 editor.$frame.hide();
398 editor.$area.show();396 editor.$area.show();
399 buttonDiv.title = "Show Rich Text";397 buttonDiv.title = 'Show Rich Text';
400 }398 }
401399
402 // Enable or disable the toolbar buttons400 // Enable or disable the toolbar buttons
403 // IE requires the timeout401 // IE requires the timeout
404 setTimeout(function() {refreshButtons(editor);}, 100);402 setTimeout(function () {refreshButtons(editor);}, 100);
405403
406 }404 }
407405
@@ -413,27 +411,28 @@
413 var $popup = $(popup);411 var $popup = $(popup);
414412
415 // URL413 // URL
416 if (popupName == "url") {414 if (popupName === 'url') {
417415
418 // Check for selection before showing the link url popup416 // Check for selection before showing the link url popup
419 if (buttonName == "link" && selectedText(editor) === "") {417 if (buttonName === 'link' && selectedText(editor) === '') {
420 showMessage(editor, "A selection is required when inserting a link.", buttonDiv);418 showMessage(editor, 'A selection is required when inserting a link.', buttonDiv);
421 return false;419 return false;
422 }420 }
423421
424 // Wire up the submit button click event handler422 // Wire up the submit button click event handler
425 $popup.children(":button")423 $popup.children(':button')
426 .unbind(CLICK)424 .unbind(CLICK)
427 .bind(CLICK, function() {425 .bind(CLICK, function () {
428426
429 // Insert the image or link if a url was entered427 // Insert the image or link if a url was entered
430 var $text = $popup.find(":text"),428 var $text = $popup.find(':text'),
431 url = $.trim($text.val());429 url = $.trim($text.val());
432 if (url !== "")430 if (url !== '') {
433 execCommand(editor, data.command, url, null, data.button);431 execCommand(editor, data.command, url, null, data.button);
432 }
434433
435 // Reset the text, hide the popup and set focus434 // Reset the text, hide the popup and set focus
436 $text.val("http://");435 $text.val('http://');
437 hidePopups();436 hidePopups();
438 focus(editor);437 focus(editor);
439438
@@ -442,21 +441,22 @@
442 }441 }
443442
444 // Paste as Text443 // Paste as Text
445 else if (popupName == "pastetext") {444 else if (popupName === 'pastetext') {
446445
447 // Wire up the submit button click event handler446 // Wire up the submit button click event handler
448 $popup.children(":button")447 $popup.children(':button')
449 .unbind(CLICK)448 .unbind(CLICK)
450 .bind(CLICK, function() {449 .bind(CLICK, function () {
451450
452 // Insert the unformatted text replacing new lines with break tags451 // Insert the unformatted text replacing new lines with break tags
453 var $textarea = $popup.find("textarea"),452 var $textarea = $popup.find('textarea'),
454 text = $textarea.val().replace(/\n/g, "<br />");453 text = $textarea.val().replace(/\n/g, '<br />');
455 if (text !== "")454 if (text !== '') {
456 execCommand(editor, data.command, text, null, data.button);455 execCommand(editor, data.command, text, null, data.button);
456 }
457457
458 // Reset the text, hide the popup and set focus458 // Reset the text, hide the popup and set focus
459 $textarea.val("");459 $textarea.val('');
460 hidePopups();460 hidePopups();
461 focus(editor);461 focus(editor);
462462
@@ -476,12 +476,14 @@
476 }476 }
477477
478 // Print478 // Print
479 else if (buttonName == "print")479 else if (buttonName === 'print') {
480 editor.$frame[0].contentWindow.print();480 editor.$frame[0].contentWindow.print();
481 }
481482
482 // All other buttons483 // All other buttons
483 else if (!execCommand(editor, data.command, data.value, data.useCSS, buttonDiv))484 else if (!execCommand(editor, data.command, data.value, data.useCSS, buttonDiv)) {
484 return false;485 return false;
486 }
485487
486 }488 }
487489
@@ -492,71 +494,78 @@
492494
493 // hoverEnter - mouseenter event handler for buttons and popup items495 // hoverEnter - mouseenter event handler for buttons and popup items
494 function hoverEnter(e) {496 function hoverEnter(e) {
495 var $div = $(e.target).closest("div");497 var $div = $(e.target).closest('div');
496 $div.css(BACKGROUND_COLOR, $div.data(BUTTON_NAME) ? "#FFF" : "#FFC");498 $div.css(BACKGROUND_COLOR, $div.data(BUTTON_NAME) ? '#FFF' : '#FFC');
497 }499 }
498500
499 // hoverLeave - mouseleave event handler for buttons and popup items501 // hoverLeave - mouseleave event handler for buttons and popup items
500 function hoverLeave(e) {502 function hoverLeave(e) {
501 $(e.target).closest("div").css(BACKGROUND_COLOR, "transparent");503 $(e.target).closest('div').css(BACKGROUND_COLOR, 'transparent');
502 }504 }
503505
504 // popupClick - click event handler for popup items506 // popupClick - click event handler for popup items
505 function popupClick(e) {507 function popupClick(e) {
506508
507 var editor = this,509 var editor = this,
508 popup = e.data.popup,510 popup = e.data.popup,
509 target = e.target;511 target = e.target;
510512
511 // Check for message and prompt popups513 // Check for message and prompt popups
512 if (popup === popups.msg || $(popup).hasClass(PROMPT_CLASS))514 if (popup === popups.msg || $(popup).hasClass(PROMPT_CLASS)) {
513 return;515 return;
516 }
514517
515 // Get the button info518 // Get the button info
516 var buttonDiv = $.data(popup, BUTTON),519 var buttonDiv = $.data(popup, BUTTON),
517 buttonName = $.data(buttonDiv, BUTTON_NAME),520 buttonName = $.data(buttonDiv, BUTTON_NAME),
518 button = buttons[buttonName],521 button = buttons[buttonName],
519 command = button.command,522 command = button.command,
520 value,523 value,
521 useCSS = editor.options.useCSS;524 useCSS = editor.options.useCSS;
522525
523 // Get the command value526 // Get the command value
524 if (buttonName == "font")527 if (buttonName === 'font') {
525 // Opera returns the fontfamily wrapped in quotes528 // Opera returns the fontfamily wrapped in quotes
526 value = target.style.fontFamily.replace(/"/g, "");529 value = target.style.fontFamily.replace(/'/g, '');
527 else if (buttonName == "size") {530 }
528 if (target.tagName == "DIV")531 else if (buttonName === 'size') {
532 if (target.tagName === 'DIV') {
529 target = target.children[0];533 target = target.children[0];
534 }
530 value = target.innerHTML;535 value = target.innerHTML;
531 }536 }
532 else if (buttonName == "style")537 else if (buttonName === 'style') {
533 value = "<" + target.tagName + ">";538 value = '<' + target.tagName + '>';
534 else if (buttonName == "color")539 }
535 value = hex(target.style.backgroundColor);540 else if (buttonName === 'color') {
536 else if (buttonName == "highlight") {541 value = hex(target.style.backgroundColor);
537 value = hex(target.style.backgroundColor);542 }
538 if (ie) command = 'backcolor';543 else if (buttonName === 'highlight') {
539 else useCSS = true;544 value = hex(target.style.backgroundColor);
545 if (ie) {command = 'backcolor';}
546 else {useCSS = true;}
540 }547 }
541548
542 // Fire the popupClick event549 // Fire the popupClick event
543 var data = {550 var data = {
544 editor: editor,551 editor: editor,
545 button: buttonDiv,552 button: buttonDiv,
546 buttonName: buttonName,553 buttonName: buttonName,
547 popup: popup,554 popup: popup,
548 popupName: button.popupName,555 popupName: button.popupName,
549 command: command,556 command: command,
550 value: value,557 value: value,
551 useCSS: useCSS558 useCSS: useCSS
552 };559 };
553560
554 if (button.popupClick && button.popupClick(e, data) === false)561 if (button.popupClick && button.popupClick(e, data) === false) {
555 return;562 return;
563 }
556564
557 // Execute the command565 // Execute the command
558 if (data.command && !execCommand(editor, data.command, data.value, data.useCSS, buttonDiv))566 if (data.command && !execCommand(editor, data.command, data.value, data.useCSS, buttonDiv)) {
559 return false;567 return false;
568 }
560569
561 // Hide the popup and focus the editor570 // Hide the popup and focus the editor
562 hidePopups();571 hidePopups();
@@ -581,7 +590,7 @@
581590
582 // clear - clears the contents of the editor591 // clear - clears the contents of the editor
583 function clear(editor) {592 function clear(editor) {
584 editor.$area.val("");593 editor.$area.val('');
585 updateFrame(editor);594 updateFrame(editor);
586 }595 }
587596
@@ -589,82 +598,90 @@
589 function createPopup(popupName, options, popupTypeClass, popupContent, popupHover) {598 function createPopup(popupName, options, popupTypeClass, popupContent, popupHover) {
590599
591 // Check if popup already exists600 // Check if popup already exists
592 if (popups[popupName])601 if (popups[popupName]) {
593 return popups[popupName];602 return popups[popupName];
603 }
594604
595 // Create the popup605 // Create the popup
596 var $popup = $(DIV_TAG)606 var $popup = $(DIV_TAG)
597 .hide()607 .hide()
598 .addClass(POPUP_CLASS)608 .addClass(POPUP_CLASS)
599 .appendTo("body");609 .appendTo('body');
600610
601 // Add the content611 // Add the content
602612
603 // Custom popup613 // Custom popup
604 if (popupContent)614 if (popupContent) {
605 $popup.html(popupContent);615 $popup.html(popupContent);
616 }
606617
607 // Color618 // Color
608 else if (popupName == "color") {619 else if (popupName === 'color') {
609 var colors = options.colors.split(" ");620 var colors = options.colors.split(' ');
610 if (colors.length < 10)621 if (colors.length < 10) {
611 $popup.width("auto");622 $popup.width('auto');
612 $.each(colors, function(idx, color) {623 }
624 $.each(colors, function (idx, color) {
613 $(DIV_TAG).appendTo($popup)625 $(DIV_TAG).appendTo($popup)
614 .css(BACKGROUND_COLOR, "#" + color);626 .css(BACKGROUND_COLOR, '#' + color);
615 });627 });
616 popupTypeClass = COLOR_CLASS;628 popupTypeClass = COLOR_CLASS;
617 }629 }
618630
619 // Font631 // Font
620 else if (popupName == "font")632 else if (popupName === 'font') {
621 $.each(options.fonts.split(","), function(idx, font) {633 $.each(options.fonts.split(','), function (idx, font) {
622 $(DIV_TAG).appendTo($popup)634 $(DIV_TAG).appendTo($popup)
623 .css("fontFamily", font)635 .css('fontFamily', font)
624 .html(font);636 .html(font);
625 });637 });
638 }
626639
627 // Size640 // Size
628 else if (popupName == "size")641 else if (popupName === 'size') {
629 $.each(options.sizes.split(","), function(idx, size) {642 $.each(options.sizes.split(','), function (idx, size) {
630 $(DIV_TAG).appendTo($popup)643 $(DIV_TAG).appendTo($popup)
631 .html("<font size=" + size + ">" + size + "</font>");644 .html('<font size=' + size + '>' + size + '</font>');
632 });645 });
646 }
633647
634 // Style648 // Style
635 else if (popupName == "style")649 else if (popupName === 'style') {
636 $.each(options.styles, function(idx, style) {650 $.each(options.styles, function (idx, style) {
637 $(DIV_TAG).appendTo($popup)651 $(DIV_TAG).appendTo($popup)
638 .html(style[1] + style[0] + style[1].replace("<", "</"));652 .html(style[1] + style[0] + style[1].replace('<', '</'));
639 });653 });
654 }
640655
641 // URL656 // URL
642 else if (popupName == "url") {657 else if (popupName === 'url') {
643 $popup.html('Enter URL:<br><input type=text value="http://" size=35><br><input type=button value="Submit">');658 $popup.html('Enter URL:<br><input type=text value="http://" size=35><br><input type=button value="Submit">');
644 popupTypeClass = PROMPT_CLASS;659 popupTypeClass = PROMPT_CLASS;
645 }660 }
646661
647 // Paste as Text662 // Paste as Text
648 else if (popupName == "pastetext") {663 else if (popupName === 'pastetext') {
649 $popup.html('Paste your content here and click submit.<br /><textarea cols=40 rows=3></textarea><br /><input type=button value=Submit>');664 $popup.html('Paste your content here and click submit.<br /><textarea cols=40 rows=3></textarea><br /><input type=button value=Submit>');
650 popupTypeClass = PROMPT_CLASS;665 popupTypeClass = PROMPT_CLASS;
651 }666 }
652667
653 // Add the popup type class name668 // Add the popup type class name
654 if (!popupTypeClass && !popupContent)669 if (!popupTypeClass && !popupContent) {
655 popupTypeClass = LIST_CLASS;670 popupTypeClass = LIST_CLASS;
671 }
656 $popup.addClass(popupTypeClass);672 $popup.addClass(popupTypeClass);
657673
658 // Add the unselectable attribute to all items674 // Add the unselectable attribute to all items
659 if (ie) {675 if (ie) {
660 $popup.attr(UNSELECTABLE, "on")676 $popup.attr(UNSELECTABLE, 'on')
661 .find("div,font,p,h1,h2,h3,h4,h5,h6")677 .find('div, font, p, h1, h2, h3, h4, h5, h6')
662 .attr(UNSELECTABLE, "on");678 .attr(UNSELECTABLE, 'on');
663 }679 }
664680
665 // Add the hover effect to all items681 // Add the hover effect to all items
666 if ($popup.hasClass(LIST_CLASS) || popupHover === true)682 if ($popup.hasClass(LIST_CLASS) || popupHover === true) {
667 $popup.children().hover(hoverEnter, hoverLeave);683 $popup.children().hover(hoverEnter, hoverLeave);
684 }
668685
669 // Add the popup to the array and return it686 // Add the popup to the array and return it
670 popups[popupName] = $popup[0];687 popups[popupName] = $popup[0];
@@ -687,10 +704,10 @@
687704
688 // Switch the iframe into design mode.705 // Switch the iframe into design mode.
689 // ie6 does not support designMode.706 // ie6 does not support designMode.
690 // ie7 & ie8 do not properly support designMode="off".707 // ie7 & ie8 do not properly support designMode='off'.
691 try {708 try {
692 if (ie) editor.doc.body.contentEditable = !disabled;709 if (ie) {editor.doc.body.contentEditable = !disabled;}
693 else editor.doc.designMode = !disabled ? "on" : "off";710 else {editor.doc.designMode = !disabled ? 'on' : 'off';}
694 }711 }
695 // Firefox 1.5 throws an exception that can be ignored712 // Firefox 1.5 throws an exception that can be ignored
696 // when toggling designMode from off to on.713 // when toggling designMode from off to on.
@@ -709,27 +726,31 @@
709726
710 // Set the styling method727 // Set the styling method
711 if (!ie) {728 if (!ie) {
712 if (useCSS === undefined || useCSS === null)729 if (useCSS === undefined || useCSS === null) {
713 useCSS = editor.options.useCSS;730 useCSS = editor.options.useCSS;
714 editor.doc.execCommand("styleWithCSS", 0, useCSS.toString());731 }
732 editor.doc.execCommand('styleWithCSS', 0, useCSS.toString());
715 }733 }
716734
717 // Execute the command and check for error735 // Execute the command and check for error
718 var success = true, description;736 var success = true, description;
719 if (ie && command.toLowerCase() == "inserthtml")737 if (ie && command.toLowerCase() === 'inserthtml') {
720 getRange(editor).pasteHTML(value);738 getRange(editor).pasteHTML(value);
739 }
721 else {740 else {
722 try { success = editor.doc.execCommand(command, 0, value || null); }741 try { success = editor.doc.execCommand(command, 0, value || null); }
723 catch (err) { description = err.description; success = false; }742 catch (err) { description = err.description; success = false; }
724 if (!success) {743 if (!success) {
725 if ("cutcopypaste".indexOf(command) > -1)744 if ('cutcopypaste'.indexOf(command) > -1) {
726 showMessage(editor, "For security reasons, your browser does not support the " +745 showMessage(editor, 'For security reasons, your browser does not support the ' +
727 command + " command. Try using the keyboard shortcut or context menu instead.",746 command + ' command. Try using the keyboard shortcut or context menu instead.',
728 button);747 button);
729 else748 }
730 showMessage(editor,749 else {
731 (description ? description : "Error executing the " + command + " command."),750 showMessage(editor,
732 button);751 (description ? description : 'Error executing the ' + command + ' command.'),
752 button);
753 }
733 }754 }
734 }755 }
735756
@@ -741,43 +762,44 @@
741762
742 // focus - sets focus to either the textarea or iframe763 // focus - sets focus to either the textarea or iframe
743 function focus(editor) {764 function focus(editor) {
744 setTimeout(function() {765 setTimeout(function () {
745 if (sourceMode(editor)) editor.$area.focus();766 if (sourceMode(editor)) {editor.$area.focus();}
746 else editor.$frame[0].contentWindow.focus();767 else {editor.$frame[0].contentWindow.focus();}
747 refreshButtons(editor);768 refreshButtons(editor);
748 }, 0);769 }, 0);
749 }770 }
750771
751 // getRange - gets the current text range object772 // getRange - gets the current text range object
752 function getRange(editor) {773 function getRange(editor) {
753 if (ie) return getSelection(editor).createRange();774 if (ie) {return getSelection(editor).createRange();}
754 return getSelection(editor).getRangeAt(0);775 return getSelection(editor).getRangeAt(0);
755 }776 }
756777
757 // getSelection - gets the current text range object778 // getSelection - gets the current text range object
758 function getSelection(editor) {779 function getSelection(editor) {
759 if (ie) return editor.doc.selection;780 if (ie) {return editor.doc.selection;}
760 return editor.$frame[0].contentWindow.getSelection();781 return editor.$frame[0].contentWindow.getSelection();
761 }782 }
762783
763 // Returns the hex value for the passed in string.784 // Returns the hex value for the passed in string.
764 // hex("rgb(255, 0, 0)"); // #FF0000785 // hex('rgb(255, 0, 0)'); // #FF0000
765 // hex("#FF0000"); // #FF0000786 // hex('#FF0000'); // #FF0000
766 // hex("#F00"); // #FF0000787 // hex('#F00'); // #FF0000
767 function hex(s) {788 function hex(s) {
768 var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s),789 var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s),
769 c = s.split("");790 c = s.split('');
770 if (m) {791 if (m) {
771 s = ( m[1] << 16 | m[2] << 8 | m[3] ).toString(16);792 s = ( m[1] << 16 | m[2] << 8 | m[3] ).toString(16);
772 while (s.length < 6)793 while (s.length < 6) {
773 s = "0" + s;794 s = '0' + s;
795 }
774 }796 }
775 return "#" + (s.length == 6 ? s : c[1] + c[1] + c[2] + c[2] + c[3] + c[3]);797 return '#' + (s.length === 6 ? s : c[1] + c[1] + c[2] + c[2] + c[3] + c[3]);
776 }798 }
777799
778 // hidePopups - hides all popups800 // hidePopups - hides all popups
779 function hidePopups() {801 function hidePopups() {
780 $.each(popups, function(idx, popup) {802 $.each(popups, function (idx, popup) {
781 $(popup)803 $(popup)
782 .hide()804 .hide()
783 .unbind(CLICK)805 .unbind(CLICK)
@@ -787,25 +809,26 @@
787809
788 // imagesPath - returns the path to the images folder810 // imagesPath - returns the path to the images folder
789 function imagesPath() {811 function imagesPath() {
790 var cssFile = "jquery.cleditor.css",812 var cssFile = 'jquery.cleditor.css',
791 href = $("link[href$='" + cssFile +"']").attr("href");813 href = $('link[href$="' + cssFile +'"]').attr('href');
792 return href.substr(0, href.length - cssFile.length) + "images/";814 return href.substr(0, href.length - cssFile.length) + 'images/';
793 }815 }
794816
795 // imageUrl - Returns the css url string for a filemane817 // imageUrl - Returns the css url string for a filemane
796 function imageUrl(filename) {818 function imageUrl(filename) {
797 return "url(" + imagesPath() + filename + ")";819 return 'url(' + imagesPath() + filename + ')';
798 }820 }
799821
800 // refresh - creates the iframe and resizes the controls822 // refresh - creates the iframe and resizes the controls
801 function refresh(editor) {823 function refresh(editor) {
802824
803 var $main = editor.$main,825 var $main = editor.$main,
804 options = editor.options;826 options = editor.options;
805827
806 // Remove the old iframe828 // Remove the old iframe
807 if (editor.$frame) 829 if (editor.$frame) {
808 editor.$frame.remove();830 editor.$frame.remove();
831 }
809832
810 // Create a new iframe833 // Create a new iframe
811 var $frame = editor.$frame = $('<iframe frameborder="0" src="javascript:true;">')834 var $frame = editor.$frame = $('<iframe frameborder="0" src="javascript:true;">')
@@ -813,8 +836,8 @@
813 .appendTo($main);836 .appendTo($main);
814837
815 // Load the iframe document content838 // Load the iframe document content
816 var contentWindow = $frame[0].contentWindow,839 var contentWindow = $frame[0].contentWindow,
817 doc = editor.doc = contentWindow.document,840 doc = editor.doc = contentWindow.document,
818 $doc = $(doc);841 $doc = $(doc);
819842
820 doc.open();843 doc.open();
@@ -828,8 +851,9 @@
828851
829 // Work around for bug in IE which causes the editor to lose852 // Work around for bug in IE which causes the editor to lose
830 // focus when clicking below the end of the document.853 // focus when clicking below the end of the document.
831 if (ie)854 if (ie) {
832 $doc.click(function() {focus(editor);});855 $doc.click(function () {focus(editor);});
856 }
833857
834 // Load the content858 // Load the content
835 updateFrame(editor);859 updateFrame(editor);
@@ -840,60 +864,64 @@
840 // Save the current user selection. This code is needed since IE will864 // Save the current user selection. This code is needed since IE will
841 // reset the selection just after the beforedeactivate event and just865 // reset the selection just after the beforedeactivate event and just
842 // before the beforeactivate event.866 // before the beforeactivate event.
843 $doc.bind("beforedeactivate beforeactivate selectionchange keypress", function(e) {867 $doc.bind('beforedeactivate beforeactivate selectionchange keypress', function (e) {
844 868
845 // Flag the editor as inactive869 // Flag the editor as inactive
846 if (e.type == "beforedeactivate")870 if (e.type === 'beforedeactivate') {
847 editor.inactive = true;871 editor.inactive = true;
872 }
848 873
849 // Get rid of the bogus selection and flag the editor as active874 // Get rid of the bogus selection and flag the editor as active
850 else if (e.type == "beforeactivate") {875 else if (e.type === 'beforeactivate') {
851 if (!editor.inactive && editor.range && editor.range.length > 1)876 if (!editor.inactive && editor.range && editor.range.length > 1) {
852 editor.range.shift();877 editor.range.shift();
878 }
853 delete editor.inactive;879 delete editor.inactive;
854 }880 }
855881
856 // Save the selection when the editor is active882 // Save the selection when the editor is active
857 else if (!editor.inactive) {883 else if (!editor.inactive) {
858 if (!editor.range) 884 if (!editor.range) {
859 editor.range = [];885 editor.range = [];
886 }
860 editor.range.unshift(getRange(editor));887 editor.range.unshift(getRange(editor));
861888
862 // We only need the last 2 selections889 // We only need the last 2 selections
863 while (editor.range.length > 2)890 while (editor.range.length > 2) {
864 editor.range.pop();891 editor.range.pop();
892 }
865 }893 }
866894
867 });895 });
868896
869 // Restore the text range when the iframe gains focus897 // Restore the text range when the iframe gains focus
870 $frame.focus(function() {898 $frame.focus(function () {
871 restoreRange(editor);899 restoreRange(editor);
872 });900 });
873901
874 }902 }
875903
876 // Update the textarea when the iframe loses focus904 // Update the textarea when the iframe loses focus
877 ($.browser.mozilla ? $doc : $(contentWindow)).blur(function() {905 ($.browser.mozilla ? $doc : $(contentWindow)).blur(function () {
878 updateTextArea(editor, true);906 updateTextArea(editor, true);
879 });907 });
880908
881 // Enable the toolbar buttons as the user types or clicks909 // Enable the toolbar buttons as the user types or clicks
882 $doc.click(hidePopups)910 $doc.click(hidePopups)
883 .bind("keyup mouseup", function() {911 .bind('keyup mouseup', function () {
884 refreshButtons(editor);912 refreshButtons(editor);
885 });913 });
886914
887 // Show the textarea for iPhone/iTouch/iPad or915 // Show the textarea for iPhone/iTouch/iPad or
888 // the iframe when design mode is supported.916 // the iframe when design mode is supported.
889 if (iOS) editor.$area.show();917 if (iOS) {editor.$area.show();}
890 else $frame.show();918 else {$frame.show();}
891919
892 // Wait for the layout to finish - shortcut for $(document).ready()920 // Wait for the layout to finish - shortcut for $(document).ready()
893 $(function() {921 $(function () {
894922
895 var $toolbar = editor.$toolbar,923 var $toolbar = editor.$toolbar,
896 $group = $toolbar.children("div:last"),924 $group = $toolbar.children('div:last'),
897 wid = $main.width();925 wid = $main.width();
898926
899 // Resize the toolbar927 // Resize the toolbar
@@ -901,7 +929,7 @@
901 $toolbar.height(hgt);929 $toolbar.height(hgt);
902930
903 // Resize the iframe931 // Resize the iframe
904 hgt = (/%/.test("" + options.height) ? $main.height() : parseInt(options.height)) - hgt;932 hgt = (/%/.test('' + options.height) ? $main.height() : parseInt(options.height)) - hgt;
905 $frame.width(wid).height(hgt);933 $frame.width(wid).height(hgt);
906934
907 // Resize the textarea. IE6 textareas have a 1px top935 // Resize the textarea. IE6 textareas have a 1px top
@@ -930,42 +958,46 @@
930958
931 // Get the object used for checking queryCommandEnabled959 // Get the object used for checking queryCommandEnabled
932 var queryObj = editor.doc;960 var queryObj = editor.doc;
933 if (ie) queryObj = getRange(editor);961 if (ie) {queryObj = getRange(editor);}
934962
935 // Loop through each button963 // Loop through each button
936 var inSourceMode = sourceMode(editor);964 var inSourceMode = sourceMode(editor);
937 $.each(editor.$toolbar.find("." + BUTTON_CLASS), function(idx, elem) {965 $.each(editor.$toolbar.find('.' + BUTTON_CLASS), function (idx, elem) {
938966
939 var $elem = $(elem),967 var $elem = $(elem),
940 button = $.cleditor.buttons[$.data(elem, BUTTON_NAME)],968 button = $.cleditor.buttons[$.data(elem, BUTTON_NAME)],
941 command = button.command,969 command = button.command,
942 enabled = true;970 enabled = true;
943971
944 // Determine the state972 // Determine the state
945 if (editor.disabled)973 if (editor.disabled) {
946 enabled = false;974 enabled = false;
975 }
947 else if (button.getEnabled) {976 else if (button.getEnabled) {
948 var data = {977 var data = {
949 editor: editor,978 editor: editor,
950 button: elem,979 button: elem,
951 buttonName: button.name,980 buttonName: button.name,
952 popup: popups[button.popupName],981 popup: popups[button.popupName],
953 popupName: button.popupName,982 popupName: button.popupName,
954 command: button.command,983 command: button.command,
955 useCSS: editor.options.useCSS984 useCSS: editor.options.useCSS
956 };985 };
957 enabled = button.getEnabled(data);986 enabled = button.getEnabled(data);
958 if (enabled === undefined)987 if (enabled === undefined) {
959 enabled = true;988 enabled = true;
989 }
960 }990 }
961 else if (((inSourceMode || iOS) && button.name != "source") ||991 else if (((inSourceMode || iOS) && button.name !== 'source') ||
962 (ie && (command == "undo" || command == "redo")))992 (ie && (command === 'undo' || command === 'redo'))) {
963 enabled = false;993 enabled = false;
964 else if (command && command != "print") {994 }
965 if (ie && command == "hilitecolor")995 else if (command && command !== 'print') {
966 command = "backcolor";996 if (ie && command === 'hilitecolor') {
997 command = 'backcolor';
998 }
967 // IE does not support inserthtml, so it's always enabled999 // IE does not support inserthtml, so it's always enabled
968 if (!ie || command != "inserthtml") {1000 if (!ie || command !== 'inserthtml') {
969 try {enabled = queryObj.queryCommandEnabled(command);}1001 try {enabled = queryObj.queryCommandEnabled(command);}
970 catch (err) {enabled = false;}1002 catch (err) {enabled = false;}
971 }1003 }
@@ -986,15 +1018,16 @@
9861018
987 // restoreRange - restores the current ie selection1019 // restoreRange - restores the current ie selection
988 function restoreRange(editor) {1020 function restoreRange(editor) {
989 if (ie && editor.range)1021 if (ie && editor.range) {
990 editor.range[0].select();1022 editor.range[0].select();
1023 }
991 }1024 }
9921025
993 // select - selects all the text in either the textarea or iframe1026 // select - selects all the text in either the textarea or iframe
994 function select(editor) {1027 function select(editor) {
995 setTimeout(function() {1028 setTimeout(function () {
996 if (sourceMode(editor)) editor.$area.select();1029 if (sourceMode(editor)) {editor.$area.select();}
997 else execCommand(editor, "selectall");1030 else {execCommand(editor, 'selectall');}
998 }, 0);1031 }, 0);
999 }1032 }
10001033
@@ -1002,9 +1035,10 @@
1002 function selectedHTML(editor) {1035 function selectedHTML(editor) {
1003 restoreRange(editor);1036 restoreRange(editor);
1004 var range = getRange(editor);1037 var range = getRange(editor);
1005 if (ie)1038 if (ie) {
1006 return range.htmlText;1039 return range.htmlText;
1007 var layer = $("<layer>")[0];1040 }
1041 var layer = $('<layer>')[0];
1008 layer.appendChild(range.cloneContents());1042 layer.appendChild(range.cloneContents());
1009 var html = layer.innerHTML;1043 var html = layer.innerHTML;
1010 layer = null;1044 layer = null;
@@ -1014,13 +1048,13 @@
1014 // selectedText - returns the current text selection or and empty string1048 // selectedText - returns the current text selection or and empty string
1015 function selectedText(editor) {1049 function selectedText(editor) {
1016 restoreRange(editor);1050 restoreRange(editor);
1017 if (ie) return getRange(editor).text;1051 if (ie) {return getRange(editor).text;}
1018 return getSelection(editor).toString();1052 return getSelection(editor).toString();
1019 }1053 }
10201054
1021 // showMessage - alert replacement1055 // showMessage - alert replacement
1022 function showMessage(editor, message, button) {1056 function showMessage(editor, message, button) {
1023 var popup = createPopup("msg", editor.options, MSG_CLASS);1057 var popup = createPopup('msg', editor.options, MSG_CLASS);
1024 popup.innerHTML = message;1058 popup.innerHTML = message;
1025 showPopup(editor, popup, button);1059 showPopup(editor, popup, button);
1026 }1060 }
@@ -1056,31 +1090,32 @@
1056 }1090 }
10571091
1058 // Focus the first input element if any1092 // Focus the first input element if any
1059 setTimeout(function() {1093 setTimeout(function () {
1060 $popup.find(":text,textarea").eq(0).focus().select();1094 $popup.find(':text, textarea').eq(0).focus().select();
1061 }, 100);1095 }, 100);
10621096
1063 }1097 }
10641098
1065 // sourceMode - returns true if the textarea is showing1099 // sourceMode - returns true if the textarea is showing
1066 function sourceMode(editor) {1100 function sourceMode(editor) {
1067 return editor.$area.is(":visible");1101 return editor.$area.is(':visible');
1068 }1102 }
10691103
1070 // updateFrame - updates the iframe with the textarea contents1104 // updateFrame - updates the iframe with the textarea contents
1071 function updateFrame(editor, checkForChange) {1105 function updateFrame(editor, checkForChange) {
1072 1106
1073 var code = editor.$area.val(),1107 var code = editor.$area.val(),
1074 options = editor.options,1108 options = editor.options,
1075 updateFrameCallback = options.updateFrame,1109 updateFrameCallback = options.updateFrame,
1076 $body = $(editor.doc.body);1110 $body = $(editor.doc.body);
10771111
1078 // Check for textarea change to avoid unnecessary firing1112 // Check for textarea change to avoid unnecessary firing
1079 // of potentially heavy updateFrame callbacks.1113 // of potentially heavy updateFrame callbacks.
1080 if (updateFrameCallback) {1114 if (updateFrameCallback) {
1081 var sum = checksum(code);1115 var sum = checksum(code);
1082 if (checkForChange && editor.areaChecksum == sum)1116 if (checkForChange && editor.areaChecksum === sum) {
1083 return;1117 return;
1118 }
1084 editor.areaChecksum = sum;1119 editor.areaChecksum = sum;
1085 }1120 }
10861121
@@ -1088,14 +1123,15 @@
1088 var html = updateFrameCallback ? updateFrameCallback(code) : code;1123 var html = updateFrameCallback ? updateFrameCallback(code) : code;
10891124
1090 // Prevent script injection attacks by html encoding script tags1125 // Prevent script injection attacks by html encoding script tags
1091 html = html.replace(/<(?=\/?script)/ig, "&lt;");1126 html = html.replace(/<(?=\/?script)/ig, '&lt;');
10921127
1093 // Update the iframe checksum1128 // Update the iframe checksum
1094 if (options.updateTextArea)1129 if (options.updateTextArea) {
1095 editor.frameChecksum = checksum(html);1130 editor.frameChecksum = checksum(html);
1131 }
10961132
1097 // Update the iframe and trigger the change event1133 // Update the iframe and trigger the change event
1098 if (html != $body.html()) {1134 if (html !== $body.html()) {
1099 $body.html(html);1135 $body.html(html);
1100 $(editor).triggerHandler(CHANGE);1136 $(editor).triggerHandler(CHANGE);
1101 }1137 }
@@ -1105,17 +1141,18 @@
1105 // updateTextArea - updates the textarea with the iframe contents1141 // updateTextArea - updates the textarea with the iframe contents
1106 function updateTextArea(editor, checkForChange) {1142 function updateTextArea(editor, checkForChange) {
11071143
1108 var html = $(editor.doc.body).html(),1144 var html = $(editor.doc.body).html(),
1109 options = editor.options,1145 options = editor.options,
1110 updateTextAreaCallback = options.updateTextArea,1146 updateTextAreaCallback = options.updateTextArea,
1111 $area = editor.$area;1147 $area = editor.$area;
11121148
1113 // Check for iframe change to avoid unnecessary firing1149 // Check for iframe change to avoid unnecessary firing
1114 // of potentially heavy updateTextArea callbacks.1150 // of potentially heavy updateTextArea callbacks.
1115 if (updateTextAreaCallback) {1151 if (updateTextAreaCallback) {
1116 var sum = checksum(html);1152 var sum = checksum(html);
1117 if (checkForChange && editor.frameChecksum == sum)1153 if (checkForChange && editor.frameChecksum === sum) {
1118 return;1154 return;
1155 }
1119 editor.frameChecksum = sum;1156 editor.frameChecksum = sum;
1120 }1157 }
11211158
@@ -1123,11 +1160,12 @@
1123 var code = updateTextAreaCallback ? updateTextAreaCallback(html) : html;1160 var code = updateTextAreaCallback ? updateTextAreaCallback(html) : html;
11241161
1125 // Update the textarea checksum1162 // Update the textarea checksum
1126 if (options.updateFrame)1163 if (options.updateFrame) {
1127 editor.areaChecksum = checksum(code);1164 editor.areaChecksum = checksum(code);
1165 }
11281166
1129 // Update the textarea and trigger the change event1167 // Update the textarea and trigger the change event
1130 if (code != $area.val()) {1168 if (code !== $area.val()) {
1131 $area.val(code);1169 $area.val(code);
1132 $(editor).triggerHandler(CHANGE);1170 $(editor).triggerHandler(CHANGE);
1133 }1171 }
11341172
=== modified file 'addons/web/static/src/js/view_form.js'
--- addons/web/static/src/js/view_form.js 2012-12-21 14:02:36 +0000
+++ addons/web/static/src/js/view_form.js 2012-12-21 17:26:22 +0000
@@ -2624,7 +2624,7 @@
2624 this.$textarea = this.$el.find('textarea');2624 this.$textarea = this.$el.find('textarea');
2625 var width = ((this.node.attrs || {}).editor_width || '100%');2625 var width = ((this.node.attrs || {}).editor_width || '100%');
2626 var height = ((this.node.attrs || {}).editor_height || 250);2626 var height = ((this.node.attrs || {}).editor_height || 250);
2627 this.$textarea.cleditor({2627 this.$cleditor = this.$textarea.cleditor({
2628 width: width, // width not including margins, borders or padding2628 width: width, // width not including margins, borders or padding
2629 height: height, // height not including margins, borders or padding2629 height: height, // height not including margins, borders or padding
2630 controls: // controls to add to the toolbar2630 controls: // controls to add to the toolbar
@@ -2634,10 +2634,9 @@
2634 bodyStyle: // style to assign to document body contained within the editor2634 bodyStyle: // style to assign to document body contained within the editor
2635 "margin:4px; font:12px monospace; cursor:text; color:#1F1F1F"2635 "margin:4px; font:12px monospace; cursor:text; color:#1F1F1F"
2636 });2636 });
2637 this.$cleditor = this.$textarea.cleditor()[0];2637 this.$cleditor.on('change', function() {
2638 this.$cleditor.change(function() {
2639 if (! self._updating_editor) {2638 if (! self._updating_editor) {
2640 self.$cleditor.updateTextArea();2639 self.$cleditor[0].updateTextArea();
2641 self.internal_set_value(self.$textarea.val());2640 self.internal_set_value(self.$textarea.val());
2642 }2641 }
2643 });2642 });
@@ -2647,7 +2646,7 @@
2647 if (! this.get("effective_readonly")) {2646 if (! this.get("effective_readonly")) {
2648 this.$textarea.val(this.get('value') || '');2647 this.$textarea.val(this.get('value') || '');
2649 this._updating_editor = true;2648 this._updating_editor = true;
2650 this.$cleditor.updateFrame();2649 this.$cleditor[0].updateFrame();
2651 this._updating_editor = false;2650 this._updating_editor = false;
2652 } else {2651 } else {
2653 this.$el.html(this.get('value'));2652 this.$el.html(this.get('value'));