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