Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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