~ubuntu-branches/ubuntu/natty/otrs2/natty-updates

« back to all changes in this revision

Viewing changes to var/httpd/htdocs/yui/2.7.0/build/editor/editor-debug.js

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2010-08-09 19:43:44 UTC
  • mfrom: (1.1.12)
  • Revision ID: package-import@ubuntu.com-20100809194344-absef1ut5mfj3qhv
Tags: 2.4.7+dfsg1-1
* Strip out yui from the source in the dfsg version.
  Closes: #591196
* Depend on libjs-yui and link to this package, instead of using the embedded
  yui version. This changes make the flash ticket statistics unuseable!
  Closes: #592146

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.net/yui/license.txt
5
 
version: 2.7.0
6
 
*/
7
 
(function() {
8
 
var Dom = YAHOO.util.Dom,
9
 
    Event = YAHOO.util.Event,
10
 
    Lang = YAHOO.lang;
11
 
    /**
12
 
     * @module editor    
13
 
     * @description <p>Creates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar</p>
14
 
     * @class ToolbarButtonAdvanced
15
 
     * @namespace YAHOO.widget
16
 
     * @requires yahoo, dom, element, event, container_core, menu, button
17
 
     * 
18
 
     * Provides a toolbar button based on the button and menu widgets.
19
 
     * @constructor
20
 
     * @class ToolbarButtonAdvanced
21
 
     * @param {String/HTMLElement} el The element to turn into a button.
22
 
     * @param {Object} attrs Object liternal containing configuration parameters.
23
 
    */
24
 
    if (YAHOO.widget.Button) {
25
 
        YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button;
26
 
        /**
27
 
        * @property buttonType
28
 
        * @private
29
 
        * @description Tells if the Button is a Rich Button or a Simple Button
30
 
        */
31
 
        YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich';
32
 
        /**
33
 
        * @method checkValue
34
 
        * @param {String} value The value of the option that we want to mark as selected
35
 
        * @description Select an option by value
36
 
        */
37
 
        YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) {
38
 
            var _menuItems = this.getMenu().getItems();
39
 
            if (_menuItems.length === 0) {
40
 
                this.getMenu()._onBeforeShow();
41
 
                _menuItems = this.getMenu().getItems();
42
 
            }
43
 
            for (var i = 0; i < _menuItems.length; i++) {
44
 
                _menuItems[i].cfg.setProperty('checked', false);
45
 
                if (_menuItems[i].value == value) {
46
 
                    _menuItems[i].cfg.setProperty('checked', true);
47
 
                }
48
 
            }      
49
 
        };
50
 
    } else {
51
 
        YAHOO.widget.ToolbarButtonAdvanced = function() {};
52
 
    }
53
 
 
54
 
 
55
 
    /**
56
 
     * @description <p>Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar</p><p>Provides a toolbar button based on the button and menu widgets, &lt;select&gt; elements are used in place of menu's.</p>
57
 
     * @class ToolbarButton
58
 
     * @namespace YAHOO.widget
59
 
     * @requires yahoo, dom, element, event
60
 
     * @extends YAHOO.util.Element
61
 
     * 
62
 
     * 
63
 
     * @constructor
64
 
     * @param {String/HTMLElement} el The element to turn into a button.
65
 
     * @param {Object} attrs Object liternal containing configuration parameters.
66
 
    */
67
 
 
68
 
    YAHOO.widget.ToolbarButton = function(el, attrs) {
69
 
        YAHOO.log('ToolbarButton Initalizing', 'info', 'ToolbarButton');
70
 
        YAHOO.log(arguments.length + ' arguments passed to constructor', 'info', 'Toolbar');
71
 
        
72
 
        if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
73
 
            attrs = el;
74
 
        }
75
 
        var local_attrs = (attrs || {});
76
 
 
77
 
        var oConfig = {
78
 
            element: null,
79
 
            attributes: local_attrs
80
 
        };
81
 
 
82
 
        if (!oConfig.attributes.type) {
83
 
            oConfig.attributes.type = 'push';
84
 
        }
85
 
        
86
 
        oConfig.element = document.createElement('span');
87
 
        oConfig.element.setAttribute('unselectable', 'on');
88
 
        oConfig.element.className = 'yui-button yui-' + oConfig.attributes.type + '-button';
89
 
        oConfig.element.innerHTML = '<span class="first-child"><a href="#">LABEL</a></span>';
90
 
        oConfig.element.firstChild.firstChild.tabIndex = '-1';
91
 
        oConfig.attributes.id = (oConfig.attributes.id || Dom.generateId());
92
 
        oConfig.element.id = oConfig.attributes.id;
93
 
 
94
 
        YAHOO.widget.ToolbarButton.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
95
 
    };
96
 
 
97
 
    YAHOO.extend(YAHOO.widget.ToolbarButton, YAHOO.util.Element, {
98
 
        /**
99
 
        * @property buttonType
100
 
        * @private
101
 
        * @description Tells if the Button is a Rich Button or a Simple Button
102
 
        */
103
 
        buttonType: 'normal',
104
 
        /**
105
 
        * @method _handleMouseOver
106
 
        * @private
107
 
        * @description Adds classes to the button elements on mouseover (hover)
108
 
        */
109
 
        _handleMouseOver: function() {
110
 
            if (!this.get('disabled')) {
111
 
                this.addClass('yui-button-hover');
112
 
                this.addClass('yui-' + this.get('type') + '-button-hover');
113
 
            }
114
 
        },
115
 
        /**
116
 
        * @method _handleMouseOut
117
 
        * @private
118
 
        * @description Removes classes from the button elements on mouseout (hover)
119
 
        */
120
 
        _handleMouseOut: function() {
121
 
            this.removeClass('yui-button-hover');
122
 
            this.removeClass('yui-' + this.get('type') + '-button-hover');
123
 
        },
124
 
        /**
125
 
        * @method checkValue
126
 
        * @param {String} value The value of the option that we want to mark as selected
127
 
        * @description Select an option by value
128
 
        */
129
 
        checkValue: function(value) {
130
 
            if (this.get('type') == 'menu') {
131
 
                var opts = this._button.options;
132
 
                for (var i = 0; i < opts.length; i++) {
133
 
                    if (opts[i].value == value) {
134
 
                        opts.selectedIndex = i;
135
 
                    }
136
 
                }
137
 
            }
138
 
        },
139
 
        /** 
140
 
        * @method init
141
 
        * @description The ToolbarButton class's initialization method
142
 
        */        
143
 
        init: function(p_oElement, p_oAttributes) {
144
 
            YAHOO.widget.ToolbarButton.superclass.init.call(this, p_oElement, p_oAttributes);
145
 
 
146
 
            this.on('mouseover', this._handleMouseOver, this, true);
147
 
            this.on('mouseout', this._handleMouseOut, this, true);
148
 
            this.on('click', function(ev) {
149
 
                Event.stopEvent(ev);
150
 
                return false;
151
 
            }, this, true);
152
 
        },
153
 
        /**
154
 
        * @method initAttributes
155
 
        * @description Initializes all of the configuration attributes used to create 
156
 
        * the toolbar.
157
 
        * @param {Object} attr Object literal specifying a set of 
158
 
        * configuration attributes used to create the toolbar.
159
 
        */        
160
 
        initAttributes: function(attr) {
161
 
            YAHOO.widget.ToolbarButton.superclass.initAttributes.call(this, attr);
162
 
            /**
163
 
            * @attribute value
164
 
            * @description The value of the button
165
 
            * @type String
166
 
            */            
167
 
            this.setAttributeConfig('value', {
168
 
                value: attr.value
169
 
            });
170
 
            /**
171
 
            * @attribute menu
172
 
            * @description The menu attribute, see YAHOO.widget.Button
173
 
            * @type Object
174
 
            */            
175
 
            this.setAttributeConfig('menu', {
176
 
                value: attr.menu || false
177
 
            });
178
 
            /**
179
 
            * @attribute type
180
 
            * @description The type of button to create: push, menu, color, select, spin
181
 
            * @type String
182
 
            */            
183
 
            this.setAttributeConfig('type', {
184
 
                value: attr.type,
185
 
                writeOnce: true,
186
 
                method: function(type) {
187
 
                    var el, opt;
188
 
                    if (!this._button) {
189
 
                        this._button = this.get('element').getElementsByTagName('a')[0];
190
 
                    }
191
 
                    switch (type) {
192
 
                        case 'select':
193
 
                        case 'menu':
194
 
                            el = document.createElement('select');
195
 
                            var menu = this.get('menu');
196
 
                            for (var i = 0; i < menu.length; i++) {
197
 
                                opt = document.createElement('option');
198
 
                                opt.innerHTML = menu[i].text;
199
 
                                opt.value = menu[i].value;
200
 
                                if (menu[i].checked) {
201
 
                                    opt.selected = true;
202
 
                                }
203
 
                                el.appendChild(opt);
204
 
                            }
205
 
                            this._button.parentNode.replaceChild(el, this._button);
206
 
                            Event.on(el, 'change', this._handleSelect, this, true);
207
 
                            this._button = el;
208
 
                            break;
209
 
                    }
210
 
                }
211
 
            });
212
 
 
213
 
            /**
214
 
            * @attribute disabled
215
 
            * @description Set the button into a disabled state
216
 
            * @type String
217
 
            */            
218
 
            this.setAttributeConfig('disabled', {
219
 
                value: attr.disabled || false,
220
 
                method: function(disabled) {
221
 
                    if (disabled) {
222
 
                        this.addClass('yui-button-disabled');
223
 
                        this.addClass('yui-' + this.get('type') + '-button-disabled');
224
 
                    } else {
225
 
                        this.removeClass('yui-button-disabled');
226
 
                        this.removeClass('yui-' + this.get('type') + '-button-disabled');
227
 
                    }
228
 
                    if (this.get('type') == 'menu') {
229
 
                        this._button.disabled = disabled;
230
 
                    }
231
 
                }
232
 
            });
233
 
 
234
 
            /**
235
 
            * @attribute label
236
 
            * @description The text label for the button
237
 
            * @type String
238
 
            */            
239
 
            this.setAttributeConfig('label', {
240
 
                value: attr.label,
241
 
                method: function(label) {
242
 
                    if (!this._button) {
243
 
                        this._button = this.get('element').getElementsByTagName('a')[0];
244
 
                    }
245
 
                    if (this.get('type') == 'push') {
246
 
                        this._button.innerHTML = label;
247
 
                    }
248
 
                }
249
 
            });
250
 
 
251
 
            /**
252
 
            * @attribute title
253
 
            * @description The title of the button
254
 
            * @type String
255
 
            */            
256
 
            this.setAttributeConfig('title', {
257
 
                value: attr.title
258
 
            });
259
 
 
260
 
            /**
261
 
            * @config container
262
 
            * @description The container that the button is rendered to, handled by Toolbar
263
 
            * @type String
264
 
            */            
265
 
            this.setAttributeConfig('container', {
266
 
                value: null,
267
 
                writeOnce: true,
268
 
                method: function(cont) {
269
 
                    this.appendTo(cont);
270
 
                }
271
 
            });
272
 
 
273
 
        },
274
 
        /** 
275
 
        * @private
276
 
        * @method _handleSelect
277
 
        * @description The event fired when a change event gets fired on a select element
278
 
        * @param {Event} ev The change event.
279
 
        */        
280
 
        _handleSelect: function(ev) {
281
 
            var tar = Event.getTarget(ev);
282
 
            var value = tar.options[tar.selectedIndex].value;
283
 
            this.fireEvent('change', {type: 'change', value: value });
284
 
        },
285
 
        /** 
286
 
        * @method getMenu
287
 
        * @description A stub function to mimic YAHOO.widget.Button's getMenu method
288
 
        */        
289
 
        getMenu: function() {
290
 
            return this.get('menu');
291
 
        },
292
 
        /** 
293
 
        * @method destroy
294
 
        * @description Destroy the button
295
 
        */        
296
 
        destroy: function() {
297
 
            Event.purgeElement(this.get('element'), true);
298
 
            this.get('element').parentNode.removeChild(this.get('element'));
299
 
            //Brutal Object Destroy
300
 
            for (var i in this) {
301
 
                if (Lang.hasOwnProperty(this, i)) {
302
 
                    this[i] = null;
303
 
                }
304
 
            }       
305
 
        },
306
 
        /** 
307
 
        * @method fireEvent
308
 
        * @description Overridden fireEvent method to prevent DOM events from firing if the button is disabled.
309
 
        */        
310
 
        fireEvent: function(p_sType, p_aArgs) {
311
 
            //  Disabled buttons should not respond to DOM events
312
 
            if (this.DOM_EVENTS[p_sType] && this.get('disabled')) {
313
 
                Event.stopEvent(p_aArgs);
314
 
                return;
315
 
            }
316
 
        
317
 
            YAHOO.widget.ToolbarButton.superclass.fireEvent.call(this, p_sType, p_aArgs);
318
 
        },
319
 
        /**
320
 
        * @method toString
321
 
        * @description Returns a string representing the toolbar.
322
 
        * @return {String}
323
 
        */        
324
 
        toString: function() {
325
 
            return 'ToolbarButton (' + this.get('id') + ')';
326
 
        }
327
 
        
328
 
    });
329
 
})();
330
 
/**
331
 
 * @module editor
332
 
 * @description <p>Creates a rich Toolbar widget based on Button. Primarily used with the Rich Text Editor</p>
333
 
 * @namespace YAHOO.widget
334
 
 * @requires yahoo, dom, element, event, toolbarbutton
335
 
 * @optional container_core, dragdrop
336
 
 */
337
 
(function() {
338
 
var Dom = YAHOO.util.Dom,
339
 
    Event = YAHOO.util.Event,
340
 
    Lang = YAHOO.lang;
341
 
    
342
 
    var getButton = function(id) {
343
 
        var button = id;
344
 
        if (Lang.isString(id)) {
345
 
            button = this.getButtonById(id);
346
 
        }
347
 
        if (Lang.isNumber(id)) {
348
 
            button = this.getButtonByIndex(id);
349
 
        }
350
 
        if ((!(button instanceof YAHOO.widget.ToolbarButton)) && (!(button instanceof YAHOO.widget.ToolbarButtonAdvanced))) {
351
 
            button = this.getButtonByValue(id);
352
 
        }
353
 
        if ((button instanceof YAHOO.widget.ToolbarButton) || (button instanceof YAHOO.widget.ToolbarButtonAdvanced)) {
354
 
            return button;
355
 
        }
356
 
        return false;
357
 
    };
358
 
 
359
 
    /**
360
 
     * Provides a rich toolbar widget based on the button and menu widgets
361
 
     * @constructor
362
 
     * @class Toolbar
363
 
     * @extends YAHOO.util.Element
364
 
     * @param {String/HTMLElement} el The element to turn into a toolbar.
365
 
     * @param {Object} attrs Object liternal containing configuration parameters.
366
 
    */
367
 
    YAHOO.widget.Toolbar = function(el, attrs) {
368
 
        YAHOO.log('Toolbar Initalizing', 'info', 'Toolbar');
369
 
        YAHOO.log(arguments.length + ' arguments passed to constructor', 'info', 'Toolbar');
370
 
        
371
 
        if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
372
 
            attrs = el;
373
 
        }
374
 
        var local_attrs = {};
375
 
        if (attrs) {
376
 
            Lang.augmentObject(local_attrs, attrs); //Break the config reference
377
 
        }
378
 
        
379
 
 
380
 
        var oConfig = {
381
 
            element: null,
382
 
            attributes: local_attrs
383
 
        };
384
 
        
385
 
        
386
 
        if (Lang.isString(el) && Dom.get(el)) {
387
 
            oConfig.element = Dom.get(el);
388
 
        } else if (Lang.isObject(el) && Dom.get(el) && Dom.get(el).nodeType) {  
389
 
            oConfig.element = Dom.get(el);
390
 
        }
391
 
        
392
 
 
393
 
        if (!oConfig.element) {
394
 
            YAHOO.log('No element defined, creating toolbar container', 'warn', 'Toolbar');
395
 
            oConfig.element = document.createElement('DIV');
396
 
            oConfig.element.id = Dom.generateId();
397
 
            
398
 
            if (local_attrs.container && Dom.get(local_attrs.container)) {
399
 
                YAHOO.log('Container found in config appending to it (' + Dom.get(local_attrs.container).id + ')', 'info', 'Toolbar');
400
 
                Dom.get(local_attrs.container).appendChild(oConfig.element);
401
 
            }
402
 
        }
403
 
        
404
 
 
405
 
        if (!oConfig.element.id) {
406
 
            oConfig.element.id = ((Lang.isString(el)) ? el : Dom.generateId());
407
 
            YAHOO.log('No element ID defined for toolbar container, creating..', 'warn', 'Toolbar');
408
 
        }
409
 
        YAHOO.log('Initing toolbar with id: ' + oConfig.element.id, 'info', 'Toolbar');
410
 
        
411
 
        var fs = document.createElement('fieldset');
412
 
        var lg = document.createElement('legend');
413
 
        lg.innerHTML = 'Toolbar';
414
 
        fs.appendChild(lg);
415
 
        
416
 
        var cont = document.createElement('DIV');
417
 
        oConfig.attributes.cont = cont;
418
 
        Dom.addClass(cont, 'yui-toolbar-subcont');
419
 
        fs.appendChild(cont);
420
 
        oConfig.element.appendChild(fs);
421
 
 
422
 
        oConfig.element.tabIndex = -1;
423
 
 
424
 
        
425
 
        oConfig.attributes.element = oConfig.element;
426
 
        oConfig.attributes.id = oConfig.element.id;
427
 
 
428
 
        YAHOO.widget.Toolbar.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
429
 
         
430
 
    };
431
 
 
432
 
    YAHOO.extend(YAHOO.widget.Toolbar, YAHOO.util.Element, {
433
 
        /**
434
 
        * @method _addMenuClasses
435
 
        * @private
436
 
        * @description This method is called from Menu's renderEvent to add a few more classes to the menu items
437
 
        * @param {String} ev The event that fired.
438
 
        * @param {Array} na Array of event information.
439
 
        * @param {Object} o Button config object. 
440
 
        */
441
 
        _addMenuClasses: function(ev, na, o) {
442
 
            Dom.addClass(this.element, 'yui-toolbar-' + o.get('value') + '-menu');
443
 
            if (Dom.hasClass(o._button.parentNode.parentNode, 'yui-toolbar-select')) {
444
 
                Dom.addClass(this.element, 'yui-toolbar-select-menu');
445
 
            }
446
 
            var items = this.getItems();
447
 
            for (var i = 0; i < items.length; i++) {
448
 
                Dom.addClass(items[i].element, 'yui-toolbar-' + o.get('value') + '-' + ((items[i].value) ? items[i].value.replace(/ /g, '-').toLowerCase() : items[i]._oText.nodeValue.replace(/ /g, '-').toLowerCase()));
449
 
                Dom.addClass(items[i].element, 'yui-toolbar-' + o.get('value') + '-' + ((items[i].value) ? items[i].value.replace(/ /g, '-') : items[i]._oText.nodeValue.replace(/ /g, '-')));
450
 
            }
451
 
        },
452
 
        /** 
453
 
        * @property buttonType
454
 
        * @description The default button to use
455
 
        * @type Object
456
 
        */
457
 
        buttonType: YAHOO.widget.ToolbarButton,
458
 
        /** 
459
 
        * @property dd
460
 
        * @description The DragDrop instance associated with the Toolbar
461
 
        * @type Object
462
 
        */
463
 
        dd: null,
464
 
        /** 
465
 
        * @property _colorData
466
 
        * @description Object reference containing colors hex and text values.
467
 
        * @type Object
468
 
        */
469
 
        _colorData: {
470
 
/* {{{ _colorData */
471
 
    '#111111': 'Obsidian',
472
 
    '#2D2D2D': 'Dark Gray',
473
 
    '#434343': 'Shale',
474
 
    '#5B5B5B': 'Flint',
475
 
    '#737373': 'Gray',
476
 
    '#8B8B8B': 'Concrete',
477
 
    '#A2A2A2': 'Gray',
478
 
    '#B9B9B9': 'Titanium',
479
 
    '#000000': 'Black',
480
 
    '#D0D0D0': 'Light Gray',
481
 
    '#E6E6E6': 'Silver',
482
 
    '#FFFFFF': 'White',
483
 
    '#BFBF00': 'Pumpkin',
484
 
    '#FFFF00': 'Yellow',
485
 
    '#FFFF40': 'Banana',
486
 
    '#FFFF80': 'Pale Yellow',
487
 
    '#FFFFBF': 'Butter',
488
 
    '#525330': 'Raw Siena',
489
 
    '#898A49': 'Mildew',
490
 
    '#AEA945': 'Olive',
491
 
    '#7F7F00': 'Paprika',
492
 
    '#C3BE71': 'Earth',
493
 
    '#E0DCAA': 'Khaki',
494
 
    '#FCFAE1': 'Cream',
495
 
    '#60BF00': 'Cactus',
496
 
    '#80FF00': 'Chartreuse',
497
 
    '#A0FF40': 'Green',
498
 
    '#C0FF80': 'Pale Lime',
499
 
    '#DFFFBF': 'Light Mint',
500
 
    '#3B5738': 'Green',
501
 
    '#668F5A': 'Lime Gray',
502
 
    '#7F9757': 'Yellow',
503
 
    '#407F00': 'Clover',
504
 
    '#8A9B55': 'Pistachio',
505
 
    '#B7C296': 'Light Jade',
506
 
    '#E6EBD5': 'Breakwater',
507
 
    '#00BF00': 'Spring Frost',
508
 
    '#00FF80': 'Pastel Green',
509
 
    '#40FFA0': 'Light Emerald',
510
 
    '#80FFC0': 'Sea Foam',
511
 
    '#BFFFDF': 'Sea Mist',
512
 
    '#033D21': 'Dark Forrest',
513
 
    '#438059': 'Moss',
514
 
    '#7FA37C': 'Medium Green',
515
 
    '#007F40': 'Pine',
516
 
    '#8DAE94': 'Yellow Gray Green',
517
 
    '#ACC6B5': 'Aqua Lung',
518
 
    '#DDEBE2': 'Sea Vapor',
519
 
    '#00BFBF': 'Fog',
520
 
    '#00FFFF': 'Cyan',
521
 
    '#40FFFF': 'Turquoise Blue',
522
 
    '#80FFFF': 'Light Aqua',
523
 
    '#BFFFFF': 'Pale Cyan',
524
 
    '#033D3D': 'Dark Teal',
525
 
    '#347D7E': 'Gray Turquoise',
526
 
    '#609A9F': 'Green Blue',
527
 
    '#007F7F': 'Seaweed',
528
 
    '#96BDC4': 'Green Gray',
529
 
    '#B5D1D7': 'Soapstone',
530
 
    '#E2F1F4': 'Light Turquoise',
531
 
    '#0060BF': 'Summer Sky',
532
 
    '#0080FF': 'Sky Blue',
533
 
    '#40A0FF': 'Electric Blue',
534
 
    '#80C0FF': 'Light Azure',
535
 
    '#BFDFFF': 'Ice Blue',
536
 
    '#1B2C48': 'Navy',
537
 
    '#385376': 'Biscay',
538
 
    '#57708F': 'Dusty Blue',
539
 
    '#00407F': 'Sea Blue',
540
 
    '#7792AC': 'Sky Blue Gray',
541
 
    '#A8BED1': 'Morning Sky',
542
 
    '#DEEBF6': 'Vapor',
543
 
    '#0000BF': 'Deep Blue',
544
 
    '#0000FF': 'Blue',
545
 
    '#4040FF': 'Cerulean Blue',
546
 
    '#8080FF': 'Evening Blue',
547
 
    '#BFBFFF': 'Light Blue',
548
 
    '#212143': 'Deep Indigo',
549
 
    '#373E68': 'Sea Blue',
550
 
    '#444F75': 'Night Blue',
551
 
    '#00007F': 'Indigo Blue',
552
 
    '#585E82': 'Dockside',
553
 
    '#8687A4': 'Blue Gray',
554
 
    '#D2D1E1': 'Light Blue Gray',
555
 
    '#6000BF': 'Neon Violet',
556
 
    '#8000FF': 'Blue Violet',
557
 
    '#A040FF': 'Violet Purple',
558
 
    '#C080FF': 'Violet Dusk',
559
 
    '#DFBFFF': 'Pale Lavender',
560
 
    '#302449': 'Cool Shale',
561
 
    '#54466F': 'Dark Indigo',
562
 
    '#655A7F': 'Dark Violet',
563
 
    '#40007F': 'Violet',
564
 
    '#726284': 'Smoky Violet',
565
 
    '#9E8FA9': 'Slate Gray',
566
 
    '#DCD1DF': 'Violet White',
567
 
    '#BF00BF': 'Royal Violet',
568
 
    '#FF00FF': 'Fuchsia',
569
 
    '#FF40FF': 'Magenta',
570
 
    '#FF80FF': 'Orchid',
571
 
    '#FFBFFF': 'Pale Magenta',
572
 
    '#4A234A': 'Dark Purple',
573
 
    '#794A72': 'Medium Purple',
574
 
    '#936386': 'Cool Granite',
575
 
    '#7F007F': 'Purple',
576
 
    '#9D7292': 'Purple Moon',
577
 
    '#C0A0B6': 'Pale Purple',
578
 
    '#ECDAE5': 'Pink Cloud',
579
 
    '#BF005F': 'Hot Pink',
580
 
    '#FF007F': 'Deep Pink',
581
 
    '#FF409F': 'Grape',
582
 
    '#FF80BF': 'Electric Pink',
583
 
    '#FFBFDF': 'Pink',
584
 
    '#451528': 'Purple Red',
585
 
    '#823857': 'Purple Dino',
586
 
    '#A94A76': 'Purple Gray',
587
 
    '#7F003F': 'Rose',
588
 
    '#BC6F95': 'Antique Mauve',
589
 
    '#D8A5BB': 'Cool Marble',
590
 
    '#F7DDE9': 'Pink Granite',
591
 
    '#C00000': 'Apple',
592
 
    '#FF0000': 'Fire Truck',
593
 
    '#FF4040': 'Pale Red',
594
 
    '#FF8080': 'Salmon',
595
 
    '#FFC0C0': 'Warm Pink',
596
 
    '#441415': 'Sepia',
597
 
    '#82393C': 'Rust',
598
 
    '#AA4D4E': 'Brick',
599
 
    '#800000': 'Brick Red',
600
 
    '#BC6E6E': 'Mauve',
601
 
    '#D8A3A4': 'Shrimp Pink',
602
 
    '#F8DDDD': 'Shell Pink',
603
 
    '#BF5F00': 'Dark Orange',
604
 
    '#FF7F00': 'Orange',
605
 
    '#FF9F40': 'Grapefruit',
606
 
    '#FFBF80': 'Canteloupe',
607
 
    '#FFDFBF': 'Wax',
608
 
    '#482C1B': 'Dark Brick',
609
 
    '#855A40': 'Dirt',
610
 
    '#B27C51': 'Tan',
611
 
    '#7F3F00': 'Nutmeg',
612
 
    '#C49B71': 'Mustard',
613
 
    '#E1C4A8': 'Pale Tan',
614
 
    '#FDEEE0': 'Marble'
615
 
/* }}} */
616
 
        },
617
 
        /** 
618
 
        * @property _colorPicker
619
 
        * @description The HTML Element containing the colorPicker
620
 
        * @type HTMLElement
621
 
        */
622
 
        _colorPicker: null,
623
 
        /** 
624
 
        * @property STR_COLLAPSE
625
 
        * @description String for Toolbar Collapse Button
626
 
        * @type String
627
 
        */
628
 
        STR_COLLAPSE: 'Collapse Toolbar',
629
 
        /** 
630
 
        * @property STR_SPIN_LABEL
631
 
        * @description String for spinbutton dynamic label. Note the {VALUE} will be replaced with YAHOO.lang.substitute
632
 
        * @type String
633
 
        */
634
 
        STR_SPIN_LABEL: 'Spin Button with value {VALUE}. Use Control Shift Up Arrow and Control Shift Down arrow keys to increase or decrease the value.',
635
 
        /** 
636
 
        * @property STR_SPIN_UP
637
 
        * @description String for spinbutton up
638
 
        * @type String
639
 
        */
640
 
        STR_SPIN_UP: 'Click to increase the value of this input',
641
 
        /** 
642
 
        * @property STR_SPIN_DOWN
643
 
        * @description String for spinbutton down
644
 
        * @type String
645
 
        */
646
 
        STR_SPIN_DOWN: 'Click to decrease the value of this input',
647
 
        /** 
648
 
        * @property _titlebar
649
 
        * @description Object reference to the titlebar
650
 
        * @type HTMLElement
651
 
        */
652
 
        _titlebar: null,
653
 
        /** 
654
 
        * @property browser
655
 
        * @description Standard browser detection
656
 
        * @type Object
657
 
        */
658
 
        browser: YAHOO.env.ua,
659
 
        /**
660
 
        * @protected
661
 
        * @property _buttonList
662
 
        * @description Internal property list of current buttons in the toolbar
663
 
        * @type Array
664
 
        */
665
 
        _buttonList: null,
666
 
        /**
667
 
        * @protected
668
 
        * @property _buttonGroupList
669
 
        * @description Internal property list of current button groups in the toolbar
670
 
        * @type Array
671
 
        */
672
 
        _buttonGroupList: null,
673
 
        /**
674
 
        * @protected
675
 
        * @property _sep
676
 
        * @description Internal reference to the separator HTML Element for cloning
677
 
        * @type HTMLElement
678
 
        */
679
 
        _sep: null,
680
 
        /**
681
 
        * @protected
682
 
        * @property _sepCount
683
 
        * @description Internal refernce for counting separators, so we can give them a useful class name for styling
684
 
        * @type Number
685
 
        */
686
 
        _sepCount: null,
687
 
        /**
688
 
        * @protected
689
 
        * @property draghandle
690
 
        * @type HTMLElement
691
 
        */
692
 
        _dragHandle: null,
693
 
        /**
694
 
        * @protected
695
 
        * @property _toolbarConfigs
696
 
        * @type Object
697
 
        */
698
 
        _toolbarConfigs: {
699
 
            renderer: true
700
 
        },
701
 
        /**
702
 
        * @protected
703
 
        * @property CLASS_CONTAINER
704
 
        * @description Default CSS class to apply to the toolbar container element
705
 
        * @type String
706
 
        */
707
 
        CLASS_CONTAINER: 'yui-toolbar-container',
708
 
        /**
709
 
        * @protected
710
 
        * @property CLASS_DRAGHANDLE
711
 
        * @description Default CSS class to apply to the toolbar's drag handle element
712
 
        * @type String
713
 
        */
714
 
        CLASS_DRAGHANDLE: 'yui-toolbar-draghandle',
715
 
        /**
716
 
        * @protected
717
 
        * @property CLASS_SEPARATOR
718
 
        * @description Default CSS class to apply to all separators in the toolbar
719
 
        * @type String
720
 
        */
721
 
        CLASS_SEPARATOR: 'yui-toolbar-separator',
722
 
        /**
723
 
        * @protected
724
 
        * @property CLASS_DISABLED
725
 
        * @description Default CSS class to apply when the toolbar is disabled
726
 
        * @type String
727
 
        */
728
 
        CLASS_DISABLED: 'yui-toolbar-disabled',
729
 
        /**
730
 
        * @protected
731
 
        * @property CLASS_PREFIX
732
 
        * @description Default prefix for dynamically created class names
733
 
        * @type String
734
 
        */
735
 
        CLASS_PREFIX: 'yui-toolbar',
736
 
        /** 
737
 
        * @method init
738
 
        * @description The Toolbar class's initialization method
739
 
        */
740
 
        init: function(p_oElement, p_oAttributes) {
741
 
            YAHOO.widget.Toolbar.superclass.init.call(this, p_oElement, p_oAttributes);
742
 
 
743
 
        },
744
 
        /**
745
 
        * @method initAttributes
746
 
        * @description Initializes all of the configuration attributes used to create 
747
 
        * the toolbar.
748
 
        * @param {Object} attr Object literal specifying a set of 
749
 
        * configuration attributes used to create the toolbar.
750
 
        */
751
 
        initAttributes: function(attr) {
752
 
            YAHOO.widget.Toolbar.superclass.initAttributes.call(this, attr);
753
 
            this.addClass(this.CLASS_CONTAINER);
754
 
 
755
 
            /**
756
 
            * @attribute buttonType
757
 
            * @description The buttonType to use (advanced or basic)
758
 
            * @type String
759
 
            */
760
 
            this.setAttributeConfig('buttonType', {
761
 
                value: attr.buttonType || 'basic',
762
 
                writeOnce: true,
763
 
                validator: function(type) {
764
 
                    switch (type) {
765
 
                        case 'advanced':
766
 
                        case 'basic':
767
 
                            return true;
768
 
                    }
769
 
                    return false;
770
 
                },
771
 
                method: function(type) {
772
 
                    if (type == 'advanced') {
773
 
                        if (YAHOO.widget.Button) {
774
 
                            this.buttonType = YAHOO.widget.ToolbarButtonAdvanced;
775
 
                        } else {
776
 
                            YAHOO.log('Can not find YAHOO.widget.Button', 'error', 'Toolbar');
777
 
                            this.buttonType = YAHOO.widget.ToolbarButton;
778
 
                        }
779
 
                    } else {
780
 
                        this.buttonType = YAHOO.widget.ToolbarButton;
781
 
                    }
782
 
                }
783
 
            });
784
 
 
785
 
 
786
 
            /**
787
 
            * @attribute buttons
788
 
            * @description Object specifying the buttons to include in the toolbar
789
 
            * Example:
790
 
            * <code><pre>
791
 
            * {
792
 
            *   { id: 'b3', type: 'button', label: 'Underline', value: 'underline' },
793
 
            *   { type: 'separator' },
794
 
            *   { id: 'b4', type: 'menu', label: 'Align', value: 'align',
795
 
            *       menu: [
796
 
            *           { text: "Left", value: 'alignleft' },
797
 
            *           { text: "Center", value: 'aligncenter' },
798
 
            *           { text: "Right", value: 'alignright' }
799
 
            *       ]
800
 
            *   }
801
 
            * }
802
 
            * </pre></code>
803
 
            * @type Array
804
 
            */
805
 
            
806
 
            this.setAttributeConfig('buttons', {
807
 
                value: [],
808
 
                writeOnce: true,
809
 
                method: function(data) {
810
 
                    for (var i in data) {
811
 
                        if (Lang.hasOwnProperty(data, i)) {
812
 
                            if (data[i].type == 'separator') {
813
 
                                this.addSeparator();
814
 
                            } else if (data[i].group !== undefined) {
815
 
                                this.addButtonGroup(data[i]);
816
 
                            } else {
817
 
                                this.addButton(data[i]);
818
 
                            }
819
 
                        }
820
 
                    }
821
 
                }
822
 
            });
823
 
 
824
 
            /**
825
 
            * @attribute disabled
826
 
            * @description Boolean indicating if the toolbar should be disabled. It will also disable the draggable attribute if it is on.
827
 
            * @default false
828
 
            * @type Boolean
829
 
            */
830
 
            this.setAttributeConfig('disabled', {
831
 
                value: false,
832
 
                method: function(disabled) {
833
 
                    if (this.get('disabled') === disabled) {
834
 
                        return false;
835
 
                    }
836
 
                    if (disabled) {
837
 
                        this.addClass(this.CLASS_DISABLED);
838
 
                        this.set('draggable', false);
839
 
                        this.disableAllButtons();
840
 
                    } else {
841
 
                        this.removeClass(this.CLASS_DISABLED);
842
 
                        if (this._configs.draggable._initialConfig.value) {
843
 
                            //Draggable by default, set it back
844
 
                            this.set('draggable', true);
845
 
                        }
846
 
                        this.resetAllButtons();
847
 
                    }
848
 
                }
849
 
            });
850
 
 
851
 
            /**
852
 
            * @config cont
853
 
            * @description The container for the toolbar.
854
 
            * @type HTMLElement
855
 
            */
856
 
            this.setAttributeConfig('cont', {
857
 
                value: attr.cont,
858
 
                readOnly: true
859
 
            });
860
 
 
861
 
 
862
 
            /**
863
 
            * @attribute grouplabels
864
 
            * @description Boolean indicating if the toolbar should show the group label's text string.
865
 
            * @default true
866
 
            * @type Boolean
867
 
            */
868
 
            this.setAttributeConfig('grouplabels', {
869
 
                value: ((attr.grouplabels === false) ? false : true),
870
 
                method: function(grouplabels) {
871
 
                    if (grouplabels) {
872
 
                        Dom.removeClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
873
 
                    } else {
874
 
                        Dom.addClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
875
 
                    }
876
 
                }
877
 
            });
878
 
            /**
879
 
            * @attribute titlebar
880
 
            * @description Boolean indicating if the toolbar should have a titlebar. If
881
 
            * passed a string, it will use that as the titlebar text
882
 
            * @default false
883
 
            * @type Boolean or String
884
 
            */
885
 
            this.setAttributeConfig('titlebar', {
886
 
                value: false,
887
 
                method: function(titlebar) {
888
 
                    if (titlebar) {
889
 
                        if (this._titlebar && this._titlebar.parentNode) {
890
 
                            this._titlebar.parentNode.removeChild(this._titlebar);
891
 
                        }
892
 
                        this._titlebar = document.createElement('DIV');
893
 
                        this._titlebar.tabIndex = '-1';
894
 
                        Event.on(this._titlebar, 'focus', function() {
895
 
                            this._handleFocus();
896
 
                        }, this, true);
897
 
                        Dom.addClass(this._titlebar, this.CLASS_PREFIX + '-titlebar');
898
 
                        if (Lang.isString(titlebar)) {
899
 
                            var h2 = document.createElement('h2');
900
 
                            h2.tabIndex = '-1';
901
 
                            h2.innerHTML = '<a href="#" tabIndex="0">' + titlebar + '</a>';
902
 
                            this._titlebar.appendChild(h2);
903
 
                            Event.on(h2.firstChild, 'click', function(ev) {
904
 
                                Event.stopEvent(ev);
905
 
                            });
906
 
                            Event.on([h2, h2.firstChild], 'focus', function() {
907
 
                                this._handleFocus();
908
 
                            }, this, true);
909
 
                        }
910
 
                        if (this.get('firstChild')) {
911
 
                            this.insertBefore(this._titlebar, this.get('firstChild'));
912
 
                        } else {
913
 
                            this.appendChild(this._titlebar);
914
 
                        }
915
 
                        if (this.get('collapse')) {
916
 
                            this.set('collapse', true);
917
 
                        }
918
 
                    } else if (this._titlebar) {
919
 
                        if (this._titlebar && this._titlebar.parentNode) {
920
 
                            this._titlebar.parentNode.removeChild(this._titlebar);
921
 
                        }
922
 
                    }
923
 
                }
924
 
            });
925
 
 
926
 
 
927
 
            /**
928
 
            * @attribute collapse
929
 
            * @description Boolean indicating if the the titlebar should have a collapse button.
930
 
            * The collapse button will not remove the toolbar, it will minimize it to the titlebar
931
 
            * @default false
932
 
            * @type Boolean
933
 
            */
934
 
            this.setAttributeConfig('collapse', {
935
 
                value: false,
936
 
                method: function(collapse) {
937
 
                    if (this._titlebar) {
938
 
                        var collapseEl = null;
939
 
                        var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
940
 
                        if (collapse) {
941
 
                            if (el.length > 0) {
942
 
                                //There is already a collapse button
943
 
                                return true;
944
 
                            }
945
 
                            collapseEl = document.createElement('SPAN');
946
 
                            collapseEl.innerHTML = 'X';
947
 
                            collapseEl.title = this.STR_COLLAPSE;
948
 
 
949
 
                            Dom.addClass(collapseEl, 'collapse');
950
 
                            this._titlebar.appendChild(collapseEl);
951
 
                            Event.addListener(collapseEl, 'click', function() {
952
 
                                if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
953
 
                                    this.collapse(false); //Expand Toolbar
954
 
                                } else {
955
 
                                    this.collapse(); //Collapse Toolbar
956
 
                                }
957
 
                            }, this, true);
958
 
                        } else {
959
 
                            collapseEl = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
960
 
                            if (collapseEl[0]) {
961
 
                                if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
962
 
                                    //We are closed, reopen the titlebar..
963
 
                                    this.collapse(false); //Expand Toolbar
964
 
                                }
965
 
                                collapseEl[0].parentNode.removeChild(collapseEl[0]);
966
 
                            }
967
 
                        }
968
 
                    }
969
 
                }
970
 
            });
971
 
 
972
 
            /**
973
 
            * @attribute draggable
974
 
            * @description Boolean indicating if the toolbar should be draggable.  
975
 
            * @default false
976
 
            * @type Boolean
977
 
            */
978
 
 
979
 
            this.setAttributeConfig('draggable', {
980
 
                value: (attr.draggable || false),
981
 
                method: function(draggable) {
982
 
                    if (draggable && !this.get('titlebar')) {
983
 
                        YAHOO.log('Dragging enabled', 'info', 'Toolbar');
984
 
                        if (!this._dragHandle) {
985
 
                            this._dragHandle = document.createElement('SPAN');
986
 
                            this._dragHandle.innerHTML = '|';
987
 
                            this._dragHandle.setAttribute('title', 'Click to drag the toolbar');
988
 
                            this._dragHandle.id = this.get('id') + '_draghandle';
989
 
                            Dom.addClass(this._dragHandle, this.CLASS_DRAGHANDLE);
990
 
                            if (this.get('cont').hasChildNodes()) {
991
 
                                this.get('cont').insertBefore(this._dragHandle, this.get('cont').firstChild);
992
 
                            } else {
993
 
                                this.get('cont').appendChild(this._dragHandle);
994
 
                            }
995
 
                            this.dd = new YAHOO.util.DD(this.get('id'));
996
 
                            this.dd.setHandleElId(this._dragHandle.id);
997
 
                            
998
 
                        }
999
 
                    } else {
1000
 
                        YAHOO.log('Dragging disabled', 'info', 'Toolbar');
1001
 
                        if (this._dragHandle) {
1002
 
                            this._dragHandle.parentNode.removeChild(this._dragHandle);
1003
 
                            this._dragHandle = null;
1004
 
                            this.dd = null;
1005
 
                        }
1006
 
                    }
1007
 
                    if (this._titlebar) {
1008
 
                        if (draggable) {
1009
 
                            this.dd = new YAHOO.util.DD(this.get('id'));
1010
 
                            this.dd.setHandleElId(this._titlebar);
1011
 
                            Dom.addClass(this._titlebar, 'draggable');
1012
 
                        } else {
1013
 
                            Dom.removeClass(this._titlebar, 'draggable');
1014
 
                            if (this.dd) {
1015
 
                                this.dd.unreg();
1016
 
                                this.dd = null;
1017
 
                            }
1018
 
                        }
1019
 
                    }
1020
 
                },
1021
 
                validator: function(value) {
1022
 
                    var ret = true;
1023
 
                    if (!YAHOO.util.DD) {
1024
 
                        ret = false;
1025
 
                    }
1026
 
                    return ret;
1027
 
                }
1028
 
            });
1029
 
 
1030
 
        },
1031
 
        /**
1032
 
        * @method addButtonGroup
1033
 
        * @description Add a new button group to the toolbar. (uses addButton)
1034
 
        * @param {Object} oGroup Object literal reference to the Groups Config (contains an array of button configs as well as the group label)
1035
 
        */
1036
 
        addButtonGroup: function(oGroup) {
1037
 
            if (!this.get('element')) {
1038
 
                this._queue[this._queue.length] = ['addButtonGroup', arguments];
1039
 
                return false;
1040
 
            }
1041
 
            
1042
 
            if (!this.hasClass(this.CLASS_PREFIX + '-grouped')) {
1043
 
                this.addClass(this.CLASS_PREFIX + '-grouped');
1044
 
            }
1045
 
            var div = document.createElement('DIV');
1046
 
            Dom.addClass(div, this.CLASS_PREFIX + '-group');
1047
 
            Dom.addClass(div, this.CLASS_PREFIX + '-group-' + oGroup.group);
1048
 
            if (oGroup.label) {
1049
 
                var label = document.createElement('h3');
1050
 
                label.innerHTML = oGroup.label;
1051
 
                div.appendChild(label);
1052
 
            }
1053
 
            if (!this.get('grouplabels')) {
1054
 
                Dom.addClass(this.get('cont'), this.CLASS_PREFIX, '-nogrouplabels');
1055
 
            }
1056
 
 
1057
 
            this.get('cont').appendChild(div);
1058
 
 
1059
 
            //For accessibility, let's put all of the group buttons in an Unordered List
1060
 
            var ul = document.createElement('ul');
1061
 
            div.appendChild(ul);
1062
 
 
1063
 
            if (!this._buttonGroupList) {
1064
 
                this._buttonGroupList = {};
1065
 
            }
1066
 
            
1067
 
            this._buttonGroupList[oGroup.group] = ul;
1068
 
 
1069
 
            for (var i = 0; i < oGroup.buttons.length; i++) {
1070
 
                var li = document.createElement('li');
1071
 
                li.className = this.CLASS_PREFIX + '-groupitem';
1072
 
                ul.appendChild(li);
1073
 
                if ((oGroup.buttons[i].type !== undefined) && oGroup.buttons[i].type == 'separator') {
1074
 
                    this.addSeparator(li);
1075
 
                } else {
1076
 
                    oGroup.buttons[i].container = li;
1077
 
                    this.addButton(oGroup.buttons[i]);
1078
 
                }
1079
 
            }
1080
 
        },
1081
 
        /**
1082
 
        * @method addButtonToGroup
1083
 
        * @description Add a new button to a toolbar group. Buttons supported:
1084
 
        *   push, split, menu, select, color, spin
1085
 
        * @param {Object} oButton Object literal reference to the Button's Config
1086
 
        * @param {String} group The Group identifier passed into the initial config
1087
 
        * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
1088
 
        */
1089
 
        addButtonToGroup: function(oButton, group, after) {
1090
 
            var groupCont = this._buttonGroupList[group];
1091
 
            var li = document.createElement('li');
1092
 
            li.className = this.CLASS_PREFIX + '-groupitem';
1093
 
            oButton.container = li;
1094
 
            this.addButton(oButton, after);
1095
 
            groupCont.appendChild(li);
1096
 
        },
1097
 
        /**
1098
 
        * @method addButton
1099
 
        * @description Add a new button to the toolbar. Buttons supported:
1100
 
        *   push, split, menu, select, color, spin
1101
 
        * @param {Object} oButton Object literal reference to the Button's Config
1102
 
        * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
1103
 
        */
1104
 
        addButton: function(oButton, after) {
1105
 
            if (!this.get('element')) {
1106
 
                this._queue[this._queue.length] = ['addButton', arguments];
1107
 
                return false;
1108
 
            }
1109
 
            if (!this._buttonList) {
1110
 
                this._buttonList = [];
1111
 
            }
1112
 
            YAHOO.log('Adding button of type: ' + oButton.type, 'info', 'Toolbar');
1113
 
            if (!oButton.container) {
1114
 
                oButton.container = this.get('cont');
1115
 
            }
1116
 
 
1117
 
            if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
1118
 
                if (Lang.isArray(oButton.menu)) {
1119
 
                    for (var i in oButton.menu) {
1120
 
                        if (Lang.hasOwnProperty(oButton.menu, i)) {
1121
 
                            var funcObject = {
1122
 
                                fn: function(ev, x, oMenu) {
1123
 
                                    if (!oButton.menucmd) {
1124
 
                                        oButton.menucmd = oButton.value;
1125
 
                                    }
1126
 
                                    oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
1127
 
                                },
1128
 
                                scope: this
1129
 
                            };
1130
 
                            oButton.menu[i].onclick = funcObject;
1131
 
                        }
1132
 
                    }
1133
 
                }
1134
 
            }
1135
 
            var _oButton = {}, skip = false;
1136
 
            for (var o in oButton) {
1137
 
                if (Lang.hasOwnProperty(oButton, o)) {
1138
 
                    if (!this._toolbarConfigs[o]) {
1139
 
                        _oButton[o] = oButton[o];
1140
 
                    }
1141
 
                }
1142
 
            }
1143
 
            if (oButton.type == 'select') {
1144
 
                _oButton.type = 'menu';
1145
 
            }
1146
 
            if (oButton.type == 'spin') {
1147
 
                _oButton.type = 'push';
1148
 
            }
1149
 
            if (_oButton.type == 'color') {
1150
 
                if (YAHOO.widget.Overlay) {
1151
 
                    _oButton = this._makeColorButton(_oButton);
1152
 
                } else {
1153
 
                    skip = true;
1154
 
                }
1155
 
            }
1156
 
            if (_oButton.menu) {
1157
 
                if ((YAHOO.widget.Overlay) && (oButton.menu instanceof YAHOO.widget.Overlay)) {
1158
 
                    oButton.menu.showEvent.subscribe(function() {
1159
 
                        this._button = _oButton;
1160
 
                    });
1161
 
                } else {
1162
 
                    for (var m = 0; m < _oButton.menu.length; m++) {
1163
 
                        if (!_oButton.menu[m].value) {
1164
 
                            _oButton.menu[m].value = _oButton.menu[m].text;
1165
 
                        }
1166
 
                    }
1167
 
                    if (this.browser.webkit) {
1168
 
                        _oButton.focusmenu = false;
1169
 
                    }
1170
 
                }
1171
 
            }
1172
 
            if (skip) {
1173
 
                oButton = false;
1174
 
            } else {
1175
 
                //Add to .get('buttons') manually
1176
 
                this._configs.buttons.value[this._configs.buttons.value.length] = oButton;
1177
 
                
1178
 
                var tmp = new this.buttonType(_oButton);
1179
 
                tmp.get('element').tabIndex = '-1';
1180
 
                tmp.get('element').setAttribute('role', 'button');
1181
 
                tmp._selected = true;
1182
 
                
1183
 
                if (this.get('disabled')) {
1184
 
                    //Toolbar is disabled, disable the new button too!
1185
 
                    tmp.set('disabled', true);
1186
 
                }
1187
 
                if (!oButton.id) {
1188
 
                    oButton.id = tmp.get('id');
1189
 
                }
1190
 
                YAHOO.log('Button created (' + oButton.type + ')', 'info', 'Toolbar');
1191
 
                
1192
 
                if (after) {
1193
 
                    var el = tmp.get('element');
1194
 
                    var nextSib = null;
1195
 
                    if (after.get) {
1196
 
                        nextSib = after.get('element').nextSibling;
1197
 
                    } else if (after.nextSibling) {
1198
 
                        nextSib = after.nextSibling;
1199
 
                    }
1200
 
                    if (nextSib) {
1201
 
                        nextSib.parentNode.insertBefore(el, nextSib);
1202
 
                    }
1203
 
                }
1204
 
                tmp.addClass(this.CLASS_PREFIX + '-' + tmp.get('value'));
1205
 
 
1206
 
                var icon = document.createElement('span');
1207
 
                icon.className = this.CLASS_PREFIX + '-icon';
1208
 
                tmp.get('element').insertBefore(icon, tmp.get('firstChild'));
1209
 
                if (tmp._button.tagName.toLowerCase() == 'button') {
1210
 
                    tmp.get('element').setAttribute('unselectable', 'on');
1211
 
                    //Replace the Button HTML Element with an a href if it exists
1212
 
                    var a = document.createElement('a');
1213
 
                    a.innerHTML = tmp._button.innerHTML;
1214
 
                    a.href = '#';
1215
 
                    a.tabIndex = '-1';
1216
 
                    Event.on(a, 'click', function(ev) {
1217
 
                        Event.stopEvent(ev);
1218
 
                    });
1219
 
                    tmp._button.parentNode.replaceChild(a, tmp._button);
1220
 
                    tmp._button = a;
1221
 
                }
1222
 
 
1223
 
                if (oButton.type == 'select') {
1224
 
                    if (tmp._button.tagName.toLowerCase() == 'select') {
1225
 
                        icon.parentNode.removeChild(icon);
1226
 
                        var iel = tmp._button;
1227
 
                        var parEl = tmp.get('element');
1228
 
                        parEl.parentNode.replaceChild(iel, parEl);
1229
 
                    } else {
1230
 
                        //Don't put a class on it if it's a real select element
1231
 
                        tmp.addClass(this.CLASS_PREFIX + '-select');
1232
 
                    }
1233
 
                }
1234
 
                if (oButton.type == 'spin') {
1235
 
                    if (!Lang.isArray(oButton.range)) {
1236
 
                        oButton.range = [ 10, 100 ];
1237
 
                    }
1238
 
                    this._makeSpinButton(tmp, oButton);
1239
 
                }
1240
 
                tmp.get('element').setAttribute('title', tmp.get('label'));
1241
 
                if (oButton.type != 'spin') {
1242
 
                    if ((YAHOO.widget.Overlay) && (_oButton.menu instanceof YAHOO.widget.Overlay)) {
1243
 
                        var showPicker = function(ev) {
1244
 
                            var exec = true;
1245
 
                            if (ev.keyCode && (ev.keyCode == 9)) {
1246
 
                                exec = false;
1247
 
                            }
1248
 
                            if (exec) {
1249
 
                                if (this._colorPicker) {
1250
 
                                    this._colorPicker._button = oButton.value;
1251
 
                                }
1252
 
                                var menuEL = tmp.getMenu().element;
1253
 
                                if (Dom.getStyle(menuEL, 'visibility') == 'hidden') {
1254
 
                                    tmp.getMenu().show();
1255
 
                                } else {
1256
 
                                    tmp.getMenu().hide();
1257
 
                                }
1258
 
                            }
1259
 
                            YAHOO.util.Event.stopEvent(ev);
1260
 
                        };
1261
 
                        tmp.on('mousedown', showPicker, oButton, this);
1262
 
                        tmp.on('keydown', showPicker, oButton, this);
1263
 
                        
1264
 
                    } else if ((oButton.type != 'menu') && (oButton.type != 'select')) {
1265
 
                        tmp.on('keypress', this._buttonClick, oButton, this);
1266
 
                        tmp.on('mousedown', function(ev) {
1267
 
                            YAHOO.util.Event.stopEvent(ev);
1268
 
                            this._buttonClick(ev, oButton);
1269
 
                        }, oButton, this);
1270
 
                        tmp.on('click', function(ev) {
1271
 
                            YAHOO.util.Event.stopEvent(ev);
1272
 
                        });
1273
 
                    } else {
1274
 
                        //Stop the mousedown event so we can trap the selection in the editor!
1275
 
                        tmp.on('mousedown', function(ev) {
1276
 
                            YAHOO.util.Event.stopEvent(ev);
1277
 
                        });
1278
 
                        tmp.on('click', function(ev) {
1279
 
                            YAHOO.util.Event.stopEvent(ev);
1280
 
                        });
1281
 
                        tmp.on('change', function(ev) {
1282
 
                            if (!oButton.menucmd) {
1283
 
                                oButton.menucmd = oButton.value;
1284
 
                            }
1285
 
                            oButton.value = ev.value;
1286
 
                            this._buttonClick(ev, oButton);
1287
 
                        }, this, true);
1288
 
 
1289
 
                        var self = this;
1290
 
                        //Hijack the mousedown event in the menu and make it fire a button click..
1291
 
                        tmp.on('appendTo', function() {
1292
 
                            var tmp = this;
1293
 
                            if (tmp.getMenu() && tmp.getMenu().mouseDownEvent) {
1294
 
                                tmp.getMenu().mouseDownEvent.subscribe(function(ev, args) {
1295
 
                                    YAHOO.log('mouseDownEvent', 'warn', 'Toolbar');
1296
 
                                    var oMenu = args[1];
1297
 
                                    YAHOO.util.Event.stopEvent(args[0]);
1298
 
                                    tmp._onMenuClick(args[0], tmp);
1299
 
                                    if (!oButton.menucmd) {
1300
 
                                        oButton.menucmd = oButton.value;
1301
 
                                    }
1302
 
                                    oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
1303
 
                                    self._buttonClick.call(self, args[1], oButton);
1304
 
                                    tmp._hideMenu();
1305
 
                                    return false;
1306
 
                                });
1307
 
                                tmp.getMenu().clickEvent.subscribe(function(ev, args) {
1308
 
                                    YAHOO.log('clickEvent', 'warn', 'Toolbar');
1309
 
                                    YAHOO.util.Event.stopEvent(args[0]);
1310
 
                                });
1311
 
                                tmp.getMenu().mouseUpEvent.subscribe(function(ev, args) {
1312
 
                                    YAHOO.log('mouseUpEvent', 'warn', 'Toolbar');
1313
 
                                    YAHOO.util.Event.stopEvent(args[0]);
1314
 
                                });
1315
 
                            }
1316
 
                        });
1317
 
                        
1318
 
                    }
1319
 
                } else {
1320
 
                    //Stop the mousedown event so we can trap the selection in the editor!
1321
 
                    tmp.on('mousedown', function(ev) {
1322
 
                        YAHOO.util.Event.stopEvent(ev);
1323
 
                    });
1324
 
                    tmp.on('click', function(ev) {
1325
 
                        YAHOO.util.Event.stopEvent(ev);
1326
 
                    });
1327
 
                }
1328
 
                if (this.browser.ie) {
1329
 
                    /*
1330
 
                    //Add a couple of new events for IE
1331
 
                    tmp.DOM_EVENTS.focusin = true;
1332
 
                    tmp.DOM_EVENTS.focusout = true;
1333
 
                    
1334
 
                    //Stop them so we don't loose focus in the Editor
1335
 
                    tmp.on('focusin', function(ev) {
1336
 
                        YAHOO.util.Event.stopEvent(ev);
1337
 
                    }, oButton, this);
1338
 
                    
1339
 
                    tmp.on('focusout', function(ev) {
1340
 
                        YAHOO.util.Event.stopEvent(ev);
1341
 
                    }, oButton, this);
1342
 
                    tmp.on('click', function(ev) {
1343
 
                        YAHOO.util.Event.stopEvent(ev);
1344
 
                    }, oButton, this);
1345
 
                    */
1346
 
                }
1347
 
                if (this.browser.webkit) {
1348
 
                    //This will keep the document from gaining focus and the editor from loosing it..
1349
 
                    //Forcefully remove the focus calls in button!
1350
 
                    tmp.hasFocus = function() {
1351
 
                        return true;
1352
 
                    };
1353
 
                }
1354
 
                this._buttonList[this._buttonList.length] = tmp;
1355
 
                if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
1356
 
                    if (Lang.isArray(oButton.menu)) {
1357
 
                        YAHOO.log('Button type is (' + oButton.type + '), doing extra renderer work.', 'info', 'Toolbar');
1358
 
                        var menu = tmp.getMenu();
1359
 
                        if (menu && menu.renderEvent) {
1360
 
                            menu.renderEvent.subscribe(this._addMenuClasses, tmp);
1361
 
                            if (oButton.renderer) {
1362
 
                                menu.renderEvent.subscribe(oButton.renderer, tmp);
1363
 
                            }
1364
 
                        }
1365
 
                    }
1366
 
                }
1367
 
            }
1368
 
            return oButton;
1369
 
        },
1370
 
        /**
1371
 
        * @method addSeparator
1372
 
        * @description Add a new button separator to the toolbar.
1373
 
        * @param {HTMLElement} cont Optional HTML element to insert this button into.
1374
 
        * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
1375
 
        */
1376
 
        addSeparator: function(cont, after) {
1377
 
            if (!this.get('element')) {
1378
 
                this._queue[this._queue.length] = ['addSeparator', arguments];
1379
 
                return false;
1380
 
            }
1381
 
            var sepCont = ((cont) ? cont : this.get('cont'));
1382
 
            if (!this.get('element')) {
1383
 
                this._queue[this._queue.length] = ['addSeparator', arguments];
1384
 
                return false;
1385
 
            }
1386
 
            if (this._sepCount === null) {
1387
 
                this._sepCount = 0;
1388
 
            }
1389
 
            if (!this._sep) {
1390
 
                YAHOO.log('Separator does not yet exist, creating', 'info', 'Toolbar');
1391
 
                this._sep = document.createElement('SPAN');
1392
 
                Dom.addClass(this._sep, this.CLASS_SEPARATOR);
1393
 
                this._sep.innerHTML = '|';
1394
 
            }
1395
 
            YAHOO.log('Separator does exist, cloning', 'info', 'Toolbar');
1396
 
            var _sep = this._sep.cloneNode(true);
1397
 
            this._sepCount++;
1398
 
            Dom.addClass(_sep, this.CLASS_SEPARATOR + '-' + this._sepCount);
1399
 
            if (after) {
1400
 
                var nextSib = null;
1401
 
                if (after.get) {
1402
 
                    nextSib = after.get('element').nextSibling;
1403
 
                } else if (after.nextSibling) {
1404
 
                    nextSib = after.nextSibling;
1405
 
                } else {
1406
 
                    nextSib = after;
1407
 
                }
1408
 
                if (nextSib) {
1409
 
                    if (nextSib == after) {
1410
 
                        nextSib.parentNode.appendChild(_sep);
1411
 
                    } else {
1412
 
                        nextSib.parentNode.insertBefore(_sep, nextSib);
1413
 
                    }
1414
 
                }
1415
 
            } else {
1416
 
                sepCont.appendChild(_sep);
1417
 
            }
1418
 
            return _sep;
1419
 
        },
1420
 
        /**
1421
 
        * @method _createColorPicker
1422
 
        * @private
1423
 
        * @description Creates the core DOM reference to the color picker menu item.
1424
 
        * @param {String} id the id of the toolbar to prefix this DOM container with.
1425
 
        */
1426
 
        _createColorPicker: function(id) {
1427
 
            if (Dom.get(id + '_colors')) {
1428
 
               Dom.get(id + '_colors').parentNode.removeChild(Dom.get(id + '_colors'));
1429
 
            }
1430
 
            var picker = document.createElement('div');
1431
 
            picker.className = 'yui-toolbar-colors';
1432
 
            picker.id = id + '_colors';
1433
 
            picker.style.display = 'none';
1434
 
            Event.on(window, 'load', function() {
1435
 
                document.body.appendChild(picker);
1436
 
            }, this, true);
1437
 
 
1438
 
            this._colorPicker = picker;
1439
 
 
1440
 
            var html = '';
1441
 
            for (var i in this._colorData) {
1442
 
                if (Lang.hasOwnProperty(this._colorData, i)) {
1443
 
                    html += '<a style="background-color: ' + i + '" href="#">' + i.replace('#', '') + '</a>';
1444
 
                }
1445
 
            }
1446
 
            html += '<span><em>X</em><strong></strong></span>';
1447
 
            window.setTimeout(function() {
1448
 
                picker.innerHTML = html;
1449
 
            }, 0);
1450
 
 
1451
 
            Event.on(picker, 'mouseover', function(ev) {
1452
 
                var picker = this._colorPicker;
1453
 
                var em = picker.getElementsByTagName('em')[0];
1454
 
                var strong = picker.getElementsByTagName('strong')[0];
1455
 
                var tar = Event.getTarget(ev);
1456
 
                if (tar.tagName.toLowerCase() == 'a') {
1457
 
                    em.style.backgroundColor = tar.style.backgroundColor;
1458
 
                    strong.innerHTML = this._colorData['#' + tar.innerHTML] + '<br>' + tar.innerHTML;
1459
 
                }
1460
 
            }, this, true);
1461
 
            Event.on(picker, 'focus', function(ev) {
1462
 
                Event.stopEvent(ev);
1463
 
            });
1464
 
            Event.on(picker, 'click', function(ev) {
1465
 
                Event.stopEvent(ev);
1466
 
            });
1467
 
            Event.on(picker, 'mousedown', function(ev) {
1468
 
                Event.stopEvent(ev);
1469
 
                var tar = Event.getTarget(ev);
1470
 
                if (tar.tagName.toLowerCase() == 'a') {
1471
 
                    var retVal = this.fireEvent('colorPickerClicked', { type: 'colorPickerClicked', target: this, button: this._colorPicker._button, color: tar.innerHTML, colorName: this._colorData['#' + tar.innerHTML] } );
1472
 
                    if (retVal !== false) {
1473
 
                        var info = {
1474
 
                            color: tar.innerHTML,
1475
 
                            colorName: this._colorData['#' + tar.innerHTML],
1476
 
                            value: this._colorPicker._button 
1477
 
                        };
1478
 
                    
1479
 
                        this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
1480
 
                    }
1481
 
                    this.getButtonByValue(this._colorPicker._button).getMenu().hide();
1482
 
                }
1483
 
            }, this, true);
1484
 
        },
1485
 
        /**
1486
 
        * @method _resetColorPicker
1487
 
        * @private
1488
 
        * @description Clears the currently selected color or mouseover color in the color picker.
1489
 
        */
1490
 
        _resetColorPicker: function() {
1491
 
            var em = this._colorPicker.getElementsByTagName('em')[0];
1492
 
            var strong = this._colorPicker.getElementsByTagName('strong')[0];
1493
 
            em.style.backgroundColor = 'transparent';
1494
 
            strong.innerHTML = '';
1495
 
        },
1496
 
        /**
1497
 
        * @method _makeColorButton
1498
 
        * @private
1499
 
        * @description Called to turn a "color" button into a menu button with an Overlay for the menu.
1500
 
        * @param {Object} _oButton <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
1501
 
        */
1502
 
        _makeColorButton: function(_oButton) {
1503
 
            if (!this._colorPicker) {   
1504
 
                this._createColorPicker(this.get('id'));
1505
 
            }
1506
 
            _oButton.type = 'color';
1507
 
            _oButton.menu = new YAHOO.widget.Overlay(this.get('id') + '_' + _oButton.value + '_menu', { visible: false, position: 'absolute', iframe: true });
1508
 
            _oButton.menu.setBody('');
1509
 
            _oButton.menu.render(this.get('cont'));
1510
 
            Dom.addClass(_oButton.menu.element, 'yui-button-menu');
1511
 
            Dom.addClass(_oButton.menu.element, 'yui-color-button-menu');
1512
 
            _oButton.menu.beforeShowEvent.subscribe(function() {
1513
 
                _oButton.menu.cfg.setProperty('zindex', 5); //Re Adjust the overlays zIndex.. not sure why.
1514
 
                _oButton.menu.cfg.setProperty('context', [this.getButtonById(_oButton.id).get('element'), 'tl', 'bl']); //Re Adjust the overlay.. not sure why.
1515
 
                //Move the DOM reference of the color picker to the Overlay that we are about to show.
1516
 
                this._resetColorPicker();
1517
 
                var _p = this._colorPicker;
1518
 
                if (_p.parentNode) {
1519
 
                    _p.parentNode.removeChild(_p);
1520
 
                }
1521
 
                _oButton.menu.setBody('');
1522
 
                _oButton.menu.appendToBody(_p);
1523
 
                this._colorPicker.style.display = 'block';
1524
 
            }, this, true);
1525
 
            return _oButton;
1526
 
        },
1527
 
        /**
1528
 
        * @private
1529
 
        * @method _makeSpinButton
1530
 
        * @description Create a button similar to an OS Spin button.. It has an up/down arrow combo to scroll through a range of int values.
1531
 
        * @param {Object} _button <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
1532
 
        * @param {Object} oButton Object literal containing the buttons initial config
1533
 
        */
1534
 
        _makeSpinButton: function(_button, oButton) {
1535
 
            _button.addClass(this.CLASS_PREFIX + '-spinbutton');
1536
 
            var self = this,
1537
 
                _par = _button._button.parentNode.parentNode, //parentNode of Button Element for appending child
1538
 
                range = oButton.range,
1539
 
                _b1 = document.createElement('a'),
1540
 
                _b2 = document.createElement('a');
1541
 
                _b1.href = '#';
1542
 
                _b2.href = '#';
1543
 
                _b1.tabIndex = '-1';
1544
 
                _b2.tabIndex = '-1';
1545
 
            
1546
 
            //Setup the up and down arrows
1547
 
            _b1.className = 'up';
1548
 
            _b1.title = this.STR_SPIN_UP;
1549
 
            _b1.innerHTML = this.STR_SPIN_UP;
1550
 
            _b2.className = 'down';
1551
 
            _b2.title = this.STR_SPIN_DOWN;
1552
 
            _b2.innerHTML = this.STR_SPIN_DOWN;
1553
 
 
1554
 
            //Append them to the container
1555
 
            _par.appendChild(_b1);
1556
 
            _par.appendChild(_b2);
1557
 
            
1558
 
            var label = YAHOO.lang.substitute(this.STR_SPIN_LABEL, { VALUE: _button.get('label') });
1559
 
            _button.set('title', label);
1560
 
 
1561
 
            var cleanVal = function(value) {
1562
 
                value = ((value < range[0]) ? range[0] : value);
1563
 
                value = ((value > range[1]) ? range[1] : value);
1564
 
                return value;
1565
 
            };
1566
 
 
1567
 
            var br = this.browser;
1568
 
            var tbar = false;
1569
 
            var strLabel = this.STR_SPIN_LABEL;
1570
 
            if (this._titlebar && this._titlebar.firstChild) {
1571
 
                tbar = this._titlebar.firstChild;
1572
 
            }
1573
 
            
1574
 
            var _intUp = function(ev) {
1575
 
                YAHOO.util.Event.stopEvent(ev);
1576
 
                if (!_button.get('disabled') && (ev.keyCode != 9)) {
1577
 
                    var value = parseInt(_button.get('label'), 10);
1578
 
                    value++;
1579
 
                    value = cleanVal(value);
1580
 
                    _button.set('label', ''+value);
1581
 
                    var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
1582
 
                    _button.set('title', label);
1583
 
                    if (!br.webkit && tbar) {
1584
 
                        //tbar.focus(); //We do this for accessibility, on the re-focus of the element, a screen reader will re-read the title that was just changed
1585
 
                        //_button.focus();
1586
 
                    }
1587
 
                    self._buttonClick(ev, oButton);
1588
 
                }
1589
 
            };
1590
 
 
1591
 
            var _intDown = function(ev) {
1592
 
                YAHOO.util.Event.stopEvent(ev);
1593
 
                if (!_button.get('disabled') && (ev.keyCode != 9)) {
1594
 
                    var value = parseInt(_button.get('label'), 10);
1595
 
                    value--;
1596
 
                    value = cleanVal(value);
1597
 
 
1598
 
                    _button.set('label', ''+value);
1599
 
                    var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
1600
 
                    _button.set('title', label);
1601
 
                    if (!br.webkit && tbar) {
1602
 
                        //tbar.focus(); //We do this for accessibility, on the re-focus of the element, a screen reader will re-read the title that was just changed
1603
 
                        //_button.focus();
1604
 
                    }
1605
 
                    self._buttonClick(ev, oButton);
1606
 
                }
1607
 
            };
1608
 
 
1609
 
            var _intKeyUp = function(ev) {
1610
 
                if (ev.keyCode == 38) {
1611
 
                    _intUp(ev);
1612
 
                } else if (ev.keyCode == 40) {
1613
 
                    _intDown(ev);
1614
 
                } else if (ev.keyCode == 107 && ev.shiftKey) {  //Plus Key
1615
 
                    _intUp(ev);
1616
 
                } else if (ev.keyCode == 109 && ev.shiftKey) {  //Minus Key
1617
 
                    _intDown(ev);
1618
 
                }
1619
 
            };
1620
 
 
1621
 
            //Handle arrow keys..
1622
 
            _button.on('keydown', _intKeyUp, this, true);
1623
 
 
1624
 
            //Listen for the click on the up button and act on it
1625
 
            //Listen for the click on the down button and act on it
1626
 
            Event.on(_b1, 'mousedown',function(ev) {
1627
 
                Event.stopEvent(ev);
1628
 
            }, this, true);
1629
 
            Event.on(_b2, 'mousedown', function(ev) {
1630
 
                Event.stopEvent(ev);
1631
 
            }, this, true);
1632
 
            Event.on(_b1, 'click', _intUp, this, true);
1633
 
            Event.on(_b2, 'click', _intDown, this, true);
1634
 
        },
1635
 
        /**
1636
 
        * @protected
1637
 
        * @method _buttonClick
1638
 
        * @description Click handler for all buttons in the toolbar.
1639
 
        * @param {String} ev The event that was passed in.
1640
 
        * @param {Object} info Object literal of information about the button that was clicked.
1641
 
        */
1642
 
        _buttonClick: function(ev, info) {
1643
 
            var doEvent = true;
1644
 
            
1645
 
            if (ev && ev.type == 'keypress') {
1646
 
                if (ev.keyCode == 9) {
1647
 
                    doEvent = false;
1648
 
                } else if ((ev.keyCode === 13) || (ev.keyCode === 0) || (ev.keyCode === 32)) {
1649
 
                } else {
1650
 
                    doEvent = false;
1651
 
                }
1652
 
            }
1653
 
 
1654
 
            if (doEvent) {
1655
 
                var fireNextEvent = true,
1656
 
                    retValue = false;
1657
 
                    
1658
 
                info.isSelected = this.isSelected(info.id);
1659
 
 
1660
 
                if (info.value) {
1661
 
                    YAHOO.log('fireEvent::' + info.value + 'Click', 'info', 'Toolbar');
1662
 
                    retValue = this.fireEvent(info.value + 'Click', { type: info.value + 'Click', target: this.get('element'), button: info });
1663
 
                    if (retValue === false) {
1664
 
                        fireNextEvent = false;
1665
 
                    }
1666
 
                }
1667
 
                
1668
 
                if (info.menucmd && fireNextEvent) {
1669
 
                    YAHOO.log('fireEvent::' + info.menucmd + 'Click', 'info', 'Toolbar');
1670
 
                    retValue = this.fireEvent(info.menucmd + 'Click', { type: info.menucmd + 'Click', target: this.get('element'), button: info });
1671
 
                    if (retValue === false) {
1672
 
                        fireNextEvent = false;
1673
 
                    }
1674
 
                }
1675
 
                if (fireNextEvent) {
1676
 
                    YAHOO.log('fireEvent::buttonClick', 'info', 'Toolbar');
1677
 
                    this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
1678
 
                }
1679
 
 
1680
 
                if (info.type == 'select') {
1681
 
                    var button = this.getButtonById(info.id);
1682
 
                    if (button.buttonType == 'rich') {
1683
 
                        var txt = info.value;
1684
 
                        for (var i = 0; i < info.menu.length; i++) {
1685
 
                            if (info.menu[i].value == info.value) {
1686
 
                                txt = info.menu[i].text;
1687
 
                                break;
1688
 
                            }
1689
 
                        }
1690
 
                        button.set('label', '<span class="yui-toolbar-' + info.menucmd + '-' + (info.value).replace(/ /g, '-').toLowerCase() + '">' + txt + '</span>');
1691
 
                        var _items = button.getMenu().getItems();
1692
 
                        for (var m = 0; m < _items.length; m++) {
1693
 
                            if (_items[m].value.toLowerCase() == info.value.toLowerCase()) {
1694
 
                                _items[m].cfg.setProperty('checked', true);
1695
 
                            } else {
1696
 
                                _items[m].cfg.setProperty('checked', false);
1697
 
                            }
1698
 
                        }
1699
 
                    }
1700
 
                }
1701
 
                if (ev) {
1702
 
                    Event.stopEvent(ev);
1703
 
                }
1704
 
            }
1705
 
        },
1706
 
        /**
1707
 
        * @private
1708
 
        * @property _keyNav
1709
 
        * @description Flag to determine if the arrow nav listeners have been attached
1710
 
        * @type Boolean
1711
 
        */
1712
 
        _keyNav: null,
1713
 
        /**
1714
 
        * @private
1715
 
        * @property _navCounter
1716
 
        * @description Internal counter for walking the buttons in the toolbar with the arrow keys
1717
 
        * @type Number
1718
 
        */
1719
 
        _navCounter: null,
1720
 
        /**
1721
 
        * @private
1722
 
        * @method _navigateButtons
1723
 
        * @description Handles the navigation/focus of toolbar buttons with the Arrow Keys
1724
 
        * @param {Event} ev The Key Event
1725
 
        */
1726
 
        _navigateButtons: function(ev) {
1727
 
            switch (ev.keyCode) {
1728
 
                case 37:
1729
 
                case 39:
1730
 
                    if (ev.keyCode == 37) {
1731
 
                        this._navCounter--;
1732
 
                    } else {
1733
 
                        this._navCounter++;
1734
 
                    }
1735
 
                    if (this._navCounter > (this._buttonList.length - 1)) {
1736
 
                        this._navCounter = 0;
1737
 
                    }
1738
 
                    if (this._navCounter < 0) {
1739
 
                        this._navCounter = (this._buttonList.length - 1);
1740
 
                    }
1741
 
                    if (this._buttonList[this._navCounter]) {
1742
 
                        var el = this._buttonList[this._navCounter].get('element');
1743
 
                        if (this.browser.ie) {
1744
 
                            el = this._buttonList[this._navCounter].get('element').getElementsByTagName('a')[0];
1745
 
                        }
1746
 
                        if (this._buttonList[this._navCounter].get('disabled')) {
1747
 
                            this._navigateButtons(ev);
1748
 
                        } else {
1749
 
                            el.focus();
1750
 
                        }
1751
 
                    }
1752
 
                    break;
1753
 
            }
1754
 
        },
1755
 
        /**
1756
 
        * @private
1757
 
        * @method _handleFocus
1758
 
        * @description Sets up the listeners for the arrow key navigation
1759
 
        */
1760
 
        _handleFocus: function() {
1761
 
            if (!this._keyNav) {
1762
 
                var ev = 'keypress';
1763
 
                if (this.browser.ie) {
1764
 
                    ev = 'keydown';
1765
 
                }
1766
 
                Event.on(this.get('element'), ev, this._navigateButtons, this, true);
1767
 
                this._keyNav = true;
1768
 
                this._navCounter = -1;
1769
 
            }
1770
 
        },
1771
 
        /**
1772
 
        * @method getButtonById
1773
 
        * @description Gets a button instance from the toolbar by is Dom id.
1774
 
        * @param {String} id The Dom id to query for.
1775
 
        * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
1776
 
        */
1777
 
        getButtonById: function(id) {
1778
 
            var len = this._buttonList.length;
1779
 
            for (var i = 0; i < len; i++) {
1780
 
                if (this._buttonList[i] && this._buttonList[i].get('id') == id) {
1781
 
                    return this._buttonList[i];
1782
 
                }
1783
 
            }
1784
 
            return false;
1785
 
        },
1786
 
        /**
1787
 
        * @method getButtonByValue
1788
 
        * @description Gets a button instance or a menuitem instance from the toolbar by it's value.
1789
 
        * @param {String} value The button value to query for.
1790
 
        * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> or <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>}
1791
 
        */
1792
 
        getButtonByValue: function(value) {
1793
 
            var _buttons = this.get('buttons');
1794
 
            var len = _buttons.length;
1795
 
            for (var i = 0; i < len; i++) {
1796
 
                if (_buttons[i].group !== undefined) {
1797
 
                    for (var m = 0; m < _buttons[i].buttons.length; m++) {
1798
 
                        if ((_buttons[i].buttons[m].value == value) || (_buttons[i].buttons[m].menucmd == value)) {
1799
 
                            return this.getButtonById(_buttons[i].buttons[m].id);
1800
 
                        }
1801
 
                        if (_buttons[i].buttons[m].menu) { //Menu Button, loop through the values
1802
 
                            for (var s = 0; s < _buttons[i].buttons[m].menu.length; s++) {
1803
 
                                if (_buttons[i].buttons[m].menu[s].value == value) {
1804
 
                                    return this.getButtonById(_buttons[i].buttons[m].id);
1805
 
                                }
1806
 
                            }
1807
 
                        }
1808
 
                    }
1809
 
                } else {
1810
 
                    if ((_buttons[i].value == value) || (_buttons[i].menucmd == value)) {
1811
 
                        return this.getButtonById(_buttons[i].id);
1812
 
                    }
1813
 
                    if (_buttons[i].menu) { //Menu Button, loop through the values
1814
 
                        for (var j = 0; j < _buttons[i].menu.length; j++) {
1815
 
                            if (_buttons[i].menu[j].value == value) {
1816
 
                                return this.getButtonById(_buttons[i].id);
1817
 
                            }
1818
 
                        }
1819
 
                    }
1820
 
                }
1821
 
            }
1822
 
            return false;
1823
 
        },
1824
 
        /**
1825
 
        * @method getButtonByIndex
1826
 
        * @description Gets a button instance from the toolbar by is index in _buttonList.
1827
 
        * @param {Number} index The index of the button in _buttonList.
1828
 
        * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
1829
 
        */
1830
 
        getButtonByIndex: function(index) {
1831
 
            if (this._buttonList[index]) {
1832
 
                return this._buttonList[index];
1833
 
            } else {
1834
 
                return false;
1835
 
            }
1836
 
        },
1837
 
        /**
1838
 
        * @method getButtons
1839
 
        * @description Returns an array of buttons in the current toolbar
1840
 
        * @return {Array}
1841
 
        */
1842
 
        getButtons: function() {
1843
 
            return this._buttonList;
1844
 
        },
1845
 
        /**
1846
 
        * @method disableButton
1847
 
        * @description Disables a button in the toolbar.
1848
 
        * @param {String/Number} id Disable a button by it's id, index or value.
1849
 
        * @return {Boolean}
1850
 
        */
1851
 
        disableButton: function(id) {
1852
 
            var button = getButton.call(this, id);
1853
 
            if (button) {
1854
 
                button.set('disabled', true);
1855
 
            } else {
1856
 
                return false;
1857
 
            }
1858
 
        },
1859
 
        /**
1860
 
        * @method enableButton
1861
 
        * @description Enables a button in the toolbar.
1862
 
        * @param {String/Number} id Enable a button by it's id, index or value.
1863
 
        * @return {Boolean}
1864
 
        */
1865
 
        enableButton: function(id) {
1866
 
            if (this.get('disabled')) {
1867
 
                return false;
1868
 
            }
1869
 
            var button = getButton.call(this, id);
1870
 
            if (button) {
1871
 
                if (button.get('disabled')) {
1872
 
                    button.set('disabled', false);
1873
 
                }
1874
 
            } else {
1875
 
                return false;
1876
 
            }
1877
 
        },
1878
 
        /**
1879
 
        * @method isSelected
1880
 
        * @description Tells if a button is selected or not.
1881
 
        * @param {String/Number} id A button by it's id, index or value.
1882
 
        * @return {Boolean}
1883
 
        */
1884
 
        isSelected: function(id) {
1885
 
            var button = getButton.call(this, id);
1886
 
            if (button) {
1887
 
                return button._selected;
1888
 
            }
1889
 
            return false;
1890
 
        },
1891
 
        /**
1892
 
        * @method selectButton
1893
 
        * @description Selects a button in the toolbar.
1894
 
        * @param {String/Number} id Select a button by it's id, index or value.
1895
 
        * @param {String} value If this is a Menu Button, check this item in the menu
1896
 
        * @return {Boolean}
1897
 
        */
1898
 
        selectButton: function(id, value) {
1899
 
            var button = getButton.call(this, id);
1900
 
            if (button) {
1901
 
                button.addClass('yui-button-selected');
1902
 
                button.addClass('yui-button-' + button.get('value') + '-selected');
1903
 
                button._selected = true;
1904
 
                if (value) {
1905
 
                    if (button.buttonType == 'rich') {
1906
 
                        var _items = button.getMenu().getItems();
1907
 
                        for (var m = 0; m < _items.length; m++) {
1908
 
                            if (_items[m].value == value) {
1909
 
                                _items[m].cfg.setProperty('checked', true);
1910
 
                                button.set('label', '<span class="yui-toolbar-' + button.get('value') + '-' + (value).replace(/ /g, '-').toLowerCase() + '">' + _items[m]._oText.nodeValue + '</span>');
1911
 
                            } else {
1912
 
                                _items[m].cfg.setProperty('checked', false);
1913
 
                            }
1914
 
                        }
1915
 
                    }
1916
 
                }
1917
 
            } else {
1918
 
                return false;
1919
 
            }
1920
 
        },
1921
 
        /**
1922
 
        * @method deselectButton
1923
 
        * @description Deselects a button in the toolbar.
1924
 
        * @param {String/Number} id Deselect a button by it's id, index or value.
1925
 
        * @return {Boolean}
1926
 
        */
1927
 
        deselectButton: function(id) {
1928
 
            var button = getButton.call(this, id);
1929
 
            if (button) {
1930
 
                button.removeClass('yui-button-selected');
1931
 
                button.removeClass('yui-button-' + button.get('value') + '-selected');
1932
 
                button.removeClass('yui-button-hover');
1933
 
                button._selected = false;
1934
 
            } else {
1935
 
                return false;
1936
 
            }
1937
 
        },
1938
 
        /**
1939
 
        * @method deselectAllButtons
1940
 
        * @description Deselects all buttons in the toolbar.
1941
 
        * @return {Boolean}
1942
 
        */
1943
 
        deselectAllButtons: function() {
1944
 
            var len = this._buttonList.length;
1945
 
            for (var i = 0; i < len; i++) {
1946
 
                this.deselectButton(this._buttonList[i]);
1947
 
            }
1948
 
        },
1949
 
        /**
1950
 
        * @method disableAllButtons
1951
 
        * @description Disables all buttons in the toolbar.
1952
 
        * @return {Boolean}
1953
 
        */
1954
 
        disableAllButtons: function() {
1955
 
            if (this.get('disabled')) {
1956
 
                return false;
1957
 
            }
1958
 
            var len = this._buttonList.length;
1959
 
            for (var i = 0; i < len; i++) {
1960
 
                this.disableButton(this._buttonList[i]);
1961
 
            }
1962
 
        },
1963
 
        /**
1964
 
        * @method enableAllButtons
1965
 
        * @description Enables all buttons in the toolbar.
1966
 
        * @return {Boolean}
1967
 
        */
1968
 
        enableAllButtons: function() {
1969
 
            if (this.get('disabled')) {
1970
 
                return false;
1971
 
            }
1972
 
            var len = this._buttonList.length;
1973
 
            for (var i = 0; i < len; i++) {
1974
 
                this.enableButton(this._buttonList[i]);
1975
 
            }
1976
 
        },
1977
 
        /**
1978
 
        * @method resetAllButtons
1979
 
        * @description Resets all buttons to their initial state.
1980
 
        * @param {Object} _ex Except these buttons
1981
 
        * @return {Boolean}
1982
 
        */
1983
 
        resetAllButtons: function(_ex) {
1984
 
            if (!Lang.isObject(_ex)) {
1985
 
                _ex = {};
1986
 
            }
1987
 
            if (this.get('disabled')) {
1988
 
                return false;
1989
 
            }
1990
 
            var len = this._buttonList.length;
1991
 
            for (var i = 0; i < len; i++) {
1992
 
                var _button = this._buttonList[i];
1993
 
                if (_button) {
1994
 
                    var disabled = _button._configs.disabled._initialConfig.value;
1995
 
                    if (_ex[_button.get('id')]) {
1996
 
                        this.enableButton(_button);
1997
 
                        this.selectButton(_button);
1998
 
                    } else {
1999
 
                        if (disabled) {
2000
 
                            this.disableButton(_button);
2001
 
                        } else {
2002
 
                            this.enableButton(_button);
2003
 
                        }
2004
 
                        this.deselectButton(_button);
2005
 
                    }
2006
 
                }
2007
 
            }
2008
 
        },
2009
 
        /**
2010
 
        * @method destroyButton
2011
 
        * @description Destroy a button in the toolbar.
2012
 
        * @param {String/Number} id Destroy a button by it's id or index.
2013
 
        * @return {Boolean}
2014
 
        */
2015
 
        destroyButton: function(id) {
2016
 
            var button = getButton.call(this, id);
2017
 
            if (button) {
2018
 
                var thisID = button.get('id');
2019
 
                button.destroy();
2020
 
 
2021
 
                var len = this._buttonList.length;
2022
 
                for (var i = 0; i < len; i++) {
2023
 
                    if (this._buttonList[i] && this._buttonList[i].get('id') == thisID) {
2024
 
                        this._buttonList[i] = null;
2025
 
                    }
2026
 
                }
2027
 
            } else {
2028
 
                return false;
2029
 
            }
2030
 
        },
2031
 
        /**
2032
 
        * @method destroy
2033
 
        * @description Destroys the toolbar, all of it's elements and objects.
2034
 
        * @return {Boolean}
2035
 
        */
2036
 
        destroy: function() {
2037
 
            this.get('element').innerHTML = '';
2038
 
            this.get('element').className = '';
2039
 
            //Brutal Object Destroy
2040
 
            for (var i in this) {
2041
 
                if (Lang.hasOwnProperty(this, i)) {
2042
 
                    this[i] = null;
2043
 
                }
2044
 
            }
2045
 
            return true;
2046
 
        },
2047
 
        /**
2048
 
        * @method collapse
2049
 
        * @description Programatically collapse the toolbar.
2050
 
        * @param {Boolean} collapse True to collapse, false to expand.
2051
 
        */
2052
 
        collapse: function(collapse) {
2053
 
            var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
2054
 
            if (collapse === false) {
2055
 
                Dom.removeClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
2056
 
                if (el[0]) {
2057
 
                    Dom.removeClass(el[0], 'collapsed');
2058
 
                }
2059
 
                this.fireEvent('toolbarExpanded', { type: 'toolbarExpanded', target: this });
2060
 
            } else {
2061
 
                if (el[0]) {
2062
 
                    Dom.addClass(el[0], 'collapsed');
2063
 
                }
2064
 
                Dom.addClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
2065
 
                this.fireEvent('toolbarCollapsed', { type: 'toolbarCollapsed', target: this });
2066
 
            }
2067
 
        },
2068
 
        /**
2069
 
        * @method toString
2070
 
        * @description Returns a string representing the toolbar.
2071
 
        * @return {String}
2072
 
        */
2073
 
        toString: function() {
2074
 
            return 'Toolbar (#' + this.get('element').id + ') with ' + this._buttonList.length + ' buttons.';
2075
 
        }
2076
 
    });
2077
 
/**
2078
 
* @event buttonClick
2079
 
* @param {Object} o The object passed to this handler is the button config used to create the button.
2080
 
* @description Fires when any botton receives a click event. Passes back a single object representing the buttons config object. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2081
 
* @type YAHOO.util.CustomEvent
2082
 
*/
2083
 
/**
2084
 
* @event valueClick
2085
 
* @param {Object} o The object passed to this handler is the button config used to create the button.
2086
 
* @description This is a special dynamic event that is created and dispatched based on the value property
2087
 
* of the button config. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2088
 
* Example:
2089
 
* <code><pre>
2090
 
* buttons : [
2091
 
*   { type: 'button', value: 'test', value: 'testButton' }
2092
 
* ]</pre>
2093
 
* </code>
2094
 
* With the valueClick event you could subscribe to this buttons click event with this:
2095
 
* tbar.in('testButtonClick', function() { alert('test button clicked'); })
2096
 
* @type YAHOO.util.CustomEvent
2097
 
*/
2098
 
/**
2099
 
* @event toolbarExpanded
2100
 
* @description Fires when the toolbar is expanded via the collapse button. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2101
 
* @type YAHOO.util.CustomEvent
2102
 
*/
2103
 
/**
2104
 
* @event toolbarCollapsed
2105
 
* @description Fires when the toolbar is collapsed via the collapse button. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2106
 
* @type YAHOO.util.CustomEvent
2107
 
*/
2108
 
})();
2109
 
/**
2110
 
 * @module editor
2111
 
 * @description <p>The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.</p>
2112
 
 * @namespace YAHOO.widget
2113
 
 * @requires yahoo, dom, element, event, toolbar
2114
 
 * @optional animation, container_core, resize, dragdrop
2115
 
 */
2116
 
 
2117
 
(function() {
2118
 
var Dom = YAHOO.util.Dom,
2119
 
    Event = YAHOO.util.Event,
2120
 
    Lang = YAHOO.lang,
2121
 
    Toolbar = YAHOO.widget.Toolbar;
2122
 
 
2123
 
    /**
2124
 
     * The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.
2125
 
     * @constructor
2126
 
     * @class SimpleEditor
2127
 
     * @extends YAHOO.util.Element
2128
 
     * @param {String/HTMLElement} el The textarea element to turn into an editor.
2129
 
     * @param {Object} attrs Object liternal containing configuration parameters.
2130
 
    */
2131
 
    
2132
 
    YAHOO.widget.SimpleEditor = function(el, attrs) {
2133
 
        YAHOO.log('SimpleEditor Initalizing', 'info', 'SimpleEditor');
2134
 
        
2135
 
        var o = {};
2136
 
        if (Lang.isObject(el) && (!el.tagName) && !attrs) {
2137
 
            Lang.augmentObject(o, el); //Break the config reference
2138
 
            el = document.createElement('textarea');
2139
 
            this.DOMReady = true;
2140
 
            if (o.container) {
2141
 
                var c = Dom.get(o.container);
2142
 
                c.appendChild(el);
2143
 
            } else {
2144
 
                document.body.appendChild(el);
2145
 
            }
2146
 
        } else {
2147
 
            if (attrs) {
2148
 
                Lang.augmentObject(o, attrs); //Break the config reference
2149
 
            }
2150
 
        }
2151
 
 
2152
 
        var oConfig = {
2153
 
            element: null,
2154
 
            attributes: o
2155
 
        }, id = null;
2156
 
 
2157
 
        if (Lang.isString(el)) {
2158
 
            id = el;
2159
 
        } else {
2160
 
            if (oConfig.attributes.id) {
2161
 
                id = oConfig.attributes.id;
2162
 
            } else {
2163
 
                this.DOMReady = true;
2164
 
                id = Dom.generateId(el);
2165
 
            }
2166
 
        }
2167
 
        oConfig.element = el;
2168
 
 
2169
 
        var element_cont = document.createElement('DIV');
2170
 
        oConfig.attributes.element_cont = new YAHOO.util.Element(element_cont, {
2171
 
            id: id + '_container'
2172
 
        });
2173
 
        var div = document.createElement('div');
2174
 
        Dom.addClass(div, 'first-child');
2175
 
        oConfig.attributes.element_cont.appendChild(div);
2176
 
        
2177
 
        if (!oConfig.attributes.toolbar_cont) {
2178
 
            oConfig.attributes.toolbar_cont = document.createElement('DIV');
2179
 
            oConfig.attributes.toolbar_cont.id = id + '_toolbar';
2180
 
            div.appendChild(oConfig.attributes.toolbar_cont);
2181
 
        }
2182
 
        var editorWrapper = document.createElement('DIV');
2183
 
        div.appendChild(editorWrapper);
2184
 
        oConfig.attributes.editor_wrapper = editorWrapper;
2185
 
 
2186
 
        YAHOO.widget.SimpleEditor.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
2187
 
    };
2188
 
 
2189
 
 
2190
 
    YAHOO.extend(YAHOO.widget.SimpleEditor, YAHOO.util.Element, {
2191
 
        /**
2192
 
        * @private
2193
 
        * @property _resizeConfig
2194
 
        * @description The default config for the Resize Utility
2195
 
        */
2196
 
        _resizeConfig: {
2197
 
            handles: ['br'],
2198
 
            autoRatio: true,
2199
 
            status: true,
2200
 
            proxy: true,
2201
 
            useShim: true,
2202
 
            setSize: false
2203
 
        },
2204
 
        /**
2205
 
        * @private
2206
 
        * @method _setupResize
2207
 
        * @description Creates the Resize instance and binds its events.
2208
 
        */
2209
 
        _setupResize: function() {
2210
 
            if (!YAHOO.util.DD || !YAHOO.util.Resize) { return false; }
2211
 
            if (this.get('resize')) {
2212
 
                var config = {};
2213
 
                Lang.augmentObject(config, this._resizeConfig); //Break the config reference
2214
 
                this.resize = new YAHOO.util.Resize(this.get('element_cont').get('element'), config);
2215
 
                this.resize.on('resize', function(args) {
2216
 
                    var anim = this.get('animate');
2217
 
                    this.set('animate', false);
2218
 
                    this.set('width', args.width + 'px');
2219
 
                    var h = args.height,
2220
 
                        th = (this.toolbar.get('element').clientHeight + 2),
2221
 
                        dh = 0;
2222
 
                    if (this.dompath) {
2223
 
                        dh = (this.dompath.clientHeight + 1); //It has a 1px top border..
2224
 
                    }
2225
 
                    var newH = (h - th - dh);
2226
 
                    this.set('height', newH + 'px');
2227
 
                    this.get('element_cont').setStyle('height', '');
2228
 
                    this.set('animate', anim);
2229
 
                }, this, true);
2230
 
            }
2231
 
        },
2232
 
        /**
2233
 
        * @property resize
2234
 
        * @description A reference to the Resize object
2235
 
        * @type YAHOO.util.Resize
2236
 
        */
2237
 
        resize: null,
2238
 
        /**
2239
 
        * @private
2240
 
        * @method _setupDD
2241
 
        * @description Sets up the DD instance used from the 'drag' config option.
2242
 
        */
2243
 
        _setupDD: function() {
2244
 
            if (!YAHOO.util.DD) { return false; }
2245
 
            if (this.get('drag')) {
2246
 
                YAHOO.log('Attaching DD instance to Editor', 'info', 'SimpleEditor');
2247
 
                var d = this.get('drag'),
2248
 
                    dd = YAHOO.util.DD;
2249
 
                if (d === 'proxy') {
2250
 
                    dd = YAHOO.util.DDProxy;
2251
 
                }
2252
 
 
2253
 
                this.dd = new dd(this.get('element_cont').get('element'));
2254
 
                this.toolbar.addClass('draggable'); 
2255
 
                this.dd.setHandleElId(this.toolbar._titlebar); 
2256
 
            }
2257
 
        },
2258
 
        /**
2259
 
        * @property dd
2260
 
        * @description A reference to the DragDrop object.
2261
 
        * @type YAHOO.util.DD/YAHOO.util.DDProxy
2262
 
        */
2263
 
        dd: null,
2264
 
        /**
2265
 
        * @private
2266
 
        * @property _lastCommand
2267
 
        * @description A cache of the last execCommand (used for Undo/Redo so they don't mark an undo level)
2268
 
        * @type String
2269
 
        */
2270
 
        _lastCommand: null,
2271
 
        _undoNodeChange: function() {},
2272
 
        _storeUndo: function() {},
2273
 
        /**
2274
 
        * @private
2275
 
        * @method _checkKey
2276
 
        * @description Checks a keyMap entry against a key event
2277
 
        * @param {Object} k The _keyMap object
2278
 
        * @param {Event} e The Mouse Event
2279
 
        * @return {Boolean}
2280
 
        */
2281
 
        _checkKey: function(k, e) {
2282
 
            var ret = false;
2283
 
            if ((e.keyCode === k.key)) {
2284
 
                if (k.mods && (k.mods.length > 0)) {
2285
 
                    var val = 0;
2286
 
                    for (var i = 0; i < k.mods.length; i++) {
2287
 
                        if (this.browser.mac) {
2288
 
                            if (k.mods[i] == 'ctrl') {
2289
 
                                k.mods[i] = 'meta';
2290
 
                            }
2291
 
                        }
2292
 
                        if (e[k.mods[i] + 'Key'] === true) {
2293
 
                            val++;
2294
 
                        }
2295
 
                    }
2296
 
                    if (val === k.mods.length) {
2297
 
                        ret = true;
2298
 
                    }
2299
 
                } else {
2300
 
                    ret = true;
2301
 
                }
2302
 
            }
2303
 
            //YAHOO.log('Shortcut Key Check: (' + k.key + ') return: ' + ret, 'info', 'SimpleEditor');
2304
 
            return ret;
2305
 
        },
2306
 
        /**
2307
 
        * @private
2308
 
        * @property _keyMap
2309
 
        * @description Named key maps for various actions in the Editor. Example: <code>CLOSE_WINDOW: { key: 87, mods: ['shift', 'ctrl'] }</code>. 
2310
 
        * This entry shows that when key 87 (W) is found with the modifiers of shift and control, the window will close. You can customize this object to tweak keyboard shortcuts.
2311
 
        * @type {Object/Mixed}
2312
 
        */
2313
 
        _keyMap: {
2314
 
            SELECT_ALL: {
2315
 
                key: 65, //A key
2316
 
                mods: ['ctrl']
2317
 
            },
2318
 
            CLOSE_WINDOW: {
2319
 
                key: 87, //W key
2320
 
                mods: ['shift', 'ctrl']
2321
 
            },
2322
 
            FOCUS_TOOLBAR: {
2323
 
                key: 27,
2324
 
                mods: ['shift']
2325
 
            },
2326
 
            FOCUS_AFTER: {
2327
 
                key: 27
2328
 
            },
2329
 
            FONT_SIZE_UP: {
2330
 
                key: 38,
2331
 
                mods: ['shift', 'ctrl']
2332
 
            },
2333
 
            FONT_SIZE_DOWN: {
2334
 
                key: 40,
2335
 
                mods: ['shift', 'ctrl']
2336
 
            },
2337
 
            CREATE_LINK: {
2338
 
                key: 76,
2339
 
                mods: ['shift', 'ctrl']
2340
 
            },
2341
 
            BOLD: {
2342
 
                key: 66,
2343
 
                mods: ['shift', 'ctrl']
2344
 
            },
2345
 
            ITALIC: {
2346
 
                key: 73,
2347
 
                mods: ['shift', 'ctrl']
2348
 
            },
2349
 
            UNDERLINE: {
2350
 
                key: 85,
2351
 
                mods: ['shift', 'ctrl']
2352
 
            },
2353
 
            UNDO: {
2354
 
                key: 90,
2355
 
                mods: ['ctrl']
2356
 
            },
2357
 
            REDO: {
2358
 
                key: 90,
2359
 
                mods: ['shift', 'ctrl']
2360
 
            },
2361
 
            JUSTIFY_LEFT: {
2362
 
                key: 219,
2363
 
                mods: ['shift', 'ctrl']
2364
 
            },
2365
 
            JUSTIFY_CENTER: {
2366
 
                key: 220,
2367
 
                mods: ['shift', 'ctrl']
2368
 
            },
2369
 
            JUSTIFY_RIGHT: {
2370
 
                key: 221,
2371
 
                mods: ['shift', 'ctrl']
2372
 
            }
2373
 
        },
2374
 
        /**
2375
 
        * @private
2376
 
        * @method _cleanClassName
2377
 
        * @description Makes a useable classname from dynamic data, by dropping it to lowercase and replacing spaces with -'s.
2378
 
        * @param {String} str The classname to clean up
2379
 
        * @return {String}
2380
 
        */
2381
 
        _cleanClassName: function(str) {
2382
 
            return str.replace(/ /g, '-').toLowerCase();
2383
 
        },
2384
 
        /**
2385
 
        * @property _textarea
2386
 
        * @description Flag to determine if we are using a textarea or an HTML Node.
2387
 
        * @type Boolean
2388
 
        */
2389
 
        _textarea: null,
2390
 
        /**
2391
 
        * @property _docType
2392
 
        * @description The DOCTYPE to use in the editable container.
2393
 
        * @type String
2394
 
        */
2395
 
        _docType: '<!DOCTYPE HTML PUBLIC "-/'+'/W3C/'+'/DTD HTML 4.01/'+'/EN" "http:/'+'/www.w3.org/TR/html4/strict.dtd">',
2396
 
        /**
2397
 
        * @property editorDirty
2398
 
        * @description This flag will be set when certain things in the Editor happen. It is to be used by the developer to check to see if content has changed.
2399
 
        * @type Boolean
2400
 
        */
2401
 
        editorDirty: null,
2402
 
        /**
2403
 
        * @property _defaultCSS
2404
 
        * @description The default CSS used in the config for 'css'. This way you can add to the config like this: { css: YAHOO.widget.SimpleEditor.prototype._defaultCSS + 'ADD MYY CSS HERE' }
2405
 
        * @type String
2406
 
        */
2407
 
        _defaultCSS: 'html { height: 95%; } body { padding: 7px; background-color: #fff; font: 13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; } a, a:visited, a:hover { color: blue !important; text-decoration: underline !important; cursor: text !important; } .warning-localfile { border-bottom: 1px dashed red !important; } .yui-busy { cursor: wait !important; } img.selected { border: 2px dotted #808080; } img { cursor: pointer !important; border: none; } body.ptags.webkit div.yui-wk-p { margin: 11px 0; } body.ptags.webkit div.yui-wk-div { margin: 0; }',
2408
 
        /**
2409
 
        * @property _defaultToolbar
2410
 
        * @private
2411
 
        * @description Default toolbar config.
2412
 
        * @type Object
2413
 
        */
2414
 
        _defaultToolbar: null,
2415
 
        /**
2416
 
        * @property _lastButton
2417
 
        * @private
2418
 
        * @description The last button pressed, so we don't disable it.
2419
 
        * @type Object
2420
 
        */
2421
 
        _lastButton: null,
2422
 
        /**
2423
 
        * @property _baseHREF
2424
 
        * @private
2425
 
        * @description The base location of the editable page (this page) so that relative paths for image work.
2426
 
        * @type String
2427
 
        */
2428
 
        _baseHREF: function() {
2429
 
            var href = document.location.href;
2430
 
            if (href.indexOf('?') !== -1) { //Remove the query string
2431
 
                href = href.substring(0, href.indexOf('?'));
2432
 
            }
2433
 
            href = href.substring(0, href.lastIndexOf('/')) + '/';
2434
 
            return href;
2435
 
        }(),
2436
 
        /**
2437
 
        * @property _lastImage
2438
 
        * @private
2439
 
        * @description Safari reference for the last image selected (for styling as selected).
2440
 
        * @type HTMLElement
2441
 
        */
2442
 
        _lastImage: null,
2443
 
        /**
2444
 
        * @property _blankImageLoaded
2445
 
        * @private
2446
 
        * @description Don't load the blank image more than once..
2447
 
        * @type Boolean
2448
 
        */
2449
 
        _blankImageLoaded: null,
2450
 
        /**
2451
 
        * @property _fixNodesTimer
2452
 
        * @private
2453
 
        * @description Holder for the fixNodes timer
2454
 
        * @type Date
2455
 
        */
2456
 
        _fixNodesTimer: null,
2457
 
        /**
2458
 
        * @property _nodeChangeTimer
2459
 
        * @private
2460
 
        * @description Holds a reference to the nodeChange setTimeout call
2461
 
        * @type Number
2462
 
        */
2463
 
        _nodeChangeTimer: null,
2464
 
        /**
2465
 
        * @property _lastNodeChangeEvent
2466
 
        * @private
2467
 
        * @description Flag to determine the last event that fired a node change
2468
 
        * @type Event
2469
 
        */
2470
 
        _lastNodeChangeEvent: null,
2471
 
        /**
2472
 
        * @property _lastNodeChange
2473
 
        * @private
2474
 
        * @description Flag to determine when the last node change was fired
2475
 
        * @type Date
2476
 
        */
2477
 
        _lastNodeChange: 0,
2478
 
        /**
2479
 
        * @property _rendered
2480
 
        * @private
2481
 
        * @description Flag to determine if editor has been rendered or not
2482
 
        * @type Boolean
2483
 
        */
2484
 
        _rendered: null,
2485
 
        /**
2486
 
        * @property DOMReady
2487
 
        * @private
2488
 
        * @description Flag to determine if DOM is ready or not
2489
 
        * @type Boolean
2490
 
        */
2491
 
        DOMReady: null,
2492
 
        /**
2493
 
        * @property _selection
2494
 
        * @private
2495
 
        * @description Holder for caching iframe selections
2496
 
        * @type Object
2497
 
        */
2498
 
        _selection: null,
2499
 
        /**
2500
 
        * @property _mask
2501
 
        * @private
2502
 
        * @description DOM Element holder for the editor Mask when disabled
2503
 
        * @type Object
2504
 
        */
2505
 
        _mask: null,
2506
 
        /**
2507
 
        * @property _showingHiddenElements
2508
 
        * @private
2509
 
        * @description Status of the hidden elements button
2510
 
        * @type Boolean
2511
 
        */
2512
 
        _showingHiddenElements: null,
2513
 
        /**
2514
 
        * @property currentWindow
2515
 
        * @description A reference to the currently open EditorWindow
2516
 
        * @type Object
2517
 
        */
2518
 
        currentWindow: null,
2519
 
        /**
2520
 
        * @property currentEvent
2521
 
        * @description A reference to the current editor event
2522
 
        * @type Event
2523
 
        */
2524
 
        currentEvent: null,
2525
 
        /**
2526
 
        * @property operaEvent
2527
 
        * @private
2528
 
        * @description setTimeout holder for Opera and Image DoubleClick event..
2529
 
        * @type Object
2530
 
        */
2531
 
        operaEvent: null,
2532
 
        /**
2533
 
        * @property currentFont
2534
 
        * @description A reference to the last font selected from the Toolbar
2535
 
        * @type HTMLElement
2536
 
        */
2537
 
        currentFont: null,
2538
 
        /**
2539
 
        * @property currentElement
2540
 
        * @description A reference to the current working element in the editor
2541
 
        * @type Array
2542
 
        */
2543
 
        currentElement: null,
2544
 
        /**
2545
 
        * @property dompath
2546
 
        * @description A reference to the dompath container for writing the current working dom path to.
2547
 
        * @type HTMLElement
2548
 
        */
2549
 
        dompath: null,
2550
 
        /**
2551
 
        * @property beforeElement
2552
 
        * @description A reference to the H2 placed before the editor for Accessibilty.
2553
 
        * @type HTMLElement
2554
 
        */
2555
 
        beforeElement: null,
2556
 
        /**
2557
 
        * @property afterElement
2558
 
        * @description A reference to the H2 placed after the editor for Accessibilty.
2559
 
        * @type HTMLElement
2560
 
        */
2561
 
        afterElement: null,
2562
 
        /**
2563
 
        * @property invalidHTML
2564
 
        * @description Contains a list of HTML elements that are invalid inside the editor. They will be removed when they are found. If you set the value of a key to "{ keepContents: true }", then the element will be replaced with a yui-non span to be filtered out when cleanHTML is called. The only tag that is ignored here is the span tag as it will force the Editor into a loop and freeze the browser. However.. all of these tags will be removed in the cleanHTML routine.
2565
 
        * @type Object
2566
 
        */
2567
 
        invalidHTML: {
2568
 
            form: true,
2569
 
            input: true,
2570
 
            button: true,
2571
 
            select: true,
2572
 
            link: true,
2573
 
            html: true,
2574
 
            body: true,
2575
 
            iframe: true,
2576
 
            script: true,
2577
 
            style: true,
2578
 
            textarea: true
2579
 
        },
2580
 
        /**
2581
 
        * @property toolbar
2582
 
        * @description Local property containing the <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a> instance
2583
 
        * @type <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>
2584
 
        */
2585
 
        toolbar: null,
2586
 
        /**
2587
 
        * @private
2588
 
        * @property _contentTimer
2589
 
        * @description setTimeout holder for documentReady check
2590
 
        */
2591
 
        _contentTimer: null,
2592
 
        /**
2593
 
        * @private
2594
 
        * @property _contentTimerCounter
2595
 
        * @description Counter to check the number of times the body is polled for before giving up
2596
 
        * @type Number
2597
 
        */
2598
 
        _contentTimerCounter: 0,
2599
 
        /**
2600
 
        * @private
2601
 
        * @property _disabled
2602
 
        * @description The Toolbar items that should be disabled if there is no selection present in the editor.
2603
 
        * @type Array
2604
 
        */
2605
 
        _disabled: [ 'createlink', 'fontname', 'fontsize', 'forecolor', 'backcolor' ],
2606
 
        /**
2607
 
        * @private
2608
 
        * @property _alwaysDisabled
2609
 
        * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
2610
 
        * @type Object
2611
 
        */
2612
 
        _alwaysDisabled: { undo: true, redo: true },
2613
 
        /**
2614
 
        * @private
2615
 
        * @property _alwaysEnabled
2616
 
        * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
2617
 
        * @type Object
2618
 
        */
2619
 
        _alwaysEnabled: { },
2620
 
        /**
2621
 
        * @private
2622
 
        * @property _semantic
2623
 
        * @description The Toolbar commands that we should attempt to make tags out of instead of using styles.
2624
 
        * @type Object
2625
 
        */
2626
 
        _semantic: { 'bold': true, 'italic' : true, 'underline' : true },
2627
 
        /**
2628
 
        * @private
2629
 
        * @property _tag2cmd
2630
 
        * @description A tag map of HTML tags to convert to the different types of commands so we can select the proper toolbar button.
2631
 
        * @type Object
2632
 
        */
2633
 
        _tag2cmd: {
2634
 
            'b': 'bold',
2635
 
            'strong': 'bold',
2636
 
            'i': 'italic',
2637
 
            'em': 'italic',
2638
 
            'u': 'underline',
2639
 
            'sup': 'superscript',
2640
 
            'sub': 'subscript',
2641
 
            'img': 'insertimage',
2642
 
            'a' : 'createlink',
2643
 
            'ul' : 'insertunorderedlist',
2644
 
            'ol' : 'insertorderedlist'
2645
 
        },
2646
 
 
2647
 
        /**
2648
 
        * @private _createIframe
2649
 
        * @description Creates the DOM and YUI Element for the iFrame editor area.
2650
 
        * @param {String} id The string ID to prefix the iframe with
2651
 
        * @return {Object} iFrame object
2652
 
        */
2653
 
        _createIframe: function() {
2654
 
            var ifrmDom = document.createElement('iframe');
2655
 
            ifrmDom.id = this.get('id') + '_editor';
2656
 
            var config = {
2657
 
                border: '0',
2658
 
                frameBorder: '0',
2659
 
                marginWidth: '0',
2660
 
                marginHeight: '0',
2661
 
                leftMargin: '0',
2662
 
                topMargin: '0',
2663
 
                allowTransparency: 'true',
2664
 
                width: '100%'
2665
 
            };
2666
 
            if (this.get('autoHeight')) {
2667
 
                config.scrolling = 'no';
2668
 
            }
2669
 
            for (var i in config) {
2670
 
                if (Lang.hasOwnProperty(config, i)) {
2671
 
                    ifrmDom.setAttribute(i, config[i]);
2672
 
                }
2673
 
            }
2674
 
            var isrc = 'javascript:;';
2675
 
            if (this.browser.ie) {
2676
 
                //isrc = 'about:blank';
2677
 
                //TODO - Check this, I have changed it before..
2678
 
                isrc = 'javascript:false;';
2679
 
            }
2680
 
            ifrmDom.setAttribute('src', isrc);
2681
 
            var ifrm = new YAHOO.util.Element(ifrmDom);
2682
 
            ifrm.setStyle('visibility', 'hidden');
2683
 
            return ifrm;
2684
 
        },
2685
 
        /**
2686
 
        * @private _isElement
2687
 
        * @description Checks to see if an Element reference is a valid one and has a certain tag type
2688
 
        * @param {HTMLElement} el The element to check
2689
 
        * @param {String} tag The tag that the element needs to be
2690
 
        * @return {Boolean}
2691
 
        */
2692
 
        _isElement: function(el, tag) {
2693
 
            if (el && el.tagName && (el.tagName.toLowerCase() == tag)) {
2694
 
                return true;
2695
 
            }
2696
 
            if (el && el.getAttribute && (el.getAttribute('tag') == tag)) {
2697
 
                return true;
2698
 
            }
2699
 
            return false;
2700
 
        },
2701
 
        /**
2702
 
        * @private _hasParent
2703
 
        * @description Checks to see if an Element reference or one of it's parents is a valid one and has a certain tag type
2704
 
        * @param {HTMLElement} el The element to check
2705
 
        * @param {String} tag The tag that the element needs to be
2706
 
        * @return HTMLElement
2707
 
        */
2708
 
        _hasParent: function(el, tag) {
2709
 
            if (!el || !el.parentNode) {
2710
 
                return false;
2711
 
            }
2712
 
            
2713
 
            while (el.parentNode) {
2714
 
                if (this._isElement(el, tag)) {
2715
 
                    return el;
2716
 
                }
2717
 
                if (el.parentNode) {
2718
 
                    el = el.parentNode;
2719
 
                } else {
2720
 
                    return false;
2721
 
                }
2722
 
            }
2723
 
            return false;
2724
 
        },
2725
 
        /**
2726
 
        * @private
2727
 
        * @method _getDoc
2728
 
        * @description Get the Document of the IFRAME
2729
 
        * @return {Object}
2730
 
        */
2731
 
        _getDoc: function() {
2732
 
            var value = false;
2733
 
            if (this.get) {
2734
 
                if (this.get('iframe')) {
2735
 
                    if (this.get('iframe').get) {
2736
 
                        if (this.get('iframe').get('element')) {
2737
 
                            try {
2738
 
                                if (this.get('iframe').get('element').contentWindow) {
2739
 
                                    if (this.get('iframe').get('element').contentWindow.document) {
2740
 
                                        value = this.get('iframe').get('element').contentWindow.document;
2741
 
                                        return value;
2742
 
                                    }
2743
 
                                }
2744
 
                            } catch (e) {}
2745
 
                        }
2746
 
                    }
2747
 
                }
2748
 
            }
2749
 
            return false;
2750
 
        },
2751
 
        /**
2752
 
        * @private
2753
 
        * @method _getWindow
2754
 
        * @description Get the Window of the IFRAME
2755
 
        * @return {Object}
2756
 
        */
2757
 
        _getWindow: function() {
2758
 
            return this.get('iframe').get('element').contentWindow;
2759
 
        },
2760
 
        /**
2761
 
        * @method focus
2762
 
        * @description Attempt to set the focus of the iframes window.
2763
 
        */
2764
 
        focus: function() {
2765
 
            this._getWindow().focus();
2766
 
        },
2767
 
        /**
2768
 
        * @private
2769
 
        * @depreciated - This should not be used, moved to this.focus();
2770
 
        * @method _focusWindow
2771
 
        * @description Attempt to set the focus of the iframes window.
2772
 
        */
2773
 
        _focusWindow: function() {
2774
 
            YAHOO.log('_focusWindow: depreciated in favor of this.focus()', 'warn', 'Editor');
2775
 
            this.focus();
2776
 
        },
2777
 
        /**
2778
 
        * @private
2779
 
        * @method _hasSelection
2780
 
        * @description Determines if there is a selection in the editor document.
2781
 
        * @return {Boolean}
2782
 
        */
2783
 
        _hasSelection: function() {
2784
 
            var sel = this._getSelection();
2785
 
            var range = this._getRange();
2786
 
            var hasSel = false;
2787
 
 
2788
 
            if (!sel || !range) {
2789
 
                return hasSel;
2790
 
            }
2791
 
 
2792
 
            //Internet Explorer
2793
 
            if (this.browser.ie || this.browser.opera) {
2794
 
                if (range.text) {
2795
 
                    hasSel = true;
2796
 
                }
2797
 
                if (range.html) {
2798
 
                    hasSel = true;
2799
 
                }
2800
 
            } else {
2801
 
                if (this.browser.webkit) {
2802
 
                    if (sel+'' !== '') {
2803
 
                        hasSel = true;
2804
 
                    }
2805
 
                } else {
2806
 
                    if (sel && (sel.toString() !== '') && (sel !== undefined)) {
2807
 
                        hasSel = true;
2808
 
                    }
2809
 
                }
2810
 
            }
2811
 
            return hasSel;
2812
 
        },
2813
 
        /**
2814
 
        * @private
2815
 
        * @method _getSelection
2816
 
        * @description Handles the different selection objects across the A-Grade list.
2817
 
        * @return {Object} Selection Object
2818
 
        */
2819
 
        _getSelection: function() {
2820
 
            var _sel = null;
2821
 
            if (this._getDoc() && this._getWindow()) {
2822
 
                if (this._getDoc().selection) {
2823
 
                    _sel = this._getDoc().selection;
2824
 
                } else {
2825
 
                    _sel = this._getWindow().getSelection();
2826
 
                }
2827
 
                //Handle Safari's lack of Selection Object
2828
 
                if (this.browser.webkit) {
2829
 
                    if (_sel.baseNode) {
2830
 
                            this._selection = {};
2831
 
                            this._selection.baseNode = _sel.baseNode;
2832
 
                            this._selection.baseOffset = _sel.baseOffset;
2833
 
                            this._selection.extentNode = _sel.extentNode;
2834
 
                            this._selection.extentOffset = _sel.extentOffset;
2835
 
                    } else if (this._selection !== null) {
2836
 
                        _sel = this._getWindow().getSelection();
2837
 
                        _sel.setBaseAndExtent(
2838
 
                            this._selection.baseNode,
2839
 
                            this._selection.baseOffset,
2840
 
                            this._selection.extentNode,
2841
 
                            this._selection.extentOffset);
2842
 
                        this._selection = null;
2843
 
                    }
2844
 
                }
2845
 
            }
2846
 
            return _sel;
2847
 
        },
2848
 
        /**
2849
 
        * @private
2850
 
        * @method _selectNode
2851
 
        * @description Places the highlight around a given node
2852
 
        * @param {HTMLElement} node The node to select
2853
 
        */
2854
 
        _selectNode: function(node, collapse) {
2855
 
            if (!node) {
2856
 
                return false;
2857
 
            }
2858
 
            var sel = this._getSelection(),
2859
 
                range = null;
2860
 
 
2861
 
            if (this.browser.ie) {
2862
 
                try { //IE freaks out here sometimes..
2863
 
                    range = this._getDoc().body.createTextRange();
2864
 
                    range.moveToElementText(node);
2865
 
                    range.select();
2866
 
                } catch (e) {
2867
 
                    YAHOO.log('IE failed to select element: ' + node.tagName, 'warn', 'SimpleEditor');
2868
 
                }
2869
 
            } else if (this.browser.webkit) {
2870
 
                if (collapse) {
2871
 
                                    sel.setBaseAndExtent(node, 1, node, node.innerText.length);
2872
 
                } else {
2873
 
                                    sel.setBaseAndExtent(node, 0, node, node.innerText.length);
2874
 
                }
2875
 
            } else if (this.browser.opera) {
2876
 
                sel = this._getWindow().getSelection();
2877
 
                range = this._getDoc().createRange();
2878
 
                range.selectNode(node);
2879
 
                sel.removeAllRanges();
2880
 
                sel.addRange(range);
2881
 
            } else {
2882
 
                range = this._getDoc().createRange();
2883
 
                range.selectNodeContents(node);
2884
 
                sel.removeAllRanges();
2885
 
                sel.addRange(range);
2886
 
            }
2887
 
            //TODO - Check Performance
2888
 
            this.nodeChange();
2889
 
        },
2890
 
        /**
2891
 
        * @private
2892
 
        * @method _getRange
2893
 
        * @description Handles the different range objects across the A-Grade list.
2894
 
        * @return {Object} Range Object
2895
 
        */
2896
 
        _getRange: function() {
2897
 
            var sel = this._getSelection();
2898
 
 
2899
 
            if (sel === null) {
2900
 
                return null;
2901
 
            }
2902
 
 
2903
 
            if (this.browser.webkit && !sel.getRangeAt) {
2904
 
                var _range = this._getDoc().createRange();
2905
 
                try {
2906
 
                    _range.setStart(sel.anchorNode, sel.anchorOffset);
2907
 
                    _range.setEnd(sel.focusNode, sel.focusOffset);
2908
 
                } catch (e) {
2909
 
                    _range = this._getWindow().getSelection()+'';
2910
 
                }
2911
 
                return _range;
2912
 
            }
2913
 
 
2914
 
            if (this.browser.ie || this.browser.opera) {
2915
 
                try {
2916
 
                    return sel.createRange();
2917
 
                } catch (e2) {
2918
 
                    return null;
2919
 
                }
2920
 
            }
2921
 
 
2922
 
            if (sel.rangeCount > 0) {
2923
 
                return sel.getRangeAt(0);
2924
 
            }
2925
 
            return null;
2926
 
        },
2927
 
        /**
2928
 
        * @private
2929
 
        * @method _setDesignMode
2930
 
        * @description Sets the designMode of the iFrame document.
2931
 
        * @param {String} state This should be either on or off
2932
 
        */
2933
 
        _setDesignMode: function(state) {
2934
 
            try {
2935
 
                var set = true;
2936
 
                //SourceForge Bug #1807057
2937
 
                if (this.browser.ie && (state.toLowerCase() == 'off')) {
2938
 
                    set = false;
2939
 
                }
2940
 
                if (set) {
2941
 
                    this._getDoc().designMode = state;
2942
 
                }
2943
 
            } catch(e) { }
2944
 
        },
2945
 
        /**
2946
 
        * @private
2947
 
        * @method _toggleDesignMode
2948
 
        * @description Toggles the designMode of the iFrame document on and off.
2949
 
        * @return {String} The state that it was set to.
2950
 
        */
2951
 
        _toggleDesignMode: function() {
2952
 
            var _dMode = this._getDoc().designMode.toLowerCase(),
2953
 
                _state = 'on';
2954
 
            if (_dMode == 'on') {
2955
 
                _state = 'off';
2956
 
            }
2957
 
            this._setDesignMode(_state);
2958
 
            return _state;
2959
 
        },
2960
 
        /**
2961
 
        * @private
2962
 
        * @property _focused
2963
 
        * @description Holder for trapping focus/blur state and prevent double events
2964
 
        * @type Boolean
2965
 
        */
2966
 
        _focused: null,
2967
 
        /**
2968
 
        * @private
2969
 
        * @method _handleFocus
2970
 
        * @description Handles the focus of the iframe. Note, this is window focus event, not an Editor focus event.
2971
 
        * @param {Event} e The DOM Event
2972
 
        */
2973
 
        _handleFocus: function(e) {
2974
 
            if (!this._focused) {
2975
 
                YAHOO.log('Editor Window Focused', 'info', 'SimpleEditor');
2976
 
                this._focused = true;
2977
 
                this.fireEvent('editorWindowFocus', { type: 'editorWindowFocus', target: this });
2978
 
            }
2979
 
        },
2980
 
        /**
2981
 
        * @private
2982
 
        * @method _handleBlur
2983
 
        * @description Handles the blur of the iframe. Note, this is window blur event, not an Editor blur event.
2984
 
        * @param {Event} e The DOM Event
2985
 
        */
2986
 
        _handleBlur: function(e) {
2987
 
            if (this._focused) {
2988
 
                YAHOO.log('Editor Window Blurred', 'info', 'SimpleEditor');
2989
 
                this._focused = false;
2990
 
                this.fireEvent('editorWindowBlur', { type: 'editorWindowBlur', target: this });
2991
 
            }
2992
 
        },
2993
 
        /**
2994
 
        * @private
2995
 
        * @method _initEditorEvents
2996
 
        * @description This method sets up the listeners on the Editors document.
2997
 
        */
2998
 
        _initEditorEvents: function() {
2999
 
            //Setup Listeners on iFrame
3000
 
            var doc = this._getDoc(),
3001
 
                win = this._getWindow();
3002
 
 
3003
 
            Event.on(doc, 'mouseup', this._handleMouseUp, this, true);
3004
 
            Event.on(doc, 'mousedown', this._handleMouseDown, this, true);
3005
 
            Event.on(doc, 'click', this._handleClick, this, true);
3006
 
            Event.on(doc, 'dblclick', this._handleDoubleClick, this, true);
3007
 
            Event.on(doc, 'keypress', this._handleKeyPress, this, true);
3008
 
            Event.on(doc, 'keyup', this._handleKeyUp, this, true);
3009
 
            Event.on(doc, 'keydown', this._handleKeyDown, this, true);
3010
 
            /* TODO -- Everyone but Opera works here..
3011
 
            Event.on(doc, 'paste', function() {
3012
 
                YAHOO.log('PASTE', 'info', 'SimpleEditor');
3013
 
            }, this, true);
3014
 
            */
3015
 
 
3016
 
            //Focus and blur..
3017
 
            Event.on(win, 'focus', this._handleFocus, this, true);
3018
 
            Event.on(win, 'blur', this._handleBlur, this, true);
3019
 
        },
3020
 
        /**
3021
 
        * @private
3022
 
        * @method _removeEditorEvents
3023
 
        * @description This method removes the listeners on the Editors document (for disabling).
3024
 
        */
3025
 
        _removeEditorEvents: function() {
3026
 
            //Remove Listeners on iFrame
3027
 
            var doc = this._getDoc(),
3028
 
                win = this._getWindow();
3029
 
 
3030
 
            Event.removeListener(doc, 'mouseup', this._handleMouseUp, this, true);
3031
 
            Event.removeListener(doc, 'mousedown', this._handleMouseDown, this, true);
3032
 
            Event.removeListener(doc, 'click', this._handleClick, this, true);
3033
 
            Event.removeListener(doc, 'dblclick', this._handleDoubleClick, this, true);
3034
 
            Event.removeListener(doc, 'keypress', this._handleKeyPress, this, true);
3035
 
            Event.removeListener(doc, 'keyup', this._handleKeyUp, this, true);
3036
 
            Event.removeListener(doc, 'keydown', this._handleKeyDown, this, true);
3037
 
 
3038
 
            //Focus and blur..
3039
 
            Event.removeListener(win, 'focus', this._handleFocus, this, true);
3040
 
            Event.removeListener(win, 'blur', this._handleBlur, this, true);
3041
 
        },
3042
 
        _fixWebkitDivs: function() {
3043
 
            if (this.browser.webkit) {
3044
 
                var divs = this._getDoc().body.getElementsByTagName('div');
3045
 
                Dom.addClass(divs, 'yui-wk-div');
3046
 
            }
3047
 
        },
3048
 
        /**
3049
 
        * @private
3050
 
        * @method _initEditor
3051
 
        * @description This method is fired from _checkLoaded when the document is ready. It turns on designMode and set's up the listeners.
3052
 
        */
3053
 
        _initEditor: function() {
3054
 
            if (this.browser.ie) {
3055
 
                this._getDoc().body.style.margin = '0';
3056
 
            }
3057
 
            if (!this.get('disabled')) {
3058
 
                if (this._getDoc().designMode.toLowerCase() != 'on') {
3059
 
                    this._setDesignMode('on');
3060
 
                    this._contentTimerCounter = 0;
3061
 
                }
3062
 
            }
3063
 
            if (!this._getDoc().body) {
3064
 
                YAHOO.log('Body is null, check again', 'error', 'SimpleEditor');
3065
 
                this._contentTimerCounter = 0;
3066
 
                this._checkLoaded();
3067
 
                return false;
3068
 
            }
3069
 
            
3070
 
            YAHOO.log('editorLoaded', 'info', 'SimpleEditor');
3071
 
            this.toolbar.on('buttonClick', this._handleToolbarClick, this, true);
3072
 
            if (!this.get('disabled')) {
3073
 
                this._initEditorEvents();
3074
 
                this.toolbar.set('disabled', false);
3075
 
            }
3076
 
 
3077
 
            this.fireEvent('editorContentLoaded', { type: 'editorLoaded', target: this });
3078
 
            this._fixWebkitDivs();
3079
 
            if (this.get('dompath')) {
3080
 
                YAHOO.log('Delayed DomPath write', 'info', 'SimpleEditor');
3081
 
                var self = this;
3082
 
                setTimeout(function() {
3083
 
                    self._writeDomPath.call(self);
3084
 
                    self._setupResize.call(self);
3085
 
                }, 150);
3086
 
            }
3087
 
            var br = [];
3088
 
            for (var i in this.browser) {
3089
 
                if (this.browser[i]) {
3090
 
                    br.push(i);
3091
 
                }
3092
 
            }
3093
 
            if (this.get('ptags')) {
3094
 
                br.push('ptags');
3095
 
            }
3096
 
            Dom.addClass(this._getDoc().body, br.join(' '));
3097
 
            this.nodeChange(true);
3098
 
        },
3099
 
        /**
3100
 
        * @private
3101
 
        * @method _checkLoaded
3102
 
        * @description Called from a setTimeout loop to check if the iframes body.onload event has fired, then it will init the editor.
3103
 
        */
3104
 
        _checkLoaded: function() {
3105
 
            this._contentTimerCounter++;
3106
 
            if (this._contentTimer) {
3107
 
                clearTimeout(this._contentTimer);
3108
 
            }
3109
 
            if (this._contentTimerCounter > 500) {
3110
 
                YAHOO.log('ERROR: Body Did Not load', 'error', 'SimpleEditor');
3111
 
                return false;
3112
 
            }
3113
 
            var init = false;
3114
 
            try {
3115
 
                if (this._getDoc() && this._getDoc().body) {
3116
 
                    if (this.browser.ie) {
3117
 
                        if (this._getDoc().body.readyState == 'complete') {
3118
 
                            init = true;
3119
 
                        }
3120
 
                    } else {
3121
 
                        if (this._getDoc().body._rteLoaded === true) {
3122
 
                            init = true;
3123
 
                        }
3124
 
                    }
3125
 
                }
3126
 
            } catch (e) {
3127
 
                init = false;
3128
 
                YAHOO.log('checking body (e)' + e, 'error', 'SimpleEditor');
3129
 
            }
3130
 
 
3131
 
            if (init === true) {
3132
 
                //The onload event has fired, clean up after ourselves and fire the _initEditor method
3133
 
                YAHOO.log('Firing _initEditor', 'info', 'SimpleEditor');
3134
 
                this._initEditor();
3135
 
            } else {
3136
 
                var self = this;
3137
 
                this._contentTimer = setTimeout(function() {
3138
 
                    self._checkLoaded.call(self);
3139
 
                }, 20);
3140
 
            }
3141
 
        },
3142
 
        /**
3143
 
        * @private
3144
 
        * @method _setInitialContent
3145
 
        * @description This method will open the iframes content document and write the textareas value into it, then start the body.onload checking.
3146
 
        */
3147
 
        _setInitialContent: function() {
3148
 
            YAHOO.log('Populating editor body with contents of the text area', 'info', 'SimpleEditor');
3149
 
 
3150
 
            var value = ((this._textarea) ? this.get('element').value : this.get('element').innerHTML),
3151
 
                doc = null;
3152
 
 
3153
 
            if ((value === '') && this.browser.gecko) {
3154
 
                //It seems that Gecko doesn't like an empty body so we have to give it something..
3155
 
                value = '<br>';
3156
 
            }
3157
 
 
3158
 
            var html = Lang.substitute(this.get('html'), {
3159
 
                TITLE: this.STR_TITLE,
3160
 
                CONTENT: this._cleanIncomingHTML(value),
3161
 
                CSS: this.get('css'),
3162
 
                HIDDEN_CSS: ((this.get('hiddencss')) ? this.get('hiddencss') : '/* No Hidden CSS */'),
3163
 
                EXTRA_CSS: ((this.get('extracss')) ? this.get('extracss') : '/* No Extra CSS */')
3164
 
            }),
3165
 
            check = true;
3166
 
            if (document.compatMode != 'BackCompat') {
3167
 
                YAHOO.log('Adding Doctype to editable area', 'info', 'SimpleEditor');
3168
 
                html = this._docType + "\n" + html;
3169
 
            } else {
3170
 
                YAHOO.log('DocType skipped because we are in BackCompat Mode.', 'warn', 'SimpleEditor');
3171
 
            }
3172
 
 
3173
 
            if (this.browser.ie || this.browser.webkit || this.browser.opera || (navigator.userAgent.indexOf('Firefox/1.5') != -1)) {
3174
 
                //Firefox 1.5 doesn't like setting designMode on an document created with a data url
3175
 
                try {
3176
 
                    //Adobe AIR Code
3177
 
                    if (this.browser.air) {
3178
 
                        doc = this._getDoc().implementation.createHTMLDocument();
3179
 
                        var origDoc = this._getDoc();
3180
 
                        origDoc.open();
3181
 
                        origDoc.close();
3182
 
                        doc.open();
3183
 
                        doc.write(html);
3184
 
                        doc.close();
3185
 
                        var node = origDoc.importNode(doc.getElementsByTagName("html")[0], true);
3186
 
                        origDoc.replaceChild(node, origDoc.getElementsByTagName("html")[0]);
3187
 
                        origDoc.body._rteLoaded = true;
3188
 
                    } else {
3189
 
                        doc = this._getDoc();
3190
 
                        doc.open();
3191
 
                        doc.write(html);
3192
 
                        doc.close();
3193
 
                    }
3194
 
                } catch (e) {
3195
 
                    YAHOO.log('Setting doc failed.. (_setInitialContent)', 'error', 'SimpleEditor');
3196
 
                    //Safari will only be here if we are hidden
3197
 
                    check = false;
3198
 
                }
3199
 
            } else {
3200
 
                //This keeps Firefox 2 from writing the iframe to history preserving the back buttons functionality
3201
 
                this.get('iframe').get('element').src = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
3202
 
            }
3203
 
            this.get('iframe').setStyle('visibility', '');
3204
 
            if (check) {
3205
 
                this._checkLoaded();
3206
 
            }            
3207
 
        },
3208
 
        /**
3209
 
        * @private
3210
 
        * @method _setMarkupType
3211
 
        * @param {String} action The action to take. Possible values are: css, default or semantic
3212
 
        * @description This method will turn on/off the useCSS execCommand.
3213
 
        */
3214
 
        _setMarkupType: function(action) {
3215
 
            switch (this.get('markup')) {
3216
 
                case 'css':
3217
 
                    this._setEditorStyle(true);
3218
 
                    break;
3219
 
                case 'default':
3220
 
                    this._setEditorStyle(false);
3221
 
                    break;
3222
 
                case 'semantic':
3223
 
                case 'xhtml':
3224
 
                    if (this._semantic[action]) {
3225
 
                        this._setEditorStyle(false);
3226
 
                    } else {
3227
 
                        this._setEditorStyle(true);
3228
 
                    }
3229
 
                    break;
3230
 
            }
3231
 
        },
3232
 
        /**
3233
 
        * Set the editor to use CSS instead of HTML
3234
 
        * @param {Booleen} stat True/False
3235
 
        */
3236
 
        _setEditorStyle: function(stat) {
3237
 
            try {
3238
 
                this._getDoc().execCommand('useCSS', false, !stat);
3239
 
            } catch (ex) {
3240
 
            }
3241
 
        },
3242
 
        /**
3243
 
        * @private
3244
 
        * @method _getSelectedElement
3245
 
        * @description This method will attempt to locate the element that was last interacted with, either via selection, location or event.
3246
 
        * @return {HTMLElement} The currently selected element.
3247
 
        */
3248
 
        _getSelectedElement: function() {
3249
 
            var doc = this._getDoc(),
3250
 
                range = null,
3251
 
                sel = null,
3252
 
                elm = null,
3253
 
                check = true;
3254
 
 
3255
 
            if (this.browser.ie) {
3256
 
                this.currentEvent = this._getWindow().event; //Event utility assumes window.event, so we need to reset it to this._getWindow().event;
3257
 
                range = this._getRange();
3258
 
                if (range) {
3259
 
                    elm = range.item ? range.item(0) : range.parentElement();
3260
 
                    if (this._hasSelection()) {
3261
 
                        //TODO
3262
 
                        //WTF.. Why can't I get an element reference here?!??!
3263
 
                    }
3264
 
                    if (elm === doc.body) {
3265
 
                        elm = null;
3266
 
                    }
3267
 
                }
3268
 
                if ((this.currentEvent !== null) && (this.currentEvent.keyCode === 0)) {
3269
 
                    elm = Event.getTarget(this.currentEvent);
3270
 
                }
3271
 
            } else {
3272
 
                sel = this._getSelection();
3273
 
                range = this._getRange();
3274
 
 
3275
 
                if (!sel || !range) {
3276
 
                    return null;
3277
 
                }
3278
 
                //TODO
3279
 
                if (!this._hasSelection() && this.browser.webkit3) {
3280
 
                    //check = false;
3281
 
                }
3282
 
                if (this.browser.gecko) {
3283
 
                    //Added in 2.6.0
3284
 
                    if (range.startContainer) {
3285
 
                        if (range.startContainer.nodeType === 3) {
3286
 
                            elm = range.startContainer.parentNode;
3287
 
                        } else if (range.startContainer.nodeType === 1) {
3288
 
                            elm = range.startContainer;
3289
 
                        }
3290
 
                        //Added in 2.7.0
3291
 
                        if (this.currentEvent) {
3292
 
                            var tar = Event.getTarget(this.currentEvent);
3293
 
                            if (!this._isElement(tar, 'html')) {
3294
 
                                if (elm !== tar) {
3295
 
                                    elm = tar;
3296
 
                                }
3297
 
                            }
3298
 
                        }
3299
 
                    }
3300
 
                }
3301
 
                
3302
 
                if (check) {
3303
 
                    if (sel.anchorNode && (sel.anchorNode.nodeType == 3)) {
3304
 
                        if (sel.anchorNode.parentNode) { //next check parentNode
3305
 
                            elm = sel.anchorNode.parentNode;
3306
 
                        }
3307
 
                        if (sel.anchorNode.nextSibling != sel.focusNode.nextSibling) {
3308
 
                            elm = sel.anchorNode.nextSibling;
3309
 
                        }
3310
 
                    }
3311
 
                    if (this._isElement(elm, 'br')) {
3312
 
                        elm = null;
3313
 
                    }
3314
 
                    if (!elm) {
3315
 
                        elm = range.commonAncestorContainer;
3316
 
                        if (!range.collapsed) {
3317
 
                            if (range.startContainer == range.endContainer) {
3318
 
                                if (range.startOffset - range.endOffset < 2) {
3319
 
                                    if (range.startContainer.hasChildNodes()) {
3320
 
                                        elm = range.startContainer.childNodes[range.startOffset];
3321
 
                                    }
3322
 
                                }
3323
 
                            }
3324
 
                        }
3325
 
                    }
3326
 
               }
3327
 
            }
3328
 
            
3329
 
            if (this.currentEvent !== null) {
3330
 
                try {
3331
 
                    switch (this.currentEvent.type) {
3332
 
                        case 'click':
3333
 
                        case 'mousedown':
3334
 
                        case 'mouseup':
3335
 
                            if (this.browser.webkit) {
3336
 
                                elm = Event.getTarget(this.currentEvent);
3337
 
                            }
3338
 
                            break;
3339
 
                        default:
3340
 
                            //Do nothing
3341
 
                            break;
3342
 
                    }
3343
 
                } catch (e) {
3344
 
                    YAHOO.log('Firefox 1.5 errors here: ' + e, 'error', 'SimpleEditor');
3345
 
                }
3346
 
            } else if ((this.currentElement && this.currentElement[0]) && (!this.browser.ie)) {
3347
 
                //TODO is this still needed?
3348
 
                //elm = this.currentElement[0];
3349
 
            }
3350
 
 
3351
 
 
3352
 
            if (this.browser.opera || this.browser.webkit) {
3353
 
                if (this.currentEvent && !elm) {
3354
 
                    elm = YAHOO.util.Event.getTarget(this.currentEvent);
3355
 
                }
3356
 
            }
3357
 
            if (!elm || !elm.tagName) {
3358
 
                elm = doc.body;
3359
 
            }
3360
 
            if (this._isElement(elm, 'html')) {
3361
 
                //Safari sometimes gives us the HTML node back..
3362
 
                elm = doc.body;
3363
 
            }
3364
 
            if (this._isElement(elm, 'body')) {
3365
 
                //make sure that body means this body not the parent..
3366
 
                elm = doc.body;
3367
 
            }
3368
 
            if (elm && !elm.parentNode) { //Not in document
3369
 
                elm = doc.body;
3370
 
            }
3371
 
            if (elm === undefined) {
3372
 
                elm = null;
3373
 
            }
3374
 
            return elm;
3375
 
        },
3376
 
        /**
3377
 
        * @private
3378
 
        * @method _getDomPath
3379
 
        * @description This method will attempt to build the DOM path from the currently selected element.
3380
 
        * @param HTMLElement el The element to start with, if not provided _getSelectedElement is used
3381
 
        * @return {Array} An array of node references that will create the DOM Path.
3382
 
        */
3383
 
        _getDomPath: function(el) {
3384
 
            if (!el) {
3385
 
                            el = this._getSelectedElement();
3386
 
            }
3387
 
                        var domPath = [];
3388
 
            while (el !== null) {
3389
 
                if (el.ownerDocument != this._getDoc()) {
3390
 
                    el = null;
3391
 
                    break;
3392
 
                }
3393
 
                //Check to see if we get el.nodeName and nodeType
3394
 
                if (el.nodeName && el.nodeType && (el.nodeType == 1)) {
3395
 
                    domPath[domPath.length] = el;
3396
 
                }
3397
 
 
3398
 
                if (this._isElement(el, 'body')) {
3399
 
                    break;
3400
 
                }
3401
 
 
3402
 
                el = el.parentNode;
3403
 
            }
3404
 
            if (domPath.length === 0) {
3405
 
                if (this._getDoc() && this._getDoc().body) {
3406
 
                    domPath[0] = this._getDoc().body;
3407
 
                }
3408
 
            }
3409
 
            return domPath.reverse();
3410
 
        },
3411
 
        /**
3412
 
        * @private
3413
 
        * @method _writeDomPath
3414
 
        * @description Write the current DOM path out to the dompath container below the editor.
3415
 
        */
3416
 
        _writeDomPath: function() { 
3417
 
            var path = this._getDomPath(),
3418
 
                pathArr = [],
3419
 
                classPath = '',
3420
 
                pathStr = '';
3421
 
 
3422
 
            for (var i = 0; i < path.length; i++) {
3423
 
                var tag = path[i].tagName.toLowerCase();
3424
 
                if ((tag == 'ol') && (path[i].type)) {
3425
 
                    tag += ':' + path[i].type;
3426
 
                }
3427
 
                if (Dom.hasClass(path[i], 'yui-tag')) {
3428
 
                    tag = path[i].getAttribute('tag');
3429
 
                }
3430
 
                if ((this.get('markup') == 'semantic') || (this.get('markup') == 'xhtml')) {
3431
 
                    switch (tag) {
3432
 
                        case 'b': tag = 'strong'; break;
3433
 
                        case 'i': tag = 'em'; break;
3434
 
                    }
3435
 
                }
3436
 
                if (!Dom.hasClass(path[i], 'yui-non')) {
3437
 
                    if (Dom.hasClass(path[i], 'yui-tag')) {
3438
 
                        pathStr = tag;
3439
 
                    } else {
3440
 
                        classPath = ((path[i].className !== '') ? '.' + path[i].className.replace(/ /g, '.') : '');
3441
 
                        if ((classPath.indexOf('yui') != -1) || (classPath.toLowerCase().indexOf('apple-style-span') != -1)) {
3442
 
                            classPath = '';
3443
 
                        }
3444
 
                        pathStr = tag + ((path[i].id) ? '#' + path[i].id : '') + classPath;
3445
 
                    }
3446
 
                    switch (tag) {
3447
 
                        case 'body':
3448
 
                            pathStr = 'body';
3449
 
                            break;
3450
 
                        case 'a':
3451
 
                            if (path[i].getAttribute('href', 2)) {
3452
 
                                pathStr += ':' + path[i].getAttribute('href', 2).replace('mailto:', '').replace('http:/'+'/', '').replace('https:/'+'/', ''); //May need to add others here ftp
3453
 
                            }
3454
 
                            break;
3455
 
                        case 'img':
3456
 
                            var h = path[i].height;
3457
 
                            var w = path[i].width;
3458
 
                            if (path[i].style.height) {
3459
 
                                h = parseInt(path[i].style.height, 10);
3460
 
                            }
3461
 
                            if (path[i].style.width) {
3462
 
                                w = parseInt(path[i].style.width, 10);
3463
 
                            }
3464
 
                            pathStr += '(' + w + 'x' + h + ')';
3465
 
                        break;
3466
 
                    }
3467
 
 
3468
 
                    if (pathStr.length > 10) {
3469
 
                        pathStr = '<span title="' + pathStr + '">' + pathStr.substring(0, 10) + '...' + '</span>';
3470
 
                    } else {
3471
 
                        pathStr = '<span title="' + pathStr + '">' + pathStr + '</span>';
3472
 
                    }
3473
 
                    pathArr[pathArr.length] = pathStr;
3474
 
                }
3475
 
            }
3476
 
            var str = pathArr.join(' ' + this.SEP_DOMPATH + ' ');
3477
 
            //Prevent flickering
3478
 
            if (this.dompath.innerHTML != str) {
3479
 
                this.dompath.innerHTML = str;
3480
 
            }
3481
 
        },
3482
 
        /**
3483
 
        * @private
3484
 
        * @method _fixNodes
3485
 
        * @description Fix href and imgs as well as remove invalid HTML.
3486
 
        */
3487
 
        _fixNodes: function() {
3488
 
            var doc = this._getDoc(),
3489
 
                els = [];
3490
 
 
3491
 
            for (var v in this.invalidHTML) {
3492
 
                if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
3493
 
                    if (v.toLowerCase() != 'span') {
3494
 
                        var tags = doc.body.getElementsByTagName(v);
3495
 
                        if (tags.length) {
3496
 
                            for (var i = 0; i < tags.length; i++) {
3497
 
                                els.push(tags[i]);
3498
 
                            }
3499
 
                        }
3500
 
                    }
3501
 
                }
3502
 
            }
3503
 
            for (var h = 0; h < els.length; h++) {
3504
 
                if (els[h].parentNode) {
3505
 
                    if (Lang.isObject(this.invalidHTML[els[h].tagName.toLowerCase()]) && this.invalidHTML[els[h].tagName.toLowerCase()].keepContents) {
3506
 
                        this._swapEl(els[h], 'span', function(el) {
3507
 
                            el.className = 'yui-non';
3508
 
                        });
3509
 
                    } else {
3510
 
                        els[h].parentNode.removeChild(els[h]);
3511
 
                    }
3512
 
                }
3513
 
            }
3514
 
            var imgs = this._getDoc().getElementsByTagName('img');
3515
 
            Dom.addClass(imgs, 'yui-img');   
3516
 
        },
3517
 
        /**
3518
 
        * @private
3519
 
        * @method _isNonEditable
3520
 
        * @param Event ev The Dom event being checked
3521
 
        * @description Method is called at the beginning of all event handlers to check if this element or a parent element has the class yui-noedit (this.CLASS_NOEDIT) applied.
3522
 
        * If it does, then this method will stop the event and return true. The event handlers will then return false and stop the nodeChange from occuring. This method will also
3523
 
        * disable and enable the Editor's toolbar based on the noedit state.
3524
 
        * @return Boolean
3525
 
        */
3526
 
        _isNonEditable: function(ev) {
3527
 
            if (this.get('allowNoEdit')) {
3528
 
                var el = Event.getTarget(ev);
3529
 
                if (this._isElement(el, 'html')) {
3530
 
                    el = null;
3531
 
                }
3532
 
                var path = this._getDomPath(el);
3533
 
                for (var i = (path.length - 1); i > -1; i--) {
3534
 
                    if (Dom.hasClass(path[i], this.CLASS_NOEDIT)) {
3535
 
                        //if (this.toolbar.get('disabled') === false) {
3536
 
                        //    this.toolbar.set('disabled', true);
3537
 
                        //}
3538
 
                        try {
3539
 
                             this._getDoc().execCommand('enableObjectResizing', false, 'false');
3540
 
                        } catch (e) {}
3541
 
                        this.nodeChange();
3542
 
                        Event.stopEvent(ev);
3543
 
                        YAHOO.log('CLASS_NOEDIT found in DOM Path, stopping event', 'info', 'SimpleEditor');
3544
 
                        return true;
3545
 
                    }
3546
 
                }
3547
 
                //if (this.toolbar.get('disabled') === true) {
3548
 
                    //Should only happen once..
3549
 
                    //this.toolbar.set('disabled', false);
3550
 
                    try {
3551
 
                         this._getDoc().execCommand('enableObjectResizing', false, 'true');
3552
 
                    } catch (e2) {}
3553
 
                //}
3554
 
            }
3555
 
            return false;
3556
 
        },
3557
 
        /**
3558
 
        * @private
3559
 
        * @method _setCurrentEvent
3560
 
        * @param {Event} ev The event to cache
3561
 
        * @description Sets the current event property
3562
 
        */
3563
 
        _setCurrentEvent: function(ev) {
3564
 
            this.currentEvent = ev;
3565
 
        },
3566
 
        /**
3567
 
        * @private
3568
 
        * @method _handleClick
3569
 
        * @param {Event} ev The event we are working on.
3570
 
        * @description Handles all click events inside the iFrame document.
3571
 
        */
3572
 
        _handleClick: function(ev) {
3573
 
            var ret = this.fireEvent('beforeEditorClick', { type: 'beforeEditorClick', target: this, ev: ev });
3574
 
            if (ret === false) {
3575
 
                return false;
3576
 
            }
3577
 
            if (this._isNonEditable(ev)) {
3578
 
                return false;
3579
 
            }
3580
 
            this._setCurrentEvent(ev);
3581
 
            if (this.currentWindow) {
3582
 
                this.closeWindow();
3583
 
            }
3584
 
            if (this.currentWindow) {
3585
 
                this.closeWindow();
3586
 
            }
3587
 
            if (this.browser.webkit) {
3588
 
                var tar =Event.getTarget(ev);
3589
 
                if (this._isElement(tar, 'a') || this._isElement(tar.parentNode, 'a')) {
3590
 
                    Event.stopEvent(ev);
3591
 
                    this.nodeChange();
3592
 
                }
3593
 
            } else {
3594
 
                this.nodeChange();
3595
 
            }
3596
 
            this.fireEvent('editorClick', { type: 'editorClick', target: this, ev: ev });
3597
 
        },
3598
 
        /**
3599
 
        * @private
3600
 
        * @method _handleMouseUp
3601
 
        * @param {Event} ev The event we are working on.
3602
 
        * @description Handles all mouseup events inside the iFrame document.
3603
 
        */
3604
 
        _handleMouseUp: function(ev) {
3605
 
            var ret = this.fireEvent('beforeEditorMouseUp', { type: 'beforeEditorMouseUp', target: this, ev: ev });
3606
 
            if (ret === false) {
3607
 
                return false;
3608
 
            }
3609
 
            if (this._isNonEditable(ev)) {
3610
 
                return false;
3611
 
            }
3612
 
            //Don't set current event for mouseup.
3613
 
            //It get's fired after a menu is closed and gives up a bogus event to work with
3614
 
            //this._setCurrentEvent(ev);
3615
 
            var self = this;
3616
 
            if (this.browser.opera) {
3617
 
                /*
3618
 
                * @knownissue Opera appears to stop the MouseDown, Click and DoubleClick events on an image inside of a document with designMode on..
3619
 
                * @browser Opera
3620
 
                * @description This work around traps the MouseUp event and sets a timer to check if another MouseUp event fires in so many seconds. If another event is fired, they we internally fire the DoubleClick event.
3621
 
                */
3622
 
                var sel = Event.getTarget(ev);
3623
 
                if (this._isElement(sel, 'img')) {
3624
 
                    this.nodeChange();
3625
 
                    if (this.operaEvent) {
3626
 
                        clearTimeout(this.operaEvent);
3627
 
                        this.operaEvent = null;
3628
 
                        this._handleDoubleClick(ev);
3629
 
                    } else {
3630
 
                        this.operaEvent = window.setTimeout(function() {
3631
 
                            self.operaEvent = false;
3632
 
                        }, 700);
3633
 
                    }
3634
 
                }
3635
 
            }
3636
 
            //This will stop Safari from selecting the entire document if you select all the text in the editor
3637
 
            if (this.browser.webkit || this.browser.opera) {
3638
 
                if (this.browser.webkit) {
3639
 
                    Event.stopEvent(ev);
3640
 
                }
3641
 
            }
3642
 
            this.nodeChange();
3643
 
            this.fireEvent('editorMouseUp', { type: 'editorMouseUp', target: this, ev: ev });
3644
 
        },
3645
 
        /**
3646
 
        * @private
3647
 
        * @method _handleMouseDown
3648
 
        * @param {Event} ev The event we are working on.
3649
 
        * @description Handles all mousedown events inside the iFrame document.
3650
 
        */
3651
 
        _handleMouseDown: function(ev) {
3652
 
            var ret = this.fireEvent('beforeEditorMouseDown', { type: 'beforeEditorMouseDown', target: this, ev: ev });
3653
 
            if (ret === false) {
3654
 
                return false;
3655
 
            }
3656
 
            if (this._isNonEditable(ev)) {
3657
 
                return false;
3658
 
            }
3659
 
            this._setCurrentEvent(ev);
3660
 
            var sel = Event.getTarget(ev);
3661
 
            if (this.browser.webkit && this._hasSelection()) {
3662
 
                var _sel = this._getSelection();
3663
 
                if (!this.browser.webkit3) {
3664
 
                    _sel.collapse(true);
3665
 
                } else {
3666
 
                    _sel.collapseToStart();
3667
 
                }
3668
 
            }
3669
 
            if (this.browser.webkit && this._lastImage) {
3670
 
                Dom.removeClass(this._lastImage, 'selected');
3671
 
                this._lastImage = null;
3672
 
            }
3673
 
            if (this._isElement(sel, 'img') || this._isElement(sel, 'a')) {
3674
 
                if (this.browser.webkit) {
3675
 
                    Event.stopEvent(ev);
3676
 
                    if (this._isElement(sel, 'img')) {
3677
 
                        Dom.addClass(sel, 'selected');
3678
 
                        this._lastImage = sel;
3679
 
                    }
3680
 
                }
3681
 
                if (this.currentWindow) {
3682
 
                    this.closeWindow();
3683
 
                }
3684
 
                this.nodeChange();
3685
 
            }
3686
 
            this.fireEvent('editorMouseDown', { type: 'editorMouseDown', target: this, ev: ev });
3687
 
        },
3688
 
        /**
3689
 
        * @private
3690
 
        * @method _handleDoubleClick
3691
 
        * @param {Event} ev The event we are working on.
3692
 
        * @description Handles all doubleclick events inside the iFrame document.
3693
 
        */
3694
 
        _handleDoubleClick: function(ev) {
3695
 
            var ret = this.fireEvent('beforeEditorDoubleClick', { type: 'beforeEditorDoubleClick', target: this, ev: ev });
3696
 
            if (ret === false) {
3697
 
                return false;
3698
 
            }
3699
 
            if (this._isNonEditable(ev)) {
3700
 
                return false;
3701
 
            }
3702
 
            this._setCurrentEvent(ev);
3703
 
            var sel = Event.getTarget(ev);
3704
 
            if (this._isElement(sel, 'img')) {
3705
 
                this.currentElement[0] = sel;
3706
 
                this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
3707
 
                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
3708
 
            } else if (this._hasParent(sel, 'a')) { //Handle elements inside an a
3709
 
                this.currentElement[0] = this._hasParent(sel, 'a');
3710
 
                this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
3711
 
                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
3712
 
            }
3713
 
            this.nodeChange();
3714
 
            this.fireEvent('editorDoubleClick', { type: 'editorDoubleClick', target: this, ev: ev });
3715
 
        },
3716
 
        /**
3717
 
        * @private
3718
 
        * @method _handleKeyUp
3719
 
        * @param {Event} ev The event we are working on.
3720
 
        * @description Handles all keyup events inside the iFrame document.
3721
 
        */
3722
 
        _handleKeyUp: function(ev) {
3723
 
            var ret = this.fireEvent('beforeEditorKeyUp', { type: 'beforeEditorKeyUp', target: this, ev: ev });
3724
 
            if (ret === false) {
3725
 
                return false;
3726
 
            }
3727
 
            if (this._isNonEditable(ev)) {
3728
 
                return false;
3729
 
            }
3730
 
            this._setCurrentEvent(ev);
3731
 
            switch (ev.keyCode) {
3732
 
                case this._keyMap.SELECT_ALL.key:
3733
 
                    if (this._checkKey(this._keyMap.SELECT_ALL, ev)) {
3734
 
                        this.nodeChange();
3735
 
                    }
3736
 
                    break;
3737
 
                case 32: //Space Bar
3738
 
                case 35: //End
3739
 
                case 36: //Home
3740
 
                case 37: //Left Arrow
3741
 
                case 38: //Up Arrow
3742
 
                case 39: //Right Arrow
3743
 
                case 40: //Down Arrow
3744
 
                case 46: //Forward Delete
3745
 
                case 8: //Delete
3746
 
                case this._keyMap.CLOSE_WINDOW.key: //W key if window is open
3747
 
                    if ((ev.keyCode == this._keyMap.CLOSE_WINDOW.key) && this.currentWindow) {
3748
 
                        if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) {
3749
 
                            this.closeWindow();
3750
 
                        }
3751
 
                    } else {
3752
 
                        if (!this.browser.ie) {
3753
 
                            if (this._nodeChangeTimer) {
3754
 
                                clearTimeout(this._nodeChangeTimer);
3755
 
                            }
3756
 
                            var self = this;
3757
 
                            this._nodeChangeTimer = setTimeout(function() {
3758
 
                                self._nodeChangeTimer = null;
3759
 
                                self.nodeChange.call(self);
3760
 
                            }, 100);
3761
 
                        } else {
3762
 
                            this.nodeChange();
3763
 
                        }
3764
 
                        this.editorDirty = true;
3765
 
                    }
3766
 
                    break;
3767
 
            }
3768
 
            this.fireEvent('editorKeyUp', { type: 'editorKeyUp', target: this, ev: ev });
3769
 
            this._storeUndo();
3770
 
        },
3771
 
        /**
3772
 
        * @private
3773
 
        * @method _handleKeyPress
3774
 
        * @param {Event} ev The event we are working on.
3775
 
        * @description Handles all keypress events inside the iFrame document.
3776
 
        */
3777
 
        _handleKeyPress: function(ev) {
3778
 
            var ret = this.fireEvent('beforeEditorKeyPress', { type: 'beforeEditorKeyPress', target: this, ev: ev });
3779
 
            if (ret === false) {
3780
 
                return false;
3781
 
            }
3782
 
 
3783
 
            if (this.get('allowNoEdit')) {
3784
 
                //if (ev && ev.keyCode && ((ev.keyCode == 46) || ev.keyCode == 63272)) {
3785
 
                if (ev && ev.keyCode && (ev.keyCode == 63272)) {
3786
 
                    //Forward delete key
3787
 
                    YAHOO.log('allowNoEdit is set, forward delete key has been disabled', 'warn', 'SimpleEditor');
3788
 
                    Event.stopEvent(ev);
3789
 
                }
3790
 
            }
3791
 
            if (this._isNonEditable(ev)) {
3792
 
                return false;
3793
 
            }
3794
 
            this._setCurrentEvent(ev);
3795
 
            if (this.browser.opera) {
3796
 
                if (ev.keyCode === 13) {
3797
 
                    var tar = this._getSelectedElement();
3798
 
                    if (!this._isElement(tar, 'li')) {
3799
 
                        this.execCommand('inserthtml', '<br>');
3800
 
                        Event.stopEvent(ev);
3801
 
                    }
3802
 
                }
3803
 
            }
3804
 
            if (this.browser.webkit) {
3805
 
                if (!this.browser.webkit3) {
3806
 
                    if (ev.keyCode && (ev.keyCode == 122) && (ev.metaKey)) {
3807
 
                        //This is CMD + z (for undo)
3808
 
                        if (this._hasParent(this._getSelectedElement(), 'li')) {
3809
 
                            YAHOO.log('We are in an LI and we found CMD + z, stopping the event', 'warn', 'SimpleEditor');
3810
 
                            Event.stopEvent(ev);
3811
 
                        }
3812
 
                    }
3813
 
                }
3814
 
                this._listFix(ev);
3815
 
            }
3816
 
            this.fireEvent('editorKeyPress', { type: 'editorKeyPress', target: this, ev: ev });
3817
 
        },
3818
 
        /**
3819
 
        * @private
3820
 
        * @method _handleKeyDown
3821
 
        * @param {Event} ev The event we are working on.
3822
 
        * @description Handles all keydown events inside the iFrame document.
3823
 
        */
3824
 
        _handleKeyDown: function(ev) {
3825
 
            var ret = this.fireEvent('beforeEditorKeyDown', { type: 'beforeEditorKeyDown', target: this, ev: ev });
3826
 
            if (ret === false) {
3827
 
                return false;
3828
 
            }
3829
 
            var tar = null, _range = null;
3830
 
            if (this._isNonEditable(ev)) {
3831
 
                return false;
3832
 
            }
3833
 
            this._setCurrentEvent(ev);
3834
 
            if (this.currentWindow) {
3835
 
                this.closeWindow();
3836
 
            }
3837
 
            if (this.currentWindow) {
3838
 
                this.closeWindow();
3839
 
            }
3840
 
            var doExec = false,
3841
 
                action = null,
3842
 
                value = null,
3843
 
                exec = false;
3844
 
 
3845
 
            //YAHOO.log('keyCode: ' + ev.keyCode, 'info', 'SimpleEditor');
3846
 
 
3847
 
            switch (ev.keyCode) {
3848
 
                case this._keyMap.FOCUS_TOOLBAR.key:
3849
 
                    if (this._checkKey(this._keyMap.FOCUS_TOOLBAR, ev)) {
3850
 
                        var h = this.toolbar.getElementsByTagName('h2')[0];
3851
 
                        if (h && h.firstChild) {
3852
 
                            h.firstChild.focus();
3853
 
                        }
3854
 
                    } else if (this._checkKey(this._keyMap.FOCUS_AFTER, ev)) {
3855
 
                        //Focus After Element - Esc
3856
 
                        this.afterElement.focus();
3857
 
                    }
3858
 
                    Event.stopEvent(ev);
3859
 
                    doExec = false;
3860
 
                    break;
3861
 
                //case 76: //L
3862
 
                case this._keyMap.CREATE_LINK.key: //L
3863
 
                    if (this._hasSelection()) {
3864
 
                        if (this._checkKey(this._keyMap.CREATE_LINK, ev)) {
3865
 
                            var makeLink = true;
3866
 
                            if (this.get('limitCommands')) {
3867
 
                                if (!this.toolbar.getButtonByValue('createlink')) {
3868
 
                                    YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'SimpleEditor');
3869
 
                                    makeLink = false;
3870
 
                                }
3871
 
                            }
3872
 
                            if (makeLink) {
3873
 
                                this.execCommand('createlink', '');
3874
 
                                this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
3875
 
                                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
3876
 
                                doExec = false;
3877
 
                            }
3878
 
                        }
3879
 
                    }
3880
 
                    break;
3881
 
                //case 90: //Z
3882
 
                case this._keyMap.UNDO.key:
3883
 
                case this._keyMap.REDO.key:
3884
 
                    if (this._checkKey(this._keyMap.REDO, ev)) {
3885
 
                        action = 'redo';
3886
 
                        doExec = true;
3887
 
                    } else if (this._checkKey(this._keyMap.UNDO, ev)) {
3888
 
                        action = 'undo';
3889
 
                        doExec = true;
3890
 
                    }
3891
 
                    break;
3892
 
                //case 66: //B
3893
 
                case this._keyMap.BOLD.key:
3894
 
                    if (this._checkKey(this._keyMap.BOLD, ev)) {
3895
 
                        action = 'bold';
3896
 
                        doExec = true;
3897
 
                    }
3898
 
                    break;
3899
 
                case this._keyMap.FONT_SIZE_UP.key:
3900
 
                case this._keyMap.FONT_SIZE_DOWN.key:
3901
 
                    var uk = false, dk = false;
3902
 
                    if (this._checkKey(this._keyMap.FONT_SIZE_UP, ev)) {
3903
 
                        uk = true;
3904
 
                    }
3905
 
                    if (this._checkKey(this._keyMap.FONT_SIZE_DOWN, ev)) {
3906
 
                        dk = true;
3907
 
                    }
3908
 
                    if (uk || dk) {
3909
 
                        var fs_button = this.toolbar.getButtonByValue('fontsize'),
3910
 
                            label = parseInt(fs_button.get('label'), 10),
3911
 
                            newValue = (label + 1);
3912
 
 
3913
 
                        if (dk) {
3914
 
                            newValue = (label - 1);
3915
 
                        }
3916
 
 
3917
 
                        action = 'fontsize';
3918
 
                        value = newValue + 'px';
3919
 
                        doExec = true;
3920
 
                    }
3921
 
                    break;
3922
 
                //case 73: //I
3923
 
                case this._keyMap.ITALIC.key:
3924
 
                    if (this._checkKey(this._keyMap.ITALIC, ev)) {
3925
 
                        action = 'italic';
3926
 
                        doExec = true;
3927
 
                    }
3928
 
                    break;
3929
 
                //case 85: //U
3930
 
                case this._keyMap.UNDERLINE.key:
3931
 
                    if (this._checkKey(this._keyMap.UNDERLINE, ev)) {
3932
 
                        action = 'underline';
3933
 
                        doExec = true;
3934
 
                    }
3935
 
                    break;
3936
 
                case 9:
3937
 
                    if (this.browser.ie) {
3938
 
                        //Insert a tab in Internet Explorer
3939
 
                        _range = this._getRange();
3940
 
                        tar = this._getSelectedElement();
3941
 
                        if (!this._isElement(tar, 'li')) {
3942
 
                            if (_range) {
3943
 
                                _range.pasteHTML('&nbsp;&nbsp;&nbsp;&nbsp;');
3944
 
                                _range.collapse(false);
3945
 
                                _range.select();
3946
 
                            }
3947
 
                            Event.stopEvent(ev);
3948
 
                        }
3949
 
                    }
3950
 
                    //Firefox 3 code
3951
 
                    if (this.browser.gecko > 1.8) {
3952
 
                        tar = this._getSelectedElement();
3953
 
                        if (this._isElement(tar, 'li')) {
3954
 
                            if (ev.shiftKey) {
3955
 
                                this._getDoc().execCommand('outdent', null, '');
3956
 
                            } else {
3957
 
                                this._getDoc().execCommand('indent', null, '');
3958
 
                            }
3959
 
                            
3960
 
                        } else if (!this._hasSelection()) {
3961
 
                            this.execCommand('inserthtml', '&nbsp;&nbsp;&nbsp;&nbsp;');
3962
 
                        }
3963
 
                        Event.stopEvent(ev);
3964
 
                    }
3965
 
                    break;
3966
 
                case 13:
3967
 
                    var p = null, i = 0;
3968
 
                    if (this.get('ptags') && !ev.shiftKey) {
3969
 
                        if (this.browser.gecko) {
3970
 
                            tar = this._getSelectedElement();
3971
 
                            if (!this._hasParent(tar, 'li')) {
3972
 
                                if (this._hasParent(tar, 'p')) {
3973
 
                                    p = this._getDoc().createElement('p');
3974
 
                                    p.innerHTML = '&nbsp;';
3975
 
                                    Dom.insertAfter(p, tar);
3976
 
                                    this._selectNode(p.firstChild);
3977
 
                                } else if (this._isElement(tar, 'body')) {
3978
 
                                    this.execCommand('insertparagraph', null);
3979
 
                                    var ps = this._getDoc().body.getElementsByTagName('p');
3980
 
                                    for (i = 0; i < ps.length; i++) {
3981
 
                                        if (ps[i].getAttribute('_moz_dirty') !== null) {
3982
 
                                            p = this._getDoc().createElement('p');
3983
 
                                            p.innerHTML = '&nbsp;';
3984
 
                                            Dom.insertAfter(p, ps[i]);
3985
 
                                            this._selectNode(p.firstChild);
3986
 
                                            ps[i].removeAttribute('_moz_dirty');
3987
 
                                        }
3988
 
                                    }
3989
 
                                } else {
3990
 
                                    YAHOO.log('Something went wrong with paragraphs, please file a bug!!', 'error', 'SimpleEditor');
3991
 
                                    doExec = true;
3992
 
                                    action = 'insertparagraph';
3993
 
                                }
3994
 
                                Event.stopEvent(ev);
3995
 
                            }
3996
 
                        }
3997
 
                        if (this.browser.webkit) {
3998
 
                            tar = this._getSelectedElement();
3999
 
                            if (!this._hasParent(tar, 'li')) {
4000
 
                                this.execCommand('insertparagraph', null);
4001
 
                                var divs = this._getDoc().body.getElementsByTagName('div');
4002
 
                                for (i = 0; i < divs.length; i++) {
4003
 
                                    if (!Dom.hasClass(divs[i], 'yui-wk-div')) {
4004
 
                                        Dom.addClass(divs[i], 'yui-wk-p');
4005
 
                                    }
4006
 
                                }
4007
 
                                Event.stopEvent(ev);
4008
 
                            }
4009
 
                        }
4010
 
                    } else {
4011
 
                        if (this.browser.webkit) {
4012
 
                            tar = this._getSelectedElement();
4013
 
                            if (!this._hasParent(tar, 'li')) {
4014
 
                                this.execCommand('inserthtml', '<var id="yui-br"></var>');
4015
 
                                var holder = this._getDoc().getElementById('yui-br'),
4016
 
                                    br = this._getDoc().createElement('br'),
4017
 
                                    caret = this._getDoc().createElement('span');
4018
 
 
4019
 
                                holder.parentNode.replaceChild(br, holder);
4020
 
                                caret.className = 'yui-non';
4021
 
                                caret.innerHTML = '&nbsp;';
4022
 
                                Dom.insertAfter(caret, br);
4023
 
                                this._selectNode(caret);
4024
 
                                Event.stopEvent(ev);
4025
 
                            }
4026
 
                        }
4027
 
                        if (this.browser.ie) {
4028
 
                            YAHOO.log('Stopping P tags', 'info', 'SimpleEditor');
4029
 
                            //Insert a <br> instead of a <p></p> in Internet Explorer
4030
 
                            _range = this._getRange();
4031
 
                            tar = this._getSelectedElement();
4032
 
                            if (!this._isElement(tar, 'li')) {
4033
 
                                if (_range) {
4034
 
                                    _range.pasteHTML('<br>');
4035
 
                                    _range.collapse(false);
4036
 
                                    _range.select();
4037
 
                                }
4038
 
                                Event.stopEvent(ev);
4039
 
                            }
4040
 
                        }
4041
 
                    }
4042
 
                    break;
4043
 
            }
4044
 
            if (this.browser.ie) {
4045
 
                this._listFix(ev);
4046
 
            }
4047
 
            if (doExec && action) {
4048
 
                this.execCommand(action, value);
4049
 
                Event.stopEvent(ev);
4050
 
                this.nodeChange();
4051
 
            }
4052
 
            this.fireEvent('editorKeyDown', { type: 'editorKeyDown', target: this, ev: ev });
4053
 
        },
4054
 
        /**
4055
 
        * @private
4056
 
        * @method _listFix
4057
 
        * @param {Event} ev The event we are working on.
4058
 
        * @description Handles the Enter key, Tab Key and Shift + Tab keys for List Items.
4059
 
        */
4060
 
        _listFix: function(ev) {
4061
 
            //YAHOO.log('Lists Fix (' + ev.keyCode + ')', 'info', 'SimpleEditor');
4062
 
            var testLi = null, par = null, preContent = false, range = null;
4063
 
            //Enter Key
4064
 
            if (this.browser.webkit) {
4065
 
                if (ev.keyCode && (ev.keyCode == 13)) {
4066
 
                    if (this._hasParent(this._getSelectedElement(), 'li')) {
4067
 
                        var tar = this._hasParent(this._getSelectedElement(), 'li');
4068
 
                        if (tar.previousSibling) {
4069
 
                            if (tar.firstChild && (tar.firstChild.length == 1)) {
4070
 
                                this._selectNode(tar);
4071
 
                            }
4072
 
                        }
4073
 
                    }
4074
 
                }
4075
 
            }
4076
 
            //Shift + Tab Key
4077
 
            if (ev.keyCode && ((!this.browser.webkit3 && (ev.keyCode == 25)) || ((this.browser.webkit3 || !this.browser.webkit) && ((ev.keyCode == 9) && ev.shiftKey)))) {
4078
 
                testLi = this._getSelectedElement();
4079
 
                if (this._hasParent(testLi, 'li')) {
4080
 
                    testLi = this._hasParent(testLi, 'li');
4081
 
                    YAHOO.log('We have a SHIFT tab in an LI, reverse it..', 'info', 'SimpleEditor');
4082
 
                    if (this._hasParent(testLi, 'ul') || this._hasParent(testLi, 'ol')) {
4083
 
                        YAHOO.log('We have a double parent, move up a level', 'info', 'SimpleEditor');
4084
 
                        par = this._hasParent(testLi, 'ul');
4085
 
                        if (!par) {
4086
 
                            par = this._hasParent(testLi, 'ol');
4087
 
                        }
4088
 
                        //YAHOO.log(par.previousSibling + ' :: ' + par.previousSibling.innerHTML);
4089
 
                        if (this._isElement(par.previousSibling, 'li')) {
4090
 
                            par.removeChild(testLi);
4091
 
                            par.parentNode.insertBefore(testLi, par.nextSibling);
4092
 
                            if (this.browser.ie) {
4093
 
                                range = this._getDoc().body.createTextRange();
4094
 
                                range.moveToElementText(testLi);
4095
 
                                range.collapse(false);
4096
 
                                range.select();
4097
 
                            }
4098
 
                            if (this.browser.webkit) {
4099
 
                                this._selectNode(testLi.firstChild);
4100
 
                            }
4101
 
                            Event.stopEvent(ev);
4102
 
                        }
4103
 
                    }
4104
 
                }
4105
 
            }
4106
 
            //Tab Key
4107
 
            if (ev.keyCode && ((ev.keyCode == 9) && (!ev.shiftKey))) {
4108
 
                YAHOO.log('List Fix - Tab', 'info', 'SimpleEditor');
4109
 
                var preLi = this._getSelectedElement();
4110
 
                if (this._hasParent(preLi, 'li')) {
4111
 
                    preContent = this._hasParent(preLi, 'li').innerHTML;
4112
 
                }
4113
 
                //YAHOO.log('preLI: ' + preLi.tagName + ' :: ' + preLi.innerHTML);
4114
 
                if (this.browser.webkit) {
4115
 
                    this._getDoc().execCommand('inserttext', false, '\t');
4116
 
                }
4117
 
                testLi = this._getSelectedElement();
4118
 
                if (this._hasParent(testLi, 'li')) {
4119
 
                    YAHOO.log('We have a tab in an LI', 'info', 'SimpleEditor');
4120
 
                    par = this._hasParent(testLi, 'li');
4121
 
                    YAHOO.log('parLI: ' + par.tagName + ' :: ' + par.innerHTML);
4122
 
                    var newUl = this._getDoc().createElement(par.parentNode.tagName.toLowerCase());
4123
 
                    if (this.browser.webkit) {
4124
 
                        var span = Dom.getElementsByClassName('Apple-tab-span', 'span', par);
4125
 
                        //Remove the span element that Safari puts in
4126
 
                        if (span[0]) {
4127
 
                            par.removeChild(span[0]);
4128
 
                            par.innerHTML = Lang.trim(par.innerHTML);
4129
 
                            //Put the HTML from the LI into this new LI
4130
 
                            if (preContent) {
4131
 
                                par.innerHTML = '<span class="yui-non">' + preContent + '</span>&nbsp;';
4132
 
                            } else {
4133
 
                                par.innerHTML = '<span class="yui-non">&nbsp;</span>&nbsp;';
4134
 
                            }
4135
 
                        }
4136
 
                    } else {
4137
 
                        if (preContent) {
4138
 
                            par.innerHTML = preContent + '&nbsp;';
4139
 
                        } else {
4140
 
                            par.innerHTML = '&nbsp;';
4141
 
                        }
4142
 
                    }
4143
 
 
4144
 
                    par.parentNode.replaceChild(newUl, par);
4145
 
                    newUl.appendChild(par);
4146
 
                    if (this.browser.webkit) {
4147
 
                        this._getSelection().setBaseAndExtent(par.firstChild, 1, par.firstChild, par.firstChild.innerText.length);
4148
 
                        if (!this.browser.webkit3) {
4149
 
                            par.parentNode.parentNode.style.display = 'list-item';
4150
 
                            setTimeout(function() {
4151
 
                                par.parentNode.parentNode.style.display = 'block';
4152
 
                            }, 1);
4153
 
                        }
4154
 
                    } else if (this.browser.ie) {
4155
 
                        range = this._getDoc().body.createTextRange();
4156
 
                        range.moveToElementText(par);
4157
 
                        range.collapse(false);
4158
 
                        range.select();
4159
 
                    } else {
4160
 
                        this._selectNode(par);
4161
 
                    }
4162
 
                    Event.stopEvent(ev);
4163
 
                }
4164
 
                if (this.browser.webkit) {
4165
 
                    Event.stopEvent(ev);
4166
 
                }
4167
 
                this.nodeChange();
4168
 
            }
4169
 
        },
4170
 
        /**
4171
 
        * @method nodeChange
4172
 
        * @param {Boolean} force Optional paramenter to skip the threshold counter
4173
 
        * @description Handles setting up the toolbar buttons, getting the Dom path, fixing nodes.
4174
 
        */
4175
 
        nodeChange: function(force) {
4176
 
            var NCself = this;
4177
 
            this._storeUndo();
4178
 
            if (this.get('nodeChangeDelay')) {
4179
 
                window.setTimeout(function() {
4180
 
                    NCself._nodeChange.apply(NCself, arguments);
4181
 
                }, 0);
4182
 
            } else {
4183
 
                this._nodeChange();
4184
 
            }
4185
 
        },
4186
 
        /**
4187
 
        * @private
4188
 
        * @method _nodeChange
4189
 
        * @param {Boolean} force Optional paramenter to skip the threshold counter
4190
 
        * @description Fired from nodeChange in a setTimeout.
4191
 
        */
4192
 
        _nodeChange: function(force) {
4193
 
            var threshold = parseInt(this.get('nodeChangeThreshold'), 10),
4194
 
                thisNodeChange = Math.round(new Date().getTime() / 1000),
4195
 
                self = this;
4196
 
 
4197
 
            if (force === true) {
4198
 
                this._lastNodeChange = 0;
4199
 
            }
4200
 
            
4201
 
            if ((this._lastNodeChange + threshold) < thisNodeChange) {
4202
 
                if (this._fixNodesTimer === null) {
4203
 
                    this._fixNodesTimer = window.setTimeout(function() {
4204
 
                        self._fixNodes.call(self);
4205
 
                        self._fixNodesTimer = null;
4206
 
                    }, 0);
4207
 
                }
4208
 
            }
4209
 
            this._lastNodeChange = thisNodeChange;
4210
 
            if (this.currentEvent) {
4211
 
                try {
4212
 
                    this._lastNodeChangeEvent = this.currentEvent.type;
4213
 
                } catch (e) {}
4214
 
            }
4215
 
 
4216
 
            var beforeNodeChange = this.fireEvent('beforeNodeChange', { type: 'beforeNodeChange', target: this });
4217
 
            if (beforeNodeChange === false) {
4218
 
                return false;
4219
 
            }
4220
 
            if (this.get('dompath')) {
4221
 
                window.setTimeout(function() {
4222
 
                    self._writeDomPath.call(self);
4223
 
                }, 0);
4224
 
            }
4225
 
            //Check to see if we are disabled before continuing
4226
 
            if (!this.get('disabled')) {
4227
 
                if (this.STOP_NODE_CHANGE) {
4228
 
                    //Reset this var for next action
4229
 
                    this.STOP_NODE_CHANGE = false;
4230
 
                    return false;
4231
 
                } else {
4232
 
                    var sel = this._getSelection(),
4233
 
                        range = this._getRange(),
4234
 
                        el = this._getSelectedElement(),
4235
 
                        fn_button = this.toolbar.getButtonByValue('fontname'),
4236
 
                        fs_button = this.toolbar.getButtonByValue('fontsize'),
4237
 
                        undo_button = this.toolbar.getButtonByValue('undo'),
4238
 
                        redo_button = this.toolbar.getButtonByValue('redo');
4239
 
 
4240
 
                    //Handle updating the toolbar with active buttons
4241
 
                    var _ex = {};
4242
 
                    if (this._lastButton) {
4243
 
                        _ex[this._lastButton.id] = true;
4244
 
                        //this._lastButton = null;
4245
 
                    }
4246
 
                    if (!this._isElement(el, 'body')) {
4247
 
                        if (fn_button) {
4248
 
                            _ex[fn_button.get('id')] = true;
4249
 
                        }
4250
 
                        if (fs_button) {
4251
 
                            _ex[fs_button.get('id')] = true;
4252
 
                        }
4253
 
                    }
4254
 
                    if (redo_button) {
4255
 
                        delete _ex[redo_button.get('id')];
4256
 
                    }
4257
 
                    this.toolbar.resetAllButtons(_ex);
4258
 
 
4259
 
                    //Handle disabled buttons
4260
 
                    for (var d = 0; d < this._disabled.length; d++) {
4261
 
                        var _button = this.toolbar.getButtonByValue(this._disabled[d]);
4262
 
                        if (_button && _button.get) {
4263
 
                            if (this._lastButton && (_button.get('id') === this._lastButton.id)) {
4264
 
                                //Skip
4265
 
                            } else {
4266
 
                                if (!this._hasSelection() && !this.get('insert')) {
4267
 
                                    switch (this._disabled[d]) {
4268
 
                                        case 'fontname':
4269
 
                                        case 'fontsize':
4270
 
                                            break;
4271
 
                                        default:
4272
 
                                            //No Selection - disable
4273
 
                                            this.toolbar.disableButton(_button);
4274
 
                                    }
4275
 
                                } else {
4276
 
                                    if (!this._alwaysDisabled[this._disabled[d]]) {
4277
 
                                        this.toolbar.enableButton(_button);
4278
 
                                    }
4279
 
                                }
4280
 
                                if (!this._alwaysEnabled[this._disabled[d]]) {
4281
 
                                    this.toolbar.deselectButton(_button);
4282
 
                                }
4283
 
                            }
4284
 
                        }
4285
 
                    }
4286
 
                    var path = this._getDomPath();
4287
 
                    var tag = null, cmd = null;
4288
 
                    for (var i = 0; i < path.length; i++) {
4289
 
                        tag = path[i].tagName.toLowerCase();
4290
 
                        if (path[i].getAttribute('tag')) {
4291
 
                            tag = path[i].getAttribute('tag').toLowerCase();
4292
 
                        }
4293
 
                        cmd = this._tag2cmd[tag];
4294
 
                        if (cmd === undefined) {
4295
 
                            cmd = [];
4296
 
                        }
4297
 
                        if (!Lang.isArray(cmd)) {
4298
 
                            cmd = [cmd];
4299
 
                        }
4300
 
 
4301
 
                        //Bold and Italic styles
4302
 
                        if (path[i].style.fontWeight.toLowerCase() == 'bold') {
4303
 
                            cmd[cmd.length] = 'bold';
4304
 
                        }
4305
 
                        if (path[i].style.fontStyle.toLowerCase() == 'italic') {
4306
 
                            cmd[cmd.length] = 'italic';
4307
 
                        }
4308
 
                        if (path[i].style.textDecoration.toLowerCase() == 'underline') {
4309
 
                            cmd[cmd.length] = 'underline';
4310
 
                        }
4311
 
                        if (path[i].style.textDecoration.toLowerCase() == 'line-through') {
4312
 
                            cmd[cmd.length] = 'strikethrough';
4313
 
                        }
4314
 
                        if (cmd.length > 0) {
4315
 
                            for (var j = 0; j < cmd.length; j++) {
4316
 
                                this.toolbar.selectButton(cmd[j]);
4317
 
                                this.toolbar.enableButton(cmd[j]);
4318
 
                            }
4319
 
                        }
4320
 
                        //Handle Alignment
4321
 
                        switch (path[i].style.textAlign.toLowerCase()) {
4322
 
                            case 'left':
4323
 
                            case 'right':
4324
 
                            case 'center':
4325
 
                            case 'justify':
4326
 
                                var alignType = path[i].style.textAlign.toLowerCase();
4327
 
                                if (path[i].style.textAlign.toLowerCase() == 'justify') {
4328
 
                                    alignType = 'full';
4329
 
                                }
4330
 
                                this.toolbar.selectButton('justify' + alignType);
4331
 
                                this.toolbar.enableButton('justify' + alignType);
4332
 
                                break;
4333
 
                        }
4334
 
                    }
4335
 
                    //After for loop
4336
 
 
4337
 
                    //Reset Font Family and Size to the inital configs
4338
 
                    if (fn_button) {
4339
 
                        var family = fn_button._configs.label._initialConfig.value;
4340
 
                        fn_button.set('label', '<span class="yui-toolbar-fontname-' + this._cleanClassName(family) + '">' + family + '</span>');
4341
 
                        this._updateMenuChecked('fontname', family);
4342
 
                    }
4343
 
 
4344
 
                    if (fs_button) {
4345
 
                        fs_button.set('label', fs_button._configs.label._initialConfig.value);
4346
 
                    }
4347
 
 
4348
 
                    var hd_button = this.toolbar.getButtonByValue('heading');
4349
 
                    if (hd_button) {
4350
 
                        hd_button.set('label', hd_button._configs.label._initialConfig.value);
4351
 
                        this._updateMenuChecked('heading', 'none');
4352
 
                    }
4353
 
                    var img_button = this.toolbar.getButtonByValue('insertimage');
4354
 
                    if (img_button && this.currentWindow && (this.currentWindow.name == 'insertimage')) {
4355
 
                        this.toolbar.disableButton(img_button);
4356
 
                    }
4357
 
                    if (this._lastButton && this._lastButton.isSelected) {
4358
 
                        this.toolbar.deselectButton(this._lastButton.id);
4359
 
                    }
4360
 
                    this._undoNodeChange();
4361
 
                }
4362
 
            }
4363
 
 
4364
 
            this.fireEvent('afterNodeChange', { type: 'afterNodeChange', target: this });
4365
 
        },
4366
 
        /**
4367
 
        * @private
4368
 
        * @method _updateMenuChecked
4369
 
        * @param {Object} button The command identifier of the button you want to check
4370
 
        * @param {String} value The value of the menu item you want to check
4371
 
        * @param {<a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>} The Toolbar instance the button belongs to (defaults to this.toolbar) 
4372
 
        * @description Gets the menu from a button instance, if the menu is not rendered it will render it. It will then search the menu for the specified value, unchecking all other items and checking the specified on.
4373
 
        */
4374
 
        _updateMenuChecked: function(button, value, tbar) {
4375
 
            if (!tbar) {
4376
 
                tbar = this.toolbar;
4377
 
            }
4378
 
            var _button = tbar.getButtonByValue(button);
4379
 
            _button.checkValue(value);
4380
 
        },
4381
 
        /**
4382
 
        * @private
4383
 
        * @method _handleToolbarClick
4384
 
        * @param {Event} ev The event that triggered the button click
4385
 
        * @description This is an event handler attached to the Toolbar's buttonClick event. It will fire execCommand with the command identifier from the Toolbar Button.
4386
 
        */
4387
 
        _handleToolbarClick: function(ev) {
4388
 
            var value = '';
4389
 
            var str = '';
4390
 
            var cmd = ev.button.value;
4391
 
            if (ev.button.menucmd) {
4392
 
                value = cmd;
4393
 
                cmd = ev.button.menucmd;
4394
 
            }
4395
 
            this._lastButton = ev.button;
4396
 
            if (this.STOP_EXEC_COMMAND) {
4397
 
                YAHOO.log('execCommand skipped because we found the STOP_EXEC_COMMAND flag set to true', 'warn', 'SimpleEditor');
4398
 
                YAHOO.log('NOEXEC::execCommand::(' + cmd + '), (' + value + ')', 'warn', 'SimpleEditor');
4399
 
                this.STOP_EXEC_COMMAND = false;
4400
 
                return false;
4401
 
            } else {
4402
 
                this.execCommand(cmd, value);
4403
 
                if (!this.browser.webkit) {
4404
 
                     var Fself = this;
4405
 
                     setTimeout(function() {
4406
 
                         Fself.focus.call(Fself);
4407
 
                     }, 5);
4408
 
                 }
4409
 
            }
4410
 
            Event.stopEvent(ev);
4411
 
        },
4412
 
        /**
4413
 
        * @private
4414
 
        * @method _setupAfterElement
4415
 
        * @description Creates the accessibility h2 header and places it after the iframe in the Dom for navigation.
4416
 
        */
4417
 
        _setupAfterElement: function() {
4418
 
            if (!this.beforeElement) {
4419
 
                this.beforeElement = document.createElement('h2');
4420
 
                this.beforeElement.className = 'yui-editor-skipheader';
4421
 
                this.beforeElement.tabIndex = '-1';
4422
 
                this.beforeElement.innerHTML = this.STR_BEFORE_EDITOR;
4423
 
                this.get('element_cont').get('firstChild').insertBefore(this.beforeElement, this.toolbar.get('nextSibling'));
4424
 
            }
4425
 
            if (!this.afterElement) {
4426
 
                this.afterElement = document.createElement('h2');
4427
 
                this.afterElement.className = 'yui-editor-skipheader';
4428
 
                this.afterElement.tabIndex = '-1';
4429
 
                this.afterElement.innerHTML = this.STR_LEAVE_EDITOR;
4430
 
                this.get('element_cont').get('firstChild').appendChild(this.afterElement);
4431
 
            }
4432
 
        },
4433
 
        /**
4434
 
        * @private
4435
 
        * @method _disableEditor
4436
 
        * @param {Boolean} disabled Pass true to disable, false to enable
4437
 
        * @description Creates a mask to place over the Editor.
4438
 
        */
4439
 
        _disableEditor: function(disabled) {
4440
 
            if (disabled) {
4441
 
                this._removeEditorEvents();
4442
 
                if (!this._mask) {
4443
 
                    if (!!this.browser.ie) {
4444
 
                        this._setDesignMode('off');
4445
 
                    }
4446
 
                    if (this.toolbar) {
4447
 
                        this.toolbar.set('disabled', true);
4448
 
                    }
4449
 
                    this._mask = document.createElement('DIV');
4450
 
                    Dom.addClass(this._mask, 'yui-editor-masked');
4451
 
                    this.get('iframe').get('parentNode').appendChild(this._mask);
4452
 
                }
4453
 
            } else {
4454
 
                this._initEditorEvents();
4455
 
                if (this._mask) {
4456
 
                    this._mask.parentNode.removeChild(this._mask);
4457
 
                    this._mask = null;
4458
 
                    if (this.toolbar) {
4459
 
                        this.toolbar.set('disabled', false);
4460
 
                    }
4461
 
                    this._setDesignMode('on');
4462
 
                    this.focus();
4463
 
                    var self = this;
4464
 
                    window.setTimeout(function() {
4465
 
                        self.nodeChange.call(self);
4466
 
                    }, 100);
4467
 
                }
4468
 
            }
4469
 
        },
4470
 
        /**
4471
 
        * @property SEP_DOMPATH
4472
 
        * @description The value to place in between the Dom path items
4473
 
        * @type String
4474
 
        */
4475
 
        SEP_DOMPATH: '<',
4476
 
        /**
4477
 
        * @property STR_LEAVE_EDITOR
4478
 
        * @description The accessibility string for the element after the iFrame
4479
 
        * @type String
4480
 
        */
4481
 
        STR_LEAVE_EDITOR: 'You have left the Rich Text Editor.',
4482
 
        /**
4483
 
        * @property STR_BEFORE_EDITOR
4484
 
        * @description The accessibility string for the element before the iFrame
4485
 
        * @type String
4486
 
        */
4487
 
        STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Shift + Escape to place focus on the toolbar and navigate between options with your arrow keys. To exit this text editor use the Escape key and continue tabbing. <h4>Common formatting keyboard shortcuts:</h4><ul><li>Control Shift B sets text to bold</li> <li>Control Shift I sets text to italic</li> <li>Control Shift U underlines text</li> <li>Control Shift L adds an HTML link</li></ul>',
4488
 
        /**
4489
 
        * @property STR_TITLE
4490
 
        * @description The Title of the HTML document that is created in the iFrame
4491
 
        * @type String
4492
 
        */
4493
 
        STR_TITLE: 'Rich Text Area.',
4494
 
        /**
4495
 
        * @property STR_IMAGE_HERE
4496
 
        * @description The text to place in the URL textbox when using the blankimage.
4497
 
        * @type String
4498
 
        */
4499
 
        STR_IMAGE_HERE: 'Image URL Here',
4500
 
        /**
4501
 
        * @property STR_IMAGE_URL
4502
 
        * @description The label string for Image URL
4503
 
        * @type String
4504
 
        */
4505
 
        STR_IMAGE_URL: 'Image URL',        
4506
 
        /**
4507
 
        * @property STR_LINK_URL
4508
 
        * @description The label string for the Link URL.
4509
 
        * @type String
4510
 
        */
4511
 
        STR_LINK_URL: 'Link URL',
4512
 
        /**
4513
 
        * @protected
4514
 
        * @property STOP_EXEC_COMMAND
4515
 
        * @description Set to true when you want the default execCommand function to not process anything
4516
 
        * @type Boolean
4517
 
        */
4518
 
        STOP_EXEC_COMMAND: false,
4519
 
        /**
4520
 
        * @protected
4521
 
        * @property STOP_NODE_CHANGE
4522
 
        * @description Set to true when you want the default nodeChange function to not process anything
4523
 
        * @type Boolean
4524
 
        */
4525
 
        STOP_NODE_CHANGE: false,
4526
 
        /**
4527
 
        * @protected
4528
 
        * @property CLASS_NOEDIT
4529
 
        * @description CSS class applied to elements that are not editable.
4530
 
        * @type String
4531
 
        */
4532
 
        CLASS_NOEDIT: 'yui-noedit',
4533
 
        /**
4534
 
        * @protected
4535
 
        * @property CLASS_CONTAINER
4536
 
        * @description Default CSS class to apply to the editors container element
4537
 
        * @type String
4538
 
        */
4539
 
        CLASS_CONTAINER: 'yui-editor-container',
4540
 
        /**
4541
 
        * @protected
4542
 
        * @property CLASS_EDITABLE
4543
 
        * @description Default CSS class to apply to the editors iframe element
4544
 
        * @type String
4545
 
        */
4546
 
        CLASS_EDITABLE: 'yui-editor-editable',
4547
 
        /**
4548
 
        * @protected
4549
 
        * @property CLASS_EDITABLE_CONT
4550
 
        * @description Default CSS class to apply to the editors iframe's parent element
4551
 
        * @type String
4552
 
        */
4553
 
        CLASS_EDITABLE_CONT: 'yui-editor-editable-container',
4554
 
        /**
4555
 
        * @protected
4556
 
        * @property CLASS_PREFIX
4557
 
        * @description Default prefix for dynamically created class names
4558
 
        * @type String
4559
 
        */
4560
 
        CLASS_PREFIX: 'yui-editor',
4561
 
        /** 
4562
 
        * @property browser
4563
 
        * @description Standard browser detection
4564
 
        * @type Object
4565
 
        */
4566
 
        browser: function() {
4567
 
            var br = YAHOO.env.ua;
4568
 
            //Check for webkit3
4569
 
            if (br.webkit >= 420) {
4570
 
                br.webkit3 = br.webkit;
4571
 
            } else {
4572
 
                br.webkit3 = 0;
4573
 
            }
4574
 
            br.mac = false;
4575
 
            //Check for Mac
4576
 
            if (navigator.userAgent.indexOf('Macintosh') !== -1) {
4577
 
                br.mac = true;
4578
 
            }
4579
 
 
4580
 
            return br;
4581
 
        }(),
4582
 
        /** 
4583
 
        * @method init
4584
 
        * @description The Editor class' initialization method
4585
 
        */
4586
 
        init: function(p_oElement, p_oAttributes) {
4587
 
            YAHOO.log('init', 'info', 'SimpleEditor');
4588
 
 
4589
 
            if (!this._defaultToolbar) {
4590
 
                this._defaultToolbar = {
4591
 
                    collapse: true,
4592
 
                    titlebar: 'Text Editing Tools',
4593
 
                    draggable: false,
4594
 
                    buttons: [
4595
 
                        { group: 'fontstyle', label: 'Font Name and Size',
4596
 
                            buttons: [
4597
 
                                { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
4598
 
                                    menu: [
4599
 
                                        { text: 'Arial', checked: true },
4600
 
                                        { text: 'Arial Black' },
4601
 
                                        { text: 'Comic Sans MS' },
4602
 
                                        { text: 'Courier New' },
4603
 
                                        { text: 'Lucida Console' },
4604
 
                                        { text: 'Tahoma' },
4605
 
                                        { text: 'Times New Roman' },
4606
 
                                        { text: 'Trebuchet MS' },
4607
 
                                        { text: 'Verdana' }
4608
 
                                    ]
4609
 
                                },
4610
 
                                { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
4611
 
                            ]
4612
 
                        },
4613
 
                        { type: 'separator' },
4614
 
                        { group: 'textstyle', label: 'Font Style',
4615
 
                            buttons: [
4616
 
                                { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
4617
 
                                { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
4618
 
                                { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
4619
 
                                { type: 'push', label: 'Strike Through', value: 'strikethrough' },
4620
 
                                { type: 'separator' },
4621
 
                                { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
4622
 
                                { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }
4623
 
                                
4624
 
                            ]
4625
 
                        },
4626
 
                        { type: 'separator' },
4627
 
                        { group: 'indentlist', label: 'Lists',
4628
 
                            buttons: [
4629
 
                                { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
4630
 
                                { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
4631
 
                            ]
4632
 
                        },
4633
 
                        { type: 'separator' },
4634
 
                        { group: 'insertitem', label: 'Insert Item',
4635
 
                            buttons: [
4636
 
                                { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
4637
 
                                { type: 'push', label: 'Insert Image', value: 'insertimage' }
4638
 
                            ]
4639
 
                        }
4640
 
                    ]
4641
 
                };
4642
 
            }
4643
 
 
4644
 
            YAHOO.widget.SimpleEditor.superclass.init.call(this, p_oElement, p_oAttributes);
4645
 
            YAHOO.widget.EditorInfo._instances[this.get('id')] = this;
4646
 
 
4647
 
 
4648
 
            this.currentElement = [];
4649
 
            this.on('contentReady', function() {
4650
 
                this.DOMReady = true;
4651
 
                this.fireQueue();
4652
 
            }, this, true);
4653
 
 
4654
 
        },
4655
 
        /**
4656
 
        * @method initAttributes
4657
 
        * @description Initializes all of the configuration attributes used to create 
4658
 
        * the editor.
4659
 
        * @param {Object} attr Object literal specifying a set of 
4660
 
        * configuration attributes used to create the editor.
4661
 
        */
4662
 
        initAttributes: function(attr) {
4663
 
            YAHOO.widget.SimpleEditor.superclass.initAttributes.call(this, attr);
4664
 
            var self = this;
4665
 
 
4666
 
            /**
4667
 
            * @config nodeChangeDelay
4668
 
            * @description Do we wrap the nodeChange method in a timeout for performance, default: true.
4669
 
            * @default true
4670
 
            * @type Number
4671
 
            */
4672
 
            this.setAttributeConfig('nodeChangeDelay', {
4673
 
                value: ((attr.nodeChangeDelay === false) ? false : true)
4674
 
            });
4675
 
            /**
4676
 
            * @config maxUndo
4677
 
            * @description The max number of undo levels to store.
4678
 
            * @default 30
4679
 
            * @type Number
4680
 
            */
4681
 
            this.setAttributeConfig('maxUndo', {
4682
 
                writeOnce: true,
4683
 
                value: attr.maxUndo || 30
4684
 
            });
4685
 
 
4686
 
            /**
4687
 
            * @config ptags
4688
 
            * @description If true, the editor uses &lt;P&gt; tags instead of &lt;br&gt; tags. (Use Shift + Enter to get a &lt;br&gt;)
4689
 
            * @default false
4690
 
            * @type Boolean
4691
 
            */
4692
 
            this.setAttributeConfig('ptags', {
4693
 
                writeOnce: true,
4694
 
                value: attr.ptags || false
4695
 
            });
4696
 
            /**
4697
 
            * @config insert
4698
 
            * @description If true, selection is not required for: fontname, fontsize, forecolor, backcolor.
4699
 
            * @default false
4700
 
            * @type Boolean
4701
 
            */
4702
 
            this.setAttributeConfig('insert', {
4703
 
                writeOnce: true,
4704
 
                value: attr.insert || false,
4705
 
                method: function(insert) {
4706
 
                    if (insert) {
4707
 
                        var buttons = {
4708
 
                            fontname: true,
4709
 
                            fontsize: true,
4710
 
                            forecolor: true,
4711
 
                            backcolor: true
4712
 
                        };
4713
 
                        var tmp = this._defaultToolbar.buttons;
4714
 
                        for (var i = 0; i < tmp.length; i++) {
4715
 
                            if (tmp[i].buttons) {
4716
 
                                for (var a = 0; a < tmp[i].buttons.length; a++) {
4717
 
                                    if (tmp[i].buttons[a].value) {
4718
 
                                        if (buttons[tmp[i].buttons[a].value]) {
4719
 
                                            delete tmp[i].buttons[a].disabled;
4720
 
                                        }
4721
 
                                    }
4722
 
                                }
4723
 
                            }
4724
 
                        }
4725
 
                    }
4726
 
                }
4727
 
            });
4728
 
            /**
4729
 
            * @config container
4730
 
            * @description Used when dynamically creating the Editor from Javascript with no default textarea.
4731
 
            * We will create one and place it in this container. If no container is passed we will append to document.body.
4732
 
            * @default false
4733
 
            * @type HTMLElement
4734
 
            */
4735
 
            this.setAttributeConfig('container', {
4736
 
                writeOnce: true,
4737
 
                value: attr.container || false
4738
 
            });
4739
 
            /**
4740
 
            * @config plainText
4741
 
            * @description Process the inital textarea data as if it was plain text. Accounting for spaces, tabs and line feeds.
4742
 
            * @default false
4743
 
            * @type Boolean
4744
 
            */
4745
 
            this.setAttributeConfig('plainText', {
4746
 
                writeOnce: true,
4747
 
                value: attr.plainText || false
4748
 
            });
4749
 
            /**
4750
 
            * @private
4751
 
            * @config iframe
4752
 
            * @description Internal config for holding the iframe element.
4753
 
            * @default null
4754
 
            * @type HTMLElement
4755
 
            */
4756
 
            this.setAttributeConfig('iframe', {
4757
 
                value: null
4758
 
            });
4759
 
            /**
4760
 
            * @private
4761
 
            * @depreciated - No longer used, should use this.get('element')
4762
 
            * @config textarea
4763
 
            * @description Internal config for holding the textarea element (replaced with element).
4764
 
            * @default null
4765
 
            * @type HTMLElement
4766
 
            */
4767
 
            this.setAttributeConfig('textarea', {
4768
 
                value: null,
4769
 
                writeOnce: true
4770
 
            });
4771
 
            /**
4772
 
            * @config nodeChangeThreshold
4773
 
            * @description The number of seconds that need to be in between nodeChange processing
4774
 
            * @default 3
4775
 
            * @type Number
4776
 
            */            
4777
 
            this.setAttributeConfig('nodeChangeThreshold', {
4778
 
                value: attr.nodeChangeThreshold || 3,
4779
 
                validator: YAHOO.lang.isNumber
4780
 
            });
4781
 
            /**
4782
 
            * @config allowNoEdit
4783
 
            * @description Should the editor check for non-edit fields. It should be noted that this technique is not perfect. If the user does the right things, they will still be able to make changes.
4784
 
            * Such as highlighting an element below and above the content and hitting a toolbar button or a shortcut key.
4785
 
            * @default false
4786
 
            * @type Boolean
4787
 
            */            
4788
 
            this.setAttributeConfig('allowNoEdit', {
4789
 
                value: attr.allowNoEdit || false,
4790
 
                validator: YAHOO.lang.isBoolean
4791
 
            });
4792
 
            /**
4793
 
            * @config limitCommands
4794
 
            * @description Should the Editor limit the allowed execCommands to the ones available in the toolbar. If true, then execCommand and keyboard shortcuts will fail if they are not defined in the toolbar.
4795
 
            * @default false
4796
 
            * @type Boolean
4797
 
            */            
4798
 
            this.setAttributeConfig('limitCommands', {
4799
 
                value: attr.limitCommands || false,
4800
 
                validator: YAHOO.lang.isBoolean
4801
 
            });
4802
 
            /**
4803
 
            * @config element_cont
4804
 
            * @description Internal config for the editors container
4805
 
            * @default false
4806
 
            * @type HTMLElement
4807
 
            */
4808
 
            this.setAttributeConfig('element_cont', {
4809
 
                value: attr.element_cont
4810
 
            });
4811
 
            /**
4812
 
            * @private
4813
 
            * @config editor_wrapper
4814
 
            * @description The outter wrapper for the entire editor.
4815
 
            * @default null
4816
 
            * @type HTMLElement
4817
 
            */
4818
 
            this.setAttributeConfig('editor_wrapper', {
4819
 
                value: attr.editor_wrapper || null,
4820
 
                writeOnce: true
4821
 
            });
4822
 
            /**
4823
 
            * @attribute height
4824
 
            * @description The height of the editor iframe container, not including the toolbar..
4825
 
            * @default Best guessed size of the textarea, for best results use CSS to style the height of the textarea or pass it in as an argument
4826
 
            * @type String
4827
 
            */
4828
 
            this.setAttributeConfig('height', {
4829
 
                value: attr.height || Dom.getStyle(self.get('element'), 'height'),
4830
 
                method: function(height) {
4831
 
                    if (this._rendered) {
4832
 
                        //We have been rendered, change the height
4833
 
                        if (this.get('animate')) {
4834
 
                            var anim = new YAHOO.util.Anim(this.get('iframe').get('parentNode'), {
4835
 
                                height: {
4836
 
                                    to: parseInt(height, 10)
4837
 
                                }
4838
 
                            }, 0.5);
4839
 
                            anim.animate();
4840
 
                        } else {
4841
 
                            Dom.setStyle(this.get('iframe').get('parentNode'), 'height', height);
4842
 
                        }
4843
 
                    }
4844
 
                }
4845
 
            });
4846
 
            /**
4847
 
            * @config autoHeight
4848
 
            * @description Remove the scrollbars from the edit area and resize it to fit the content. It will not go any lower than the current config height.
4849
 
            * @default false
4850
 
            * @type Boolean || Number
4851
 
            */
4852
 
            this.setAttributeConfig('autoHeight', {
4853
 
                value: attr.autoHeight || false,
4854
 
                method: function(a) {
4855
 
                    if (a) {
4856
 
                        if (this.get('iframe')) {
4857
 
                            this.get('iframe').get('element').setAttribute('scrolling', 'no');
4858
 
                        }
4859
 
                        this.on('afterNodeChange', this._handleAutoHeight, this, true);
4860
 
                        this.on('editorKeyDown', this._handleAutoHeight, this, true);
4861
 
                        this.on('editorKeyPress', this._handleAutoHeight, this, true);
4862
 
                    } else {
4863
 
                        if (this.get('iframe')) {
4864
 
                            this.get('iframe').get('element').setAttribute('scrolling', 'auto');
4865
 
                        }
4866
 
                        this.unsubscribe('afterNodeChange', this._handleAutoHeight);
4867
 
                        this.unsubscribe('editorKeyDown', this._handleAutoHeight);
4868
 
                        this.unsubscribe('editorKeyPress', this._handleAutoHeight);
4869
 
                    }
4870
 
                }
4871
 
            });
4872
 
            /**
4873
 
            * @attribute width
4874
 
            * @description The width of the editor container.
4875
 
            * @default Best guessed size of the textarea, for best results use CSS to style the width of the textarea or pass it in as an argument
4876
 
            * @type String
4877
 
            */            
4878
 
            this.setAttributeConfig('width', {
4879
 
                value: attr.width || Dom.getStyle(this.get('element'), 'width'),
4880
 
                method: function(width) {
4881
 
                    if (this._rendered) {
4882
 
                        //We have been rendered, change the width
4883
 
                        if (this.get('animate')) {
4884
 
                            var anim = new YAHOO.util.Anim(this.get('element_cont').get('element'), {
4885
 
                                width: {
4886
 
                                    to: parseInt(width, 10)
4887
 
                                }
4888
 
                            }, 0.5);
4889
 
                            anim.animate();
4890
 
                        } else {
4891
 
                            this.get('element_cont').setStyle('width', width);
4892
 
                        }
4893
 
                    }
4894
 
                }
4895
 
            });
4896
 
                        
4897
 
            /**
4898
 
            * @attribute blankimage
4899
 
            * @description The URL for the image placeholder to put in when inserting an image.
4900
 
            * @default The yahooapis.com address for the current release + 'assets/blankimage.png'
4901
 
            * @type String
4902
 
            */            
4903
 
            this.setAttributeConfig('blankimage', {
4904
 
                value: attr.blankimage || this._getBlankImage()
4905
 
            });
4906
 
            /**
4907
 
            * @attribute css
4908
 
            * @description The Base CSS used to format the content of the editor
4909
 
            * @default <code><pre>html {
4910
 
                height: 95%;
4911
 
            }
4912
 
            body {
4913
 
                height: 100%;
4914
 
                padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;
4915
 
            }
4916
 
            a {
4917
 
                color: blue;
4918
 
                text-decoration: underline;
4919
 
                cursor: pointer;
4920
 
            }
4921
 
            .warning-localfile {
4922
 
                border-bottom: 1px dashed red !important;
4923
 
            }
4924
 
            .yui-busy {
4925
 
                cursor: wait !important;
4926
 
            }
4927
 
            img.selected { //Safari image selection
4928
 
                border: 2px dotted #808080;
4929
 
            }
4930
 
            img {
4931
 
                cursor: pointer !important;
4932
 
                border: none;
4933
 
            }
4934
 
            </pre></code>
4935
 
            * @type String
4936
 
            */            
4937
 
            this.setAttributeConfig('css', {
4938
 
                value: attr.css || this._defaultCSS,
4939
 
                writeOnce: true
4940
 
            });
4941
 
            /**
4942
 
            * @attribute html
4943
 
            * @description The default HTML to be written to the iframe document before the contents are loaded (Note that the DOCTYPE attr will be added at render item)
4944
 
            * @default This HTML requires a few things if you are to override:
4945
 
                <p><code>{TITLE}, {CSS}, {HIDDEN_CSS}, {EXTRA_CSS}</code> and <code>{CONTENT}</code> need to be there, they are passed to YAHOO.lang.substitute to be replace with other strings.<p>
4946
 
                <p><code>onload="document.body._rteLoaded = true;"</code> : the onload statement must be there or the editor will not finish loading.</p>
4947
 
                <code>
4948
 
                <pre>
4949
 
                &lt;html&gt;
4950
 
                    &lt;head&gt;
4951
 
                        &lt;title&gt;{TITLE}&lt;/title&gt;
4952
 
                        &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
4953
 
                        &lt;style&gt;
4954
 
                        {CSS}
4955
 
                        &lt;/style&gt;
4956
 
                        &lt;style&gt;
4957
 
                        {HIDDEN_CSS}
4958
 
                        &lt;/style&gt;
4959
 
                        &lt;style&gt;
4960
 
                        {EXTRA_CSS}
4961
 
                        &lt;/style&gt;
4962
 
                    &lt;/head&gt;
4963
 
                &lt;body onload="document.body._rteLoaded = true;"&gt;
4964
 
                {CONTENT}
4965
 
                &lt;/body&gt;
4966
 
                &lt;/html&gt;
4967
 
                </pre>
4968
 
                </code>
4969
 
            * @type String
4970
 
            */            
4971
 
            this.setAttributeConfig('html', {
4972
 
                value: attr.html || '<html><head><title>{TITLE}</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><base href="' + this._baseHREF + '"><style>{CSS}</style><style>{HIDDEN_CSS}</style><style>{EXTRA_CSS}</style></head><body onload="document.body._rteLoaded = true;">{CONTENT}</body></html>',
4973
 
                writeOnce: true
4974
 
            });
4975
 
 
4976
 
            /**
4977
 
            * @attribute extracss
4978
 
            * @description Extra user defined css to load after the default SimpleEditor CSS
4979
 
            * @default ''
4980
 
            * @type String
4981
 
            */            
4982
 
            this.setAttributeConfig('extracss', {
4983
 
                value: attr.extracss || '',
4984
 
                writeOnce: true
4985
 
            });
4986
 
 
4987
 
            /**
4988
 
            * @attribute handleSubmit
4989
 
            * @description Config handles if the editor will attach itself to the textareas parent form's submit handler.
4990
 
            If it is set to true, the editor will attempt to attach a submit listener to the textareas parent form.
4991
 
            Then it will trigger the editors save handler and place the new content back into the text area before the form is submitted.
4992
 
            * @default false
4993
 
            * @type Boolean
4994
 
            */            
4995
 
            this.setAttributeConfig('handleSubmit', {
4996
 
                value: attr.handleSubmit || false,
4997
 
                method: function(exec) {
4998
 
                    if (this.get('element').form) {
4999
 
                        if (!this._formButtons) {
5000
 
                            this._formButtons = [];
5001
 
                        }
5002
 
                        if (exec) {
5003
 
                            Event.on(this.get('element').form, 'submit', this._handleFormSubmit, this, true);
5004
 
                            var i = this.get('element').form.getElementsByTagName('input');
5005
 
                            for (var s = 0; s < i.length; s++) {
5006
 
                                var type = i[s].getAttribute('type');
5007
 
                                if (type && (type.toLowerCase() == 'submit')) {
5008
 
                                    Event.on(i[s], 'click', this._handleFormButtonClick, this, true);
5009
 
                                    this._formButtons[this._formButtons.length] = i[s];
5010
 
                                }
5011
 
                            }
5012
 
                        } else {
5013
 
                            Event.removeListener(this.get('element').form, 'submit', this._handleFormSubmit);
5014
 
                            if (this._formButtons) {
5015
 
                                Event.removeListener(this._formButtons, 'click', this._handleFormButtonClick);
5016
 
                            }
5017
 
                        }
5018
 
                    }
5019
 
                }
5020
 
            });
5021
 
            /**
5022
 
            * @attribute disabled
5023
 
            * @description This will toggle the editor's disabled state. When the editor is disabled, designMode is turned off and a mask is placed over the iframe so no interaction can take place.
5024
 
            All Toolbar buttons are also disabled so they cannot be used.
5025
 
            * @default false
5026
 
            * @type Boolean
5027
 
            */
5028
 
 
5029
 
            this.setAttributeConfig('disabled', {
5030
 
                value: false,
5031
 
                method: function(disabled) {
5032
 
                    if (this._rendered) {
5033
 
                        this._disableEditor(disabled);
5034
 
                    }
5035
 
                }
5036
 
            });
5037
 
            /**
5038
 
            * @config saveEl
5039
 
            * @description When save HTML is called, this element will be updated as well as the source of data.
5040
 
            * @default element
5041
 
            * @type HTMLElement
5042
 
            */
5043
 
            this.setAttributeConfig('saveEl', {
5044
 
                value: this.get('element')
5045
 
            });
5046
 
            /**
5047
 
            * @config toolbar_cont
5048
 
            * @description Internal config for the toolbars container
5049
 
            * @default false
5050
 
            * @type Boolean
5051
 
            */
5052
 
            this.setAttributeConfig('toolbar_cont', {
5053
 
                value: null,
5054
 
                writeOnce: true
5055
 
            });
5056
 
            /**
5057
 
            * @attribute toolbar
5058
 
            * @description The default toolbar config.
5059
 
            * @type Object
5060
 
            */            
5061
 
            this.setAttributeConfig('toolbar', {
5062
 
                value: attr.toolbar || this._defaultToolbar,
5063
 
                writeOnce: true,
5064
 
                method: function(toolbar) {
5065
 
                    if (!toolbar.buttonType) {
5066
 
                        toolbar.buttonType = this._defaultToolbar.buttonType;
5067
 
                    }
5068
 
                    this._defaultToolbar = toolbar;
5069
 
                }
5070
 
            });
5071
 
            /**
5072
 
            * @attribute animate
5073
 
            * @description Should the editor animate window movements
5074
 
            * @default false unless Animation is found, then true
5075
 
            * @type Boolean
5076
 
            */            
5077
 
            this.setAttributeConfig('animate', {
5078
 
                value: ((attr.animate) ? ((YAHOO.util.Anim) ? true : false) : false),
5079
 
                validator: function(value) {
5080
 
                    var ret = true;
5081
 
                    if (!YAHOO.util.Anim) {
5082
 
                        ret = false;
5083
 
                    }
5084
 
                    return ret;
5085
 
                }
5086
 
            });
5087
 
            /**
5088
 
            * @config panel
5089
 
            * @description A reference to the panel we are using for windows.
5090
 
            * @default false
5091
 
            * @type Boolean
5092
 
            */            
5093
 
            this.setAttributeConfig('panel', {
5094
 
                value: null,
5095
 
                writeOnce: true,
5096
 
                validator: function(value) {
5097
 
                    var ret = true;
5098
 
                    if (!YAHOO.widget.Overlay) {
5099
 
                        ret = false;
5100
 
                    }
5101
 
                    return ret;
5102
 
                }               
5103
 
            });
5104
 
            /**
5105
 
            * @attribute focusAtStart
5106
 
            * @description Should we focus the window when the content is ready?
5107
 
            * @default false
5108
 
            * @type Boolean
5109
 
            */            
5110
 
            this.setAttributeConfig('focusAtStart', {
5111
 
                value: attr.focusAtStart || false,
5112
 
                writeOnce: true,
5113
 
                method: function(fs) {
5114
 
                    if (fs) {
5115
 
                        this.on('editorContentLoaded', function() {
5116
 
                            var self = this;
5117
 
                            setTimeout(function() {
5118
 
                                self.focus.call(self);
5119
 
                                self.editorDirty = false;
5120
 
                            }, 400);
5121
 
                        }, this, true);
5122
 
                    }
5123
 
                }
5124
 
            });
5125
 
            /**
5126
 
            * @attribute dompath
5127
 
            * @description Toggle the display of the current Dom path below the editor
5128
 
            * @default false
5129
 
            * @type Boolean
5130
 
            */            
5131
 
            this.setAttributeConfig('dompath', {
5132
 
                value: attr.dompath || false,
5133
 
                method: function(dompath) {
5134
 
                    if (dompath && !this.dompath) {
5135
 
                        this.dompath = document.createElement('DIV');
5136
 
                        this.dompath.id = this.get('id') + '_dompath';
5137
 
                        Dom.addClass(this.dompath, 'dompath');
5138
 
                        this.get('element_cont').get('firstChild').appendChild(this.dompath);
5139
 
                        if (this.get('iframe')) {
5140
 
                            this._writeDomPath();
5141
 
                        }
5142
 
                    } else if (!dompath && this.dompath) {
5143
 
                        this.dompath.parentNode.removeChild(this.dompath);
5144
 
                        this.dompath = null;
5145
 
                    }
5146
 
                }
5147
 
            });
5148
 
            /**
5149
 
            * @attribute markup
5150
 
            * @description Should we try to adjust the markup for the following types: semantic, css, default or xhtml
5151
 
            * @default "semantic"
5152
 
            * @type String
5153
 
            */            
5154
 
            this.setAttributeConfig('markup', {
5155
 
                value: attr.markup || 'semantic',
5156
 
                validator: function(markup) {
5157
 
                    switch (markup.toLowerCase()) {
5158
 
                        case 'semantic':
5159
 
                        case 'css':
5160
 
                        case 'default':
5161
 
                        case 'xhtml':
5162
 
                        return true;
5163
 
                    }
5164
 
                    return false;
5165
 
                }
5166
 
            });
5167
 
            /**
5168
 
            * @attribute removeLineBreaks
5169
 
            * @description Should we remove linebreaks and extra spaces on cleanup
5170
 
            * @default false
5171
 
            * @type Boolean
5172
 
            */            
5173
 
            this.setAttributeConfig('removeLineBreaks', {
5174
 
                value: attr.removeLineBreaks || false,
5175
 
                validator: YAHOO.lang.isBoolean
5176
 
            });
5177
 
            
5178
 
            /**
5179
 
            * @config drag
5180
 
            * @description Set this config to make the Editor draggable, pass 'proxy' to make use YAHOO.util.DDProxy.
5181
 
            * @type {Boolean/String}
5182
 
            */
5183
 
            this.setAttributeConfig('drag', {
5184
 
                writeOnce: true,
5185
 
                value: attr.drag || false
5186
 
            });
5187
 
 
5188
 
            /**
5189
 
            * @config resize
5190
 
            * @description Set this to true to make the Editor Resizable with YAHOO.util.Resize. The default config is available: myEditor._resizeConfig
5191
 
            * Animation will be ignored while performing this resize to allow for the dynamic change in size of the toolbar.
5192
 
            * @type Boolean
5193
 
            */
5194
 
            this.setAttributeConfig('resize', {
5195
 
                writeOnce: true,
5196
 
                value: attr.resize || false
5197
 
            });
5198
 
 
5199
 
            /**
5200
 
            * @config filterWord
5201
 
            * @description Attempt to filter out MS Word HTML from the Editor's output.
5202
 
            * @type Boolean
5203
 
            */
5204
 
            this.setAttributeConfig('filterWord', {
5205
 
                value: attr.filterWord || false,
5206
 
                validator: YAHOO.lang.isBoolean
5207
 
            });
5208
 
 
5209
 
        },
5210
 
        /**
5211
 
        * @private
5212
 
        * @method _getBlankImage
5213
 
        * @description Retrieves the full url of the image to use as the blank image.
5214
 
        * @return {String} The URL to the blank image
5215
 
        */
5216
 
        _getBlankImage: function() {
5217
 
            if (!this.DOMReady) {
5218
 
                this._queue[this._queue.length] = ['_getBlankImage', arguments];
5219
 
                return '';
5220
 
            }
5221
 
            var img = '';
5222
 
            if (!this._blankImageLoaded) {
5223
 
                if (YAHOO.widget.EditorInfo.blankImage) {
5224
 
                    this.set('blankimage', YAHOO.widget.EditorInfo.blankImage);
5225
 
                    this._blankImageLoaded = true;
5226
 
                } else {
5227
 
                    var div = document.createElement('div');
5228
 
                    div.style.position = 'absolute';
5229
 
                    div.style.top = '-9999px';
5230
 
                    div.style.left = '-9999px';
5231
 
                    div.className = this.CLASS_PREFIX + '-blankimage';
5232
 
                    document.body.appendChild(div);
5233
 
                    img = YAHOO.util.Dom.getStyle(div, 'background-image');
5234
 
                    img = img.replace('url(', '').replace(')', '').replace(/"/g, '');
5235
 
                    //Adobe AIR Code
5236
 
                    img = img.replace('app:/', '');             
5237
 
                    this.set('blankimage', img);
5238
 
                    this._blankImageLoaded = true;
5239
 
                    div.parentNode.removeChild(div);
5240
 
                    YAHOO.widget.EditorInfo.blankImage = img;
5241
 
                }
5242
 
            } else {
5243
 
                img = this.get('blankimage');
5244
 
            }
5245
 
            return img;
5246
 
        },
5247
 
        /**
5248
 
        * @private
5249
 
        * @method _handleAutoHeight
5250
 
        * @description Handles resizing the editor's height based on the content
5251
 
        */
5252
 
        _handleAutoHeight: function() {
5253
 
            var doc = this._getDoc(),
5254
 
                body = doc.body,
5255
 
                docEl = doc.documentElement;
5256
 
 
5257
 
            var height = parseInt(Dom.getStyle(this.get('editor_wrapper'), 'height'), 10);
5258
 
            var newHeight = body.scrollHeight;
5259
 
            if (this.browser.webkit) {
5260
 
                newHeight = docEl.scrollHeight;
5261
 
            }
5262
 
            if (newHeight < parseInt(this.get('height'), 10)) {
5263
 
                newHeight = parseInt(this.get('height'), 10);
5264
 
            }
5265
 
            if ((height != newHeight) && (newHeight >= parseInt(this.get('height'), 10))) {   
5266
 
                var anim = this.get('animate');
5267
 
                this.set('animate', false);
5268
 
                this.set('height', newHeight + 'px');
5269
 
                this.set('animate', anim);
5270
 
                if (this.browser.ie) {
5271
 
                    //Internet Explorer needs this
5272
 
                    this.get('iframe').setStyle('height', '99%');
5273
 
                    this.get('iframe').setStyle('zoom', '1');
5274
 
                    var self = this;
5275
 
                    window.setTimeout(function() {
5276
 
                        self.get('iframe').setStyle('height', '100%');
5277
 
                    }, 1);
5278
 
                }
5279
 
            }
5280
 
        },
5281
 
        /**
5282
 
        * @private
5283
 
        * @property _formButtons
5284
 
        * @description Array of buttons that are in the Editor's parent form (for handleSubmit)
5285
 
        * @type Array
5286
 
        */
5287
 
        _formButtons: null,
5288
 
        /**
5289
 
        * @private
5290
 
        * @property _formButtonClicked
5291
 
        * @description The form button that was clicked to submit the form.
5292
 
        * @type HTMLElement
5293
 
        */
5294
 
        _formButtonClicked: null,
5295
 
        /**
5296
 
        * @private
5297
 
        * @method _handleFormButtonClick
5298
 
        * @description The click listener assigned to each submit button in the Editor's parent form.
5299
 
        * @param {Event} ev The click event
5300
 
        */
5301
 
        _handleFormButtonClick: function(ev) {
5302
 
            var tar = Event.getTarget(ev);
5303
 
            this._formButtonClicked = tar;
5304
 
        },
5305
 
        /**
5306
 
        * @private
5307
 
        * @method _handleFormSubmit
5308
 
        * @description Handles the form submission.
5309
 
        * @param {Object} ev The Form Submit Event
5310
 
        */
5311
 
        _handleFormSubmit: function(ev) {
5312
 
            this.saveHTML();
5313
 
 
5314
 
            var form = this.get('element').form,
5315
 
                tar = this._formButtonClicked || false;
5316
 
 
5317
 
            Event.removeListener(form, 'submit', this._handleFormSubmit);
5318
 
            if (YAHOO.env.ua.ie) {
5319
 
                //form.fireEvent("onsubmit");
5320
 
                if (tar && !tar.disabled) {
5321
 
                    tar.click();
5322
 
                }
5323
 
            } else {  // Gecko, Opera, and Safari
5324
 
                if (tar && !tar.disabled) {
5325
 
                    tar.click();
5326
 
                }
5327
 
                var oEvent = document.createEvent("HTMLEvents");
5328
 
                oEvent.initEvent("submit", true, true);
5329
 
                form.dispatchEvent(oEvent);
5330
 
                if (YAHOO.env.ua.webkit) {
5331
 
                    if (YAHOO.lang.isFunction(form.submit)) {
5332
 
                        form.submit();
5333
 
                    }
5334
 
                }
5335
 
            }
5336
 
            //2.6.0
5337
 
            //Removed this, not need since removing Safari 2.x
5338
 
            //Event.stopEvent(ev);
5339
 
        },
5340
 
        /**
5341
 
        * @private
5342
 
        * @method _handleFontSize
5343
 
        * @description Handles the font size button in the toolbar.
5344
 
        * @param {Object} o Object returned from Toolbar's buttonClick Event
5345
 
        */
5346
 
        _handleFontSize: function(o) {
5347
 
            var button = this.toolbar.getButtonById(o.button.id);
5348
 
            var value = button.get('label') + 'px';
5349
 
            this.execCommand('fontsize', value);
5350
 
            return false;
5351
 
        },
5352
 
        /**
5353
 
        * @private
5354
 
        * @description Handles the colorpicker buttons in the toolbar.
5355
 
        * @param {Object} o Object returned from Toolbar's buttonClick Event
5356
 
        */
5357
 
        _handleColorPicker: function(o) {
5358
 
            var cmd = o.button;
5359
 
            var value = '#' + o.color;
5360
 
            if ((cmd == 'forecolor') || (cmd == 'backcolor')) {
5361
 
                this.execCommand(cmd, value);
5362
 
            }
5363
 
        },
5364
 
        /**
5365
 
        * @private
5366
 
        * @method _handleAlign
5367
 
        * @description Handles the alignment buttons in the toolbar.
5368
 
        * @param {Object} o Object returned from Toolbar's buttonClick Event
5369
 
        */
5370
 
        _handleAlign: function(o) {
5371
 
            var cmd = null;
5372
 
            for (var i = 0; i < o.button.menu.length; i++) {
5373
 
                if (o.button.menu[i].value == o.button.value) {
5374
 
                    cmd = o.button.menu[i].value;
5375
 
                }
5376
 
            }
5377
 
            var value = this._getSelection();
5378
 
 
5379
 
            this.execCommand(cmd, value);
5380
 
            return false;
5381
 
        },
5382
 
        /**
5383
 
        * @private
5384
 
        * @method _handleAfterNodeChange
5385
 
        * @description Fires after a nodeChange happens to setup the things that where reset on the node change (button state).
5386
 
        */
5387
 
        _handleAfterNodeChange: function() {
5388
 
            var path = this._getDomPath(),
5389
 
                elm = null,
5390
 
                family = null,
5391
 
                fontsize = null,
5392
 
                validFont = false,
5393
 
                fn_button = this.toolbar.getButtonByValue('fontname'),
5394
 
                fs_button = this.toolbar.getButtonByValue('fontsize'),
5395
 
                hd_button = this.toolbar.getButtonByValue('heading');
5396
 
 
5397
 
            for (var i = 0; i < path.length; i++) {
5398
 
                elm = path[i];
5399
 
 
5400
 
                var tag = elm.tagName.toLowerCase();
5401
 
 
5402
 
 
5403
 
                if (elm.getAttribute('tag')) {
5404
 
                    tag = elm.getAttribute('tag');
5405
 
                }
5406
 
 
5407
 
                family = elm.getAttribute('face');
5408
 
                if (Dom.getStyle(elm, 'font-family')) {
5409
 
                    family = Dom.getStyle(elm, 'font-family');
5410
 
                    //Adobe AIR Code
5411
 
                    family = family.replace(/'/g, '');                    
5412
 
                }
5413
 
 
5414
 
                if (tag.substring(0, 1) == 'h') {
5415
 
                    if (hd_button) {
5416
 
                        for (var h = 0; h < hd_button._configs.menu.value.length; h++) {
5417
 
                            if (hd_button._configs.menu.value[h].value.toLowerCase() == tag) {
5418
 
                                hd_button.set('label', hd_button._configs.menu.value[h].text);
5419
 
                            }
5420
 
                        }
5421
 
                        this._updateMenuChecked('heading', tag);
5422
 
                    }
5423
 
                }
5424
 
            }
5425
 
 
5426
 
            if (fn_button) {
5427
 
                for (var b = 0; b < fn_button._configs.menu.value.length; b++) {
5428
 
                    if (family && fn_button._configs.menu.value[b].text.toLowerCase() == family.toLowerCase()) {
5429
 
                        validFont = true;
5430
 
                        family = fn_button._configs.menu.value[b].text; //Put the proper menu name in the button
5431
 
                    }
5432
 
                }
5433
 
                if (!validFont) {
5434
 
                    family = fn_button._configs.label._initialConfig.value;
5435
 
                }
5436
 
                var familyLabel = '<span class="yui-toolbar-fontname-' + this._cleanClassName(family) + '">' + family + '</span>';
5437
 
                if (fn_button.get('label') != familyLabel) {
5438
 
                    fn_button.set('label', familyLabel);
5439
 
                    this._updateMenuChecked('fontname', family);
5440
 
                }
5441
 
            }
5442
 
 
5443
 
            if (fs_button) {
5444
 
                fontsize = parseInt(Dom.getStyle(elm, 'fontSize'), 10);
5445
 
                if ((fontsize === null) || isNaN(fontsize)) {
5446
 
                    fontsize = fs_button._configs.label._initialConfig.value;
5447
 
                }
5448
 
                fs_button.set('label', ''+fontsize);
5449
 
            }
5450
 
            
5451
 
            if (!this._isElement(elm, 'body') && !this._isElement(elm, 'img')) {
5452
 
                this.toolbar.enableButton(fn_button);
5453
 
                this.toolbar.enableButton(fs_button);
5454
 
                this.toolbar.enableButton('forecolor');
5455
 
                this.toolbar.enableButton('backcolor');
5456
 
            }
5457
 
            if (this._isElement(elm, 'img')) {
5458
 
                if (YAHOO.widget.Overlay) {
5459
 
                    this.toolbar.enableButton('createlink');
5460
 
                }
5461
 
            }
5462
 
            if (this._hasParent(elm, 'blockquote')) {
5463
 
                this.toolbar.selectButton('indent');
5464
 
                this.toolbar.disableButton('indent');
5465
 
                this.toolbar.enableButton('outdent');
5466
 
            }
5467
 
            if (this._hasParent(elm, 'ol') || this._hasParent(elm, 'ul')) {
5468
 
                this.toolbar.disableButton('indent');
5469
 
            }
5470
 
            this._lastButton = null;
5471
 
            
5472
 
        },
5473
 
        /**
5474
 
        * @private
5475
 
        * @method _handleInsertImageClick
5476
 
        * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
5477
 
        */
5478
 
        _handleInsertImageClick: function() {
5479
 
            if (this.get('limitCommands')) {
5480
 
                if (!this.toolbar.getButtonByValue('insertimage')) {
5481
 
                    YAHOO.log('Toolbar Button for (insertimage) was not found, skipping exec.', 'info', 'SimpleEditor');
5482
 
                    return false;
5483
 
                }
5484
 
            }
5485
 
        
5486
 
            this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
5487
 
            var _handleAEC = function() {
5488
 
                var el = this.currentElement[0],
5489
 
                    src = 'http://';
5490
 
                if (!el) {
5491
 
                    el = this._getSelectedElement();
5492
 
                }
5493
 
                if (el) {
5494
 
                    if (el.getAttribute('src')) {
5495
 
                        src = el.getAttribute('src', 2);
5496
 
                        if (src.indexOf(this.get('blankimage')) != -1) {
5497
 
                            src = this.STR_IMAGE_HERE;
5498
 
                        }
5499
 
                    }
5500
 
                }
5501
 
                var str = prompt(this.STR_IMAGE_URL + ': ', src);
5502
 
                if ((str !== '') && (str !== null)) {
5503
 
                    el.setAttribute('src', str);
5504
 
                } else if (str === '') {
5505
 
                    el.parentNode.removeChild(el);
5506
 
                    this.currentElement = [];
5507
 
                    this.nodeChange();
5508
 
                } else if ((str === null)) {
5509
 
                    src = el.getAttribute('src', 2);
5510
 
                    if (src.indexOf(this.get('blankimage')) != -1) {
5511
 
                        el.parentNode.removeChild(el);
5512
 
                        this.currentElement = [];
5513
 
                        this.nodeChange();
5514
 
                    }
5515
 
                }
5516
 
                this.closeWindow();
5517
 
                this.toolbar.set('disabled', false);
5518
 
                this.unsubscribe('afterExecCommand', _handleAEC, this, true);
5519
 
            };
5520
 
            this.on('afterExecCommand', _handleAEC, this, true);
5521
 
        },
5522
 
        /**
5523
 
        * @private
5524
 
        * @method _handleInsertImageWindowClose
5525
 
        * @description Handles the closing of the Image Properties Window.
5526
 
        */
5527
 
        _handleInsertImageWindowClose: function() {
5528
 
            this.nodeChange();
5529
 
        },
5530
 
        /**
5531
 
        * @private
5532
 
        * @method _isLocalFile
5533
 
        * @param {String} url THe url/string to check
5534
 
        * @description Checks to see if a string (href or img src) is possibly a local file reference..
5535
 
        */
5536
 
        _isLocalFile: function(url) {
5537
 
            if ((url) && (url !== '') && ((url.indexOf('file:/') != -1) || (url.indexOf(':\\') != -1))) {
5538
 
                return true;
5539
 
            }
5540
 
            return false;
5541
 
        },
5542
 
        /**
5543
 
        * @private
5544
 
        * @method _handleCreateLinkClick
5545
 
        * @description Handles the opening of the Link Properties Window when the Create Link button is clicked or an href is doubleclicked.
5546
 
        */
5547
 
        _handleCreateLinkClick: function() {
5548
 
            if (this.get('limitCommands')) {
5549
 
                if (!this.toolbar.getButtonByValue('createlink')) {
5550
 
                    YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'SimpleEditor');
5551
 
                    return false;
5552
 
                }
5553
 
            }
5554
 
        
5555
 
            this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
5556
 
 
5557
 
            var _handleAEC = function() {
5558
 
                var el = this.currentElement[0],
5559
 
                    url = '';
5560
 
 
5561
 
                if (el) {
5562
 
                    if (el.getAttribute('href', 2) !== null) {
5563
 
                        url = el.getAttribute('href', 2);
5564
 
                    }
5565
 
                }
5566
 
                var str = prompt(this.STR_LINK_URL + ': ', url);
5567
 
                if ((str !== '') && (str !== null)) {
5568
 
                    var urlValue = str;
5569
 
                    if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
5570
 
                        if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
5571
 
                            //Found an @ sign, prefix with mailto:
5572
 
                            urlValue = 'mailto:' + urlValue;
5573
 
                        } else {
5574
 
                            /* :// not found adding */
5575
 
                            if (urlValue.substring(0, 1) != '#') {
5576
 
                                //urlValue = 'http:/'+'/' + urlValue;
5577
 
                            }
5578
 
                        }
5579
 
                    }
5580
 
                    el.setAttribute('href', urlValue);
5581
 
                } else if (str !== null) {
5582
 
                    var _span = this._getDoc().createElement('span');
5583
 
                    _span.innerHTML = el.innerHTML;
5584
 
                    Dom.addClass(_span, 'yui-non');
5585
 
                    el.parentNode.replaceChild(_span, el);
5586
 
                }
5587
 
                this.closeWindow();
5588
 
                this.toolbar.set('disabled', false);
5589
 
                this.unsubscribe('afterExecCommand', _handleAEC, this, true);
5590
 
            };
5591
 
            this.on('afterExecCommand', _handleAEC, this);
5592
 
 
5593
 
        },
5594
 
        /**
5595
 
        * @private
5596
 
        * @method _handleCreateLinkWindowClose
5597
 
        * @description Handles the closing of the Link Properties Window.
5598
 
        */
5599
 
        _handleCreateLinkWindowClose: function() {
5600
 
            this.nodeChange();
5601
 
            this.currentElement = [];
5602
 
        },
5603
 
        /**
5604
 
        * @method render
5605
 
        * @description Calls the private method _render in a setTimeout to allow for other things on the page to continue to load.
5606
 
        */
5607
 
        render: function() {
5608
 
            if (this._rendered) {
5609
 
                return false;
5610
 
            }
5611
 
            YAHOO.log('Render', 'info', 'SimpleEditor');
5612
 
            if (!this.DOMReady) {
5613
 
                YAHOO.log('!DOMReady', 'info', 'SimpleEditor');
5614
 
                this._queue[this._queue.length] = ['render', arguments];
5615
 
                return false;
5616
 
            }
5617
 
            if (this.get('element')) {
5618
 
                if (this.get('element').tagName) {
5619
 
                    this._textarea = true;
5620
 
                    if (this.get('element').tagName.toLowerCase() !== 'textarea') {
5621
 
                        this._textarea = false;
5622
 
                    }
5623
 
                } else {
5624
 
                    YAHOO.log('No Valid Element', 'error', 'SimpleEditor');
5625
 
                    return false;
5626
 
                }
5627
 
            } else {
5628
 
                YAHOO.log('No Element', 'error', 'SimpleEditor');
5629
 
                return false;
5630
 
            }
5631
 
            this._rendered = true;
5632
 
            var self = this;
5633
 
            window.setTimeout(function() {
5634
 
                self._render.call(self);
5635
 
            }, 4);
5636
 
        },
5637
 
        /**
5638
 
        * @private
5639
 
        * @method _render
5640
 
        * @description Causes the toolbar and the editor to render and replace the textarea.
5641
 
        */
5642
 
        _render: function() {
5643
 
            var self = this;
5644
 
            this.set('textarea', this.get('element'));
5645
 
 
5646
 
            this.get('element_cont').setStyle('display', 'none');
5647
 
            this.get('element_cont').addClass(this.CLASS_CONTAINER);
5648
 
            
5649
 
            this.set('iframe', this._createIframe());
5650
 
 
5651
 
            window.setTimeout(function() {
5652
 
                self._setInitialContent.call(self);
5653
 
            }, 10);
5654
 
 
5655
 
            this.get('editor_wrapper').appendChild(this.get('iframe').get('element'));
5656
 
 
5657
 
            if (this.get('disabled')) {
5658
 
                this._disableEditor(true);
5659
 
            }
5660
 
 
5661
 
            var tbarConf = this.get('toolbar');
5662
 
            //Create Toolbar instance
5663
 
            if (tbarConf instanceof Toolbar) {
5664
 
                this.toolbar = tbarConf;
5665
 
                //Set the toolbar to disabled until content is loaded
5666
 
                this.toolbar.set('disabled', true);
5667
 
            } else {
5668
 
                //Set the toolbar to disabled until content is loaded
5669
 
                tbarConf.disabled = true;
5670
 
                this.toolbar = new Toolbar(this.get('toolbar_cont'), tbarConf);
5671
 
            }
5672
 
 
5673
 
            YAHOO.log('fireEvent::toolbarLoaded', 'info', 'SimpleEditor');
5674
 
            this.fireEvent('toolbarLoaded', { type: 'toolbarLoaded', target: this.toolbar });
5675
 
 
5676
 
            
5677
 
            this.toolbar.on('toolbarCollapsed', function() {
5678
 
                if (this.currentWindow) {
5679
 
                    this.moveWindow();
5680
 
                }
5681
 
            }, this, true);
5682
 
            this.toolbar.on('toolbarExpanded', function() {
5683
 
                if (this.currentWindow) {
5684
 
                    this.moveWindow();
5685
 
                }
5686
 
            }, this, true);
5687
 
            this.toolbar.on('fontsizeClick', this._handleFontSize, this, true);
5688
 
            
5689
 
            this.toolbar.on('colorPickerClicked', function(o) {
5690
 
                this._handleColorPicker(o);
5691
 
                return false; //Stop the buttonClick event
5692
 
            }, this, true);
5693
 
 
5694
 
            this.toolbar.on('alignClick', this._handleAlign, this, true);
5695
 
            this.on('afterNodeChange', this._handleAfterNodeChange, this, true);
5696
 
            this.toolbar.on('insertimageClick', this._handleInsertImageClick, this, true);
5697
 
            this.on('windowinsertimageClose', this._handleInsertImageWindowClose, this, true);
5698
 
            this.toolbar.on('createlinkClick', this._handleCreateLinkClick, this, true);
5699
 
            this.on('windowcreatelinkClose', this._handleCreateLinkWindowClose, this, true);
5700
 
            
5701
 
 
5702
 
            //Replace Textarea with editable area
5703
 
            this.get('parentNode').replaceChild(this.get('element_cont').get('element'), this.get('element'));
5704
 
 
5705
 
            
5706
 
            this.setStyle('visibility', 'hidden');
5707
 
            this.setStyle('position', 'absolute');
5708
 
            this.setStyle('top', '-9999px');
5709
 
            this.setStyle('left', '-9999px');
5710
 
            this.get('element_cont').appendChild(this.get('element'));
5711
 
            this.get('element_cont').setStyle('display', 'block');
5712
 
 
5713
 
 
5714
 
            Dom.addClass(this.get('iframe').get('parentNode'), this.CLASS_EDITABLE_CONT);
5715
 
            this.get('iframe').addClass(this.CLASS_EDITABLE);
5716
 
 
5717
 
            //Set height and width of editor container
5718
 
            this.get('element_cont').setStyle('width', this.get('width'));
5719
 
            Dom.setStyle(this.get('iframe').get('parentNode'), 'height', this.get('height'));
5720
 
 
5721
 
            this.get('iframe').setStyle('width', '100%'); //WIDTH
5722
 
            this.get('iframe').setStyle('height', '100%');
5723
 
 
5724
 
            this._setupDD();
5725
 
 
5726
 
            window.setTimeout(function() {
5727
 
                self._setupAfterElement.call(self);
5728
 
            }, 0);
5729
 
            this.fireEvent('afterRender', { type: 'afterRender', target: this });
5730
 
        },
5731
 
        /**
5732
 
        * @method execCommand
5733
 
        * @param {String} action The "execCommand" action to try to execute (Example: bold, insertimage, inserthtml)
5734
 
        * @param {String} value (optional) The value for a given action such as action: fontname value: 'Verdana'
5735
 
        * @description This method attempts to try and level the differences in the various browsers and their support for execCommand actions
5736
 
        */
5737
 
        execCommand: function(action, value) {
5738
 
            var beforeExec = this.fireEvent('beforeExecCommand', { type: 'beforeExecCommand', target: this, args: arguments });
5739
 
            if ((beforeExec === false) || (this.STOP_EXEC_COMMAND)) {
5740
 
                this.STOP_EXEC_COMMAND = false;
5741
 
                return false;
5742
 
            }
5743
 
            this._lastCommand = action;
5744
 
            this._setMarkupType(action);
5745
 
            if (this.browser.ie) {
5746
 
                this._getWindow().focus();
5747
 
            }
5748
 
            var exec = true;
5749
 
            
5750
 
            if (this.get('limitCommands')) {
5751
 
                if (!this.toolbar.getButtonByValue(action)) {
5752
 
                    YAHOO.log('Toolbar Button for (' + action + ') was not found, skipping exec.', 'info', 'SimpleEditor');
5753
 
                    exec = false;
5754
 
                }
5755
 
            }
5756
 
 
5757
 
            this.editorDirty = true;
5758
 
            
5759
 
            if ((typeof this['cmd_' + action.toLowerCase()] == 'function') && exec) {
5760
 
                YAHOO.log('Found execCommand override method: (cmd_' + action.toLowerCase() + ')', 'info', 'SimpleEditor');
5761
 
                var retValue = this['cmd_' + action.toLowerCase()](value);
5762
 
                exec = retValue[0];
5763
 
                if (retValue[1]) {
5764
 
                    action = retValue[1];
5765
 
                }
5766
 
                if (retValue[2]) {
5767
 
                    value = retValue[2];
5768
 
                }
5769
 
            }
5770
 
            if (exec) {
5771
 
                YAHOO.log('execCommand::(' + action + '), (' + value + ')', 'info', 'SimpleEditor');
5772
 
                try {
5773
 
                    this._getDoc().execCommand(action, false, value);
5774
 
                } catch(e) {
5775
 
                    YAHOO.log('execCommand Failed', 'error', 'SimpleEditor');
5776
 
                }
5777
 
            } else {
5778
 
                YAHOO.log('OVERRIDE::execCommand::(' + action + '),(' + value + ') skipped', 'warn', 'SimpleEditor');
5779
 
            }
5780
 
            this.on('afterExecCommand', function() {
5781
 
                this.unsubscribeAll('afterExecCommand');
5782
 
                this.nodeChange();
5783
 
            }, this, true);
5784
 
            this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
5785
 
            
5786
 
        },
5787
 
    /* {{{  Command Overrides */
5788
 
 
5789
 
        /**
5790
 
        * @method cmd_bold
5791
 
        * @param value Value passed from the execCommand method
5792
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('bold') is used.
5793
 
        */
5794
 
        cmd_bold: function(value) {
5795
 
            if (!this.browser.webkit) {
5796
 
                var el = this._getSelectedElement();
5797
 
                if (el && this._isElement(el, 'span') && this._hasSelection()) {
5798
 
                    if (el.style.fontWeight == 'bold') {
5799
 
                        el.style.fontWeight = '';
5800
 
                        var b = this._getDoc().createElement('b'),
5801
 
                        par = el.parentNode;
5802
 
                        par.replaceChild(b, el);
5803
 
                        b.appendChild(el);
5804
 
                    }
5805
 
                }
5806
 
            }
5807
 
            return [true];
5808
 
        },
5809
 
        /**
5810
 
        * @method cmd_italic
5811
 
        * @param value Value passed from the execCommand method
5812
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('italic') is used.
5813
 
        */
5814
 
 
5815
 
        cmd_italic: function(value) {
5816
 
            if (!this.browser.webkit) {
5817
 
                var el = this._getSelectedElement();
5818
 
                if (el && this._isElement(el, 'span') && this._hasSelection()) {
5819
 
                    if (el.style.fontStyle == 'italic') {
5820
 
                        el.style.fontStyle = '';
5821
 
                        var i = this._getDoc().createElement('i'),
5822
 
                        par = el.parentNode;
5823
 
                        par.replaceChild(i, el);
5824
 
                        i.appendChild(el);
5825
 
                    }
5826
 
                }
5827
 
            }
5828
 
            return [true];
5829
 
        },
5830
 
 
5831
 
 
5832
 
        /**
5833
 
        * @method cmd_underline
5834
 
        * @param value Value passed from the execCommand method
5835
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('underline') is used.
5836
 
        */
5837
 
        cmd_underline: function(value) {
5838
 
            if (!this.browser.webkit) {
5839
 
                var el = this._getSelectedElement();
5840
 
                if (el && this._isElement(el, 'span')) {
5841
 
                    if (el.style.textDecoration == 'underline') {
5842
 
                        el.style.textDecoration = 'none';
5843
 
                    } else {
5844
 
                        el.style.textDecoration = 'underline';
5845
 
                    }
5846
 
                    return [false];
5847
 
                }
5848
 
            }
5849
 
            return [true];
5850
 
        },
5851
 
        /**
5852
 
        * @method cmd_backcolor
5853
 
        * @param value Value passed from the execCommand method
5854
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('backcolor') is used.
5855
 
        */
5856
 
        cmd_backcolor: function(value) {
5857
 
            var exec = true,
5858
 
                el = this._getSelectedElement(),
5859
 
                action = 'backcolor';
5860
 
 
5861
 
            if (this.browser.gecko || this.browser.opera) {
5862
 
                this._setEditorStyle(true);
5863
 
                action = 'hilitecolor';
5864
 
            }
5865
 
 
5866
 
            if (!this._isElement(el, 'body') && !this._hasSelection()) {
5867
 
                el.style.backgroundColor = value;
5868
 
                this._selectNode(el);
5869
 
                exec = false;
5870
 
            } else {
5871
 
                if (this.get('insert')) {
5872
 
                    el = this._createInsertElement({ backgroundColor: value });
5873
 
                } else {
5874
 
                    this._createCurrentElement('span', { backgroundColor: value, color: el.style.color, fontSize: el.style.fontSize, fontFamily: el.style.fontFamily });
5875
 
                    this._selectNode(this.currentElement[0]);
5876
 
                }
5877
 
                exec = false;
5878
 
            }
5879
 
 
5880
 
            return [exec, action];
5881
 
        },
5882
 
        /**
5883
 
        * @method cmd_forecolor
5884
 
        * @param value Value passed from the execCommand method
5885
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('forecolor') is used.
5886
 
        */
5887
 
        cmd_forecolor: function(value) {
5888
 
            var exec = true,
5889
 
                el = this._getSelectedElement();
5890
 
                
5891
 
                if (!this._isElement(el, 'body') && !this._hasSelection()) {
5892
 
                    Dom.setStyle(el, 'color', value);
5893
 
                    this._selectNode(el);
5894
 
                    exec = false;
5895
 
                } else {
5896
 
                    if (this.get('insert')) {
5897
 
                        el = this._createInsertElement({ color: value });
5898
 
                    } else {
5899
 
                        this._createCurrentElement('span', { color: value, fontSize: el.style.fontSize, fontFamily: el.style.fontFamily, backgroundColor: el.style.backgroundColor });
5900
 
                        this._selectNode(this.currentElement[0]);
5901
 
                    }
5902
 
                    exec = false;
5903
 
                }
5904
 
                return [exec];
5905
 
        },
5906
 
        /**
5907
 
        * @method cmd_unlink
5908
 
        * @param value Value passed from the execCommand method
5909
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('unlink') is used.
5910
 
        */
5911
 
        cmd_unlink: function(value) {
5912
 
            this._swapEl(this.currentElement[0], 'span', function(el) {
5913
 
                el.className = 'yui-non';
5914
 
            });
5915
 
            return [false];
5916
 
        },
5917
 
        /**
5918
 
        * @method cmd_createlink
5919
 
        * @param value Value passed from the execCommand method
5920
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('createlink') is used.
5921
 
        */
5922
 
        cmd_createlink: function(value) {
5923
 
            var el = this._getSelectedElement(), _a = null;
5924
 
            if (this._hasParent(el, 'a')) {
5925
 
                this.currentElement[0] = this._hasParent(el, 'a');
5926
 
            } else if (this._isElement(el, 'li')) {
5927
 
                _a = this._getDoc().createElement('a');
5928
 
                _a.innerHTML = el.innerHTML;
5929
 
                el.innerHTML = '';
5930
 
                el.appendChild(_a);
5931
 
                this.currentElement[0] = _a;
5932
 
            } else if (!this._isElement(el, 'a')) {
5933
 
                this._createCurrentElement('a');
5934
 
                _a = this._swapEl(this.currentElement[0], 'a');
5935
 
                this.currentElement[0] = _a;
5936
 
            } else {
5937
 
                this.currentElement[0] = el;
5938
 
            }
5939
 
            return [false];
5940
 
        },
5941
 
        /**
5942
 
        * @method cmd_insertimage
5943
 
        * @param value Value passed from the execCommand method
5944
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertimage') is used.
5945
 
        */
5946
 
        cmd_insertimage: function(value) {
5947
 
            var exec = true, _img = null, action = 'insertimage',
5948
 
                el = this._getSelectedElement();
5949
 
 
5950
 
            if (value === '') {
5951
 
                value = this.get('blankimage');
5952
 
            }
5953
 
 
5954
 
            /*
5955
 
            * @knownissue Safari Cursor Position
5956
 
            * @browser Safari 2.x
5957
 
            * @description The issue here is that we have no way of knowing where the cursor position is
5958
 
            * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
5959
 
            */
5960
 
            
5961
 
            YAHOO.log('InsertImage: ' + el.tagName, 'info', 'SimpleEditor');
5962
 
            if (this._isElement(el, 'img')) {
5963
 
                this.currentElement[0] = el;
5964
 
                exec = false;
5965
 
            } else {
5966
 
                if (this._getDoc().queryCommandEnabled(action)) {
5967
 
                    this._getDoc().execCommand('insertimage', false, value);
5968
 
                    var imgs = this._getDoc().getElementsByTagName('img');
5969
 
                    for (var i = 0; i < imgs.length; i++) {
5970
 
                        if (!YAHOO.util.Dom.hasClass(imgs[i], 'yui-img')) {
5971
 
                            YAHOO.util.Dom.addClass(imgs[i], 'yui-img');
5972
 
                            this.currentElement[0] = imgs[i];
5973
 
                        }
5974
 
                    }
5975
 
                    exec = false;
5976
 
                } else {
5977
 
                    if (el == this._getDoc().body) {
5978
 
                        _img = this._getDoc().createElement('img');
5979
 
                        _img.setAttribute('src', value);
5980
 
                        YAHOO.util.Dom.addClass(_img, 'yui-img');
5981
 
                        this._getDoc().body.appendChild(_img);
5982
 
                    } else {
5983
 
                        this._createCurrentElement('img');
5984
 
                        _img = this._getDoc().createElement('img');
5985
 
                        _img.setAttribute('src', value);
5986
 
                        YAHOO.util.Dom.addClass(_img, 'yui-img');
5987
 
                        this.currentElement[0].parentNode.replaceChild(_img, this.currentElement[0]);
5988
 
                    }
5989
 
                    this.currentElement[0] = _img;
5990
 
                    exec = false;
5991
 
                }
5992
 
            }
5993
 
            return [exec];
5994
 
        },
5995
 
        /**
5996
 
        * @method cmd_inserthtml
5997
 
        * @param value Value passed from the execCommand method
5998
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('inserthtml') is used.
5999
 
        */
6000
 
        cmd_inserthtml: function(value) {
6001
 
            var exec = true, action = 'inserthtml', _span = null, _range = null;
6002
 
            /*
6003
 
            * @knownissue Safari cursor position
6004
 
            * @browser Safari 2.x
6005
 
            * @description The issue here is that we have no way of knowing where the cursor position is
6006
 
            * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
6007
 
            */
6008
 
            if (this.browser.webkit && !this._getDoc().queryCommandEnabled(action)) {
6009
 
                YAHOO.log('More Safari DOM tricks (inserthtml)', 'info', 'EditorSafari');
6010
 
                this._createCurrentElement('img');
6011
 
                _span = this._getDoc().createElement('span');
6012
 
                _span.innerHTML = value;
6013
 
                this.currentElement[0].parentNode.replaceChild(_span, this.currentElement[0]);
6014
 
                exec = false;
6015
 
            } else if (this.browser.ie) {
6016
 
                _range = this._getRange();
6017
 
                if (_range.item) {
6018
 
                    _range.item(0).outerHTML = value;
6019
 
                } else {
6020
 
                    _range.pasteHTML(value);
6021
 
                }
6022
 
                exec = false;                    
6023
 
            }
6024
 
            return [exec];
6025
 
        },
6026
 
        /**
6027
 
        * @method cmd_list
6028
 
        * @param tag The tag of the list you want to create (eg, ul or ol)
6029
 
        * @description This is a combined execCommand override method. It is called from the cmd_insertorderedlist and cmd_insertunorderedlist methods.
6030
 
        */
6031
 
        cmd_list: function(tag) {
6032
 
            var exec = true, list = null, li = 0, el = null, str = '',
6033
 
                selEl = this._getSelectedElement(), action = 'insertorderedlist';
6034
 
                if (tag == 'ul') {
6035
 
                    action = 'insertunorderedlist';
6036
 
                }
6037
 
            /*
6038
 
            * @knownissue Safari 2.+ doesn't support ordered and unordered lists
6039
 
            * @browser Safari 2.x
6040
 
            * The issue with this workaround is that when applied to a set of text
6041
 
            * that has BR's in it, Safari may or may not pick up the individual items as
6042
 
            * list items. This is fixed in WebKit (Safari 3)
6043
 
            * 2.6.0: Seems there are still some issues with List Creation and Safari 3, reverting to previously working Safari 2.x code
6044
 
            */
6045
 
            //if ((this.browser.webkit && !this._getDoc().queryCommandEnabled(action))) {
6046
 
            if (this.browser.webkit) {
6047
 
                if (this._isElement(selEl, 'li') && this._isElement(selEl.parentNode, tag)) {
6048
 
                    YAHOO.log('We already have a list, undo it', 'info', 'SimpleEditor');
6049
 
                    el = selEl.parentNode;
6050
 
                    list = this._getDoc().createElement('span');
6051
 
                    YAHOO.util.Dom.addClass(list, 'yui-non');
6052
 
                    str = '';
6053
 
                    var lis = el.getElementsByTagName('li');
6054
 
                    for (li = 0; li < lis.length; li++) {
6055
 
                        str += '<div>' + lis[li].innerHTML + '</div>';
6056
 
                    }
6057
 
                    list.innerHTML = str;
6058
 
                    this.currentElement[0] = el;
6059
 
                    this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
6060
 
                } else {
6061
 
                    YAHOO.log('Create list item', 'info', 'SimpleEditor');
6062
 
                    this._createCurrentElement(tag.toLowerCase());
6063
 
                    list = this._getDoc().createElement(tag);
6064
 
                    for (li = 0; li < this.currentElement.length; li++) {
6065
 
                        var newli = this._getDoc().createElement('li');
6066
 
                        newli.innerHTML = this.currentElement[li].innerHTML + '<span class="yui-non">&nbsp;</span>&nbsp;';
6067
 
                        list.appendChild(newli);
6068
 
                        if (li > 0) {
6069
 
                            this.currentElement[li].parentNode.removeChild(this.currentElement[li]);
6070
 
                        }
6071
 
                    }
6072
 
                    
6073
 
                    var items = list.firstChild.innerHTML.split('<br>');
6074
 
                    if (items.length > 0) {
6075
 
                        list.innerHTML = '';
6076
 
                        for (var i = 0; i < items.length; i++) {
6077
 
                            var item = this._getDoc().createElement('li');
6078
 
                            item.innerHTML = items[i];
6079
 
                            list.appendChild(item);
6080
 
                        }
6081
 
                    }
6082
 
 
6083
 
                    this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
6084
 
                    this.currentElement[0] = list;
6085
 
                    var _h = this.currentElement[0].firstChild;
6086
 
                    _h = Dom.getElementsByClassName('yui-non', 'span', _h)[0];
6087
 
                    this._getSelection().setBaseAndExtent(_h, 1, _h, _h.innerText.length);
6088
 
                }
6089
 
                exec = false;
6090
 
            } else {
6091
 
                el = this._getSelectedElement();
6092
 
                YAHOO.log(el.tagName);
6093
 
                if (this._isElement(el, 'li') && this._isElement(el.parentNode, tag) || (this.browser.ie && this._isElement(this._getRange().parentElement, 'li')) || (this.browser.ie && this._isElement(el, 'ul')) || (this.browser.ie && this._isElement(el, 'ol'))) { //we are in a list..
6094
 
                    YAHOO.log('We already have a list, undo it', 'info', 'SimpleEditor');
6095
 
                    if (this.browser.ie) {
6096
 
                        if ((this.browser.ie && this._isElement(el, 'ul')) || (this.browser.ie && this._isElement(el, 'ol'))) {
6097
 
                            el = el.getElementsByTagName('li')[0];
6098
 
                        }
6099
 
                        YAHOO.log('Undo IE', 'info', 'SimpleEditor');
6100
 
                        str = '';
6101
 
                        var lis2 = el.parentNode.getElementsByTagName('li');
6102
 
                        for (var j = 0; j < lis2.length; j++) {
6103
 
                            str += lis2[j].innerHTML + '<br>';
6104
 
                        }
6105
 
                        var newEl = this._getDoc().createElement('span');
6106
 
                        newEl.innerHTML = str;
6107
 
                        el.parentNode.parentNode.replaceChild(newEl, el.parentNode);
6108
 
                    } else {
6109
 
                        this.nodeChange();
6110
 
                        this._getDoc().execCommand(action, '', el.parentNode);
6111
 
                        this.nodeChange();
6112
 
                    }
6113
 
                    exec = false;
6114
 
                }
6115
 
                if (this.browser.opera) {
6116
 
                    var self = this;
6117
 
                    window.setTimeout(function() {
6118
 
                        var liso = self._getDoc().getElementsByTagName('li');
6119
 
                        for (var i = 0; i < liso.length; i++) {
6120
 
                            if (liso[i].innerHTML.toLowerCase() == '<br>') {
6121
 
                                liso[i].parentNode.parentNode.removeChild(liso[i].parentNode);
6122
 
                            }
6123
 
                        }
6124
 
                    },30);
6125
 
                }
6126
 
                if (this.browser.ie && exec) {
6127
 
                    var html = '';
6128
 
                    if (this._getRange().html) {
6129
 
                        html = '<li>' + this._getRange().html+ '</li>';
6130
 
                    } else {
6131
 
                        var t = this._getRange().text.split('\n');
6132
 
                        if (t.length > 1) {
6133
 
                            html = '';
6134
 
                            for (var ie = 0; ie < t.length; ie++) {
6135
 
                                html += '<li>' + t[ie] + '</li>';
6136
 
                            }
6137
 
                        } else {
6138
 
                            var txt = this._getRange().text;
6139
 
                            if (txt === '') {
6140
 
                                html = '<li id="new_list_item">' + txt + '</li>';
6141
 
                            } else {
6142
 
                                html = '<li>' + txt + '</li>';
6143
 
                            }
6144
 
                        }
6145
 
                    }
6146
 
                    this._getRange().pasteHTML('<' + tag + '>' + html + '</' + tag + '>');
6147
 
                    var new_item = this._getDoc().getElementById('new_list_item');
6148
 
                    if (new_item) {
6149
 
                        var range = this._getDoc().body.createTextRange();
6150
 
                        range.moveToElementText(new_item);
6151
 
                        range.collapse(false);
6152
 
                        range.select();                       
6153
 
                        new_item.id = '';
6154
 
                    }
6155
 
                    exec = false;
6156
 
                }
6157
 
            }
6158
 
            return exec;
6159
 
        },
6160
 
        /**
6161
 
        * @method cmd_insertorderedlist
6162
 
        * @param value Value passed from the execCommand method
6163
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertorderedlist ') is used.
6164
 
        */
6165
 
        cmd_insertorderedlist: function(value) {
6166
 
            return [this.cmd_list('ol')];
6167
 
        },
6168
 
        /**
6169
 
        * @method cmd_insertunorderedlist 
6170
 
        * @param value Value passed from the execCommand method
6171
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertunorderedlist') is used.
6172
 
        */
6173
 
        cmd_insertunorderedlist: function(value) {
6174
 
            return [this.cmd_list('ul')];
6175
 
        },
6176
 
        /**
6177
 
        * @method cmd_fontname
6178
 
        * @param value Value passed from the execCommand method
6179
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontname') is used.
6180
 
        */
6181
 
        cmd_fontname: function(value) {
6182
 
            var exec = true,
6183
 
                selEl = this._getSelectedElement();
6184
 
 
6185
 
            this.currentFont = value;
6186
 
            if (selEl && selEl.tagName && !this._hasSelection() && !this._isElement(selEl, 'body') && !this.get('insert')) {
6187
 
                YAHOO.util.Dom.setStyle(selEl, 'font-family', value);
6188
 
                exec = false;
6189
 
            } else if (this.get('insert') && !this._hasSelection()) {
6190
 
                YAHOO.log('No selection and no selected element and we are in insert mode', 'info', 'SimpleEditor');
6191
 
                var el = this._createInsertElement({ fontFamily: value });
6192
 
                exec = false;
6193
 
            }
6194
 
            return [exec];
6195
 
        },
6196
 
        /**
6197
 
        * @method cmd_fontsize
6198
 
        * @param value Value passed from the execCommand method
6199
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontsize') is used.
6200
 
        */
6201
 
        cmd_fontsize: function(value) {
6202
 
            var el = null, go = true;
6203
 
            el = this._getSelectedElement();
6204
 
            if (this.browser.webkit) {
6205
 
                if (this.currentElement[0]) {
6206
 
                    if (el == this.currentElement[0]) {
6207
 
                        go = false;
6208
 
                        YAHOO.util.Dom.setStyle(el, 'fontSize', value);
6209
 
                        this._selectNode(el);
6210
 
                        this.currentElement[0] = el;
6211
 
                    }
6212
 
                }
6213
 
            }
6214
 
            if (go) {
6215
 
                if (!this._isElement(this._getSelectedElement(), 'body') && (!this._hasSelection())) {
6216
 
                    el = this._getSelectedElement();
6217
 
                    YAHOO.util.Dom.setStyle(el, 'fontSize', value);
6218
 
                    if (this.get('insert') && this.browser.ie) {
6219
 
                        var r = this._getRange();
6220
 
                        r.collapse(false);
6221
 
                        r.select();
6222
 
                    } else {
6223
 
                        this._selectNode(el);
6224
 
                    }
6225
 
                } else if (this.currentElement && (this.currentElement.length > 0) && (!this._hasSelection()) && (!this.get('insert'))) {
6226
 
                    YAHOO.util.Dom.setStyle(this.currentElement, 'fontSize', value);
6227
 
                } else {
6228
 
                    if (this.get('insert') && !this._hasSelection()) {
6229
 
                        el = this._createInsertElement({ fontSize: value });
6230
 
                        this.currentElement[0] = el;
6231
 
                        this._selectNode(this.currentElement[0]);
6232
 
                    } else {
6233
 
                        this._createCurrentElement('span', {'fontSize': value, fontFamily: el.style.fontFamily, color: el.style.color, backgroundColor: el.style.backgroundColor });
6234
 
                        this._selectNode(this.currentElement[0]);
6235
 
                    }
6236
 
                }
6237
 
            }
6238
 
            return [false];
6239
 
        },
6240
 
    /* }}} */
6241
 
        /**
6242
 
        * @private
6243
 
        * @method _swapEl
6244
 
        * @param {HTMLElement} el The element to swap with
6245
 
        * @param {String} tagName The tagname of the element that you wish to create
6246
 
        * @param {Function} callback (optional) A function to run on the element after it is created, but before it is replaced. An element reference is passed to this function.
6247
 
        * @description This function will create a new element in the DOM and populate it with the contents of another element. Then it will assume it's place.
6248
 
        */
6249
 
        _swapEl: function(el, tagName, callback) {
6250
 
            var _el = this._getDoc().createElement(tagName);
6251
 
            if (el) {
6252
 
                _el.innerHTML = el.innerHTML;
6253
 
            }
6254
 
            if (typeof callback == 'function') {
6255
 
                callback.call(this, _el);
6256
 
            }
6257
 
            if (el) {
6258
 
                el.parentNode.replaceChild(_el, el);
6259
 
            }
6260
 
            return _el;
6261
 
        },
6262
 
        /**
6263
 
        * @private
6264
 
        * @method _createInsertElement
6265
 
        * @description Creates a new "currentElement" then adds some text (and other things) to make it selectable and stylable. Then the user can continue typing.
6266
 
        * @param {Object} css (optional) Object literal containing styles to apply to the new element.
6267
 
        * @return {HTMLElement}
6268
 
        */
6269
 
        _createInsertElement: function(css) {
6270
 
            this._createCurrentElement('span', css);
6271
 
            var el = this.currentElement[0];
6272
 
            if (this.browser.webkit) {
6273
 
                //Little Safari Hackery here..
6274
 
                el.innerHTML = '<span class="yui-non">&nbsp;</span>';
6275
 
                el = el.firstChild;
6276
 
                this._getSelection().setBaseAndExtent(el, 1, el, el.innerText.length);                    
6277
 
            } else if (this.browser.ie || this.browser.opera) {
6278
 
                el.innerHTML = '&nbsp;';
6279
 
            }
6280
 
            this.focus();
6281
 
            this._selectNode(el, true);
6282
 
            return el;
6283
 
        },
6284
 
        /**
6285
 
        * @private
6286
 
        * @method _createCurrentElement
6287
 
        * @param {String} tagName (optional defaults to a) The tagname of the element that you wish to create
6288
 
        * @param {Object} tagStyle (optional) Object literal containing styles to apply to the new element.
6289
 
        * @description This is a work around for the various browser issues with execCommand. This method will run <code>execCommand('fontname', false, 'yui-tmp')</code> on the given selection.
6290
 
        * It will then search the document for an element with the font-family set to <strong>yui-tmp</strong> and replace that with another span that has other information in it, then assign the new span to the 
6291
 
        * <code>this.currentElement</code> array, so we now have element references to the elements that were just modified. At this point we can use standard DOM manipulation to change them as we see fit.
6292
 
        */
6293
 
        _createCurrentElement: function(tagName, tagStyle) {
6294
 
            tagName = ((tagName) ? tagName : 'a');
6295
 
            var tar = null,
6296
 
                el = [],
6297
 
                _doc = this._getDoc();
6298
 
            
6299
 
            if (this.currentFont) {
6300
 
                if (!tagStyle) {
6301
 
                    tagStyle = {};
6302
 
                }
6303
 
                tagStyle.fontFamily = this.currentFont;
6304
 
                this.currentFont = null;
6305
 
            }
6306
 
            this.currentElement = [];
6307
 
 
6308
 
            var _elCreate = function(tagName, tagStyle) {
6309
 
                var el = null;
6310
 
                tagName = ((tagName) ? tagName : 'span');
6311
 
                tagName = tagName.toLowerCase();
6312
 
                switch (tagName) {
6313
 
                    case 'h1':
6314
 
                    case 'h2':
6315
 
                    case 'h3':
6316
 
                    case 'h4':
6317
 
                    case 'h5':
6318
 
                    case 'h6':
6319
 
                        el = _doc.createElement(tagName);
6320
 
                        break;
6321
 
                    default:
6322
 
                        el = _doc.createElement(tagName);
6323
 
                        if (tagName === 'span') {
6324
 
                            YAHOO.util.Dom.addClass(el, 'yui-tag-' + tagName);
6325
 
                            YAHOO.util.Dom.addClass(el, 'yui-tag');
6326
 
                            el.setAttribute('tag', tagName);
6327
 
                        }
6328
 
 
6329
 
                        for (var k in tagStyle) {
6330
 
                            if (YAHOO.lang.hasOwnProperty(tagStyle, k)) {
6331
 
                                el.style[k] = tagStyle[k];
6332
 
                            }
6333
 
                        }
6334
 
                        break;
6335
 
                }
6336
 
                return el;
6337
 
            };
6338
 
 
6339
 
            if (!this._hasSelection()) {
6340
 
                if (this._getDoc().queryCommandEnabled('insertimage')) {
6341
 
                    this._getDoc().execCommand('insertimage', false, 'yui-tmp-img');
6342
 
                    var imgs = this._getDoc().getElementsByTagName('img');
6343
 
                    for (var j = 0; j < imgs.length; j++) {
6344
 
                        if (imgs[j].getAttribute('src', 2) == 'yui-tmp-img') {
6345
 
                            el = _elCreate(tagName, tagStyle);
6346
 
                            imgs[j].parentNode.replaceChild(el, imgs[j]);
6347
 
                            this.currentElement[this.currentElement.length] = el;
6348
 
                        }
6349
 
                    }
6350
 
                } else {
6351
 
                    if (this.currentEvent) {
6352
 
                        tar = YAHOO.util.Event.getTarget(this.currentEvent);
6353
 
                    } else {
6354
 
                        //For Safari..
6355
 
                        tar = this._getDoc().body;                        
6356
 
                    }
6357
 
                }
6358
 
                if (tar) {
6359
 
                    /*
6360
 
                    * @knownissue Safari Cursor Position
6361
 
                    * @browser Safari 2.x
6362
 
                    * @description The issue here is that we have no way of knowing where the cursor position is
6363
 
                    * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
6364
 
                    */
6365
 
                    el = _elCreate(tagName, tagStyle);
6366
 
                    if (this._isElement(tar, 'body') || this._isElement(tar, 'html')) {
6367
 
                        if (this._isElement(tar, 'html')) {
6368
 
                            tar = this._getDoc().body;
6369
 
                        }
6370
 
                        tar.appendChild(el);
6371
 
                    } else if (tar.nextSibling) {
6372
 
                        tar.parentNode.insertBefore(el, tar.nextSibling);
6373
 
                    } else {
6374
 
                        tar.parentNode.appendChild(el);
6375
 
                    }
6376
 
                    //this.currentElement = el;
6377
 
                    this.currentElement[this.currentElement.length] = el;
6378
 
                    this.currentEvent = null;
6379
 
                    if (this.browser.webkit) {
6380
 
                        //Force Safari to focus the new element
6381
 
                        this._getSelection().setBaseAndExtent(el, 0, el, 0);
6382
 
                        if (this.browser.webkit3) {
6383
 
                            this._getSelection().collapseToStart();
6384
 
                        } else {
6385
 
                            this._getSelection().collapse(true);
6386
 
                        }
6387
 
                    }
6388
 
                }
6389
 
            } else {
6390
 
                //Force CSS Styling for this action...
6391
 
                this._setEditorStyle(true);
6392
 
                this._getDoc().execCommand('fontname', false, 'yui-tmp');
6393
 
                var _tmp = [], __tmp, __els = ['font', 'span', 'i', 'b', 'u'];
6394
 
 
6395
 
                if (!this._isElement(this._getSelectedElement(), 'body')) {
6396
 
                    __els[__els.length] = this._getDoc().getElementsByTagName(this._getSelectedElement().tagName);
6397
 
                    __els[__els.length] = this._getDoc().getElementsByTagName(this._getSelectedElement().parentNode.tagName);
6398
 
                }
6399
 
                for (var _els = 0; _els < __els.length; _els++) {
6400
 
                    var _tmp1 = this._getDoc().getElementsByTagName(__els[_els]);
6401
 
                    for (var e = 0; e < _tmp1.length; e++) {
6402
 
                        _tmp[_tmp.length] = _tmp1[e];
6403
 
                    }
6404
 
                }
6405
 
 
6406
 
                
6407
 
                for (var i = 0; i < _tmp.length; i++) {
6408
 
                    if ((YAHOO.util.Dom.getStyle(_tmp[i], 'font-family') == 'yui-tmp') || (_tmp[i].face && (_tmp[i].face == 'yui-tmp'))) {
6409
 
                        if (tagName !== 'span') {
6410
 
                            el = _elCreate(tagName, tagStyle);
6411
 
                        } else {
6412
 
                            el = _elCreate(_tmp[i].tagName, tagStyle);
6413
 
                        }
6414
 
                        el.innerHTML = _tmp[i].innerHTML;
6415
 
                        if (this._isElement(_tmp[i], 'ol') || (this._isElement(_tmp[i], 'ul'))) {
6416
 
                            var fc = _tmp[i].getElementsByTagName('li')[0];
6417
 
                            _tmp[i].style.fontFamily = 'inherit';
6418
 
                            fc.style.fontFamily = 'inherit';
6419
 
                            el.innerHTML = fc.innerHTML;
6420
 
                            fc.innerHTML = '';
6421
 
                            fc.appendChild(el);
6422
 
                            this.currentElement[this.currentElement.length] = el;
6423
 
                        } else if (this._isElement(_tmp[i], 'li')) {
6424
 
                            _tmp[i].innerHTML = '';
6425
 
                            _tmp[i].appendChild(el);
6426
 
                            _tmp[i].style.fontFamily = 'inherit';
6427
 
                            this.currentElement[this.currentElement.length] = el;
6428
 
                        } else {
6429
 
                            if (_tmp[i].parentNode) {
6430
 
                                _tmp[i].parentNode.replaceChild(el, _tmp[i]);
6431
 
                                this.currentElement[this.currentElement.length] = el;
6432
 
                                this.currentEvent = null;
6433
 
                                if (this.browser.webkit) {
6434
 
                                    //Force Safari to focus the new element
6435
 
                                    this._getSelection().setBaseAndExtent(el, 0, el, 0);
6436
 
                                    if (this.browser.webkit3) {
6437
 
                                        this._getSelection().collapseToStart();
6438
 
                                    } else {
6439
 
                                        this._getSelection().collapse(true);
6440
 
                                    }
6441
 
                                }
6442
 
                                if (this.browser.ie && tagStyle && tagStyle.fontSize) {
6443
 
                                    this._getSelection().empty();
6444
 
                                }
6445
 
                                if (this.browser.gecko) {
6446
 
                                    this._getSelection().collapseToStart();
6447
 
                                }
6448
 
                            }
6449
 
                        }
6450
 
                    }
6451
 
                }
6452
 
                var len = this.currentElement.length;
6453
 
                for (var o = 0; o < len; o++) {
6454
 
                    if ((o + 1) != len) { //Skip the last one in the list
6455
 
                        if (this.currentElement[o] && this.currentElement[o].nextSibling) {
6456
 
                            if (this._isElement(this.currentElement[o], 'br')) {
6457
 
                                this.currentElement[this.currentElement.length] = this.currentElement[o].nextSibling;
6458
 
                            }
6459
 
                        }
6460
 
                    }
6461
 
                }
6462
 
            }
6463
 
        },
6464
 
        /**
6465
 
        * @method saveHTML
6466
 
        * @description Cleans the HTML with the cleanHTML method then places that string back into the textarea.
6467
 
        * @return String
6468
 
        */
6469
 
        saveHTML: function() {
6470
 
            var html = this.cleanHTML();
6471
 
            if (this._textarea) {
6472
 
                this.get('element').value = html;
6473
 
            } else {
6474
 
                this.get('element').innerHTML = html;
6475
 
            }
6476
 
            if (this.get('saveEl') !== this.get('element')) {
6477
 
                var out = this.get('saveEl');
6478
 
                if (Lang.isString(out)) {
6479
 
                    out = Dom.get(out);
6480
 
                }
6481
 
                if (out) {
6482
 
                    if (out.tagName.toLowerCase() === 'textarea') {
6483
 
                        out.value = html;
6484
 
                    } else {
6485
 
                        out.innerHTML = html;
6486
 
                    }
6487
 
                }
6488
 
            }
6489
 
            return html;
6490
 
        },
6491
 
        /**
6492
 
        * @method setEditorHTML
6493
 
        * @param {String} incomingHTML The html content to load into the editor
6494
 
        * @description Loads HTML into the editors body
6495
 
        */
6496
 
        setEditorHTML: function(incomingHTML) {
6497
 
            var html = this._cleanIncomingHTML(incomingHTML);
6498
 
            this._getDoc().body.innerHTML = html;
6499
 
            this.nodeChange();
6500
 
        },
6501
 
        /**
6502
 
        * @method getEditorHTML
6503
 
        * @description Gets the unprocessed/unfiltered HTML from the editor
6504
 
        */
6505
 
        getEditorHTML: function() {
6506
 
            var b = this._getDoc().body;
6507
 
            if (b === null) {
6508
 
                YAHOO.log('Body is null, returning null.', 'error', 'SimpleEditor');
6509
 
                return null;
6510
 
            }
6511
 
            return this._getDoc().body.innerHTML;
6512
 
        },
6513
 
        /**
6514
 
        * @method show
6515
 
        * @description This method needs to be called if the Editor was hidden (like in a TabView or Panel). It is used to reset the editor after being in a container that was set to display none.
6516
 
        */
6517
 
        show: function() {
6518
 
            if (this.browser.gecko) {
6519
 
                this._setDesignMode('on');
6520
 
                this.focus();
6521
 
            }
6522
 
            if (this.browser.webkit) {
6523
 
                var self = this;
6524
 
                window.setTimeout(function() {
6525
 
                    self._setInitialContent.call(self);
6526
 
                }, 10);
6527
 
            }
6528
 
            //Adding this will close all other Editor window's when showing this one.
6529
 
            if (this.currentWindow) {
6530
 
                this.closeWindow();
6531
 
            }
6532
 
            //Put the iframe back in place
6533
 
            this.get('iframe').setStyle('position', 'static');
6534
 
            this.get('iframe').setStyle('left', '');
6535
 
        },
6536
 
        /**
6537
 
        * @method hide
6538
 
        * @description This method needs to be called if the Editor is to be hidden (like in a TabView or Panel). It should be called to clear timeouts and close open editor windows.
6539
 
        */
6540
 
        hide: function() {
6541
 
            //Adding this will close all other Editor window's.
6542
 
            if (this.currentWindow) {
6543
 
                this.closeWindow();
6544
 
            }
6545
 
            if (this._fixNodesTimer) {
6546
 
                clearTimeout(this._fixNodesTimer);
6547
 
                this._fixNodesTimer = null;
6548
 
            }
6549
 
            if (this._nodeChangeTimer) {
6550
 
                clearTimeout(this._nodeChangeTimer);
6551
 
                this._nodeChangeTimer = null;
6552
 
            }
6553
 
            this._lastNodeChange = 0;
6554
 
            //Move the iframe off of the screen, so that in containers with visiblity hidden, IE will not cover other elements.
6555
 
            this.get('iframe').setStyle('position', 'absolute');
6556
 
            this.get('iframe').setStyle('left', '-9999px');
6557
 
        },
6558
 
        /**
6559
 
        * @method _cleanIncomingHTML
6560
 
        * @param {String} html The unfiltered HTML
6561
 
        * @description Process the HTML with a few regexes to clean it up and stabilize the input
6562
 
        * @return {String} The filtered HTML
6563
 
        */
6564
 
        _cleanIncomingHTML: function(html) {
6565
 
            html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
6566
 
            html = html.replace(/<\/strong>/gi, '</b>');   
6567
 
 
6568
 
            //replace embed before em check
6569
 
            html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
6570
 
            html = html.replace(/<\/embed>/gi, '</YUI_EMBED>');
6571
 
 
6572
 
            html = html.replace(/<em([^>]*)>/gi, '<i$1>');
6573
 
            html = html.replace(/<\/em>/gi, '</i>');
6574
 
            html = html.replace(/_moz_dirty=""/gi, '');
6575
 
            
6576
 
            //Put embed tags back in..
6577
 
            html = html.replace(/<YUI_EMBED([^>]*)>/gi, '<embed$1>');
6578
 
            html = html.replace(/<\/YUI_EMBED>/gi, '</embed>');
6579
 
            if (this.get('plainText')) {
6580
 
                YAHOO.log('Filtering as plain text', 'info', 'SimpleEditor');
6581
 
                html = html.replace(/\n/g, '<br>').replace(/\r/g, '<br>');
6582
 
                html = html.replace(/  /gi, '&nbsp;&nbsp;'); //Replace all double spaces
6583
 
                html = html.replace(/\t/gi, '&nbsp;&nbsp;&nbsp;&nbsp;'); //Replace all tabs
6584
 
            }
6585
 
            //Removing Script Tags from the Editor
6586
 
            html = html.replace(/<script([^>]*)>/gi, '<bad>');
6587
 
            html = html.replace(/<\/script([^>]*)>/gi, '</bad>');
6588
 
            html = html.replace(/&lt;script([^>]*)&gt;/gi, '<bad>');
6589
 
            html = html.replace(/&lt;\/script([^>]*)&gt;/gi, '</bad>');
6590
 
            //Replace the line feeds
6591
 
            html = html.replace(/\r\n/g, '<YUI_LF>').replace(/\n/g, '<YUI_LF>').replace(/\r/g, '<YUI_LF>');
6592
 
            
6593
 
            //Remove Bad HTML elements (used to be script nodes)
6594
 
            html = html.replace(new RegExp('<bad([^>]*)>(.*?)<\/bad>', 'gi'), '');
6595
 
            //Replace the lines feeds
6596
 
            html = html.replace(/<YUI_LF>/g, '\n');
6597
 
            return html;
6598
 
        },
6599
 
        /**
6600
 
        * @method cleanHTML
6601
 
        * @param {String} html The unfiltered HTML
6602
 
        * @description Process the HTML with a few regexes to clean it up and stabilize the output
6603
 
        * @return {String} The filtered HTML
6604
 
        */
6605
 
        cleanHTML: function(html) {
6606
 
            //Start Filtering Output
6607
 
            //Begin RegExs..
6608
 
            if (!html) { 
6609
 
                html = this.getEditorHTML();
6610
 
            }
6611
 
            var markup = this.get('markup');
6612
 
            //Make some backups...
6613
 
            html = this.pre_filter_linebreaks(html, markup);
6614
 
 
6615
 
            //Filter MS Word
6616
 
            html = this.filter_msword(html);
6617
 
 
6618
 
                    html = html.replace(/<img([^>]*)\/>/gi, '<YUI_IMG$1>');
6619
 
                    html = html.replace(/<img([^>]*)>/gi, '<YUI_IMG$1>');
6620
 
 
6621
 
                    html = html.replace(/<input([^>]*)\/>/gi, '<YUI_INPUT$1>');
6622
 
                    html = html.replace(/<input([^>]*)>/gi, '<YUI_INPUT$1>');
6623
 
 
6624
 
                    html = html.replace(/<ul([^>]*)>/gi, '<YUI_UL$1>');
6625
 
                    html = html.replace(/<\/ul>/gi, '<\/YUI_UL>');
6626
 
                    html = html.replace(/<blockquote([^>]*)>/gi, '<YUI_BQ$1>');
6627
 
                    html = html.replace(/<\/blockquote>/gi, '<\/YUI_BQ>');
6628
 
 
6629
 
                    html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
6630
 
                    html = html.replace(/<\/embed>/gi, '<\/YUI_EMBED>');
6631
 
 
6632
 
            //Convert b and i tags to strong and em tags
6633
 
            if ((markup == 'semantic') || (markup == 'xhtml')) {
6634
 
                html = html.replace(/<i(\s+[^>]*)?>/gi, '<em$1>');
6635
 
                html = html.replace(/<\/i>/gi, '</em>');
6636
 
                html = html.replace(/<b(\s+[^>]*)?>/gi, '<strong$1>');
6637
 
                html = html.replace(/<\/b>/gi, '</strong>');
6638
 
            }
6639
 
 
6640
 
            html = html.replace(/_moz_dirty=""/gi, '');
6641
 
 
6642
 
            //normalize strikethrough
6643
 
            html = html.replace(/<strike/gi, '<span style="text-decoration: line-through;"');
6644
 
            html = html.replace(/\/strike>/gi, '/span>');
6645
 
            
6646
 
            
6647
 
            //Case Changing
6648
 
            if (this.browser.ie) {
6649
 
                html = html.replace(/text-decoration/gi, 'text-decoration');
6650
 
                html = html.replace(/font-weight/gi, 'font-weight');
6651
 
                html = html.replace(/_width="([^>]*)"/gi, '');
6652
 
                html = html.replace(/_height="([^>]*)"/gi, '');
6653
 
                //Cleanup Image URL's
6654
 
                var url = this._baseHREF.replace(/\//gi, '\\/'),
6655
 
                    re = new RegExp('src="' + url, 'gi');
6656
 
                html = html.replace(re, 'src="');
6657
 
            }
6658
 
                    html = html.replace(/<font/gi, '<font');
6659
 
                    html = html.replace(/<\/font>/gi, '</font>');
6660
 
                    html = html.replace(/<span/gi, '<span');
6661
 
                    html = html.replace(/<\/span>/gi, '</span>');
6662
 
            if ((markup == 'semantic') || (markup == 'xhtml') || (markup == 'css')) {
6663
 
                html = html.replace(new RegExp('<font([^>]*)face="([^>]*)">(.*?)<\/font>', 'gi'), '<span $1 style="font-family: $2;">$3</span>');
6664
 
                html = html.replace(/<u/gi, '<span style="text-decoration: underline;"');
6665
 
                if (this.browser.webkit) {
6666
 
                    html = html.replace(new RegExp('<span class="Apple-style-span" style="font-weight: bold;">([^>]*)<\/span>', 'gi'), '<strong>$1</strong>');
6667
 
                    html = html.replace(new RegExp('<span class="Apple-style-span" style="font-style: italic;">([^>]*)<\/span>', 'gi'), '<em>$1</em>');
6668
 
                }
6669
 
                html = html.replace(/\/u>/gi, '/span>');
6670
 
                if (markup == 'css') {
6671
 
                    html = html.replace(/<em([^>]*)>/gi, '<i$1>');
6672
 
                    html = html.replace(/<\/em>/gi, '</i>');
6673
 
                    html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
6674
 
                    html = html.replace(/<\/strong>/gi, '</b>');
6675
 
                    html = html.replace(/<b/gi, '<span style="font-weight: bold;"');
6676
 
                    html = html.replace(/\/b>/gi, '/span>');
6677
 
                    html = html.replace(/<i/gi, '<span style="font-style: italic;"');
6678
 
                    html = html.replace(/\/i>/gi, '/span>');
6679
 
                }
6680
 
                html = html.replace(/  /gi, ' '); //Replace all double spaces and replace with a single
6681
 
            } else {
6682
 
                        html = html.replace(/<u/gi, '<u');
6683
 
                        html = html.replace(/\/u>/gi, '/u>');
6684
 
            }
6685
 
                    html = html.replace(/<ol([^>]*)>/gi, '<ol$1>');
6686
 
                    html = html.replace(/\/ol>/gi, '/ol>');
6687
 
                    html = html.replace(/<li/gi, '<li');
6688
 
                    html = html.replace(/\/li>/gi, '/li>');
6689
 
            html = this.filter_safari(html);
6690
 
 
6691
 
            html = this.filter_internals(html);
6692
 
 
6693
 
            html = this.filter_all_rgb(html);
6694
 
 
6695
 
            //Replace our backups with the real thing
6696
 
            html = this.post_filter_linebreaks(html, markup);
6697
 
 
6698
 
            if (markup == 'xhtml') {
6699
 
                        html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1 />');
6700
 
                        html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1 />');
6701
 
            } else {
6702
 
                        html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1>');
6703
 
                        html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1>');
6704
 
            }
6705
 
                    html = html.replace(/<YUI_UL([^>]*)>/g, '<ul$1>');
6706
 
                    html = html.replace(/<\/YUI_UL>/g, '<\/ul>');
6707
 
 
6708
 
            html = this.filter_invalid_lists(html);
6709
 
 
6710
 
                    html = html.replace(/<YUI_BQ([^>]*)>/g, '<blockquote$1>');
6711
 
                    html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>');
6712
 
 
6713
 
                    html = html.replace(/<YUI_EMBED([^>]*)>/g, '<embed$1>');
6714
 
                    html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>');
6715
 
            
6716
 
            //This should fix &amp;s in URL's
6717
 
            html = html.replace(/ &amp; /gi, 'YUI_AMP');
6718
 
            html = html.replace(/&amp;/gi, '&');
6719
 
            html = html.replace(/YUI_AMP/gi, ' &amp; ');
6720
 
 
6721
 
            //Trim the output, removing whitespace from the beginning and end
6722
 
            html = YAHOO.lang.trim(html);
6723
 
 
6724
 
            if (this.get('removeLineBreaks')) {
6725
 
                html = html.replace(/\n/g, '').replace(/\r/g, '');
6726
 
                html = html.replace(/  /gi, ' '); //Replace all double spaces and replace with a single
6727
 
            }
6728
 
            
6729
 
            //First empty span
6730
 
            if (html.substring(0, 6).toLowerCase() == '<span>')  {
6731
 
                html = html.substring(6);
6732
 
                //Last empty span
6733
 
                if (html.substring(html.length - 7, html.length).toLowerCase() == '</span>')  {
6734
 
                    html = html.substring(0, html.length - 7);
6735
 
                }
6736
 
            }
6737
 
 
6738
 
            for (var v in this.invalidHTML) {
6739
 
                if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
6740
 
                    if (Lang.isObject(v) && v.keepContents) {
6741
 
                        html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1');
6742
 
                    } else {
6743
 
                        html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '');
6744
 
                    }
6745
 
                }
6746
 
            }
6747
 
 
6748
 
            this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html });
6749
 
 
6750
 
            return html;
6751
 
        },
6752
 
        /**
6753
 
        * @method filter_msword
6754
 
        * @param String html The HTML string to filter
6755
 
        * @description Filters out msword html attributes and other junk. Activate with filterWord: true in config
6756
 
        */
6757
 
        filter_msword: function(html) {
6758
 
            if (!this.get('filterWord')) {
6759
 
                return html;
6760
 
            }
6761
 
            //Remove the ms o: tags
6762
 
            html = html.replace(/<o:p>\s*<\/o:p>/g, '');
6763
 
            html = html.replace(/<o:p>[\s\S]*?<\/o:p>/g, '&nbsp;');
6764
 
 
6765
 
            //Remove the ms w: tags
6766
 
            html = html.replace( /<w:[^>]*>[\s\S]*?<\/w:[^>]*>/gi, '');
6767
 
 
6768
 
            //Remove mso-? styles.
6769
 
            html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '');
6770
 
 
6771
 
            //Remove more bogus MS styles.
6772
 
            html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*;/gi, '');
6773
 
            html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*"/gi, "\"");
6774
 
            html = html.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '');
6775
 
            html = html.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"");
6776
 
            html = html.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"");
6777
 
            html = html.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" );
6778
 
            html = html.replace( /\s*tab-stops:[^;"]*;?/gi, '');
6779
 
            html = html.replace( /\s*tab-stops:[^"]*/gi, '');
6780
 
 
6781
 
            //Remove XML declarations
6782
 
            html = html.replace(/<\\?\?xml[^>]*>/gi, '');
6783
 
 
6784
 
            //Remove lang
6785
 
            html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
6786
 
 
6787
 
            //Remove language tags
6788
 
            html = html.replace( /<(\w[^>]*) language=([^ |>]*)([^>]*)/gi, "<$1$3");
6789
 
 
6790
 
            //Remove onmouseover and onmouseout events (from MS Word comments effect)
6791
 
            html = html.replace( /<(\w[^>]*) onmouseover="([^\"]*)"([^>]*)/gi, "<$1$3");
6792
 
            html = html.replace( /<(\w[^>]*) onmouseout="([^\"]*)"([^>]*)/gi, "<$1$3");
6793
 
            
6794
 
            return html;
6795
 
        },
6796
 
        /**
6797
 
        * @method filter_invalid_lists
6798
 
        * @param String html The HTML string to filter
6799
 
        * @description Filters invalid ol and ul list markup, converts this: <li></li><ol>..</ol> to this: <li></li><li><ol>..</ol></li>
6800
 
        */
6801
 
        filter_invalid_lists: function(html) {
6802
 
            html = html.replace(/<\/li>\n/gi, '</li>');
6803
 
 
6804
 
            html = html.replace(/<\/li><ol>/gi, '</li><li><ol>');
6805
 
            html = html.replace(/<\/ol>/gi, '</ol></li>');
6806
 
            html = html.replace(/<\/ol><\/li>\n/gi, "</ol>");
6807
 
 
6808
 
            html = html.replace(/<\/li><ul>/gi, '</li><li><ul>');
6809
 
            html = html.replace(/<\/ul>/gi, '</ul></li>');
6810
 
            html = html.replace(/<\/ul><\/li>\n?/gi, "</ul>");
6811
 
 
6812
 
            html = html.replace(/<\/li>/gi, "</li>");
6813
 
            html = html.replace(/<\/ol>/gi, "</ol>");
6814
 
            html = html.replace(/<ol>/gi, "<ol>");
6815
 
            html = html.replace(/<ul>/gi, "<ul>");
6816
 
            return html;
6817
 
        },
6818
 
        /**
6819
 
        * @method filter_safari
6820
 
        * @param String html The HTML string to filter
6821
 
        * @description Filters strings specific to Safari
6822
 
        * @return String
6823
 
        */
6824
 
        filter_safari: function(html) {
6825
 
            if (this.browser.webkit) {
6826
 
                //<span class="Apple-tab-span" style="white-space:pre"> </span>
6827
 
                html = html.replace(/<span class="Apple-tab-span" style="white-space:pre">([^>])<\/span>/gi, '&nbsp;&nbsp;&nbsp;&nbsp;');
6828
 
                html = html.replace(/Apple-style-span/gi, '');
6829
 
                html = html.replace(/style="line-height: normal;"/gi, '');
6830
 
                html = html.replace(/yui-wk-div/gi, '');
6831
 
                html = html.replace(/yui-wk-p/gi, '');
6832
 
 
6833
 
 
6834
 
                //Remove bogus LI's
6835
 
                html = html.replace(/<li><\/li>/gi, '');
6836
 
                html = html.replace(/<li> <\/li>/gi, '');
6837
 
                html = html.replace(/<li>  <\/li>/gi, '');
6838
 
                //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break
6839
 
                if (this.get('ptags')) {
6840
 
                            html = html.replace(/<div([^>]*)>/g, '<p$1>');
6841
 
                                    html = html.replace(/<\/div>/gi, '</p>');
6842
 
                } else {
6843
 
                    html = html.replace(/<div>/gi, '<br>');
6844
 
                                    html = html.replace(/<\/div>/gi, '');
6845
 
                }
6846
 
            }
6847
 
            return html;
6848
 
        },
6849
 
        /**
6850
 
        * @method filter_internals
6851
 
        * @param String html The HTML string to filter
6852
 
        * @description Filters internal RTE strings and bogus attrs we don't want
6853
 
        * @return String
6854
 
        */
6855
 
        filter_internals: function(html) {
6856
 
                    html = html.replace(/\r/g, '');
6857
 
            //Fix stuff we don't want
6858
 
                html = html.replace(/<\/?(body|head|html)[^>]*>/gi, '');
6859
 
            //Fix last BR in LI
6860
 
                    html = html.replace(/<YUI_BR><\/li>/gi, '</li>');
6861
 
 
6862
 
                    html = html.replace(/yui-tag-span/gi, '');
6863
 
                    html = html.replace(/yui-tag/gi, '');
6864
 
                    html = html.replace(/yui-non/gi, '');
6865
 
                    html = html.replace(/yui-img/gi, '');
6866
 
                    html = html.replace(/ tag="span"/gi, '');
6867
 
                    html = html.replace(/ class=""/gi, '');
6868
 
                    html = html.replace(/ style=""/gi, '');
6869
 
                    html = html.replace(/ class=" "/gi, '');
6870
 
                    html = html.replace(/ class="  "/gi, '');
6871
 
                    html = html.replace(/ target=""/gi, '');
6872
 
                    html = html.replace(/ title=""/gi, '');
6873
 
 
6874
 
            if (this.browser.ie) {
6875
 
                        html = html.replace(/ class= /gi, '');
6876
 
                        html = html.replace(/ class= >/gi, '');
6877
 
            }
6878
 
            
6879
 
            return html;
6880
 
        },
6881
 
        /**
6882
 
        * @method filter_all_rgb
6883
 
        * @param String str The HTML string to filter
6884
 
        * @description Converts all RGB color strings found in passed string to a hex color, example: style="color: rgb(0, 255, 0)" converts to style="color: #00ff00"
6885
 
        * @return String
6886
 
        */
6887
 
        filter_all_rgb: function(str) {
6888
 
            var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi");
6889
 
            var arr = str.match(exp);
6890
 
            if (Lang.isArray(arr)) {
6891
 
                for (var i = 0; i < arr.length; i++) {
6892
 
                    var color = this.filter_rgb(arr[i]);
6893
 
                    str = str.replace(arr[i].toString(), color);
6894
 
                }
6895
 
            }
6896
 
            
6897
 
            return str;
6898
 
        },
6899
 
        /**
6900
 
        * @method filter_rgb
6901
 
        * @param String css The CSS string containing rgb(#,#,#);
6902
 
        * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00
6903
 
        * @return String
6904
 
        */
6905
 
        filter_rgb: function(css) {
6906
 
            if (css.toLowerCase().indexOf('rgb') != -1) {
6907
 
                var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
6908
 
                var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(',');
6909
 
            
6910
 
                if (rgb.length == 5) {
6911
 
                    var r = parseInt(rgb[1], 10).toString(16);
6912
 
                    var g = parseInt(rgb[2], 10).toString(16);
6913
 
                    var b = parseInt(rgb[3], 10).toString(16);
6914
 
 
6915
 
                    r = r.length == 1 ? '0' + r : r;
6916
 
                    g = g.length == 1 ? '0' + g : g;
6917
 
                    b = b.length == 1 ? '0' + b : b;
6918
 
 
6919
 
                    css = "#" + r + g + b;
6920
 
                }
6921
 
            }
6922
 
            return css;
6923
 
        },
6924
 
        /**
6925
 
        * @method pre_filter_linebreaks
6926
 
        * @param String html The HTML to filter
6927
 
        * @param String markup The markup type to filter to
6928
 
        * @description HTML Pre Filter
6929
 
        * @return String
6930
 
        */
6931
 
        pre_filter_linebreaks: function(html, markup) {
6932
 
            if (this.browser.webkit) {
6933
 
                        html = html.replace(/<br class="khtml-block-placeholder">/gi, '<YUI_BR>');
6934
 
                        html = html.replace(/<br class="webkit-block-placeholder">/gi, '<YUI_BR>');
6935
 
            }
6936
 
                    html = html.replace(/<br>/gi, '<YUI_BR>');
6937
 
                    html = html.replace(/<br (.*?)>/gi, '<YUI_BR>');
6938
 
                    html = html.replace(/<br\/>/gi, '<YUI_BR>');
6939
 
                    html = html.replace(/<br \/>/gi, '<YUI_BR>');
6940
 
                    html = html.replace(/<div><YUI_BR><\/div>/gi, '<YUI_BR>');
6941
 
                    html = html.replace(/<p>(&nbsp;|&#160;)<\/p>/g, '<YUI_BR>');            
6942
 
                    html = html.replace(/<p><br>&nbsp;<\/p>/gi, '<YUI_BR>');
6943
 
                    html = html.replace(/<p>&nbsp;<\/p>/gi, '<YUI_BR>');
6944
 
            //Fix last BR
6945
 
                html = html.replace(/<YUI_BR>$/, '');
6946
 
            //Fix last BR in P
6947
 
                html = html.replace(/<YUI_BR><\/p>/g, '</p>');
6948
 
            if (this.browser.ie) {
6949
 
                    html = html.replace(/&nbsp;&nbsp;&nbsp;&nbsp;/g, '\t');
6950
 
            }
6951
 
            return html;
6952
 
        },
6953
 
        /**
6954
 
        * @method post_filter_linebreaks
6955
 
        * @param String html The HTML to filter
6956
 
        * @param String markup The markup type to filter to
6957
 
        * @description HTML Pre Filter
6958
 
        * @return String
6959
 
        */
6960
 
        post_filter_linebreaks: function(html, markup) {
6961
 
            if (markup == 'xhtml') {
6962
 
                        html = html.replace(/<YUI_BR>/g, '<br />');
6963
 
            } else {
6964
 
                        html = html.replace(/<YUI_BR>/g, '<br>');
6965
 
            }
6966
 
            return html;
6967
 
        },
6968
 
        /**
6969
 
        * @method clearEditorDoc
6970
 
        * @description Clear the doc of the Editor
6971
 
        */
6972
 
        clearEditorDoc: function() {
6973
 
            this._getDoc().body.innerHTML = '&nbsp;';
6974
 
        },
6975
 
        /**
6976
 
        * @method openWindow
6977
 
        * @description Override Method for Advanced Editor
6978
 
        */
6979
 
        openWindow: function(win) {
6980
 
        },
6981
 
        /**
6982
 
        * @method moveWindow
6983
 
        * @description Override Method for Advanced Editor
6984
 
        */
6985
 
        moveWindow: function() {
6986
 
        },
6987
 
        /**
6988
 
        * @private
6989
 
        * @method _closeWindow
6990
 
        * @description Override Method for Advanced Editor
6991
 
        */
6992
 
        _closeWindow: function() {
6993
 
        },
6994
 
        /**
6995
 
        * @method closeWindow
6996
 
        * @description Override Method for Advanced Editor
6997
 
        */
6998
 
        closeWindow: function() {
6999
 
            //this.unsubscribeAll('afterExecCommand');
7000
 
            this.toolbar.resetAllButtons();
7001
 
            this.focus();        
7002
 
        },
7003
 
        /**
7004
 
        * @method destroy
7005
 
        * @description Destroys the editor, all of it's elements and objects.
7006
 
        * @return {Boolean}
7007
 
        */
7008
 
        destroy: function() {
7009
 
            YAHOO.log('Destroying Editor', 'warn', 'SimpleEditor');
7010
 
            if (this.resize) {
7011
 
                YAHOO.log('Destroying Resize', 'warn', 'SimpleEditor');
7012
 
                this.resize.destroy();
7013
 
            }
7014
 
            if (this.dd) {
7015
 
                YAHOO.log('Unreg DragDrop Instance', 'warn', 'SimpleEditor');
7016
 
                this.dd.unreg();
7017
 
            }
7018
 
            if (this.get('panel')) {
7019
 
                YAHOO.log('Destroying Editor Panel', 'warn', 'SimpleEditor');
7020
 
                this.get('panel').destroy();
7021
 
            }
7022
 
            this.saveHTML();
7023
 
            this.toolbar.destroy();
7024
 
            YAHOO.log('Restoring TextArea', 'info', 'SimpleEditor');
7025
 
            this.setStyle('visibility', 'visible');
7026
 
            this.setStyle('position', 'static');
7027
 
            this.setStyle('top', '');
7028
 
            this.setStyle('left', '');
7029
 
            var textArea = this.get('element');
7030
 
            this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element'));
7031
 
            this.get('element_cont').get('element').innerHTML = '';
7032
 
            this.set('handleSubmit', false); //Remove the submit handler
7033
 
            return true;
7034
 
        },        
7035
 
        /**
7036
 
        * @method toString
7037
 
        * @description Returns a string representing the editor.
7038
 
        * @return {String}
7039
 
        */
7040
 
        toString: function() {
7041
 
            var str = 'SimpleEditor';
7042
 
            if (this.get && this.get('element_cont')) {
7043
 
                str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
7044
 
            }
7045
 
            return str;
7046
 
        }
7047
 
    });
7048
 
 
7049
 
/**
7050
 
* @event toolbarLoaded
7051
 
* @description Event is fired during the render process directly after the Toolbar is loaded. Allowing you to attach events to the toolbar. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7052
 
* @type YAHOO.util.CustomEvent
7053
 
*/
7054
 
/**
7055
 
* @event cleanHTML
7056
 
* @description Event is fired after the cleanHTML method is called.
7057
 
* @type YAHOO.util.CustomEvent
7058
 
*/
7059
 
/**
7060
 
* @event afterRender
7061
 
* @description Event is fired after the render process finishes. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7062
 
* @type YAHOO.util.CustomEvent
7063
 
*/
7064
 
/**
7065
 
* @event editorContentLoaded
7066
 
* @description Event is fired after the editor iframe's document fully loads and fires it's onload event. From here you can start injecting your own things into the document. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7067
 
* @type YAHOO.util.CustomEvent
7068
 
*/
7069
 
/**
7070
 
* @event beforeNodeChange
7071
 
* @description Event fires at the beginning of the nodeChange process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7072
 
* @type YAHOO.util.CustomEvent
7073
 
*/
7074
 
/**
7075
 
* @event afterNodeChange
7076
 
* @description Event fires at the end of the nodeChange process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7077
 
* @type YAHOO.util.CustomEvent
7078
 
*/
7079
 
/**
7080
 
* @event beforeExecCommand
7081
 
* @description Event fires at the beginning of the execCommand process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7082
 
* @type YAHOO.util.CustomEvent
7083
 
*/
7084
 
/**
7085
 
* @event afterExecCommand
7086
 
* @description Event fires at the end of the execCommand process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7087
 
* @type YAHOO.util.CustomEvent
7088
 
*/
7089
 
/**
7090
 
* @event editorMouseUp
7091
 
* @param {Event} ev The DOM Event that occured
7092
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7093
 
* @type YAHOO.util.CustomEvent
7094
 
*/
7095
 
/**
7096
 
* @event editorMouseDown
7097
 
* @param {Event} ev The DOM Event that occured
7098
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7099
 
* @type YAHOO.util.CustomEvent
7100
 
*/
7101
 
/**
7102
 
* @event editorDoubleClick
7103
 
* @param {Event} ev The DOM Event that occured
7104
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7105
 
* @type YAHOO.util.CustomEvent
7106
 
*/
7107
 
/**
7108
 
* @event editorClick
7109
 
* @param {Event} ev The DOM Event that occured
7110
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7111
 
* @type YAHOO.util.CustomEvent
7112
 
*/
7113
 
/**
7114
 
* @event editorKeyUp
7115
 
* @param {Event} ev The DOM Event that occured
7116
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7117
 
* @type YAHOO.util.CustomEvent
7118
 
*/
7119
 
/**
7120
 
* @event editorKeyPress
7121
 
* @param {Event} ev The DOM Event that occured
7122
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7123
 
* @type YAHOO.util.CustomEvent
7124
 
*/
7125
 
/**
7126
 
* @event editorKeyDown
7127
 
* @param {Event} ev The DOM Event that occured
7128
 
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
7129
 
* @type YAHOO.util.CustomEvent
7130
 
*/
7131
 
/**
7132
 
* @event beforeEditorMouseUp
7133
 
* @param {Event} ev The DOM Event that occured
7134
 
* @description Fires before editor event, returning false will stop the internal processing.
7135
 
* @type YAHOO.util.CustomEvent
7136
 
*/
7137
 
/**
7138
 
* @event beforeEditorMouseDown
7139
 
* @param {Event} ev The DOM Event that occured
7140
 
* @description Fires before editor event, returning false will stop the internal processing.
7141
 
* @type YAHOO.util.CustomEvent
7142
 
*/
7143
 
/**
7144
 
* @event beforeEditorDoubleClick
7145
 
* @param {Event} ev The DOM Event that occured
7146
 
* @description Fires before editor event, returning false will stop the internal processing.
7147
 
* @type YAHOO.util.CustomEvent
7148
 
*/
7149
 
/**
7150
 
* @event beforeEditorClick
7151
 
* @param {Event} ev The DOM Event that occured
7152
 
* @description Fires before editor event, returning false will stop the internal processing.
7153
 
* @type YAHOO.util.CustomEvent
7154
 
*/
7155
 
/**
7156
 
* @event beforeEditorKeyUp
7157
 
* @param {Event} ev The DOM Event that occured
7158
 
* @description Fires before editor event, returning false will stop the internal processing.
7159
 
* @type YAHOO.util.CustomEvent
7160
 
*/
7161
 
/**
7162
 
* @event beforeEditorKeyPress
7163
 
* @param {Event} ev The DOM Event that occured
7164
 
* @description Fires before editor event, returning false will stop the internal processing.
7165
 
* @type YAHOO.util.CustomEvent
7166
 
*/
7167
 
/**
7168
 
* @event beforeEditorKeyDown
7169
 
* @param {Event} ev The DOM Event that occured
7170
 
* @description Fires before editor event, returning false will stop the internal processing.
7171
 
* @type YAHOO.util.CustomEvent
7172
 
*/
7173
 
 
7174
 
/**
7175
 
* @event editorWindowFocus
7176
 
* @description Fires when the iframe is focused. Note, this is window focus event, not an Editor focus event.
7177
 
* @type YAHOO.util.CustomEvent
7178
 
*/
7179
 
/**
7180
 
* @event editorWindowBlur
7181
 
* @description Fires when the iframe is blurred. Note, this is window blur event, not an Editor blur event.
7182
 
* @type YAHOO.util.CustomEvent
7183
 
*/
7184
 
 
7185
 
 
7186
 
/**
7187
 
 * @description Singleton object used to track the open window objects and panels across the various open editors
7188
 
 * @class EditorInfo
7189
 
 * @static
7190
 
*/
7191
 
YAHOO.widget.EditorInfo = {
7192
 
    /**
7193
 
    * @private
7194
 
    * @property _instances
7195
 
    * @description A reference to all editors on the page.
7196
 
    * @type Object
7197
 
    */
7198
 
    _instances: {},
7199
 
    /**
7200
 
    * @private
7201
 
    * @property blankImage
7202
 
    * @description A reference to the blankImage url
7203
 
    * @type String 
7204
 
    */
7205
 
    blankImage: '',
7206
 
    /**
7207
 
    * @private
7208
 
    * @property window
7209
 
    * @description A reference to the currently open window object in any editor on the page.
7210
 
    * @type Object <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>
7211
 
    */
7212
 
    window: {},
7213
 
    /**
7214
 
    * @private
7215
 
    * @property panel
7216
 
    * @description A reference to the currently open panel in any editor on the page.
7217
 
    * @type Object <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
7218
 
    */
7219
 
    panel: null,
7220
 
    /**
7221
 
    * @method getEditorById
7222
 
    * @description Returns a reference to the Editor object associated with the given textarea
7223
 
    * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of
7224
 
    * @return Object <a href="YAHOO.widget.Editor.html">YAHOO.widget.Editor</a>
7225
 
    */
7226
 
    getEditorById: function(id) {
7227
 
        if (!YAHOO.lang.isString(id)) {
7228
 
            //Not a string, assume a node Reference
7229
 
            id = id.id;
7230
 
        }
7231
 
        if (this._instances[id]) {
7232
 
            return this._instances[id];
7233
 
        }
7234
 
        return false;
7235
 
    },
7236
 
    /**
7237
 
    * @method toString
7238
 
    * @description Returns a string representing the EditorInfo.
7239
 
    * @return {String}
7240
 
    */
7241
 
    toString: function() {
7242
 
        var len = 0;
7243
 
        for (var i in this._instances) {
7244
 
            if (Lang.hasOwnProperty(this._instances, i)) {
7245
 
                len++;
7246
 
            }
7247
 
        }
7248
 
        return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')';
7249
 
    }
7250
 
};
7251
 
 
7252
 
 
7253
 
 
7254
 
    
7255
 
})();
7256
 
/**
7257
 
 * @module editor
7258
 
 * @description <p>The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.</p>
7259
 
 * @namespace YAHOO.widget
7260
 
 * @requires yahoo, dom, element, event, container_core, simpleeditor
7261
 
 * @optional dragdrop, animation, menu, button, resize
7262
 
 */
7263
 
 
7264
 
(function() {
7265
 
var Dom = YAHOO.util.Dom,
7266
 
    Event = YAHOO.util.Event,
7267
 
    Lang = YAHOO.lang,
7268
 
    Toolbar = YAHOO.widget.Toolbar;
7269
 
 
7270
 
    /**
7271
 
     * The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.
7272
 
     * @constructor
7273
 
     * @class Editor
7274
 
     * @extends YAHOO.widget.SimpleEditor
7275
 
     * @param {String/HTMLElement} el The textarea element to turn into an editor.
7276
 
     * @param {Object} attrs Object liternal containing configuration parameters.
7277
 
    */
7278
 
    
7279
 
    YAHOO.widget.Editor = function(el, attrs) {
7280
 
        YAHOO.log('Editor Initalizing', 'info', 'Editor');
7281
 
        YAHOO.widget.Editor.superclass.constructor.call(this, el, attrs);
7282
 
    };
7283
 
 
7284
 
    YAHOO.extend(YAHOO.widget.Editor, YAHOO.widget.SimpleEditor, {
7285
 
        /**
7286
 
        * @private
7287
 
        * @property _undoCache
7288
 
        * @description An Array hash of the Undo Levels.
7289
 
        * @type Array
7290
 
        */
7291
 
        _undoCache: null,
7292
 
        /**
7293
 
        * @private
7294
 
        * @property _undoLevel
7295
 
        * @description The index of the current undo state.
7296
 
        * @type Number
7297
 
        */
7298
 
        _undoLevel: null,    
7299
 
        /**
7300
 
        * @private
7301
 
        * @method _hasUndoLevel
7302
 
        * @description Checks to see if we have an undo level available
7303
 
        * @return Boolean
7304
 
        */
7305
 
        _hasUndoLevel: function() {
7306
 
            return ((this._undoCache.length > 1) && this._undoLevel);
7307
 
        },
7308
 
        /**
7309
 
        * @private
7310
 
        * @method _undoNodeChange
7311
 
        * @description nodeChange listener for undo processing
7312
 
        */
7313
 
        _undoNodeChange: function() {
7314
 
            var undo_button = this.toolbar.getButtonByValue('undo'),
7315
 
                redo_button = this.toolbar.getButtonByValue('redo');
7316
 
            if (undo_button && redo_button) {
7317
 
                if (this._hasUndoLevel()) {
7318
 
                    this.toolbar.enableButton(undo_button);
7319
 
                }
7320
 
                if (this._undoLevel < this._undoCache.length) {
7321
 
                    this.toolbar.enableButton(redo_button);
7322
 
                }
7323
 
            }
7324
 
            this._lastCommand = null;
7325
 
        },
7326
 
        /**
7327
 
        * @private
7328
 
        * @method _checkUndo
7329
 
        * @description Prunes the undo cache when it reaches the maxUndo config
7330
 
        */
7331
 
        _checkUndo: function() {
7332
 
            var len = this._undoCache.length,
7333
 
            tmp = [];
7334
 
            if (len >= this.get('maxUndo')) {
7335
 
                //YAHOO.log('Undo cache too large (' + len + '), pruning..', 'info', 'SimpleEditor');
7336
 
                for (var i = (len - this.get('maxUndo')); i < len; i++) {
7337
 
                    tmp.push(this._undoCache[i]);
7338
 
                }
7339
 
                this._undoCache = tmp;
7340
 
            }
7341
 
        },
7342
 
        /**
7343
 
        * @private
7344
 
        * @method _putUndo
7345
 
        * @description Puts the content of the Editor into the _undoCache.
7346
 
        * //TODO Convert the hash to a series of TEXTAREAS to store state in.
7347
 
        * @param {String} str The content of the Editor
7348
 
        */
7349
 
        _putUndo: function(str) {
7350
 
            this._undoCache.push(str);
7351
 
        },
7352
 
        /**
7353
 
        * @private
7354
 
        * @method _getUndo
7355
 
        * @description Get's a level from the undo cache.
7356
 
        * @param {Number} index The index of the undo level we want to get.
7357
 
        * @return {String}
7358
 
        */
7359
 
        _getUndo: function(index) {
7360
 
            return this._undoCache[index];
7361
 
        },
7362
 
        /**
7363
 
        * @private
7364
 
        * @method _storeUndo
7365
 
        * @description Method to call when you want to store an undo state. Currently called from nodeChange and _handleKeyUp
7366
 
        */
7367
 
        _storeUndo: function() {
7368
 
            if (this._lastCommand === 'undo' || this._lastCommand === 'redo') {
7369
 
                return false;
7370
 
            }
7371
 
            if (!this._undoCache) {
7372
 
                this._undoCache = [];
7373
 
            }
7374
 
            this._checkUndo();
7375
 
            var str = this.getEditorHTML();
7376
 
            var last = this._undoCache[this._undoCache.length - 1];
7377
 
            if (last) {
7378
 
                if (str !== last) {
7379
 
                    //YAHOO.log('Storing Undo', 'info', 'SimpleEditor');
7380
 
                    this._putUndo(str);
7381
 
                }
7382
 
            } else {
7383
 
                //YAHOO.log('Storing Undo', 'info', 'SimpleEditor');
7384
 
                this._putUndo(str);
7385
 
            }
7386
 
            this._undoLevel = this._undoCache.length;
7387
 
            this._undoNodeChange();
7388
 
        },    
7389
 
        /**
7390
 
        * @property STR_BEFORE_EDITOR
7391
 
        * @description The accessibility string for the element before the iFrame
7392
 
        * @type String
7393
 
        */
7394
 
        STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names. <h4>Common formatting keyboard shortcuts:</h4><ul><li>Control Shift B sets text to bold</li> <li>Control Shift I sets text to italic</li> <li>Control Shift U underlines text</li> <li>Control Shift [ aligns text left</li> <li>Control Shift | centers text</li> <li>Control Shift ] aligns text right</li> <li>Control Shift L adds an HTML link</li> <li>To exit this text editor use the keyboard shortcut Control + Shift + ESC.</li></ul>',    
7395
 
        /**
7396
 
        * @property STR_CLOSE_WINDOW
7397
 
        * @description The Title of the close button in the Editor Window
7398
 
        * @type String
7399
 
        */
7400
 
        STR_CLOSE_WINDOW: 'Close Window',
7401
 
        /**
7402
 
        * @property STR_CLOSE_WINDOW_NOTE
7403
 
        * @description A note appearing in the Editor Window to tell the user that the Escape key will close the window
7404
 
        * @type String
7405
 
        */
7406
 
        STR_CLOSE_WINDOW_NOTE: 'To close this window use the Control + Shift + W key',
7407
 
        /**
7408
 
        * @property STR_IMAGE_PROP_TITLE
7409
 
        * @description The title for the Image Property Editor Window
7410
 
        * @type String
7411
 
        */
7412
 
        STR_IMAGE_PROP_TITLE: 'Image Options',
7413
 
        /**
7414
 
        * @property STR_IMAGE_TITLE
7415
 
        * @description The label string for Image Description
7416
 
        * @type String
7417
 
        */
7418
 
        STR_IMAGE_TITLE: 'Description',
7419
 
        /**
7420
 
        * @property STR_IMAGE_SIZE
7421
 
        * @description The label string for Image Size
7422
 
        * @type String
7423
 
        */
7424
 
        STR_IMAGE_SIZE: 'Size',
7425
 
        /**
7426
 
        * @property STR_IMAGE_ORIG_SIZE
7427
 
        * @description The label string for Original Image Size
7428
 
        * @type String
7429
 
        */
7430
 
        STR_IMAGE_ORIG_SIZE: 'Original Size',
7431
 
        /**
7432
 
        * @property STR_IMAGE_COPY
7433
 
        * @description The label string for the image copy and paste message for Opera and Safari
7434
 
        * @type String
7435
 
        */
7436
 
        STR_IMAGE_COPY: '<span class="tip"><span class="icon icon-info"></span><strong>Note:</strong>To move this image just highlight it, cut, and paste where ever you\'d like.</span>',
7437
 
        /**
7438
 
        * @property STR_IMAGE_PADDING
7439
 
        * @description The label string for the image padding.
7440
 
        * @type String
7441
 
        */
7442
 
        STR_IMAGE_PADDING: 'Padding',
7443
 
        /**
7444
 
        * @property STR_IMAGE_BORDER
7445
 
        * @description The label string for the image border.
7446
 
        * @type String
7447
 
        */
7448
 
        STR_IMAGE_BORDER: 'Border',
7449
 
        /**
7450
 
        * @property STR_IMAGE_BORDER_SIZE
7451
 
        * @description The label string for the image border size.
7452
 
        * @type String
7453
 
        */
7454
 
        STR_IMAGE_BORDER_SIZE: 'Border Size',
7455
 
        /**
7456
 
        * @property STR_IMAGE_BORDER_TYPE
7457
 
        * @description The label string for the image border type.
7458
 
        * @type String
7459
 
        */
7460
 
        STR_IMAGE_BORDER_TYPE: 'Border Type',
7461
 
        /**
7462
 
        * @property STR_IMAGE_TEXTFLOW
7463
 
        * @description The label string for the image text flow.
7464
 
        * @type String
7465
 
        */
7466
 
        STR_IMAGE_TEXTFLOW: 'Text Flow',
7467
 
        /**
7468
 
        * @property STR_LOCAL_FILE_WARNING
7469
 
        * @description The label string for the local file warning.
7470
 
        * @type String
7471
 
        */
7472
 
        STR_LOCAL_FILE_WARNING: '<span class="tip"><span class="icon icon-warn"></span><strong>Note:</strong>This image/link points to a file on your computer and will not be accessible to others on the internet.</span>',
7473
 
        /**
7474
 
        * @property STR_LINK_PROP_TITLE
7475
 
        * @description The label string for the Link Property Editor Window.
7476
 
        * @type String
7477
 
        */
7478
 
        STR_LINK_PROP_TITLE: 'Link Options',
7479
 
        /**
7480
 
        * @property STR_LINK_PROP_REMOVE
7481
 
        * @description The label string for the Remove link from text link inside the property editor.
7482
 
        * @type String
7483
 
        */
7484
 
        STR_LINK_PROP_REMOVE: 'Remove link from text',
7485
 
        /**
7486
 
        * @property STR_LINK_NEW_WINDOW
7487
 
        * @description The string for the open in a new window label.
7488
 
        * @type String
7489
 
        */
7490
 
        STR_LINK_NEW_WINDOW: 'Open in a new window.',
7491
 
        /**
7492
 
        * @property STR_LINK_TITLE
7493
 
        * @description The string for the link description.
7494
 
        * @type String
7495
 
        */
7496
 
        STR_LINK_TITLE: 'Description',
7497
 
        /**
7498
 
        * @property STR_NONE
7499
 
        * @description The string for the word none.
7500
 
        * @type String
7501
 
        */
7502
 
        STR_NONE: 'none',
7503
 
        /**
7504
 
        * @protected
7505
 
        * @property CLASS_LOCAL_FILE
7506
 
        * @description CSS class applied to an element when it's found to have a local url.
7507
 
        * @type String
7508
 
        */
7509
 
        CLASS_LOCAL_FILE: 'warning-localfile',
7510
 
        /**
7511
 
        * @protected
7512
 
        * @property CLASS_HIDDEN
7513
 
        * @description CSS class applied to the body when the hiddenelements button is pressed.
7514
 
        * @type String
7515
 
        */
7516
 
        CLASS_HIDDEN: 'yui-hidden',
7517
 
        /** 
7518
 
        * @method init
7519
 
        * @description The Editor class' initialization method
7520
 
        */
7521
 
        init: function(p_oElement, p_oAttributes) {
7522
 
            YAHOO.log('init', 'info', 'Editor');
7523
 
            
7524
 
            this._windows = {};
7525
 
            this._defaultToolbar = {
7526
 
                collapse: true,
7527
 
                titlebar: 'Text Editing Tools',
7528
 
                draggable: false,
7529
 
                buttonType: 'advanced',
7530
 
                buttons: [
7531
 
                    { group: 'fontstyle', label: 'Font Name and Size',
7532
 
                        buttons: [
7533
 
                            { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
7534
 
                                menu: [
7535
 
                                    { text: 'Arial', checked: true },
7536
 
                                    { text: 'Arial Black' },
7537
 
                                    { text: 'Comic Sans MS' },
7538
 
                                    { text: 'Courier New' },
7539
 
                                    { text: 'Lucida Console' },
7540
 
                                    { text: 'Tahoma' },
7541
 
                                    { text: 'Times New Roman' },
7542
 
                                    { text: 'Trebuchet MS' },
7543
 
                                    { text: 'Verdana' }
7544
 
                                ]
7545
 
                            },
7546
 
                            { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
7547
 
                        ]
7548
 
                    },
7549
 
                    { type: 'separator' },
7550
 
                    { group: 'textstyle', label: 'Font Style',
7551
 
                        buttons: [
7552
 
                            { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
7553
 
                            { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
7554
 
                            { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
7555
 
                            { type: 'separator' },
7556
 
                            { type: 'push', label: 'Subscript', value: 'subscript', disabled: true },
7557
 
                            { type: 'push', label: 'Superscript', value: 'superscript', disabled: true }
7558
 
                        ]
7559
 
                    },
7560
 
                    { type: 'separator' },
7561
 
                    { group: 'textstyle2', label: '&nbsp;',
7562
 
                        buttons: [
7563
 
                            { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
7564
 
                            { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true },
7565
 
                            { type: 'separator' },
7566
 
                            { type: 'push', label: 'Remove Formatting', value: 'removeformat', disabled: true },
7567
 
                            { type: 'push', label: 'Show/Hide Hidden Elements', value: 'hiddenelements' }
7568
 
                        ]
7569
 
                    },
7570
 
                    { type: 'separator' },
7571
 
                    { group: 'undoredo', label: 'Undo/Redo',
7572
 
                        buttons: [
7573
 
                            { type: 'push', label: 'Undo', value: 'undo', disabled: true },
7574
 
                            { type: 'push', label: 'Redo', value: 'redo', disabled: true }
7575
 
                            
7576
 
                        ]
7577
 
                    },
7578
 
                    { type: 'separator' },
7579
 
                    { group: 'alignment', label: 'Alignment',
7580
 
                        buttons: [
7581
 
                            { type: 'push', label: 'Align Left CTRL + SHIFT + [', value: 'justifyleft' },
7582
 
                            { type: 'push', label: 'Align Center CTRL + SHIFT + |', value: 'justifycenter' },
7583
 
                            { type: 'push', label: 'Align Right CTRL + SHIFT + ]', value: 'justifyright' },
7584
 
                            { type: 'push', label: 'Justify', value: 'justifyfull' }
7585
 
                        ]
7586
 
                    },
7587
 
                    { type: 'separator' },
7588
 
                    { group: 'parastyle', label: 'Paragraph Style',
7589
 
                        buttons: [
7590
 
                        { type: 'select', label: 'Normal', value: 'heading', disabled: true,
7591
 
                            menu: [
7592
 
                                { text: 'Normal', value: 'none', checked: true },
7593
 
                                { text: 'Header 1', value: 'h1' },
7594
 
                                { text: 'Header 2', value: 'h2' },
7595
 
                                { text: 'Header 3', value: 'h3' },
7596
 
                                { text: 'Header 4', value: 'h4' },
7597
 
                                { text: 'Header 5', value: 'h5' },
7598
 
                                { text: 'Header 6', value: 'h6' }
7599
 
                            ]
7600
 
                        }
7601
 
                        ]
7602
 
                    },
7603
 
                    { type: 'separator' },
7604
 
                    
7605
 
                    { group: 'indentlist2', label: 'Indenting and Lists',
7606
 
                        buttons: [
7607
 
                            { type: 'push', label: 'Indent', value: 'indent', disabled: true },
7608
 
                            { type: 'push', label: 'Outdent', value: 'outdent', disabled: true },
7609
 
                            { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
7610
 
                            { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
7611
 
                        ]
7612
 
                    },
7613
 
                    { type: 'separator' },
7614
 
                    { group: 'insertitem', label: 'Insert Item',
7615
 
                        buttons: [
7616
 
                            { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
7617
 
                            { type: 'push', label: 'Insert Image', value: 'insertimage' }
7618
 
                        ]
7619
 
                    }
7620
 
                ]
7621
 
            };
7622
 
 
7623
 
            this._defaultImageToolbarConfig = {
7624
 
                buttonType: this._defaultToolbar.buttonType,
7625
 
                buttons: [
7626
 
                    { group: 'textflow', label: this.STR_IMAGE_TEXTFLOW + ':',
7627
 
                        buttons: [
7628
 
                            { type: 'push', label: 'Left', value: 'left' },
7629
 
                            { type: 'push', label: 'Inline', value: 'inline' },
7630
 
                            { type: 'push', label: 'Block', value: 'block' },
7631
 
                            { type: 'push', label: 'Right', value: 'right' }
7632
 
                        ]
7633
 
                    },
7634
 
                    { type: 'separator' },
7635
 
                    { group: 'padding', label: this.STR_IMAGE_PADDING + ':',
7636
 
                        buttons: [
7637
 
                            { type: 'spin', label: '0', value: 'padding', range: [0, 50] }
7638
 
                        ]
7639
 
                    },
7640
 
                    { type: 'separator' },
7641
 
                    { group: 'border', label: this.STR_IMAGE_BORDER + ':',
7642
 
                        buttons: [
7643
 
                            { type: 'select', label: this.STR_IMAGE_BORDER_SIZE, value: 'bordersize',
7644
 
                                menu: [
7645
 
                                    { text: 'none', value: '0', checked: true },
7646
 
                                    { text: '1px', value: '1' },
7647
 
                                    { text: '2px', value: '2' },
7648
 
                                    { text: '3px', value: '3' },
7649
 
                                    { text: '4px', value: '4' },
7650
 
                                    { text: '5px', value: '5' }
7651
 
                                ]
7652
 
                            },
7653
 
                            { type: 'select', label: this.STR_IMAGE_BORDER_TYPE, value: 'bordertype', disabled: true,
7654
 
                                menu: [
7655
 
                                    { text: 'Solid', value: 'solid', checked: true },
7656
 
                                    { text: 'Dashed', value: 'dashed' },
7657
 
                                    { text: 'Dotted', value: 'dotted' }
7658
 
                                ]
7659
 
                            },
7660
 
                            { type: 'color', label: 'Border Color', value: 'bordercolor', disabled: true }
7661
 
                        ]
7662
 
                    }
7663
 
                ]
7664
 
            };
7665
 
 
7666
 
            YAHOO.widget.Editor.superclass.init.call(this, p_oElement, p_oAttributes);
7667
 
        },
7668
 
        _render: function() {
7669
 
            YAHOO.widget.Editor.superclass._render.apply(this, arguments);
7670
 
            var self = this;
7671
 
            //Render the panel in another thread and delay it a little..
7672
 
            window.setTimeout(function() {
7673
 
                self._renderPanel.call(self);
7674
 
            }, 800);
7675
 
        },
7676
 
        /**
7677
 
        * @method initAttributes
7678
 
        * @description Initializes all of the configuration attributes used to create 
7679
 
        * the editor.
7680
 
        * @param {Object} attr Object literal specifying a set of 
7681
 
        * configuration attributes used to create the editor.
7682
 
        */
7683
 
        initAttributes: function(attr) {
7684
 
            YAHOO.widget.Editor.superclass.initAttributes.call(this, attr);
7685
 
 
7686
 
            /**
7687
 
            * @attribute localFileWarning
7688
 
            * @description Should we throw the warning if we detect a file that is local to their machine?
7689
 
            * @default true
7690
 
            * @type Boolean
7691
 
            */            
7692
 
            this.setAttributeConfig('localFileWarning', {
7693
 
                value: attr.locaFileWarning || true
7694
 
            });
7695
 
 
7696
 
            /**
7697
 
            * @attribute hiddencss
7698
 
            * @description The CSS used to show/hide hidden elements on the page, these rules must be prefixed with the class provided in <code>this.CLASS_HIDDEN</code>
7699
 
            * @default <code><pre>
7700
 
            .yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u,
7701
 
            .yui-hidden div, .yui-hidden p, .yui-hidden span, .yui-hidden img, .yui-hidden ul, .yui-hidden ol,
7702
 
            .yui-hidden li, .yui-hidden table {
7703
 
                border: 1px dotted #ccc;
7704
 
            }
7705
 
            .yui-hidden .yui-non {
7706
 
                border: none;
7707
 
            }
7708
 
            .yui-hidden img {
7709
 
                padding: 2px;
7710
 
            }</pre></code>
7711
 
            * @type String
7712
 
            */            
7713
 
            this.setAttributeConfig('hiddencss', {
7714
 
                value: attr.hiddencss || '.yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div,.yui-hidden p,.yui-hidden span,.yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table { border: 1px dotted #ccc; } .yui-hidden .yui-non { border: none; } .yui-hidden img { padding: 2px; }',
7715
 
                writeOnce: true
7716
 
            });
7717
 
           
7718
 
        },
7719
 
        /**
7720
 
        * @private
7721
 
        * @method _windows
7722
 
        * @description A reference to the HTML elements used for the body of Editor Windows.
7723
 
        */
7724
 
        _windows: null,
7725
 
        /**
7726
 
        * @private
7727
 
        * @method _defaultImageToolbar
7728
 
        * @description A reference to the Toolbar Object inside Image Editor Window.
7729
 
        */
7730
 
        _defaultImageToolbar: null,
7731
 
        /**
7732
 
        * @private
7733
 
        * @method _defaultImageToolbarConfig
7734
 
        * @description Config to be used for the default Image Editor Window.
7735
 
        */
7736
 
        _defaultImageToolbarConfig: null,
7737
 
        /**
7738
 
        * @private
7739
 
        * @method _fixNodes
7740
 
        * @description Fix href and imgs as well as remove invalid HTML.
7741
 
        */
7742
 
        _fixNodes: function() {
7743
 
            YAHOO.widget.Editor.superclass._fixNodes.call(this);
7744
 
            var url = '';
7745
 
 
7746
 
            var imgs = this._getDoc().getElementsByTagName('img');
7747
 
            for (var im = 0; im < imgs.length; im++) {
7748
 
                if (imgs[im].getAttribute('href', 2)) {
7749
 
                    url = imgs[im].getAttribute('src', 2);
7750
 
                    if (this._isLocalFile(url)) {
7751
 
                        Dom.addClass(imgs[im], this.CLASS_LOCAL_FILE);
7752
 
                    } else {
7753
 
                        Dom.removeClass(imgs[im], this.CLASS_LOCAL_FILE);
7754
 
                    }
7755
 
                }
7756
 
            }
7757
 
            var fakeAs = this._getDoc().body.getElementsByTagName('a');
7758
 
            for (var a = 0; a < fakeAs.length; a++) {
7759
 
                if (fakeAs[a].getAttribute('href', 2)) {
7760
 
                    url = fakeAs[a].getAttribute('href', 2);
7761
 
                    if (this._isLocalFile(url)) {
7762
 
                        Dom.addClass(fakeAs[a], this.CLASS_LOCAL_FILE);
7763
 
                    } else {
7764
 
                        Dom.removeClass(fakeAs[a], this.CLASS_LOCAL_FILE);
7765
 
                    }
7766
 
                }
7767
 
            }
7768
 
        },
7769
 
        /**
7770
 
        * @private
7771
 
        * @property _disabled
7772
 
        * @description The Toolbar items that should be disabled if there is no selection present in the editor.
7773
 
        * @type Array
7774
 
        */
7775
 
        _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading', 'indent' ],
7776
 
        /**
7777
 
        * @private
7778
 
        * @property _alwaysDisabled
7779
 
        * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
7780
 
        * @type Object
7781
 
        */
7782
 
        _alwaysDisabled: { 'outdent': true },
7783
 
        /**
7784
 
        * @private
7785
 
        * @property _alwaysEnabled
7786
 
        * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
7787
 
        * @type Object
7788
 
        */
7789
 
        _alwaysEnabled: { hiddenelements: true },
7790
 
        /**
7791
 
        * @private
7792
 
        * @method _handleKeyDown
7793
 
        * @param {Event} ev The event we are working on.
7794
 
        * @description Override method that handles some new keydown events inside the iFrame document.
7795
 
        */
7796
 
        _handleKeyDown: function(ev) {
7797
 
            YAHOO.widget.Editor.superclass._handleKeyDown.call(this, ev);
7798
 
            var doExec = false,
7799
 
                action = null,
7800
 
                exec = false;
7801
 
 
7802
 
            switch (ev.keyCode) {
7803
 
                //case 219: //Left
7804
 
                case this._keyMap.JUSTIFY_LEFT.key: //Left
7805
 
                    if (this._checkKey(this._keyMap.JUSTIFY_LEFT, ev)) {
7806
 
                        action = 'justifyleft';
7807
 
                        doExec = true;
7808
 
                    }
7809
 
                    break;
7810
 
                //case 220: //Center
7811
 
                case this._keyMap.JUSTIFY_CENTER.key:
7812
 
                    if (this._checkKey(this._keyMap.JUSTIFY_CENTER, ev)) {
7813
 
                        action = 'justifycenter';
7814
 
                        doExec = true;
7815
 
                    }
7816
 
                    break;
7817
 
                case 221: //Right
7818
 
                case this._keyMap.JUSTIFY_RIGHT.key:
7819
 
                    if (this._checkKey(this._keyMap.JUSTIFY_RIGHT, ev)) {
7820
 
                        action = 'justifyright';
7821
 
                        doExec = true;
7822
 
                    }
7823
 
                    break;
7824
 
            }
7825
 
            if (doExec && action) {
7826
 
                this.execCommand(action, null);
7827
 
                Event.stopEvent(ev);
7828
 
                this.nodeChange();
7829
 
            }
7830
 
        },        
7831
 
        /**
7832
 
        * @private
7833
 
        * @method _renderCreateLinkWindow
7834
 
        * @description Pre renders the CreateLink window so we get faster window opening.
7835
 
        */
7836
 
        _renderCreateLinkWindow: function() {
7837
 
                var str = '<label for="' + this.get('id') + '_createlink_url"><strong>' + this.STR_LINK_URL + ':</strong> <input type="text" name="' + this.get('id') + '_createlink_url" id="' + this.get('id') + '_createlink_url" value=""></label>';
7838
 
                str += '<label for="' + this.get('id') + '_createlink_target"><strong>&nbsp;</strong><input type="checkbox" name="' + this.get('id') + '_createlink_target" id="' + this.get('id') + '_createlink_target" value="_blank" class="createlink_target"> ' + this.STR_LINK_NEW_WINDOW + '</label>';
7839
 
                str += '<label for="' + this.get('id') + '_createlink_title"><strong>' + this.STR_LINK_TITLE + ':</strong> <input type="text" name="' + this.get('id') + '_createlink_title" id="' + this.get('id') + '_createlink_title" value=""></label>';
7840
 
                
7841
 
                var body = document.createElement('div');
7842
 
                body.innerHTML = str;
7843
 
 
7844
 
                var unlinkCont = document.createElement('div');
7845
 
                unlinkCont.className = 'removeLink';
7846
 
                var unlink = document.createElement('a');
7847
 
                unlink.href = '#';
7848
 
                unlink.innerHTML = this.STR_LINK_PROP_REMOVE;
7849
 
                unlink.title = this.STR_LINK_PROP_REMOVE;
7850
 
                Event.on(unlink, 'click', function(ev) {
7851
 
                    Event.stopEvent(ev);
7852
 
                    this.unsubscribeAll('afterExecCommand');
7853
 
                    this.execCommand('unlink');
7854
 
                    this.closeWindow();
7855
 
                }, this, true);
7856
 
                unlinkCont.appendChild(unlink);
7857
 
                body.appendChild(unlinkCont);
7858
 
                
7859
 
                this._windows.createlink = {};
7860
 
                this._windows.createlink.body = body;
7861
 
                //body.style.display = 'none';
7862
 
                Event.on(body, 'keyup', function(e) {
7863
 
                    Event.stopPropagation(e);
7864
 
                });
7865
 
                this.get('panel').editor_form.appendChild(body);
7866
 
                this.fireEvent('windowCreateLinkRender', { type: 'windowCreateLinkRender', panel: this.get('panel'), body: body });
7867
 
                return body;
7868
 
        },
7869
 
        _handleCreateLinkClick: function() {
7870
 
            var el = this._getSelectedElement();
7871
 
            if (this._isElement(el, 'img')) {
7872
 
                this.STOP_EXEC_COMMAND = true;
7873
 
                this.currentElement[0] = el;
7874
 
                this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
7875
 
                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
7876
 
                return false;
7877
 
            }
7878
 
            if (this.get('limitCommands')) {
7879
 
                if (!this.toolbar.getButtonByValue('createlink')) {
7880
 
                    YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'Editor');
7881
 
                    return false;
7882
 
                }
7883
 
            }
7884
 
            
7885
 
            this.on('afterExecCommand', function() {
7886
 
                var win = new YAHOO.widget.EditorWindow('createlink', {
7887
 
                    width: '350px'
7888
 
                });
7889
 
                
7890
 
                var el = this.currentElement[0],
7891
 
                    url = '',
7892
 
                    title = '',
7893
 
                    target = '',
7894
 
                    localFile = false;
7895
 
                if (el) {
7896
 
                    win.el = el;
7897
 
                    if (el.getAttribute('href', 2) !== null) {
7898
 
                        url = el.getAttribute('href', 2);
7899
 
                        if (this._isLocalFile(url)) {
7900
 
                            //Local File throw Warning
7901
 
                            YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
7902
 
                            win.setFooter(this.STR_LOCAL_FILE_WARNING);
7903
 
                            localFile = true;
7904
 
                        } else {
7905
 
                            win.setFooter(' ');
7906
 
                        }
7907
 
                    }
7908
 
                    if (el.getAttribute('title') !== null) {
7909
 
                        title = el.getAttribute('title');
7910
 
                    }
7911
 
                    if (el.getAttribute('target') !== null) {
7912
 
                        target = el.getAttribute('target');
7913
 
                    }
7914
 
                }
7915
 
                var body = null;
7916
 
                if (this._windows.createlink && this._windows.createlink.body) {
7917
 
                    body = this._windows.createlink.body;
7918
 
                } else {
7919
 
                    body = this._renderCreateLinkWindow();
7920
 
                }
7921
 
 
7922
 
                win.setHeader(this.STR_LINK_PROP_TITLE);
7923
 
                win.setBody(body);
7924
 
 
7925
 
                Event.purgeElement(this.get('id') + '_createlink_url');
7926
 
 
7927
 
                Dom.get(this.get('id') + '_createlink_url').value = url;
7928
 
                Dom.get(this.get('id') + '_createlink_title').value = title;
7929
 
                Dom.get(this.get('id') + '_createlink_target').checked = ((target) ? true : false);
7930
 
                
7931
 
 
7932
 
                Event.onAvailable(this.get('id') + '_createlink_url', function() {
7933
 
                    var id = this.get('id');
7934
 
                    window.setTimeout(function() {
7935
 
                        try {
7936
 
                            YAHOO.util.Dom.get(id + '_createlink_url').focus();
7937
 
                        } catch (e) {}
7938
 
                    }, 50);
7939
 
 
7940
 
                    if (this._isLocalFile(url)) {
7941
 
                        //Local File throw Warning
7942
 
                        Dom.addClass(this.get('id') + '_createlink_url', 'warning');
7943
 
                        YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
7944
 
                        this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
7945
 
                    } else {
7946
 
                        Dom.removeClass(this.get('id') + '_createlink_url', 'warning');
7947
 
                        this.get('panel').setFooter(' ');
7948
 
                    }
7949
 
                    Event.on(this.get('id') + '_createlink_url', 'blur', function() {
7950
 
                        var url = Dom.get(this.get('id') + '_createlink_url');
7951
 
                        if (this._isLocalFile(url.value)) {
7952
 
                            //Local File throw Warning
7953
 
                            Dom.addClass(url, 'warning');
7954
 
                            YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
7955
 
                            this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
7956
 
                        } else {
7957
 
                            Dom.removeClass(url, 'warning');
7958
 
                            this.get('panel').setFooter(' ');
7959
 
                        }
7960
 
                    }, this, true);
7961
 
                }, this, true);
7962
 
                
7963
 
                this.openWindow(win);
7964
 
 
7965
 
            });
7966
 
        },
7967
 
        /**
7968
 
        * @private
7969
 
        * @method _handleCreateLinkWindowClose
7970
 
        * @description Handles the closing of the Link Properties Window.
7971
 
        */
7972
 
        _handleCreateLinkWindowClose: function() {
7973
 
            
7974
 
            var url = Dom.get(this.get('id') + '_createlink_url'),
7975
 
                target = Dom.get(this.get('id') + '_createlink_target'),
7976
 
                title = Dom.get(this.get('id') + '_createlink_title'),
7977
 
                el = arguments[0].win.el,
7978
 
                a = el;
7979
 
 
7980
 
            if (url && url.value) {
7981
 
                var urlValue = url.value;
7982
 
                if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
7983
 
                    if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
7984
 
                        //Found an @ sign, prefix with mailto:
7985
 
                        urlValue = 'mailto:' + urlValue;
7986
 
                    } else {
7987
 
                        // :// not found adding
7988
 
                        if (urlValue.substring(0, 1) != '#') {
7989
 
                            urlValue = 'http:/'+'/' + urlValue;
7990
 
                        }
7991
 
                        
7992
 
                    }
7993
 
                }
7994
 
                el.setAttribute('href', urlValue);
7995
 
                if (target.checked) {
7996
 
                    el.setAttribute('target', target.value);
7997
 
                } else {
7998
 
                    el.setAttribute('target', '');
7999
 
                }
8000
 
                el.setAttribute('title', ((title.value) ? title.value : ''));
8001
 
 
8002
 
            } else {
8003
 
                var _span = this._getDoc().createElement('span');
8004
 
                _span.innerHTML = el.innerHTML;
8005
 
                Dom.addClass(_span, 'yui-non');
8006
 
                el.parentNode.replaceChild(_span, el);
8007
 
            }
8008
 
            Dom.removeClass(url, 'warning');
8009
 
            Dom.get(this.get('id') + '_createlink_url').value = '';
8010
 
            Dom.get(this.get('id') + '_createlink_title').value = '';
8011
 
            Dom.get(this.get('id') + '_createlink_target').checked = false;
8012
 
            this.nodeChange();
8013
 
            this.currentElement = [];
8014
 
            
8015
 
        },
8016
 
        /**
8017
 
        * @private
8018
 
        * @method _renderInsertImageWindow
8019
 
        * @description Pre renders the InsertImage window so we get faster window opening.
8020
 
        */
8021
 
        _renderInsertImageWindow: function() {
8022
 
                var el = this.currentElement[0];
8023
 
                var str = '<label for="' + this.get('id') + '_insertimage_url"><strong>' + this.STR_IMAGE_URL + ':</strong> <input type="text" id="' + this.get('id') + '_insertimage_url" value="" size="40"></label>';
8024
 
                var body = document.createElement('div');
8025
 
                body.innerHTML = str;
8026
 
 
8027
 
                var tbarCont = document.createElement('div');
8028
 
                tbarCont.id = this.get('id') + '_img_toolbar';
8029
 
                body.appendChild(tbarCont);
8030
 
 
8031
 
                var str2 = '<label for="' + this.get('id') + '_insertimage_title"><strong>' + this.STR_IMAGE_TITLE + ':</strong> <input type="text" id="' + this.get('id') + '_insertimage_title" value="" size="40"></label>';
8032
 
                str2 += '<label for="' + this.get('id') + '_insertimage_link"><strong>' + this.STR_LINK_URL + ':</strong> <input type="text" name="' + this.get('id') + '_insertimage_link" id="' + this.get('id') + '_insertimage_link" value=""></label>';
8033
 
                str2 += '<label for="' + this.get('id') + '_insertimage_target"><strong>&nbsp;</strong><input type="checkbox" name="' + this.get('id') + '_insertimage_target_" id="' + this.get('id') + '_insertimage_target" value="_blank" class="insertimage_target"> ' + this.STR_LINK_NEW_WINDOW + '</label>';
8034
 
                var div = document.createElement('div');
8035
 
                div.innerHTML = str2;
8036
 
                body.appendChild(div);
8037
 
 
8038
 
                var o = {};
8039
 
                Lang.augmentObject(o, this._defaultImageToolbarConfig); //Break the config reference
8040
 
 
8041
 
                var tbar = new YAHOO.widget.Toolbar(tbarCont, o);
8042
 
                tbar.editor_el = el;
8043
 
                this._defaultImageToolbar = tbar;
8044
 
                
8045
 
                var cont = tbar.get('cont');
8046
 
                var hw = document.createElement('div');
8047
 
                hw.className = 'yui-toolbar-group yui-toolbar-group-height-width height-width';
8048
 
                hw.innerHTML = '<h3>' + this.STR_IMAGE_SIZE + ':</h3>';
8049
 
                /*
8050
 
                var orgSize = '';
8051
 
                if ((height != oheight) || (width != owidth)) {
8052
 
                    orgSize = '<span class="info">' + this.STR_IMAGE_ORIG_SIZE + '<br>'+ owidth +' x ' + oheight + '</span>';
8053
 
                }
8054
 
                */
8055
 
                hw.innerHTML += '<span tabIndex="-1"><input type="text" size="3" value="" id="' + this.get('id') + '_insertimage_width"> x <input type="text" size="3" value="" id="' + this.get('id') + '_insertimage_height"></span>';
8056
 
                cont.insertBefore(hw, cont.firstChild);
8057
 
 
8058
 
                Event.onAvailable(this.get('id') + '_insertimage_width', function() {
8059
 
                    Event.on(this.get('id') + '_insertimage_width', 'blur', function() {
8060
 
                        var value = parseInt(Dom.get(this.get('id') + '_insertimage_width').value, 10);
8061
 
                        if (value > 5) {
8062
 
                           this._defaultImageToolbar.editor_el.style.width = value + 'px';
8063
 
                            //Removed moveWindow call so the window doesn't jump
8064
 
                            //this.moveWindow();
8065
 
                        }
8066
 
                    }, this, true);
8067
 
                }, this, true);
8068
 
                Event.onAvailable(this.get('id') + '_insertimage_height', function() {
8069
 
                    Event.on(this.get('id') + '_insertimage_height', 'blur', function() {
8070
 
                        var value = parseInt(Dom.get(this.get('id') + '_insertimage_height').value, 10);
8071
 
                        if (value > 5) {
8072
 
                            this._defaultImageToolbar.editor_el.style.height = value + 'px';
8073
 
                            //Removed moveWindow call so the window doesn't jump
8074
 
                            //this.moveWindow();
8075
 
                        }
8076
 
                    }, this, true);
8077
 
                }, this, true);
8078
 
 
8079
 
 
8080
 
                tbar.on('colorPickerClicked', function(o) {
8081
 
                    var size = '1', type = 'solid', color = 'black', el = this._defaultImageToolbar.editor_el;
8082
 
 
8083
 
                    if (el.style.borderLeftWidth) {
8084
 
                        size = parseInt(el.style.borderLeftWidth, 10);
8085
 
                    }
8086
 
                    if (el.style.borderLeftStyle) {
8087
 
                        type = el.style.borderLeftStyle;
8088
 
                    }
8089
 
                    if (el.style.borderLeftColor) {
8090
 
                        color = el.style.borderLeftColor;
8091
 
                    }
8092
 
                    var borderString = size + 'px ' + type + ' #' + o.color;
8093
 
                    el.style.border = borderString;
8094
 
                }, this, true);
8095
 
 
8096
 
                tbar.on('buttonClick', function(o) {
8097
 
                    var value = o.button.value,
8098
 
                        el = this._defaultImageToolbar.editor_el,
8099
 
                        borderString = '';
8100
 
                    if (o.button.menucmd) {
8101
 
                        value = o.button.menucmd;
8102
 
                    }
8103
 
                    var size = '1', type = 'solid', color = 'black';
8104
 
 
8105
 
                    /* All border calcs are done on the left border
8106
 
                        since our default interface only supports
8107
 
                        one border size/type and color */
8108
 
                    if (el.style.borderLeftWidth) {
8109
 
                        size = parseInt(el.style.borderLeftWidth, 10);
8110
 
                    }
8111
 
                    if (el.style.borderLeftStyle) {
8112
 
                        type = el.style.borderLeftStyle;
8113
 
                    }
8114
 
                    if (el.style.borderLeftColor) {
8115
 
                        color = el.style.borderLeftColor;
8116
 
                    }
8117
 
                    switch(value) {
8118
 
                        case 'bordersize':
8119
 
                            if (this.browser.webkit && this._lastImage) {
8120
 
                                Dom.removeClass(this._lastImage, 'selected');
8121
 
                                this._lastImage = null;
8122
 
                            }
8123
 
 
8124
 
                            borderString = parseInt(o.button.value, 10) + 'px ' + type + ' ' + color;
8125
 
                            el.style.border = borderString;
8126
 
                            if (parseInt(o.button.value, 10) > 0) {
8127
 
                                tbar.enableButton('bordertype');
8128
 
                                tbar.enableButton('bordercolor');
8129
 
                            } else {
8130
 
                                tbar.disableButton('bordertype');
8131
 
                                tbar.disableButton('bordercolor');
8132
 
                            }
8133
 
                            break;
8134
 
                        case 'bordertype':
8135
 
                            if (this.browser.webkit && this._lastImage) {
8136
 
                                Dom.removeClass(this._lastImage, 'selected');
8137
 
                                this._lastImage = null;
8138
 
                            }
8139
 
                            borderString = size + 'px ' + o.button.value + ' ' + color;
8140
 
                            el.style.border = borderString;
8141
 
                            break;
8142
 
                        case 'right':
8143
 
                        case 'left':
8144
 
                            tbar.deselectAllButtons();
8145
 
                            el.style.display = '';
8146
 
                            el.align = o.button.value;
8147
 
                            break;
8148
 
                        case 'inline':
8149
 
                            tbar.deselectAllButtons();
8150
 
                            el.style.display = '';
8151
 
                            el.align = '';
8152
 
                            break;
8153
 
                        case 'block':
8154
 
                            tbar.deselectAllButtons();
8155
 
                            el.style.display = 'block';
8156
 
                            el.align = 'center';
8157
 
                            break;
8158
 
                        case 'padding':
8159
 
                            var _button = tbar.getButtonById(o.button.id);
8160
 
                            el.style.margin = _button.get('label') + 'px';
8161
 
                            break;
8162
 
                    }
8163
 
                    tbar.selectButton(o.button.value);
8164
 
                    if (value !== 'padding') {
8165
 
                        this.moveWindow();
8166
 
                    }
8167
 
                }, this, true);
8168
 
 
8169
 
 
8170
 
 
8171
 
                if (this.get('localFileWarning')) {
8172
 
                    Event.on(this.get('id') + '_insertimage_link', 'blur', function() {
8173
 
                        var url = Dom.get(this.get('id') + '_insertimage_link');
8174
 
                        if (this._isLocalFile(url.value)) {
8175
 
                            //Local File throw Warning
8176
 
                            Dom.addClass(url, 'warning');
8177
 
                            YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
8178
 
                            this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
8179
 
                        } else {
8180
 
                            Dom.removeClass(url, 'warning');
8181
 
                            this.get('panel').setFooter(' ');
8182
 
                            //Adobe AIR Code
8183
 
                            if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {                
8184
 
                                this.get('panel').setFooter(this.STR_IMAGE_COPY);
8185
 
                            }
8186
 
                        }
8187
 
                    }, this, true);
8188
 
                }
8189
 
 
8190
 
                Event.on(this.get('id') + '_insertimage_url', 'blur', function() {
8191
 
                    var url = Dom.get(this.get('id') + '_insertimage_url');
8192
 
                    if (url.value && el) {
8193
 
                        if (url.value == el.getAttribute('src', 2)) {
8194
 
                            YAHOO.log('Images are the same, bail on blur handler', 'info', 'Editor');
8195
 
                            return false;
8196
 
                        }
8197
 
                    }
8198
 
                    YAHOO.log('Images are different, process blur handler', 'info', 'Editor');
8199
 
                    if (this._isLocalFile(url.value)) {
8200
 
                        //Local File throw Warning
8201
 
                        Dom.addClass(url, 'warning');
8202
 
                        YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
8203
 
                        this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
8204
 
                    } else if (this.currentElement[0]) {
8205
 
                        Dom.removeClass(url, 'warning');
8206
 
                        this.get('panel').setFooter(' ');
8207
 
                        //Adobe AIR Code
8208
 
                        if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {                
8209
 
                            this.get('panel').setFooter(this.STR_IMAGE_COPY);
8210
 
                        }
8211
 
                        
8212
 
                        if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
8213
 
                            this.currentElement[0].setAttribute('src', url.value);
8214
 
                            var self = this,
8215
 
                                img = new Image();
8216
 
 
8217
 
                            img.onerror = function() {
8218
 
                                url.value = self.STR_IMAGE_HERE;
8219
 
                                img.setAttribute('src', self.get('blankimage'));
8220
 
                                self.currentElement[0].setAttribute('src', self.get('blankimage'));
8221
 
                                YAHOO.util.Dom.get(self.get('id') + '_insertimage_height').value = img.height;
8222
 
                                YAHOO.util.Dom.get(self.get('id') + '_insertimage_width').value = img.width;
8223
 
                            };
8224
 
                            var id = this.get('id');
8225
 
                            window.setTimeout(function() {
8226
 
                                YAHOO.util.Dom.get(id + '_insertimage_height').value = img.height;
8227
 
                                YAHOO.util.Dom.get(id + '_insertimage_width').value = img.width;
8228
 
                                if (self.currentElement && self.currentElement[0]) {
8229
 
                                    if (!self.currentElement[0]._height) {
8230
 
                                        self.currentElement[0]._height = img.height;
8231
 
                                    }
8232
 
                                    if (!self.currentElement[0]._width) {
8233
 
                                        self.currentElement[0]._width = img.width;
8234
 
                                    }
8235
 
                                }
8236
 
                                //Removed moveWindow call so the window doesn't jump
8237
 
                                //self.moveWindow();
8238
 
                            }, 800); //Bumped the timeout up to account for larger images..
8239
 
 
8240
 
                            if (url.value != this.STR_IMAGE_HERE) {
8241
 
                                img.src = url.value;
8242
 
                            }
8243
 
                        }
8244
 
                    }
8245
 
                    }, this, true);
8246
 
 
8247
 
 
8248
 
 
8249
 
                this._windows.insertimage = {};
8250
 
                this._windows.insertimage.body = body;
8251
 
                //body.style.display = 'none';
8252
 
                this.get('panel').editor_form.appendChild(body);
8253
 
                this.fireEvent('windowInsertImageRender', { type: 'windowInsertImageRender', panel: this.get('panel'), body: body, toolbar: tbar });
8254
 
                return body;
8255
 
        },
8256
 
        /**
8257
 
        * @private
8258
 
        * @method _handleInsertImageClick
8259
 
        * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
8260
 
        */
8261
 
        _handleInsertImageClick: function() {
8262
 
            if (this.get('limitCommands')) {
8263
 
                if (!this.toolbar.getButtonByValue('insertimage')) {
8264
 
                    YAHOO.log('Toolbar Button for (insertimage) was not found, skipping exec.', 'info', 'Editor');
8265
 
                    return false;
8266
 
                }
8267
 
            }
8268
 
            this.on('afterExecCommand', function() {
8269
 
                YAHOO.log('afterExecCommand :: _handleInsertImageClick', 'info', 'Editor');
8270
 
                var el = this.currentElement[0],
8271
 
                    body = null,
8272
 
                    link = '',
8273
 
                    target = '',
8274
 
                    tbar = null,
8275
 
                    title = '',
8276
 
                    src = '',
8277
 
                    align = '',
8278
 
                    height = 75,
8279
 
                    width = 75,
8280
 
                    padding = 0,
8281
 
                    oheight = 0,
8282
 
                    owidth = 0,
8283
 
                    blankimage = false,
8284
 
                    win = new YAHOO.widget.EditorWindow('insertimage', {
8285
 
                        width: '415px'
8286
 
                    });
8287
 
 
8288
 
                if (!el) {
8289
 
                    el = this._getSelectedElement();
8290
 
                }
8291
 
                if (el) {
8292
 
                    win.el = el;
8293
 
                    if (el.getAttribute('src')) {
8294
 
                        src = el.getAttribute('src', 2);
8295
 
                        if (src.indexOf(this.get('blankimage')) != -1) {
8296
 
                            src = this.STR_IMAGE_HERE;
8297
 
                            blankimage = true;
8298
 
                        }
8299
 
                    }
8300
 
                    if (el.getAttribute('alt', 2)) {
8301
 
                        title = el.getAttribute('alt', 2);
8302
 
                    }
8303
 
                    if (el.getAttribute('title', 2)) {
8304
 
                        title = el.getAttribute('title', 2);
8305
 
                    }
8306
 
 
8307
 
                    if (el.parentNode && this._isElement(el.parentNode, 'a')) {
8308
 
                        link = el.parentNode.getAttribute('href', 2);
8309
 
                        if (el.parentNode.getAttribute('target') !== null) {
8310
 
                            target = el.parentNode.getAttribute('target');
8311
 
                        }
8312
 
                    }
8313
 
                    height = parseInt(el.height, 10);
8314
 
                    width = parseInt(el.width, 10);
8315
 
                    if (el.style.height) {
8316
 
                        height = parseInt(el.style.height, 10);
8317
 
                    }
8318
 
                    if (el.style.width) {
8319
 
                        width = parseInt(el.style.width, 10);
8320
 
                    }
8321
 
                    if (el.style.margin) {
8322
 
                        padding = parseInt(el.style.margin, 10);
8323
 
                    }
8324
 
                    if (!el._height) {
8325
 
                        el._height = height;
8326
 
                    }
8327
 
                    if (!el._width) {
8328
 
                        el._width = width;
8329
 
                    }
8330
 
                    oheight = el._height;
8331
 
                    owidth = el._width;
8332
 
                }
8333
 
                if (this._windows.insertimage && this._windows.insertimage.body) {
8334
 
                    body = this._windows.insertimage.body;
8335
 
                    this._defaultImageToolbar.resetAllButtons();
8336
 
                } else {
8337
 
                    body = this._renderInsertImageWindow();
8338
 
                }
8339
 
 
8340
 
                tbar = this._defaultImageToolbar;
8341
 
                tbar.editor_el = el;
8342
 
                
8343
 
 
8344
 
                var bsize = '0',
8345
 
                    btype = 'solid';
8346
 
 
8347
 
                if (el.style.borderLeftWidth) {
8348
 
                    bsize = parseInt(el.style.borderLeftWidth, 10);
8349
 
                }
8350
 
                if (el.style.borderLeftStyle) {
8351
 
                    btype = el.style.borderLeftStyle;
8352
 
                }
8353
 
                var bs_button = tbar.getButtonByValue('bordersize'),
8354
 
                    bSizeStr = ((parseInt(bsize, 10) > 0) ? '' : this.STR_NONE);
8355
 
                bs_button.set('label', '<span class="yui-toolbar-bordersize-' + bsize + '">' + bSizeStr + '</span>');
8356
 
                this._updateMenuChecked('bordersize', bsize, tbar);
8357
 
 
8358
 
                var bt_button = tbar.getButtonByValue('bordertype');
8359
 
                bt_button.set('label', '<span class="yui-toolbar-bordertype-' + btype + '">asdfa</span>');
8360
 
                this._updateMenuChecked('bordertype', btype, tbar);
8361
 
                if (parseInt(bsize, 10) > 0) {
8362
 
                    tbar.enableButton(bt_button);
8363
 
                    tbar.enableButton(bs_button);
8364
 
                    tbar.enableButton('bordercolor');
8365
 
                }
8366
 
 
8367
 
                if ((el.align == 'right') || (el.align == 'left')) {
8368
 
                    tbar.selectButton(el.align);
8369
 
                } else if (el.style.display == 'block') {
8370
 
                    tbar.selectButton('block');
8371
 
                } else {
8372
 
                    tbar.selectButton('inline');
8373
 
                }
8374
 
                if (parseInt(el.style.marginLeft, 10) > 0) {
8375
 
                    tbar.getButtonByValue('padding').set('label', ''+parseInt(el.style.marginLeft, 10));
8376
 
                }
8377
 
                if (el.style.borderSize) {
8378
 
                    tbar.selectButton('bordersize');
8379
 
                    tbar.selectButton(parseInt(el.style.borderSize, 10));
8380
 
                }
8381
 
                tbar.getButtonByValue('padding').set('label', ''+padding);
8382
 
 
8383
 
 
8384
 
 
8385
 
                win.setHeader(this.STR_IMAGE_PROP_TITLE);
8386
 
                win.setBody(body);
8387
 
                //Adobe AIR Code
8388
 
                if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {                
8389
 
                    win.setFooter(this.STR_IMAGE_COPY);
8390
 
                }
8391
 
                this.openWindow(win);
8392
 
                Dom.get(this.get('id') + '_insertimage_url').value = src;
8393
 
                Dom.get(this.get('id') + '_insertimage_title').value = title;
8394
 
                Dom.get(this.get('id') + '_insertimage_link').value = link;
8395
 
                Dom.get(this.get('id') + '_insertimage_target').checked = ((target) ? true : false);
8396
 
                Dom.get(this.get('id') + '_insertimage_width').value = width;
8397
 
                Dom.get(this.get('id') + '_insertimage_height').value = height;
8398
 
 
8399
 
 
8400
 
                var orgSize = '';
8401
 
                if ((height != oheight) || (width != owidth)) {
8402
 
                    var s = document.createElement('span');
8403
 
                    s.className = 'info';
8404
 
                    s.innerHTML = this.STR_IMAGE_ORIG_SIZE + ': ('+ owidth +' x ' + oheight + ')';
8405
 
                    if (Dom.get(this.get('id') + '_insertimage_height').nextSibling) {
8406
 
                        var old = Dom.get(this.get('id') + '_insertimage_height').nextSibling;
8407
 
                        old.parentNode.removeChild(old);
8408
 
                    }
8409
 
                    Dom.get(this.get('id') + '_insertimage_height').parentNode.appendChild(s);
8410
 
                }
8411
 
 
8412
 
                this.toolbar.selectButton('insertimage');
8413
 
                var id = this.get('id');
8414
 
                window.setTimeout(function() {
8415
 
                    try {
8416
 
                        YAHOO.util.Dom.get(id + '_insertimage_url').focus();
8417
 
                        if (blankimage) {
8418
 
                            YAHOO.util.Dom.get(id + '_insertimage_url').select();
8419
 
                        }
8420
 
                    } catch (e) {}
8421
 
                }, 50);
8422
 
 
8423
 
            });
8424
 
        },
8425
 
        /**
8426
 
        * @private
8427
 
        * @method _handleInsertImageWindowClose
8428
 
        * @description Handles the closing of the Image Properties Window.
8429
 
        */
8430
 
        _handleInsertImageWindowClose: function() {
8431
 
            var url = Dom.get(this.get('id') + '_insertimage_url'),
8432
 
                title = Dom.get(this.get('id') + '_insertimage_title'),
8433
 
                link = Dom.get(this.get('id') + '_insertimage_link'),
8434
 
                target = Dom.get(this.get('id') + '_insertimage_target'),
8435
 
                el = arguments[0].win.el;
8436
 
 
8437
 
            if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
8438
 
                el.setAttribute('src', url.value);
8439
 
                el.setAttribute('title', title.value);
8440
 
                el.setAttribute('alt', title.value);
8441
 
                var par = el.parentNode;
8442
 
                if (link.value) {
8443
 
                    var urlValue = link.value;
8444
 
                    if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
8445
 
                        if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
8446
 
                            //Found an @ sign, prefix with mailto:
8447
 
                            urlValue = 'mailto:' + urlValue;
8448
 
                        } else {
8449
 
                            // :// not found adding
8450
 
                            urlValue = 'http:/'+'/' + urlValue;
8451
 
                        }
8452
 
                    }
8453
 
                    if (par && this._isElement(par, 'a')) {
8454
 
                        par.setAttribute('href', urlValue);
8455
 
                        if (target.checked) {
8456
 
                            par.setAttribute('target', target.value);
8457
 
                        } else {
8458
 
                            par.setAttribute('target', '');
8459
 
                        }
8460
 
                    } else {
8461
 
                        var _a = this._getDoc().createElement('a');
8462
 
                        _a.setAttribute('href', urlValue);
8463
 
                        if (target.checked) {
8464
 
                            _a.setAttribute('target', target.value);
8465
 
                        } else {
8466
 
                            _a.setAttribute('target', '');
8467
 
                        }
8468
 
                        el.parentNode.replaceChild(_a, el);
8469
 
                        _a.appendChild(el);
8470
 
                    }
8471
 
                } else {
8472
 
                    if (par && this._isElement(par, 'a')) {
8473
 
                        par.parentNode.replaceChild(el, par);
8474
 
                    }
8475
 
                }
8476
 
            } else {
8477
 
                //No url/src given, remove the node from the document
8478
 
                el.parentNode.removeChild(el);
8479
 
            }
8480
 
            Dom.get(this.get('id') + '_insertimage_url').value = '';
8481
 
            Dom.get(this.get('id') + '_insertimage_title').value = '';
8482
 
            Dom.get(this.get('id') + '_insertimage_link').value = '';
8483
 
            Dom.get(this.get('id') + '_insertimage_target').checked = false;
8484
 
            Dom.get(this.get('id') + '_insertimage_width').value = 0;
8485
 
            Dom.get(this.get('id') + '_insertimage_height').value = 0;
8486
 
            this._defaultImageToolbar.resetAllButtons();
8487
 
            this.currentElement = [];
8488
 
            this.nodeChange();
8489
 
        },
8490
 
        /**
8491
 
        * @property EDITOR_PANEL_ID
8492
 
        * @description HTML id to give the properties window in the DOM.
8493
 
        * @type String
8494
 
        */
8495
 
        EDITOR_PANEL_ID: '-panel',
8496
 
        /**
8497
 
        * @private
8498
 
        * @method _renderPanel
8499
 
        * @description Renders the panel used for Editor Windows to the document so we can start using it..
8500
 
        * @return {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>}
8501
 
        */
8502
 
        _renderPanel: function() {
8503
 
            var panelEl = document.createElement('div');
8504
 
            Dom.addClass(panelEl, 'yui-editor-panel');
8505
 
            panelEl.id = this.get('id') + this.EDITOR_PANEL_ID;
8506
 
            panelEl.style.position = 'absolute';
8507
 
            panelEl.style.top = '-9999px';
8508
 
            panelEl.style.left = '-9999px';
8509
 
            document.body.appendChild(panelEl);
8510
 
            this.get('element_cont').insertBefore(panelEl, this.get('element_cont').get('firstChild'));
8511
 
 
8512
 
                
8513
 
 
8514
 
            var panel = new YAHOO.widget.Overlay(this.get('id') + this.EDITOR_PANEL_ID, {
8515
 
                    width: '300px',
8516
 
                    iframe: true,
8517
 
                    visible: false,
8518
 
                    underlay: 'none',
8519
 
                    draggable: false,
8520
 
                    close: false
8521
 
                });
8522
 
            this.set('panel', panel);
8523
 
 
8524
 
            panel.setBody('---');
8525
 
            panel.setHeader(' ');
8526
 
            panel.setFooter(' ');
8527
 
 
8528
 
 
8529
 
            var body = document.createElement('div');
8530
 
            body.className = this.CLASS_PREFIX + '-body-cont';
8531
 
            for (var b in this.browser) {
8532
 
                if (this.browser[b]) {
8533
 
                    Dom.addClass(body, b);
8534
 
                    break;
8535
 
                }
8536
 
            }
8537
 
            Dom.addClass(body, ((YAHOO.widget.Button && (this._defaultToolbar.buttonType == 'advanced')) ? 'good-button' : 'no-button'));
8538
 
 
8539
 
            var _note = document.createElement('h3');
8540
 
            _note.className = 'yui-editor-skipheader';
8541
 
            _note.innerHTML = this.STR_CLOSE_WINDOW_NOTE;
8542
 
            body.appendChild(_note);
8543
 
            var form = document.createElement('fieldset');
8544
 
            panel.editor_form = form;
8545
 
 
8546
 
            body.appendChild(form);
8547
 
            var _close = document.createElement('span');
8548
 
            _close.innerHTML = 'X';
8549
 
            _close.title = this.STR_CLOSE_WINDOW;
8550
 
            _close.className = 'close';
8551
 
            
8552
 
            Event.on(_close, 'click', this.closeWindow, this, true);
8553
 
 
8554
 
            var _knob = document.createElement('span');
8555
 
            _knob.innerHTML = '^';
8556
 
            _knob.className = 'knob';
8557
 
            panel.editor_knob = _knob;
8558
 
 
8559
 
            var _header = document.createElement('h3');
8560
 
            panel.editor_header = _header;
8561
 
            _header.innerHTML = '<span></span>';
8562
 
 
8563
 
            panel.setHeader(' '); //Clear the current header
8564
 
            panel.appendToHeader(_header);
8565
 
            _header.appendChild(_close);
8566
 
            _header.appendChild(_knob);
8567
 
            panel.setBody(' '); //Clear the current body
8568
 
            panel.setFooter(' '); //Clear the current footer
8569
 
            panel.appendToBody(body); //Append the new DOM node to it
8570
 
 
8571
 
            Event.on(panel.element, 'click', function(ev) {
8572
 
                Event.stopPropagation(ev);
8573
 
            });
8574
 
 
8575
 
            var fireShowEvent = function() {
8576
 
                panel.bringToTop();
8577
 
                YAHOO.util.Dom.setStyle(this.element, 'display', 'block');
8578
 
                this._handleWindowInputs(false);
8579
 
            };
8580
 
            panel.showEvent.subscribe(fireShowEvent, this, true);
8581
 
            panel.hideEvent.subscribe(function() {
8582
 
                this._handleWindowInputs(true);
8583
 
            }, this, true);
8584
 
            panel.renderEvent.subscribe(function() {
8585
 
                this._renderInsertImageWindow();
8586
 
                this._renderCreateLinkWindow();
8587
 
                this.fireEvent('windowRender', { type: 'windowRender', panel: panel });
8588
 
                this._handleWindowInputs(true);
8589
 
            }, this, true);
8590
 
 
8591
 
            if (this.DOMReady) {
8592
 
                this.get('panel').render();
8593
 
            } else {
8594
 
                Event.onDOMReady(function() {
8595
 
                    this.get('panel').render();
8596
 
                }, this, true);
8597
 
            }
8598
 
            return this.get('panel');
8599
 
        },
8600
 
        /**
8601
 
        * @method _handleWindowInputs
8602
 
        * @param {Boolean} disable The state to set all inputs in all Editor windows to. Defaults to: false.
8603
 
        * @description Disables/Enables all fields inside Editor windows. Used in show/hide events to keep window fields from submitting when the parent form is submitted.
8604
 
        */
8605
 
        _handleWindowInputs: function(disable) {
8606
 
            if (!Lang.isBoolean(disable)) {
8607
 
                disable = false;
8608
 
            }
8609
 
            var inputs = this.get('panel').element.getElementsByTagName('input');
8610
 
            for (var i = 0; i < inputs.length; i++) {
8611
 
                try {
8612
 
                    inputs[i].disabled = disable;
8613
 
                } catch (e) {}
8614
 
            }
8615
 
        },
8616
 
        /**
8617
 
        * @method openWindow
8618
 
        * @param {<a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>} win A <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a> instance
8619
 
        * @description Opens a new "window/panel"
8620
 
        */
8621
 
        openWindow: function(win) {
8622
 
            
8623
 
            YAHOO.log('openWindow: ' + win.name, 'info', 'Editor');
8624
 
            var self = this;
8625
 
            window.setTimeout(function() {
8626
 
                self.toolbar.set('disabled', true); //Disable the toolbar when an editor window is open..
8627
 
            }, 10);
8628
 
            Event.on(document, 'keydown', this._closeWindow, this, true);
8629
 
            
8630
 
            if (this.currentWindow) {
8631
 
                this.closeWindow();
8632
 
            }
8633
 
            
8634
 
            var xy = Dom.getXY(this.currentElement[0]),
8635
 
            elXY = Dom.getXY(this.get('iframe').get('element')),
8636
 
            panel = this.get('panel'),
8637
 
            newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
8638
 
            wWidth = (parseInt(win.attrs.width, 10) / 2),
8639
 
            align = 'center',
8640
 
            body = null;
8641
 
 
8642
 
            this.fireEvent('beforeOpenWindow', { type: 'beforeOpenWindow', win: win, panel: panel });
8643
 
 
8644
 
            var form = panel.editor_form;
8645
 
            
8646
 
            var wins = this._windows;
8647
 
            for (var b in wins) {
8648
 
                if (Lang.hasOwnProperty(wins, b)) {
8649
 
                    if (wins[b] && wins[b].body) {
8650
 
                        if (b == win.name) {
8651
 
                            Dom.setStyle(wins[b].body, 'display', 'block');
8652
 
                        } else {
8653
 
                            Dom.setStyle(wins[b].body, 'display', 'none');
8654
 
                        }
8655
 
                    }
8656
 
                }
8657
 
            }
8658
 
            
8659
 
            if (this._windows[win.name].body) {
8660
 
                Dom.setStyle(this._windows[win.name].body, 'display', 'block');
8661
 
                form.appendChild(this._windows[win.name].body);
8662
 
            } else {
8663
 
                if (Lang.isObject(win.body)) { //Assume it's a reference
8664
 
                    form.appendChild(win.body);
8665
 
                } else { //Assume it's a string
8666
 
                    var _tmp = document.createElement('div');
8667
 
                    _tmp.innerHTML = win.body;
8668
 
                    form.appendChild(_tmp);
8669
 
                }
8670
 
            }
8671
 
            panel.editor_header.firstChild.innerHTML = win.header;
8672
 
            if (win.footer !== null) {
8673
 
                panel.setFooter(win.footer);
8674
 
                Dom.addClass(panel.footer, 'open');
8675
 
            } else {
8676
 
                Dom.removeClass(panel.footer, 'open');
8677
 
            }
8678
 
            panel.cfg.setProperty('width', win.attrs.width);
8679
 
 
8680
 
            this.currentWindow = win;
8681
 
            this.moveWindow(true);
8682
 
            panel.show();
8683
 
            this.fireEvent('afterOpenWindow', { type: 'afterOpenWindow', win: win, panel: panel });
8684
 
        },
8685
 
        /**
8686
 
        * @method moveWindow
8687
 
        * @param {Boolean} force Boolean to tell it to move but not use any animation (Usually done the first time the window is loaded.)
8688
 
        * @description Realign the window with the currentElement and reposition the knob above the panel.
8689
 
        */
8690
 
        moveWindow: function(force) {
8691
 
            if (!this.currentWindow) {
8692
 
                return false;
8693
 
            }
8694
 
            var win = this.currentWindow,
8695
 
                xy = Dom.getXY(this.currentElement[0]),
8696
 
                elXY = Dom.getXY(this.get('iframe').get('element')),
8697
 
                panel = this.get('panel'),
8698
 
                //newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
8699
 
                newXY = [(xy[0] + elXY[0]), (xy[1] + elXY[1])],
8700
 
                wWidth = (parseInt(win.attrs.width, 10) / 2),
8701
 
                align = 'center',
8702
 
                orgXY = panel.cfg.getProperty('xy') || [0,0],
8703
 
                _knob = panel.editor_knob,
8704
 
                xDiff = 0,
8705
 
                yDiff = 0,
8706
 
                anim = false;
8707
 
 
8708
 
 
8709
 
            newXY[0] = ((newXY[0] - wWidth) + 20);
8710
 
            //Account for the Scroll bars in a scrolled editor window.
8711
 
            newXY[0] = newXY[0] - Dom.getDocumentScrollLeft(this._getDoc());
8712
 
            newXY[1] = newXY[1] - Dom.getDocumentScrollTop(this._getDoc());
8713
 
            
8714
 
            if (this._isElement(this.currentElement[0], 'img')) {
8715
 
                if (this.currentElement[0].src.indexOf(this.get('blankimage')) != -1) {
8716
 
                    newXY[0] = (newXY[0] + (75 / 2)); //Placeholder size
8717
 
                    newXY[1] = (newXY[1] + 75); //Placeholder sizea
8718
 
                } else {
8719
 
                    var w = parseInt(this.currentElement[0].width, 10);
8720
 
                    var h = parseInt(this.currentElement[0].height, 10);
8721
 
                    newXY[0] = (newXY[0] + (w / 2));
8722
 
                    newXY[1] = (newXY[1] + h);
8723
 
                }
8724
 
                newXY[1] = newXY[1] + 15;
8725
 
            } else {
8726
 
                var fs = Dom.getStyle(this.currentElement[0], 'fontSize');
8727
 
                if (fs && fs.indexOf && fs.indexOf('px') != -1) {
8728
 
                    newXY[1] = newXY[1] + parseInt(Dom.getStyle(this.currentElement[0], 'fontSize'), 10) + 5;
8729
 
                } else {
8730
 
                    newXY[1] = newXY[1] + 20;
8731
 
                }
8732
 
            }
8733
 
            if (newXY[0] < elXY[0]) {
8734
 
                newXY[0] = elXY[0] + 5;
8735
 
                align = 'left';
8736
 
            }
8737
 
 
8738
 
            if ((newXY[0] + (wWidth * 2)) > (elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10))) {
8739
 
                newXY[0] = ((elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10)) - (wWidth * 2) - 5);
8740
 
                align = 'right';
8741
 
            }
8742
 
            
8743
 
            try {
8744
 
                xDiff = (newXY[0] - orgXY[0]);
8745
 
                yDiff = (newXY[1] - orgXY[1]);
8746
 
            } catch (e) {}
8747
 
 
8748
 
 
8749
 
            var iTop = elXY[1] + parseInt(this.get('height'), 10);
8750
 
            var iLeft = elXY[0] + parseInt(this.get('width'), 10);
8751
 
            if (newXY[1] > iTop) {
8752
 
                newXY[1] = iTop;
8753
 
            }
8754
 
            if (newXY[0] > iLeft) {
8755
 
                newXY[0] = (iLeft / 2);
8756
 
            }
8757
 
            
8758
 
            //Convert negative numbers to positive so we can get the difference in distance
8759
 
            xDiff = ((xDiff < 0) ? (xDiff * -1) : xDiff);
8760
 
            yDiff = ((yDiff < 0) ? (yDiff * -1) : yDiff);
8761
 
 
8762
 
            if (((xDiff > 10) || (yDiff > 10)) || force) { //Only move the window if it's supposed to move more than 10px or force was passed (new window)
8763
 
                var _knobLeft = 0,
8764
 
                    elW = 0;
8765
 
 
8766
 
                if (this.currentElement[0].width) {
8767
 
                    elW = (parseInt(this.currentElement[0].width, 10) / 2);
8768
 
                }
8769
 
 
8770
 
                var leftOffset = xy[0] + elXY[0] + elW;
8771
 
                _knobLeft = leftOffset - newXY[0];
8772
 
                //Check to see if the knob will go off either side & reposition it
8773
 
                if (_knobLeft > (parseInt(win.attrs.width, 10) - 1)) {
8774
 
                    _knobLeft = ((parseInt(win.attrs.width, 10) - 30) - 1);
8775
 
                } else if (_knobLeft < 40) {
8776
 
                    _knobLeft = 1;
8777
 
                }
8778
 
                if (isNaN(_knobLeft)) {
8779
 
                    _knobLeft = 1;
8780
 
                }
8781
 
                if (force) {
8782
 
                    if (_knob) {
8783
 
                        _knob.style.left = _knobLeft + 'px';
8784
 
                    }
8785
 
                    //Removed Animation from a forced move..
8786
 
                    panel.cfg.setProperty('xy', newXY);
8787
 
                } else {
8788
 
                    if (this.get('animate')) {
8789
 
                        anim = new YAHOO.util.Anim(panel.element, {}, 0.5, YAHOO.util.Easing.easeOut);
8790
 
                        anim.attributes = {
8791
 
                            top: {
8792
 
                                to: newXY[1]
8793
 
                            },
8794
 
                            left: {
8795
 
                                to: newXY[0]
8796
 
                            }
8797
 
                        };
8798
 
                        anim.onComplete.subscribe(function() {
8799
 
                            panel.cfg.setProperty('xy', newXY);
8800
 
                        });
8801
 
                        //We have to animate the iframe shim at the same time as the panel or we get scrollbar bleed ..
8802
 
                        var iframeAnim = new YAHOO.util.Anim(panel.iframe, anim.attributes, 0.5, YAHOO.util.Easing.easeOut);
8803
 
 
8804
 
                        var _knobAnim = new YAHOO.util.Anim(_knob, {
8805
 
                            left: {
8806
 
                                to: _knobLeft
8807
 
                            }
8808
 
                        }, 0.6, YAHOO.util.Easing.easeOut);
8809
 
                        anim.animate();
8810
 
                        iframeAnim.animate();
8811
 
                        _knobAnim.animate();
8812
 
                    } else {
8813
 
                        _knob.style.left = _knobLeft + 'px';
8814
 
                        panel.cfg.setProperty('xy', newXY);
8815
 
                    }
8816
 
                }
8817
 
            }
8818
 
        },
8819
 
        /**
8820
 
        * @private
8821
 
        * @method _closeWindow
8822
 
        * @description Close the currently open EditorWindow with the Escape key.
8823
 
        * @param {Event} ev The keypress Event that we are trapping
8824
 
        */
8825
 
        _closeWindow: function(ev) {
8826
 
            //if ((ev.charCode == 87) && ev.shiftKey && ev.ctrlKey) {
8827
 
            if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) {            
8828
 
                if (this.currentWindow) {
8829
 
                    this.closeWindow();
8830
 
                }
8831
 
            }
8832
 
        },
8833
 
        /**
8834
 
        * @method closeWindow
8835
 
        * @description Close the currently open EditorWindow.
8836
 
        */
8837
 
        closeWindow: function(keepOpen) {
8838
 
            YAHOO.log('closeWindow: ' + this.currentWindow.name, 'info', 'Editor');
8839
 
            this.fireEvent('window' + this.currentWindow.name + 'Close', { type: 'window' + this.currentWindow.name + 'Close', win: this.currentWindow, el: this.currentElement[0] });
8840
 
            this.fireEvent('closeWindow', { type: 'closeWindow', win: this.currentWindow });
8841
 
            this.currentWindow = null;
8842
 
            this.get('panel').hide();
8843
 
            this.get('panel').cfg.setProperty('xy', [-900,-900]);
8844
 
            this.get('panel').syncIframe(); //Needed to move the iframe with the hidden panel
8845
 
            this.unsubscribeAll('afterExecCommand');
8846
 
            this.toolbar.set('disabled', false); //enable the toolbar now that the window is closed
8847
 
            this.toolbar.resetAllButtons();
8848
 
            this.focus();
8849
 
            Event.removeListener(document, 'keydown', this._closeWindow);
8850
 
        },
8851
 
 
8852
 
        /* {{{  Command Overrides - These commands are only over written when we are using the advanced version */
8853
 
        
8854
 
        /**
8855
 
        * @method cmd_undo
8856
 
        * @description Pulls an item from the Undo stack and updates the Editor
8857
 
        * @param value Value passed from the execCommand method
8858
 
        */
8859
 
        cmd_undo: function(value) {
8860
 
            if (this._hasUndoLevel()) {
8861
 
                if (!this._undoLevel) {
8862
 
                    this._undoLevel = this._undoCache.length;
8863
 
                }
8864
 
                this._undoLevel = (this._undoLevel - 1);
8865
 
                if (this._undoCache[this._undoLevel]) {
8866
 
                    var html = this._getUndo(this._undoLevel);
8867
 
                    this.setEditorHTML(html);
8868
 
                } else {
8869
 
                    this._undoLevel = null;
8870
 
                    this.toolbar.disableButton('undo');
8871
 
                }
8872
 
            }
8873
 
            return [false];
8874
 
        },
8875
 
 
8876
 
        /**
8877
 
        * @method cmd_redo
8878
 
        * @description Pulls an item from the Undo stack and updates the Editor
8879
 
        * @param value Value passed from the execCommand method
8880
 
        */
8881
 
        cmd_redo: function(value) {
8882
 
            this._undoLevel = this._undoLevel + 1;
8883
 
            if (this._undoLevel >= this._undoCache.length) {
8884
 
                this._undoLevel = this._undoCache.length;
8885
 
            }
8886
 
            YAHOO.log(this._undoLevel + ' :: ' + this._undoCache.length, 'warn', 'SimpleEditor');
8887
 
            if (this._undoCache[this._undoLevel]) {
8888
 
                var html = this._getUndo(this._undoLevel);
8889
 
                this.setEditorHTML(html);
8890
 
            } else {
8891
 
                this.toolbar.disableButton('redo');
8892
 
            }
8893
 
            return [false];
8894
 
        },       
8895
 
        
8896
 
        /**
8897
 
        * @method cmd_heading
8898
 
        * @param value Value passed from the execCommand method
8899
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('heading') is used.
8900
 
        */
8901
 
        cmd_heading: function(value) {
8902
 
            var exec = true,
8903
 
                el = null,
8904
 
                action = 'heading',
8905
 
                _sel = this._getSelection(),
8906
 
                _selEl = this._getSelectedElement();
8907
 
 
8908
 
            if (_selEl) {
8909
 
                _sel = _selEl;
8910
 
            }
8911
 
            
8912
 
            if (this.browser.ie) {
8913
 
                action = 'formatblock';
8914
 
            }
8915
 
            if (value == this.STR_NONE) {
8916
 
                if ((_sel && _sel.tagName && (_sel.tagName.toLowerCase().substring(0,1) == 'h')) || (_sel && _sel.parentNode && _sel.parentNode.tagName && (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h'))) {
8917
 
                    if (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h') {
8918
 
                        _sel = _sel.parentNode;
8919
 
                    }
8920
 
                    if (this._isElement(_sel, 'html')) {
8921
 
                        return [false];
8922
 
                    }
8923
 
                    el = this._swapEl(_selEl, 'span', function(el) {
8924
 
                        el.className = 'yui-non';
8925
 
                    });
8926
 
                    this._selectNode(el);
8927
 
                    this.currentElement[0] = el;
8928
 
                }
8929
 
                exec = false;
8930
 
            } else {
8931
 
                if (this._isElement(_selEl, 'h1') || this._isElement(_selEl, 'h2') || this._isElement(_selEl, 'h3') || this._isElement(_selEl, 'h4') || this._isElement(_selEl, 'h5') || this._isElement(_selEl, 'h6')) {
8932
 
                    el = this._swapEl(_selEl, value);
8933
 
                    this._selectNode(el);
8934
 
                    this.currentElement[0] = el;
8935
 
                } else {
8936
 
                    this._createCurrentElement(value);
8937
 
                    this._selectNode(this.currentElement[0]);
8938
 
                }
8939
 
                exec = false;
8940
 
            }
8941
 
            return [exec, action];
8942
 
        },
8943
 
        /**
8944
 
        * @method cmd_hiddenelements
8945
 
        * @param value Value passed from the execCommand method
8946
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('hiddenelements') is used.
8947
 
        */
8948
 
        cmd_hiddenelements: function(value) {
8949
 
            if (this._showingHiddenElements) {
8950
 
                //Don't auto highlight the hidden button
8951
 
                this._lastButton = null;
8952
 
                YAHOO.log('Enabling hidden CSS File', 'info', 'SimpleEditor');
8953
 
                this._showingHiddenElements = false;
8954
 
                this.toolbar.deselectButton('hiddenelements');
8955
 
                Dom.removeClass(this._getDoc().body, this.CLASS_HIDDEN);
8956
 
            } else {
8957
 
                YAHOO.log('Disabling hidden CSS File', 'info', 'SimpleEditor');
8958
 
                this._showingHiddenElements = true;
8959
 
                Dom.addClass(this._getDoc().body, this.CLASS_HIDDEN);
8960
 
                this.toolbar.selectButton('hiddenelements');
8961
 
            }
8962
 
            return [false];
8963
 
        },
8964
 
        /**
8965
 
        * @method cmd_removeformat
8966
 
        * @param value Value passed from the execCommand method
8967
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('removeformat') is used.
8968
 
        */
8969
 
        cmd_removeformat: function(value) {
8970
 
            var exec = true;
8971
 
            /*
8972
 
            * @knownissue Remove Format issue
8973
 
            * @browser Safari 2.x
8974
 
            * @description There is an issue here with Safari, that it may not always remove the format of the item that is selected.
8975
 
            * Due to the way that Safari 2.x handles ranges, it is very difficult to determine what the selection holds.
8976
 
            * So here we are making the best possible guess and acting on it.
8977
 
            */
8978
 
            if (this.browser.webkit && !this._getDoc().queryCommandEnabled('removeformat')) {
8979
 
                var _txt = this._getSelection()+'';
8980
 
                this._createCurrentElement('span');
8981
 
                this.currentElement[0].className = 'yui-non';
8982
 
                this.currentElement[0].innerHTML = _txt;
8983
 
                for (var i = 1; i < this.currentElement.length; i++) {
8984
 
                    this.currentElement[i].parentNode.removeChild(this.currentElement[i]);
8985
 
                }
8986
 
                
8987
 
                exec = false;
8988
 
            }
8989
 
            return [exec];
8990
 
        },
8991
 
        /**
8992
 
        * @method cmd_script
8993
 
        * @param action action passed from the execCommand method
8994
 
        * @param value Value passed from the execCommand method
8995
 
        * @description This is a combined execCommand override method. It is called from the cmd_superscript and cmd_subscript methods.
8996
 
        */
8997
 
        cmd_script: function(action, value) {
8998
 
            var exec = true, tag = action.toLowerCase().substring(0, 3),
8999
 
                _span = null, _selEl = this._getSelectedElement();
9000
 
 
9001
 
            if (this.browser.webkit) {
9002
 
                YAHOO.log('Safari dom fun again (' + action + ')..', 'info', 'EditorSafari');
9003
 
                if (this._isElement(_selEl, tag)) {
9004
 
                    YAHOO.log('we are a child of tag (' + tag + '), reverse process', 'info', 'EditorSafari');
9005
 
                    _span = this._swapEl(this.currentElement[0], 'span', function(el) {
9006
 
                        el.className = 'yui-non';
9007
 
                    });
9008
 
                    this._selectNode(_span);
9009
 
                } else {
9010
 
                    this._createCurrentElement(tag);
9011
 
                    var _sub = this._swapEl(this.currentElement[0], tag);
9012
 
                    this._selectNode(_sub);
9013
 
                    this.currentElement[0] = _sub;
9014
 
                }
9015
 
                exec = false;
9016
 
            }
9017
 
            return exec;
9018
 
        },
9019
 
        /**
9020
 
        * @method cmd_superscript
9021
 
        * @param value Value passed from the execCommand method
9022
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('superscript') is used.
9023
 
        */
9024
 
        cmd_superscript: function(value) {
9025
 
            return [this.cmd_script('superscript', value)];
9026
 
        },
9027
 
        /**
9028
 
        * @method cmd_subscript
9029
 
        * @param value Value passed from the execCommand method
9030
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('subscript') is used.
9031
 
        */
9032
 
        cmd_subscript: function(value) {
9033
 
            return [this.cmd_script('subscript', value)];
9034
 
        },
9035
 
        /**
9036
 
        * @method cmd_indent
9037
 
        * @param value Value passed from the execCommand method
9038
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('indent') is used.
9039
 
        */
9040
 
        cmd_indent: function(value) {
9041
 
            var exec = true, selEl = this._getSelectedElement(), _bq = null;
9042
 
 
9043
 
            //if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
9044
 
            //if (this.browser.webkit || this.browser.ie) {
9045
 
            if (this.browser.ie) {
9046
 
                if (this._isElement(selEl, 'blockquote')) {
9047
 
                    _bq = this._getDoc().createElement('blockquote');
9048
 
                    _bq.innerHTML = selEl.innerHTML;
9049
 
                    selEl.innerHTML = '';
9050
 
                    selEl.appendChild(_bq);
9051
 
                    this._selectNode(_bq);
9052
 
                } else {
9053
 
                    _bq = this._getDoc().createElement('blockquote');
9054
 
                    var html = this._getRange().htmlText;
9055
 
                    _bq.innerHTML = html;
9056
 
                    this._createCurrentElement('blockquote');
9057
 
                    /*
9058
 
                    for (var i = 0; i < this.currentElement.length; i++) {
9059
 
                        _bq = this._getDoc().createElement('blockquote');
9060
 
                        _bq.innerHTML = this.currentElement[i].innerHTML;
9061
 
                        this.currentElement[i].parentNode.replaceChild(_bq, this.currentElement[i]);
9062
 
                        this.currentElement[i] = _bq;
9063
 
                    }
9064
 
                    */
9065
 
                    this.currentElement[0].parentNode.replaceChild(_bq, this.currentElement[0]);
9066
 
                    this.currentElement[0] = _bq;
9067
 
                    this._selectNode(this.currentElement[0]);
9068
 
                }
9069
 
                exec = false;
9070
 
            } else {
9071
 
                value = 'blockquote';
9072
 
            }
9073
 
            return [exec, 'formatblock', value];
9074
 
        },
9075
 
        /**
9076
 
        * @method cmd_outdent
9077
 
        * @param value Value passed from the execCommand method
9078
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('outdent') is used.
9079
 
        */
9080
 
        cmd_outdent: function(value) {
9081
 
            var exec = true, selEl = this._getSelectedElement(), _bq = null, _span = null;
9082
 
            //if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
9083
 
            if (this.browser.webkit || this.browser.ie) {
9084
 
            //if (this.browser.ie) {
9085
 
                selEl = this._getSelectedElement();
9086
 
                if (this._isElement(selEl, 'blockquote')) {
9087
 
                    var par = selEl.parentNode;
9088
 
                    if (this._isElement(selEl.parentNode, 'blockquote')) {
9089
 
                        par.innerHTML = selEl.innerHTML;
9090
 
                        this._selectNode(par);
9091
 
                    } else {
9092
 
                        _span = this._getDoc().createElement('span');
9093
 
                        _span.innerHTML = selEl.innerHTML;
9094
 
                        YAHOO.util.Dom.addClass(_span, 'yui-non');
9095
 
                        par.replaceChild(_span, selEl);
9096
 
                        this._selectNode(_span);
9097
 
                    }
9098
 
                } else {
9099
 
                    YAHOO.log('Can not outdent, we are not inside a blockquote', 'warn', 'Editor');
9100
 
                }
9101
 
                exec = false;
9102
 
            } else {
9103
 
                value = false;
9104
 
            }
9105
 
            return [exec, 'outdent', value];
9106
 
        },
9107
 
        /**
9108
 
        * @method cmd_justify
9109
 
        * @param dir The direction to justify
9110
 
        * @description This is a factory method for the justify family of commands.
9111
 
        */
9112
 
        cmd_justify: function(dir) {
9113
 
            if (this.browser.ie) {
9114
 
                if (this._hasSelection()) {
9115
 
                    this._createCurrentElement('span');
9116
 
                    this._swapEl(this.currentElement[0], 'div', function(el) {
9117
 
                        el.style.textAlign = dir;
9118
 
                    });
9119
 
                    
9120
 
                    return [false];
9121
 
                }
9122
 
            }
9123
 
            return [true, 'justify' + dir, ''];
9124
 
        },
9125
 
        /**
9126
 
        * @method cmd_justifycenter
9127
 
        * @param value Value passed from the execCommand method
9128
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifycenter') is used.
9129
 
        */
9130
 
        cmd_justifycenter: function() {
9131
 
            return [this.cmd_justify('center')];
9132
 
        },
9133
 
        /**
9134
 
        * @method cmd_justifyleft
9135
 
        * @param value Value passed from the execCommand method
9136
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyleft') is used.
9137
 
        */
9138
 
        cmd_justifyleft: function() {
9139
 
            return [this.cmd_justify('left')];
9140
 
        },
9141
 
        /**
9142
 
        * @method cmd_justifyright
9143
 
        * @param value Value passed from the execCommand method
9144
 
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyright') is used.
9145
 
        */
9146
 
        cmd_justifyright: function() {
9147
 
            return [this.cmd_justify('right')];
9148
 
        },
9149
 
        /* }}}*/        
9150
 
        /**
9151
 
        * @method toString
9152
 
        * @description Returns a string representing the editor.
9153
 
        * @return {String}
9154
 
        */
9155
 
        toString: function() {
9156
 
            var str = 'Editor';
9157
 
            if (this.get && this.get('element_cont')) {
9158
 
                str = 'Editor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
9159
 
            }
9160
 
            return str;
9161
 
        }
9162
 
    });
9163
 
/**
9164
 
* @event beforeOpenWindow
9165
 
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
9166
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9167
 
* @description Event fires before an Editor Window is opened. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
9168
 
* @type YAHOO.util.CustomEvent
9169
 
*/
9170
 
/**
9171
 
* @event afterOpenWindow
9172
 
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
9173
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9174
 
* @description Event fires after an Editor Window is opened. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
9175
 
* @type YAHOO.util.CustomEvent
9176
 
*/
9177
 
/**
9178
 
* @event closeWindow
9179
 
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
9180
 
* @description Event fires after an Editor Window is closed. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
9181
 
* @type YAHOO.util.CustomEvent
9182
 
*/
9183
 
/**
9184
 
* @event windowCMDOpen
9185
 
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
9186
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9187
 
* @description Dynamic event fired when an <a href="YAHOO.widget.EditorWindow.html">EditorWindow</a> is opened.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkOpen event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
9188
 
* @type YAHOO.util.CustomEvent
9189
 
*/
9190
 
/**
9191
 
* @event windowCMDClose
9192
 
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
9193
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9194
 
* @description Dynamic event fired when an <a href="YAHOO.widget.EditorWindow.html">EditorWindow</a> is closed.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkClose event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
9195
 
* @type YAHOO.util.CustomEvent
9196
 
*/
9197
 
/**
9198
 
* @event windowRender
9199
 
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
9200
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9201
 
* @description Event fired when the initial Overlay is rendered. Can be used to manipulate the content of the panel.
9202
 
* @type YAHOO.util.CustomEvent
9203
 
*/
9204
 
/**
9205
 
* @event windowInsertImageRender
9206
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9207
 
* @param {HTMLElement} body The HTML element used as the body of the window..
9208
 
* @param {Toolbar} toolbar A reference to the toolbar object used inside this window.
9209
 
* @description Event fired when the pre render of the Insert Image window has finished.
9210
 
* @type YAHOO.util.CustomEvent
9211
 
*/
9212
 
/**
9213
 
* @event windowCreateLinkRender
9214
 
* @param {Overlay} panel The Overlay object that is used to create the window.
9215
 
* @param {HTMLElement} body The HTML element used as the body of the window..
9216
 
* @description Event fired when the pre render of the Create Link window has finished.
9217
 
* @type YAHOO.util.CustomEvent
9218
 
*/
9219
 
 
9220
 
 
9221
 
 
9222
 
    /**
9223
 
     * @description Class to hold Window information between uses. We use the same panel to show the windows, so using this will allow you to configure a window before it is shown.
9224
 
     * This is what you pass to Editor.openWindow();. These parameters will not take effect until the openWindow() is called in the editor.
9225
 
     * @class EditorWindow
9226
 
     * @param {String} name The name of the window.
9227
 
     * @param {Object} attrs Attributes for the window. Current attributes used are : height and width
9228
 
    */
9229
 
    YAHOO.widget.EditorWindow = function(name, attrs) {
9230
 
        /**
9231
 
        * @private
9232
 
        * @property name
9233
 
        * @description A unique name for the window
9234
 
        */
9235
 
        this.name = name.replace(' ', '_');
9236
 
        /**
9237
 
        * @private
9238
 
        * @property attrs
9239
 
        * @description The window attributes
9240
 
        */
9241
 
        this.attrs = attrs;
9242
 
    };
9243
 
 
9244
 
    YAHOO.widget.EditorWindow.prototype = {
9245
 
        /**
9246
 
        * @private
9247
 
        * @property header
9248
 
        * @description Holder for the header of the window, used in Editor.openWindow
9249
 
        */
9250
 
        header: null,
9251
 
        /**
9252
 
        * @private
9253
 
        * @property body
9254
 
        * @description Holder for the body of the window, used in Editor.openWindow
9255
 
        */
9256
 
        body: null,
9257
 
        /**
9258
 
        * @private
9259
 
        * @property footer
9260
 
        * @description Holder for the footer of the window, used in Editor.openWindow
9261
 
        */
9262
 
        footer: null,
9263
 
        /**
9264
 
        * @method setHeader
9265
 
        * @description Sets the header for the window.
9266
 
        * @param {String/HTMLElement} str The string or DOM reference to be used as the windows header.
9267
 
        */
9268
 
        setHeader: function(str) {
9269
 
            this.header = str;
9270
 
        },
9271
 
        /**
9272
 
        * @method setBody
9273
 
        * @description Sets the body for the window.
9274
 
        * @param {String/HTMLElement} str The string or DOM reference to be used as the windows body.
9275
 
        */
9276
 
        setBody: function(str) {
9277
 
            this.body = str;
9278
 
        },
9279
 
        /**
9280
 
        * @method setFooter
9281
 
        * @description Sets the footer for the window.
9282
 
        * @param {String/HTMLElement} str The string or DOM reference to be used as the windows footer.
9283
 
        */
9284
 
        setFooter: function(str) {
9285
 
            this.footer = str;
9286
 
        },
9287
 
        /**
9288
 
        * @method toString
9289
 
        * @description Returns a string representing the EditorWindow.
9290
 
        * @return {String}
9291
 
        */
9292
 
        toString: function() {
9293
 
            return 'Editor Window (' + this.name + ')';
9294
 
        }
9295
 
    };
9296
 
})();
9297
 
YAHOO.register("editor", YAHOO.widget.Editor, {version: "2.7.0", build: "1799"});