]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/editor/exec-command.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / editor / exec-command.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('exec-command', function(Y) {
9
10
11     /**
12      * Plugin for the frame module to handle execCommands for Editor
13      * @module editor
14      * @submodule exec-command
15      */     
16     /**
17      * Plugin for the frame module to handle execCommands for Editor
18      * @class Plugin.ExecCommand
19      * @extends Base
20      * @constructor
21      */
22         var ExecCommand = function() {
23             ExecCommand.superclass.constructor.apply(this, arguments);
24         };
25
26         Y.extend(ExecCommand, Y.Base, {
27             /**
28             * An internal reference to the keyCode of the last key that was pressed.
29             * @private
30             * @property _lastKey
31             */
32             _lastKey: null,
33             /**
34             * An internal reference to the instance of the frame plugged into.
35             * @private
36             * @property _inst
37             */
38             _inst: null,
39             /**
40             * Execute a command on the frame's document.
41             * @method command
42             * @param {String} action The action to perform (bold, italic, fontname)
43             * @param {String} value The optional value (helvetica)
44             * @return {Node/NodeList} Should return the Node/Nodelist affected
45             */
46             command: function(action, value) {
47                 var fn = ExecCommand.COMMANDS[action];
48                 
49                 /*
50                 if (action !== 'insertbr') {
51                     Y.later(0, this, function() {
52                         var inst = this.getInstance();
53                         if (inst && inst.Selection) {
54                             inst.Selection.cleanCursor();
55                         }
56                     });
57                 }
58                 */
59
60                 if (fn) {
61                     return fn.call(this, action, value);
62                 } else {
63                     return this._command(action, value);
64                 }
65             },
66             /**
67             * The private version of execCommand that doesn't filter for overrides.
68             * @private
69             * @method _command
70             * @param {String} action The action to perform (bold, italic, fontname)
71             * @param {String} value The optional value (helvetica)
72             */
73             _command: function(action, value) {
74                 var inst = this.getInstance();
75                 try {
76                     try {
77                         inst.config.doc.execCommand('styleWithCSS', null, 1);
78                     } catch (e1) {
79                         try {
80                             inst.config.doc.execCommand('useCSS', null, 0);
81                         } catch (e2) {
82                         }
83                     }
84                     inst.config.doc.execCommand(action, null, value);
85                 } catch (e) {
86                 }
87             },
88             /**
89             * Get's the instance of YUI bound to the parent frame
90             * @method getInstance
91             * @return {YUI} The YUI instance bound to the parent frame
92             */
93             getInstance: function() {
94                 if (!this._inst) {
95                     this._inst = this.get('host').getInstance();
96                 }
97                 return this._inst;
98             },
99             initializer: function() {
100                 Y.mix(this.get('host'), {
101                     execCommand: function(action, value) {
102                         return this.exec.command(action, value);
103                     },
104                     _execCommand: function(action, value) {
105                         return this.exec._command(action, value);
106                     }
107                 });
108
109                 this.get('host').on('dom:keypress', Y.bind(function(e) {
110                     this._lastKey = e.keyCode;
111                 }, this));
112             }
113         }, {
114             /**
115             * execCommand
116             * @property NAME
117             * @static
118             */
119             NAME: 'execCommand',
120             /**
121             * exec
122             * @property NS
123             * @static
124             */
125             NS: 'exec',
126             ATTRS: {
127                 host: {
128                     value: false
129                 }
130             },
131             /**
132             * Static object literal of execCommand overrides
133             * @property COMMANDS
134             * @static
135             */
136             COMMANDS: {
137                 /**
138                 * Wraps the content with a new element of type (tag)
139                 * @method COMMANDS.wrap
140                 * @static
141                 * @param {String} cmd The command executed: wrap
142                 * @param {String} tag The tag to wrap the selection with
143                 * @return {NodeList} NodeList of the items touched by this command.
144                 */
145                 wrap: function(cmd, tag) {
146                     var inst = this.getInstance();
147                     return (new inst.Selection()).wrapContent(tag);
148                 },
149                 /**
150                 * Inserts the provided HTML at the cursor, should be a single element.
151                 * @method COMMANDS.inserthtml
152                 * @static
153                 * @param {String} cmd The command executed: inserthtml
154                 * @param {String} html The html to insert
155                 * @return {Node} Node instance of the item touched by this command.
156                 */
157                 inserthtml: function(cmd, html) {
158                     var inst = this.getInstance();
159                     if (inst.Selection.hasCursor() || Y.UA.ie) {
160                         return (new inst.Selection()).insertContent(html);
161                     } else {
162                         this._command('inserthtml', html);
163                     }
164                 },
165                 /**
166                 * Inserts the provided HTML at the cursor, and focuses the cursor afterwards.
167                 * @method COMMANDS.insertandfocus
168                 * @static
169                 * @param {String} cmd The command executed: insertandfocus
170                 * @param {String} html The html to insert
171                 * @return {Node} Node instance of the item touched by this command.
172                 */
173                 insertandfocus: function(cmd, html) {
174                     var inst = this.getInstance(), out, sel;
175                     if (inst.Selection.hasCursor()) {
176                         html += inst.Selection.CURSOR;
177                         out = this.command('inserthtml', html);
178                         sel = new inst.Selection();
179                         sel.focusCursor(true, true);
180                     } else {
181                         this.command('inserthtml', html);
182                     }
183                     return out;
184                 },
185                 /**
186                 * Inserts a BR at the current cursor position
187                 * @method COMMANDS.insertbr
188                 * @static
189                 * @param {String} cmd The command executed: insertbr
190                 */
191                 insertbr: function(cmd) {
192                     var inst = this.getInstance(), cur,
193                         sel = new inst.Selection();
194
195                     sel.setCursor();
196                     cur = sel.getCursor();
197                     cur.insert('<br>', 'before');
198                     sel.focusCursor(true, false);
199                     return ((cur && cur.previous) ? cur.previous() : null);
200                 },
201                 /**
202                 * Inserts an image at the cursor position
203                 * @method COMMANDS.insertimage
204                 * @static
205                 * @param {String} cmd The command executed: insertimage
206                 * @param {String} img The url of the image to be inserted
207                 * @return {Node} Node instance of the item touched by this command.
208                 */
209                 insertimage: function(cmd, img) {
210                     return this.command('inserthtml', '<img src="' + img + '">');
211                 },
212                 /**
213                 * Add a class to all of the elements in the selection
214                 * @method COMMANDS.addclass
215                 * @static
216                 * @param {String} cmd The command executed: addclass
217                 * @param {String} cls The className to add
218                 * @return {NodeList} NodeList of the items touched by this command.
219                 */
220                 addclass: function(cmd, cls) {
221                     var inst = this.getInstance();
222                     return (new inst.Selection()).getSelected().addClass(cls);
223                 },
224                 /**
225                 * Remove a class from all of the elements in the selection
226                 * @method COMMANDS.removeclass
227                 * @static
228                 * @param {String} cmd The command executed: removeclass
229                 * @param {String} cls The className to remove
230                 * @return {NodeList} NodeList of the items touched by this command.
231                 */
232                 removeclass: function(cmd, cls) {
233                     var inst = this.getInstance();
234                     return (new inst.Selection()).getSelected().removeClass(cls);
235                 },
236                 /**
237                 * Adds a forecolor to the current selection, or creates a new element and applies it
238                 * @method COMMANDS.forecolor
239                 * @static
240                 * @param {String} cmd The command executed: forecolor
241                 * @param {String} val The color value to apply
242                 * @return {NodeList} NodeList of the items touched by this command.
243                 */
244                 forecolor: function(cmd, val) {
245                     var inst = this.getInstance(),
246                         sel = new inst.Selection(), n;
247
248                     if (!Y.UA.ie) {
249                         this._command('useCSS', false);
250                     }
251                     if (inst.Selection.hasCursor()) {
252                         if (sel.isCollapsed) {
253                             if (sel.anchorNode && (sel.anchorNode.get('innerHTML') === '&nbsp;')) {
254                                 sel.anchorNode.setStyle('color', val);
255                                 n = sel.anchorNode;
256                             } else {
257                                 n = this.command('inserthtml', '<span style="color: ' + val + '">' + inst.Selection.CURSOR + '</span>');
258                                 sel.focusCursor(true, true);
259                             }
260                             return n;
261                         } else {
262                             return this._command(cmd, val);
263                         }
264                     } else {
265                         this._command(cmd, val);
266                     }
267                 },
268                 /**
269                 * Adds a background color to the current selection, or creates a new element and applies it
270                 * @method COMMANDS.backcolor
271                 * @static
272                 * @param {String} cmd The command executed: backcolor
273                 * @param {String} val The color value to apply
274                 * @return {NodeList} NodeList of the items touched by this command.
275                 */
276                 backcolor: function(cmd, val) {
277                     var inst = this.getInstance(),
278                         sel = new inst.Selection(), n;
279                     
280                     if (Y.UA.gecko || Y.UA.opera) {
281                         cmd = 'hilitecolor';
282                     }
283                     if (!Y.UA.ie) {
284                         this._command('useCSS', false);
285                     }
286                     if (inst.Selection.hasCursor()) {
287                         if (sel.isCollapsed) {
288                             if (sel.anchorNode && (sel.anchorNode.get('innerHTML') === '&nbsp;')) {
289                                 sel.anchorNode.setStyle('backgroundColor', val);
290                                 n = sel.anchorNode;
291                             } else {
292                                 n = this.command('inserthtml', '<span style="background-color: ' + val + '">' + inst.Selection.CURSOR + '</span>');
293                                 sel.focusCursor(true, true);
294                             }
295                             return n;
296                         } else {
297                             return this._command(cmd, val);
298                         }
299                     } else {
300                         this._command(cmd, val);
301                     }
302                 },
303                 /**
304                 * Sugar method, calles backcolor
305                 * @method COMMANDS.hilitecolor
306                 * @static
307                 * @param {String} cmd The command executed: backcolor
308                 * @param {String} val The color value to apply
309                 * @return {NodeList} NodeList of the items touched by this command.
310                 */
311                 hilitecolor: function() {
312                     return ExecCommand.COMMANDS.backcolor.apply(this, arguments);
313                 },
314                 /**
315                 * Adds a font name to the current selection, or creates a new element and applies it
316                 * @method COMMANDS.fontname
317                 * @static
318                 * @param {String} cmd The command executed: fontname
319                 * @param {String} val The font name to apply
320                 * @return {NodeList} NodeList of the items touched by this command.
321                 */
322                 fontname: function(cmd, val) {
323                     this._command('fontname', val);
324                     var inst = this.getInstance(),
325                         sel = new inst.Selection();
326                     
327                     if (sel.isCollapsed && (this._lastKey != 32)) {
328                         if (sel.anchorNode.test('font')) {
329                             sel.anchorNode.set('face', val);
330                         }
331                     }
332                 },
333                 /**
334                 * Adds a fontsize to the current selection, or creates a new element and applies it
335                 * @method COMMANDS.fontsize
336                 * @static
337                 * @param {String} cmd The command executed: fontsize
338                 * @param {String} val The font size to apply
339                 * @return {NodeList} NodeList of the items touched by this command.
340                 */
341                 fontsize: function(cmd, val) {
342                     this._command('fontsize', val);
343
344                     var inst = this.getInstance(),
345                         sel = new inst.Selection();
346                     
347                     if (sel.isCollapsed && sel.anchorNode && (this._lastKey != 32)) {
348                         if (Y.UA.webkit) {
349                             if (sel.anchorNode.getStyle('lineHeight')) {
350                                 sel.anchorNode.setStyle('lineHeight', '');
351                             }
352                         }
353                         if (sel.anchorNode.test('font')) {
354                             sel.anchorNode.set('size', val);
355                         } else if (Y.UA.gecko) {
356                             var p = sel.anchorNode.ancestor(inst.Selection.DEFAULT_BLOCK_TAG);
357                             if (p) {
358                                 p.setStyle('fontSize', '');
359                             }
360                         }
361                     }
362                 }
363             }
364         });
365         
366         /**
367         * This method is meant to normalize IE's in ability to exec the proper command on elements with CSS styling.
368         * @method fixIETags
369         * @protected
370         * @param {String} cmd The command to execute
371         * @param {String} tag The tag to create
372         * @param {String} rule The rule that we are looking for.
373         */
374         var fixIETags = function(cmd, tag, rule) {
375             var inst = this.getInstance(),
376                 doc = inst.config.doc,
377                 sel = doc.selection.createRange(),
378                 o = doc.queryCommandValue(cmd),
379                 html, reg, m, p, d, s, c;
380
381             if (o) {
382                 html = sel.htmlText;
383                 reg = new RegExp(rule, 'g');
384                 m = html.match(reg);
385
386                 if (m) {
387                     html = html.replace(rule + ';', '').replace(rule, '');
388
389                     sel.pasteHTML('<var id="yui-ie-bs">');
390
391                     p = doc.getElementById('yui-ie-bs');
392                     d = doc.createElement('div');
393                     s = doc.createElement(tag);
394                     
395                     d.innerHTML = html;
396                     if (p.parentNode !== inst.config.doc.body) {
397                         p = p.parentNode;
398                     }
399
400                     c = d.childNodes;
401
402                     p.parentNode.replaceChild(s, p);
403
404                     Y.each(c, function(f) {
405                         s.appendChild(f);
406                     });
407                     sel.collapse();
408                     sel.moveToElementText(s);
409                     sel.select();
410                 }
411             }
412             this._command(cmd);
413         };
414
415         if (Y.UA.ie) {
416             ExecCommand.COMMANDS.bold = function() {
417                 fixIETags.call(this, 'bold', 'b', 'FONT-WEIGHT: bold');
418             }
419             ExecCommand.COMMANDS.italic = function() {
420                 fixIETags.call(this, 'italic', 'i', 'FONT-STYLE: italic');
421             }
422             ExecCommand.COMMANDS.underline = function() {
423                 fixIETags.call(this, 'underline', 'u', 'TEXT-DECORATION: underline');
424             }
425         }
426
427         Y.namespace('Plugin');
428         Y.Plugin.ExecCommand = ExecCommand;
429
430
431
432 }, '3.3.0' ,{requires:['frame'], skinnable:false});