0
|
1 /*
|
|
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
|
|
3 Code licensed under the BSD License:
|
|
4 http://developer.yahoo.net/yui/license.txt
|
|
5 version: 2.8.0r4
|
|
6 */
|
|
7 (function() {
|
|
8 var Dom = YAHOO.util.Dom,
|
|
9 Event = YAHOO.util.Event,
|
|
10 Lang = YAHOO.lang;
|
|
11 /**
|
|
12 * @module editor
|
|
13 * @description <p>Creates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar</p>
|
|
14 * @class ToolbarButtonAdvanced
|
|
15 * @namespace YAHOO.widget
|
|
16 * @requires yahoo, dom, element, event, container_core, menu, button
|
|
17 *
|
|
18 * Provides a toolbar button based on the button and menu widgets.
|
|
19 * @constructor
|
|
20 * @class ToolbarButtonAdvanced
|
|
21 * @param {String/HTMLElement} el The element to turn into a button.
|
|
22 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
23 */
|
|
24 if (YAHOO.widget.Button) {
|
|
25 YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button;
|
|
26 /**
|
|
27 * @property buttonType
|
|
28 * @private
|
|
29 * @description Tells if the Button is a Rich Button or a Simple Button
|
|
30 */
|
|
31 YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich';
|
|
32 /**
|
|
33 * @method checkValue
|
|
34 * @param {String} value The value of the option that we want to mark as selected
|
|
35 * @description Select an option by value
|
|
36 */
|
|
37 YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) {
|
|
38 var _menuItems = this.getMenu().getItems();
|
|
39 if (_menuItems.length === 0) {
|
|
40 this.getMenu()._onBeforeShow();
|
|
41 _menuItems = this.getMenu().getItems();
|
|
42 }
|
|
43 for (var i = 0; i < _menuItems.length; i++) {
|
|
44 _menuItems[i].cfg.setProperty('checked', false);
|
|
45 if (_menuItems[i].value == value) {
|
|
46 _menuItems[i].cfg.setProperty('checked', true);
|
|
47 }
|
|
48 }
|
|
49 };
|
|
50 } else {
|
|
51 YAHOO.widget.ToolbarButtonAdvanced = function() {};
|
|
52 }
|
|
53
|
|
54
|
|
55 /**
|
|
56 * @description <p>Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar</p><p>Provides a toolbar button based on the button and menu widgets, <select> elements are used in place of menu's.</p>
|
|
57 * @class ToolbarButton
|
|
58 * @namespace YAHOO.widget
|
|
59 * @requires yahoo, dom, element, event
|
|
60 * @extends YAHOO.util.Element
|
|
61 *
|
|
62 *
|
|
63 * @constructor
|
|
64 * @param {String/HTMLElement} el The element to turn into a button.
|
|
65 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
66 */
|
|
67
|
|
68 YAHOO.widget.ToolbarButton = function(el, attrs) {
|
|
69
|
|
70 if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
|
|
71 attrs = el;
|
|
72 }
|
|
73 var local_attrs = (attrs || {});
|
|
74
|
|
75 var oConfig = {
|
|
76 element: null,
|
|
77 attributes: local_attrs
|
|
78 };
|
|
79
|
|
80 if (!oConfig.attributes.type) {
|
|
81 oConfig.attributes.type = 'push';
|
|
82 }
|
|
83
|
|
84 oConfig.element = document.createElement('span');
|
|
85 oConfig.element.setAttribute('unselectable', 'on');
|
|
86 oConfig.element.className = 'yui-button yui-' + oConfig.attributes.type + '-button';
|
|
87 oConfig.element.innerHTML = '<span class="first-child"><a href="#">LABEL</a></span>';
|
|
88 oConfig.element.firstChild.firstChild.tabIndex = '-1';
|
|
89 oConfig.attributes.id = (oConfig.attributes.id || Dom.generateId());
|
|
90 oConfig.element.id = oConfig.attributes.id;
|
|
91
|
|
92 YAHOO.widget.ToolbarButton.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
|
|
93 };
|
|
94
|
|
95 YAHOO.extend(YAHOO.widget.ToolbarButton, YAHOO.util.Element, {
|
|
96 /**
|
|
97 * @property buttonType
|
|
98 * @private
|
|
99 * @description Tells if the Button is a Rich Button or a Simple Button
|
|
100 */
|
|
101 buttonType: 'normal',
|
|
102 /**
|
|
103 * @method _handleMouseOver
|
|
104 * @private
|
|
105 * @description Adds classes to the button elements on mouseover (hover)
|
|
106 */
|
|
107 _handleMouseOver: function() {
|
|
108 if (!this.get('disabled')) {
|
|
109 this.addClass('yui-button-hover');
|
|
110 this.addClass('yui-' + this.get('type') + '-button-hover');
|
|
111 }
|
|
112 },
|
|
113 /**
|
|
114 * @method _handleMouseOut
|
|
115 * @private
|
|
116 * @description Removes classes from the button elements on mouseout (hover)
|
|
117 */
|
|
118 _handleMouseOut: function() {
|
|
119 this.removeClass('yui-button-hover');
|
|
120 this.removeClass('yui-' + this.get('type') + '-button-hover');
|
|
121 },
|
|
122 /**
|
|
123 * @method checkValue
|
|
124 * @param {String} value The value of the option that we want to mark as selected
|
|
125 * @description Select an option by value
|
|
126 */
|
|
127 checkValue: function(value) {
|
|
128 if (this.get('type') == 'menu') {
|
|
129 var opts = this._button.options;
|
|
130 for (var i = 0; i < opts.length; i++) {
|
|
131 if (opts[i].value == value) {
|
|
132 opts.selectedIndex = i;
|
|
133 }
|
|
134 }
|
|
135 }
|
|
136 },
|
|
137 /**
|
|
138 * @method init
|
|
139 * @description The ToolbarButton class's initialization method
|
|
140 */
|
|
141 init: function(p_oElement, p_oAttributes) {
|
|
142 YAHOO.widget.ToolbarButton.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
143
|
|
144 this.on('mouseover', this._handleMouseOver, this, true);
|
|
145 this.on('mouseout', this._handleMouseOut, this, true);
|
|
146 this.on('click', function(ev) {
|
|
147 Event.stopEvent(ev);
|
|
148 return false;
|
|
149 }, this, true);
|
|
150 },
|
|
151 /**
|
|
152 * @method initAttributes
|
|
153 * @description Initializes all of the configuration attributes used to create
|
|
154 * the toolbar.
|
|
155 * @param {Object} attr Object literal specifying a set of
|
|
156 * configuration attributes used to create the toolbar.
|
|
157 */
|
|
158 initAttributes: function(attr) {
|
|
159 YAHOO.widget.ToolbarButton.superclass.initAttributes.call(this, attr);
|
|
160 /**
|
|
161 * @attribute value
|
|
162 * @description The value of the button
|
|
163 * @type String
|
|
164 */
|
|
165 this.setAttributeConfig('value', {
|
|
166 value: attr.value
|
|
167 });
|
|
168 /**
|
|
169 * @attribute menu
|
|
170 * @description The menu attribute, see YAHOO.widget.Button
|
|
171 * @type Object
|
|
172 */
|
|
173 this.setAttributeConfig('menu', {
|
|
174 value: attr.menu || false
|
|
175 });
|
|
176 /**
|
|
177 * @attribute type
|
|
178 * @description The type of button to create: push, menu, color, select, spin
|
|
179 * @type String
|
|
180 */
|
|
181 this.setAttributeConfig('type', {
|
|
182 value: attr.type,
|
|
183 writeOnce: true,
|
|
184 method: function(type) {
|
|
185 var el, opt;
|
|
186 if (!this._button) {
|
|
187 this._button = this.get('element').getElementsByTagName('a')[0];
|
|
188 }
|
|
189 switch (type) {
|
|
190 case 'select':
|
|
191 case 'menu':
|
|
192 el = document.createElement('select');
|
|
193 el.id = this.get('id');
|
|
194 var menu = this.get('menu');
|
|
195 for (var i = 0; i < menu.length; i++) {
|
|
196 opt = document.createElement('option');
|
|
197 opt.innerHTML = menu[i].text;
|
|
198 opt.value = menu[i].value;
|
|
199 if (menu[i].checked) {
|
|
200 opt.selected = true;
|
|
201 }
|
|
202 el.appendChild(opt);
|
|
203 }
|
|
204 this._button.parentNode.replaceChild(el, this._button);
|
|
205 Event.on(el, 'change', this._handleSelect, this, true);
|
|
206 this._button = el;
|
|
207 break;
|
|
208 }
|
|
209 }
|
|
210 });
|
|
211
|
|
212 /**
|
|
213 * @attribute disabled
|
|
214 * @description Set the button into a disabled state
|
|
215 * @type String
|
|
216 */
|
|
217 this.setAttributeConfig('disabled', {
|
|
218 value: attr.disabled || false,
|
|
219 method: function(disabled) {
|
|
220 if (disabled) {
|
|
221 this.addClass('yui-button-disabled');
|
|
222 this.addClass('yui-' + this.get('type') + '-button-disabled');
|
|
223 } else {
|
|
224 this.removeClass('yui-button-disabled');
|
|
225 this.removeClass('yui-' + this.get('type') + '-button-disabled');
|
|
226 }
|
|
227 if ((this.get('type') == 'menu') || (this.get('type') == 'select')) {
|
|
228 this._button.disabled = disabled;
|
|
229 }
|
|
230 }
|
|
231 });
|
|
232
|
|
233 /**
|
|
234 * @attribute label
|
|
235 * @description The text label for the button
|
|
236 * @type String
|
|
237 */
|
|
238 this.setAttributeConfig('label', {
|
|
239 value: attr.label,
|
|
240 method: function(label) {
|
|
241 if (!this._button) {
|
|
242 this._button = this.get('element').getElementsByTagName('a')[0];
|
|
243 }
|
|
244 if (this.get('type') == 'push') {
|
|
245 this._button.innerHTML = label;
|
|
246 }
|
|
247 }
|
|
248 });
|
|
249
|
|
250 /**
|
|
251 * @attribute title
|
|
252 * @description The title of the button
|
|
253 * @type String
|
|
254 */
|
|
255 this.setAttributeConfig('title', {
|
|
256 value: attr.title
|
|
257 });
|
|
258
|
|
259 /**
|
|
260 * @config container
|
|
261 * @description The container that the button is rendered to, handled by Toolbar
|
|
262 * @type String
|
|
263 */
|
|
264 this.setAttributeConfig('container', {
|
|
265 value: null,
|
|
266 writeOnce: true,
|
|
267 method: function(cont) {
|
|
268 this.appendTo(cont);
|
|
269 }
|
|
270 });
|
|
271
|
|
272 },
|
|
273 /**
|
|
274 * @private
|
|
275 * @method _handleSelect
|
|
276 * @description The event fired when a change event gets fired on a select element
|
|
277 * @param {Event} ev The change event.
|
|
278 */
|
|
279 _handleSelect: function(ev) {
|
|
280 var tar = Event.getTarget(ev);
|
|
281 var value = tar.options[tar.selectedIndex].value;
|
|
282 this.fireEvent('change', {type: 'change', value: value });
|
|
283 },
|
|
284 /**
|
|
285 * @method getMenu
|
|
286 * @description A stub function to mimic YAHOO.widget.Button's getMenu method
|
|
287 */
|
|
288 getMenu: function() {
|
|
289 return this.get('menu');
|
|
290 },
|
|
291 /**
|
|
292 * @method destroy
|
|
293 * @description Destroy the button
|
|
294 */
|
|
295 destroy: function() {
|
|
296 Event.purgeElement(this.get('element'), true);
|
|
297 this.get('element').parentNode.removeChild(this.get('element'));
|
|
298 //Brutal Object Destroy
|
|
299 for (var i in this) {
|
|
300 if (Lang.hasOwnProperty(this, i)) {
|
|
301 this[i] = null;
|
|
302 }
|
|
303 }
|
|
304 },
|
|
305 /**
|
|
306 * @method fireEvent
|
|
307 * @description Overridden fireEvent method to prevent DOM events from firing if the button is disabled.
|
|
308 */
|
|
309 fireEvent: function(p_sType, p_aArgs) {
|
|
310 // Disabled buttons should not respond to DOM events
|
|
311 if (this.DOM_EVENTS[p_sType] && this.get('disabled')) {
|
|
312 Event.stopEvent(p_aArgs);
|
|
313 return;
|
|
314 }
|
|
315
|
|
316 YAHOO.widget.ToolbarButton.superclass.fireEvent.call(this, p_sType, p_aArgs);
|
|
317 },
|
|
318 /**
|
|
319 * @method toString
|
|
320 * @description Returns a string representing the toolbar.
|
|
321 * @return {String}
|
|
322 */
|
|
323 toString: function() {
|
|
324 return 'ToolbarButton (' + this.get('id') + ')';
|
|
325 }
|
|
326
|
|
327 });
|
|
328 })();
|
|
329 /**
|
|
330 * @module editor
|
|
331 * @description <p>Creates a rich Toolbar widget based on Button. Primarily used with the Rich Text Editor</p>
|
|
332 * @namespace YAHOO.widget
|
|
333 * @requires yahoo, dom, element, event, toolbarbutton
|
|
334 * @optional container_core, dragdrop
|
|
335 */
|
|
336 (function() {
|
|
337 var Dom = YAHOO.util.Dom,
|
|
338 Event = YAHOO.util.Event,
|
|
339 Lang = YAHOO.lang;
|
|
340
|
|
341 var getButton = function(id) {
|
|
342 var button = id;
|
|
343 if (Lang.isString(id)) {
|
|
344 button = this.getButtonById(id);
|
|
345 }
|
|
346 if (Lang.isNumber(id)) {
|
|
347 button = this.getButtonByIndex(id);
|
|
348 }
|
|
349 if ((!(button instanceof YAHOO.widget.ToolbarButton)) && (!(button instanceof YAHOO.widget.ToolbarButtonAdvanced))) {
|
|
350 button = this.getButtonByValue(id);
|
|
351 }
|
|
352 if ((button instanceof YAHOO.widget.ToolbarButton) || (button instanceof YAHOO.widget.ToolbarButtonAdvanced)) {
|
|
353 return button;
|
|
354 }
|
|
355 return false;
|
|
356 };
|
|
357
|
|
358 /**
|
|
359 * Provides a rich toolbar widget based on the button and menu widgets
|
|
360 * @constructor
|
|
361 * @class Toolbar
|
|
362 * @extends YAHOO.util.Element
|
|
363 * @param {String/HTMLElement} el The element to turn into a toolbar.
|
|
364 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
365 */
|
|
366 YAHOO.widget.Toolbar = function(el, attrs) {
|
|
367
|
|
368 if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
|
|
369 attrs = el;
|
|
370 }
|
|
371 var local_attrs = {};
|
|
372 if (attrs) {
|
|
373 Lang.augmentObject(local_attrs, attrs); //Break the config reference
|
|
374 }
|
|
375
|
|
376
|
|
377 var oConfig = {
|
|
378 element: null,
|
|
379 attributes: local_attrs
|
|
380 };
|
|
381
|
|
382
|
|
383 if (Lang.isString(el) && Dom.get(el)) {
|
|
384 oConfig.element = Dom.get(el);
|
|
385 } else if (Lang.isObject(el) && Dom.get(el) && Dom.get(el).nodeType) {
|
|
386 oConfig.element = Dom.get(el);
|
|
387 }
|
|
388
|
|
389
|
|
390 if (!oConfig.element) {
|
|
391 oConfig.element = document.createElement('DIV');
|
|
392 oConfig.element.id = Dom.generateId();
|
|
393
|
|
394 if (local_attrs.container && Dom.get(local_attrs.container)) {
|
|
395 Dom.get(local_attrs.container).appendChild(oConfig.element);
|
|
396 }
|
|
397 }
|
|
398
|
|
399
|
|
400 if (!oConfig.element.id) {
|
|
401 oConfig.element.id = ((Lang.isString(el)) ? el : Dom.generateId());
|
|
402 }
|
|
403
|
|
404 var fs = document.createElement('fieldset');
|
|
405 var lg = document.createElement('legend');
|
|
406 lg.innerHTML = 'Toolbar';
|
|
407 fs.appendChild(lg);
|
|
408
|
|
409 var cont = document.createElement('DIV');
|
|
410 oConfig.attributes.cont = cont;
|
|
411 Dom.addClass(cont, 'yui-toolbar-subcont');
|
|
412 fs.appendChild(cont);
|
|
413 oConfig.element.appendChild(fs);
|
|
414
|
|
415 oConfig.element.tabIndex = -1;
|
|
416
|
|
417
|
|
418 oConfig.attributes.element = oConfig.element;
|
|
419 oConfig.attributes.id = oConfig.element.id;
|
|
420
|
|
421 this._configuredButtons = [];
|
|
422
|
|
423 YAHOO.widget.Toolbar.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
|
|
424
|
|
425 };
|
|
426
|
|
427 YAHOO.extend(YAHOO.widget.Toolbar, YAHOO.util.Element, {
|
|
428 /**
|
|
429 * @protected
|
|
430 * @property _configuredButtons
|
|
431 * @type Array
|
|
432 */
|
|
433 _configuredButtons: null,
|
|
434 /**
|
|
435 * @method _addMenuClasses
|
|
436 * @private
|
|
437 * @description This method is called from Menu's renderEvent to add a few more classes to the menu items
|
|
438 * @param {String} ev The event that fired.
|
|
439 * @param {Array} na Array of event information.
|
|
440 * @param {Object} o Button config object.
|
|
441 */
|
|
442 _addMenuClasses: function(ev, na, o) {
|
|
443 Dom.addClass(this.element, 'yui-toolbar-' + o.get('value') + '-menu');
|
|
444 if (Dom.hasClass(o._button.parentNode.parentNode, 'yui-toolbar-select')) {
|
|
445 Dom.addClass(this.element, 'yui-toolbar-select-menu');
|
|
446 }
|
|
447 var items = this.getItems();
|
|
448 for (var i = 0; i < items.length; i++) {
|
|
449 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()));
|
|
450 Dom.addClass(items[i].element, 'yui-toolbar-' + o.get('value') + '-' + ((items[i].value) ? items[i].value.replace(/ /g, '-') : items[i]._oText.nodeValue.replace(/ /g, '-')));
|
|
451 }
|
|
452 },
|
|
453 /**
|
|
454 * @property buttonType
|
|
455 * @description The default button to use
|
|
456 * @type Object
|
|
457 */
|
|
458 buttonType: YAHOO.widget.ToolbarButton,
|
|
459 /**
|
|
460 * @property dd
|
|
461 * @description The DragDrop instance associated with the Toolbar
|
|
462 * @type Object
|
|
463 */
|
|
464 dd: null,
|
|
465 /**
|
|
466 * @property _colorData
|
|
467 * @description Object reference containing colors hex and text values.
|
|
468 * @type Object
|
|
469 */
|
|
470 _colorData: {
|
|
471 /* {{{ _colorData */
|
|
472 '#111111': 'Obsidian',
|
|
473 '#2D2D2D': 'Dark Gray',
|
|
474 '#434343': 'Shale',
|
|
475 '#5B5B5B': 'Flint',
|
|
476 '#737373': 'Gray',
|
|
477 '#8B8B8B': 'Concrete',
|
|
478 '#A2A2A2': 'Gray',
|
|
479 '#B9B9B9': 'Titanium',
|
|
480 '#000000': 'Black',
|
|
481 '#D0D0D0': 'Light Gray',
|
|
482 '#E6E6E6': 'Silver',
|
|
483 '#FFFFFF': 'White',
|
|
484 '#BFBF00': 'Pumpkin',
|
|
485 '#FFFF00': 'Yellow',
|
|
486 '#FFFF40': 'Banana',
|
|
487 '#FFFF80': 'Pale Yellow',
|
|
488 '#FFFFBF': 'Butter',
|
|
489 '#525330': 'Raw Siena',
|
|
490 '#898A49': 'Mildew',
|
|
491 '#AEA945': 'Olive',
|
|
492 '#7F7F00': 'Paprika',
|
|
493 '#C3BE71': 'Earth',
|
|
494 '#E0DCAA': 'Khaki',
|
|
495 '#FCFAE1': 'Cream',
|
|
496 '#60BF00': 'Cactus',
|
|
497 '#80FF00': 'Chartreuse',
|
|
498 '#A0FF40': 'Green',
|
|
499 '#C0FF80': 'Pale Lime',
|
|
500 '#DFFFBF': 'Light Mint',
|
|
501 '#3B5738': 'Green',
|
|
502 '#668F5A': 'Lime Gray',
|
|
503 '#7F9757': 'Yellow',
|
|
504 '#407F00': 'Clover',
|
|
505 '#8A9B55': 'Pistachio',
|
|
506 '#B7C296': 'Light Jade',
|
|
507 '#E6EBD5': 'Breakwater',
|
|
508 '#00BF00': 'Spring Frost',
|
|
509 '#00FF80': 'Pastel Green',
|
|
510 '#40FFA0': 'Light Emerald',
|
|
511 '#80FFC0': 'Sea Foam',
|
|
512 '#BFFFDF': 'Sea Mist',
|
|
513 '#033D21': 'Dark Forrest',
|
|
514 '#438059': 'Moss',
|
|
515 '#7FA37C': 'Medium Green',
|
|
516 '#007F40': 'Pine',
|
|
517 '#8DAE94': 'Yellow Gray Green',
|
|
518 '#ACC6B5': 'Aqua Lung',
|
|
519 '#DDEBE2': 'Sea Vapor',
|
|
520 '#00BFBF': 'Fog',
|
|
521 '#00FFFF': 'Cyan',
|
|
522 '#40FFFF': 'Turquoise Blue',
|
|
523 '#80FFFF': 'Light Aqua',
|
|
524 '#BFFFFF': 'Pale Cyan',
|
|
525 '#033D3D': 'Dark Teal',
|
|
526 '#347D7E': 'Gray Turquoise',
|
|
527 '#609A9F': 'Green Blue',
|
|
528 '#007F7F': 'Seaweed',
|
|
529 '#96BDC4': 'Green Gray',
|
|
530 '#B5D1D7': 'Soapstone',
|
|
531 '#E2F1F4': 'Light Turquoise',
|
|
532 '#0060BF': 'Summer Sky',
|
|
533 '#0080FF': 'Sky Blue',
|
|
534 '#40A0FF': 'Electric Blue',
|
|
535 '#80C0FF': 'Light Azure',
|
|
536 '#BFDFFF': 'Ice Blue',
|
|
537 '#1B2C48': 'Navy',
|
|
538 '#385376': 'Biscay',
|
|
539 '#57708F': 'Dusty Blue',
|
|
540 '#00407F': 'Sea Blue',
|
|
541 '#7792AC': 'Sky Blue Gray',
|
|
542 '#A8BED1': 'Morning Sky',
|
|
543 '#DEEBF6': 'Vapor',
|
|
544 '#0000BF': 'Deep Blue',
|
|
545 '#0000FF': 'Blue',
|
|
546 '#4040FF': 'Cerulean Blue',
|
|
547 '#8080FF': 'Evening Blue',
|
|
548 '#BFBFFF': 'Light Blue',
|
|
549 '#212143': 'Deep Indigo',
|
|
550 '#373E68': 'Sea Blue',
|
|
551 '#444F75': 'Night Blue',
|
|
552 '#00007F': 'Indigo Blue',
|
|
553 '#585E82': 'Dockside',
|
|
554 '#8687A4': 'Blue Gray',
|
|
555 '#D2D1E1': 'Light Blue Gray',
|
|
556 '#6000BF': 'Neon Violet',
|
|
557 '#8000FF': 'Blue Violet',
|
|
558 '#A040FF': 'Violet Purple',
|
|
559 '#C080FF': 'Violet Dusk',
|
|
560 '#DFBFFF': 'Pale Lavender',
|
|
561 '#302449': 'Cool Shale',
|
|
562 '#54466F': 'Dark Indigo',
|
|
563 '#655A7F': 'Dark Violet',
|
|
564 '#40007F': 'Violet',
|
|
565 '#726284': 'Smoky Violet',
|
|
566 '#9E8FA9': 'Slate Gray',
|
|
567 '#DCD1DF': 'Violet White',
|
|
568 '#BF00BF': 'Royal Violet',
|
|
569 '#FF00FF': 'Fuchsia',
|
|
570 '#FF40FF': 'Magenta',
|
|
571 '#FF80FF': 'Orchid',
|
|
572 '#FFBFFF': 'Pale Magenta',
|
|
573 '#4A234A': 'Dark Purple',
|
|
574 '#794A72': 'Medium Purple',
|
|
575 '#936386': 'Cool Granite',
|
|
576 '#7F007F': 'Purple',
|
|
577 '#9D7292': 'Purple Moon',
|
|
578 '#C0A0B6': 'Pale Purple',
|
|
579 '#ECDAE5': 'Pink Cloud',
|
|
580 '#BF005F': 'Hot Pink',
|
|
581 '#FF007F': 'Deep Pink',
|
|
582 '#FF409F': 'Grape',
|
|
583 '#FF80BF': 'Electric Pink',
|
|
584 '#FFBFDF': 'Pink',
|
|
585 '#451528': 'Purple Red',
|
|
586 '#823857': 'Purple Dino',
|
|
587 '#A94A76': 'Purple Gray',
|
|
588 '#7F003F': 'Rose',
|
|
589 '#BC6F95': 'Antique Mauve',
|
|
590 '#D8A5BB': 'Cool Marble',
|
|
591 '#F7DDE9': 'Pink Granite',
|
|
592 '#C00000': 'Apple',
|
|
593 '#FF0000': 'Fire Truck',
|
|
594 '#FF4040': 'Pale Red',
|
|
595 '#FF8080': 'Salmon',
|
|
596 '#FFC0C0': 'Warm Pink',
|
|
597 '#441415': 'Sepia',
|
|
598 '#82393C': 'Rust',
|
|
599 '#AA4D4E': 'Brick',
|
|
600 '#800000': 'Brick Red',
|
|
601 '#BC6E6E': 'Mauve',
|
|
602 '#D8A3A4': 'Shrimp Pink',
|
|
603 '#F8DDDD': 'Shell Pink',
|
|
604 '#BF5F00': 'Dark Orange',
|
|
605 '#FF7F00': 'Orange',
|
|
606 '#FF9F40': 'Grapefruit',
|
|
607 '#FFBF80': 'Canteloupe',
|
|
608 '#FFDFBF': 'Wax',
|
|
609 '#482C1B': 'Dark Brick',
|
|
610 '#855A40': 'Dirt',
|
|
611 '#B27C51': 'Tan',
|
|
612 '#7F3F00': 'Nutmeg',
|
|
613 '#C49B71': 'Mustard',
|
|
614 '#E1C4A8': 'Pale Tan',
|
|
615 '#FDEEE0': 'Marble'
|
|
616 /* }}} */
|
|
617 },
|
|
618 /**
|
|
619 * @property _colorPicker
|
|
620 * @description The HTML Element containing the colorPicker
|
|
621 * @type HTMLElement
|
|
622 */
|
|
623 _colorPicker: null,
|
|
624 /**
|
|
625 * @property STR_COLLAPSE
|
|
626 * @description String for Toolbar Collapse Button
|
|
627 * @type String
|
|
628 */
|
|
629 STR_COLLAPSE: 'Collapse Toolbar',
|
|
630 /**
|
|
631 * @property STR_EXPAND
|
|
632 * @description String for Toolbar Collapse Button - Expand
|
|
633 * @type String
|
|
634 */
|
|
635 STR_EXPAND: 'Expand Toolbar',
|
|
636 /**
|
|
637 * @property STR_SPIN_LABEL
|
|
638 * @description String for spinbutton dynamic label. Note the {VALUE} will be replaced with YAHOO.lang.substitute
|
|
639 * @type String
|
|
640 */
|
|
641 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.',
|
|
642 /**
|
|
643 * @property STR_SPIN_UP
|
|
644 * @description String for spinbutton up
|
|
645 * @type String
|
|
646 */
|
|
647 STR_SPIN_UP: 'Click to increase the value of this input',
|
|
648 /**
|
|
649 * @property STR_SPIN_DOWN
|
|
650 * @description String for spinbutton down
|
|
651 * @type String
|
|
652 */
|
|
653 STR_SPIN_DOWN: 'Click to decrease the value of this input',
|
|
654 /**
|
|
655 * @property _titlebar
|
|
656 * @description Object reference to the titlebar
|
|
657 * @type HTMLElement
|
|
658 */
|
|
659 _titlebar: null,
|
|
660 /**
|
|
661 * @property browser
|
|
662 * @description Standard browser detection
|
|
663 * @type Object
|
|
664 */
|
|
665 browser: YAHOO.env.ua,
|
|
666 /**
|
|
667 * @protected
|
|
668 * @property _buttonList
|
|
669 * @description Internal property list of current buttons in the toolbar
|
|
670 * @type Array
|
|
671 */
|
|
672 _buttonList: null,
|
|
673 /**
|
|
674 * @protected
|
|
675 * @property _buttonGroupList
|
|
676 * @description Internal property list of current button groups in the toolbar
|
|
677 * @type Array
|
|
678 */
|
|
679 _buttonGroupList: null,
|
|
680 /**
|
|
681 * @protected
|
|
682 * @property _sep
|
|
683 * @description Internal reference to the separator HTML Element for cloning
|
|
684 * @type HTMLElement
|
|
685 */
|
|
686 _sep: null,
|
|
687 /**
|
|
688 * @protected
|
|
689 * @property _sepCount
|
|
690 * @description Internal refernce for counting separators, so we can give them a useful class name for styling
|
|
691 * @type Number
|
|
692 */
|
|
693 _sepCount: null,
|
|
694 /**
|
|
695 * @protected
|
|
696 * @property draghandle
|
|
697 * @type HTMLElement
|
|
698 */
|
|
699 _dragHandle: null,
|
|
700 /**
|
|
701 * @protected
|
|
702 * @property _toolbarConfigs
|
|
703 * @type Object
|
|
704 */
|
|
705 _toolbarConfigs: {
|
|
706 renderer: true
|
|
707 },
|
|
708 /**
|
|
709 * @protected
|
|
710 * @property CLASS_CONTAINER
|
|
711 * @description Default CSS class to apply to the toolbar container element
|
|
712 * @type String
|
|
713 */
|
|
714 CLASS_CONTAINER: 'yui-toolbar-container',
|
|
715 /**
|
|
716 * @protected
|
|
717 * @property CLASS_DRAGHANDLE
|
|
718 * @description Default CSS class to apply to the toolbar's drag handle element
|
|
719 * @type String
|
|
720 */
|
|
721 CLASS_DRAGHANDLE: 'yui-toolbar-draghandle',
|
|
722 /**
|
|
723 * @protected
|
|
724 * @property CLASS_SEPARATOR
|
|
725 * @description Default CSS class to apply to all separators in the toolbar
|
|
726 * @type String
|
|
727 */
|
|
728 CLASS_SEPARATOR: 'yui-toolbar-separator',
|
|
729 /**
|
|
730 * @protected
|
|
731 * @property CLASS_DISABLED
|
|
732 * @description Default CSS class to apply when the toolbar is disabled
|
|
733 * @type String
|
|
734 */
|
|
735 CLASS_DISABLED: 'yui-toolbar-disabled',
|
|
736 /**
|
|
737 * @protected
|
|
738 * @property CLASS_PREFIX
|
|
739 * @description Default prefix for dynamically created class names
|
|
740 * @type String
|
|
741 */
|
|
742 CLASS_PREFIX: 'yui-toolbar',
|
|
743 /**
|
|
744 * @method init
|
|
745 * @description The Toolbar class's initialization method
|
|
746 */
|
|
747 init: function(p_oElement, p_oAttributes) {
|
|
748 YAHOO.widget.Toolbar.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
749 },
|
|
750 /**
|
|
751 * @method initAttributes
|
|
752 * @description Initializes all of the configuration attributes used to create
|
|
753 * the toolbar.
|
|
754 * @param {Object} attr Object literal specifying a set of
|
|
755 * configuration attributes used to create the toolbar.
|
|
756 */
|
|
757 initAttributes: function(attr) {
|
|
758 YAHOO.widget.Toolbar.superclass.initAttributes.call(this, attr);
|
|
759 this.addClass(this.CLASS_CONTAINER);
|
|
760
|
|
761 /**
|
|
762 * @attribute buttonType
|
|
763 * @description The buttonType to use (advanced or basic)
|
|
764 * @type String
|
|
765 */
|
|
766 this.setAttributeConfig('buttonType', {
|
|
767 value: attr.buttonType || 'basic',
|
|
768 writeOnce: true,
|
|
769 validator: function(type) {
|
|
770 switch (type) {
|
|
771 case 'advanced':
|
|
772 case 'basic':
|
|
773 return true;
|
|
774 }
|
|
775 return false;
|
|
776 },
|
|
777 method: function(type) {
|
|
778 if (type == 'advanced') {
|
|
779 if (YAHOO.widget.Button) {
|
|
780 this.buttonType = YAHOO.widget.ToolbarButtonAdvanced;
|
|
781 } else {
|
|
782 this.buttonType = YAHOO.widget.ToolbarButton;
|
|
783 }
|
|
784 } else {
|
|
785 this.buttonType = YAHOO.widget.ToolbarButton;
|
|
786 }
|
|
787 }
|
|
788 });
|
|
789
|
|
790
|
|
791 /**
|
|
792 * @attribute buttons
|
|
793 * @description Object specifying the buttons to include in the toolbar
|
|
794 * Example:
|
|
795 * <code><pre>
|
|
796 * {
|
|
797 * { id: 'b3', type: 'button', label: 'Underline', value: 'underline' },
|
|
798 * { type: 'separator' },
|
|
799 * { id: 'b4', type: 'menu', label: 'Align', value: 'align',
|
|
800 * menu: [
|
|
801 * { text: "Left", value: 'alignleft' },
|
|
802 * { text: "Center", value: 'aligncenter' },
|
|
803 * { text: "Right", value: 'alignright' }
|
|
804 * ]
|
|
805 * }
|
|
806 * }
|
|
807 * </pre></code>
|
|
808 * @type Array
|
|
809 */
|
|
810
|
|
811 this.setAttributeConfig('buttons', {
|
|
812 value: [],
|
|
813 writeOnce: true,
|
|
814 method: function(data) {
|
|
815 var i, button, buttons, len, b;
|
|
816 for (i in data) {
|
|
817 if (Lang.hasOwnProperty(data, i)) {
|
|
818 if (data[i].type == 'separator') {
|
|
819 this.addSeparator();
|
|
820 } else if (data[i].group !== undefined) {
|
|
821 buttons = this.addButtonGroup(data[i]);
|
|
822 if (buttons) {
|
|
823 len = buttons.length;
|
|
824 for(b = 0; b < len; b++) {
|
|
825 if (buttons[b]) {
|
|
826 this._configuredButtons[this._configuredButtons.length] = buttons[b].id;
|
|
827 }
|
|
828 }
|
|
829 }
|
|
830
|
|
831 } else {
|
|
832 button = this.addButton(data[i]);
|
|
833 if (button) {
|
|
834 this._configuredButtons[this._configuredButtons.length] = button.id;
|
|
835 }
|
|
836 }
|
|
837 }
|
|
838 }
|
|
839 }
|
|
840 });
|
|
841
|
|
842 /**
|
|
843 * @attribute disabled
|
|
844 * @description Boolean indicating if the toolbar should be disabled. It will also disable the draggable attribute if it is on.
|
|
845 * @default false
|
|
846 * @type Boolean
|
|
847 */
|
|
848 this.setAttributeConfig('disabled', {
|
|
849 value: false,
|
|
850 method: function(disabled) {
|
|
851 if (this.get('disabled') === disabled) {
|
|
852 return false;
|
|
853 }
|
|
854 if (disabled) {
|
|
855 this.addClass(this.CLASS_DISABLED);
|
|
856 this.set('draggable', false);
|
|
857 this.disableAllButtons();
|
|
858 } else {
|
|
859 this.removeClass(this.CLASS_DISABLED);
|
|
860 if (this._configs.draggable._initialConfig.value) {
|
|
861 //Draggable by default, set it back
|
|
862 this.set('draggable', true);
|
|
863 }
|
|
864 this.resetAllButtons();
|
|
865 }
|
|
866 }
|
|
867 });
|
|
868
|
|
869 /**
|
|
870 * @config cont
|
|
871 * @description The container for the toolbar.
|
|
872 * @type HTMLElement
|
|
873 */
|
|
874 this.setAttributeConfig('cont', {
|
|
875 value: attr.cont,
|
|
876 readOnly: true
|
|
877 });
|
|
878
|
|
879
|
|
880 /**
|
|
881 * @attribute grouplabels
|
|
882 * @description Boolean indicating if the toolbar should show the group label's text string.
|
|
883 * @default true
|
|
884 * @type Boolean
|
|
885 */
|
|
886 this.setAttributeConfig('grouplabels', {
|
|
887 value: ((attr.grouplabels === false) ? false : true),
|
|
888 method: function(grouplabels) {
|
|
889 if (grouplabels) {
|
|
890 Dom.removeClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
|
|
891 } else {
|
|
892 Dom.addClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
|
|
893 }
|
|
894 }
|
|
895 });
|
|
896 /**
|
|
897 * @attribute titlebar
|
|
898 * @description Boolean indicating if the toolbar should have a titlebar. If
|
|
899 * passed a string, it will use that as the titlebar text
|
|
900 * @default false
|
|
901 * @type Boolean or String
|
|
902 */
|
|
903 this.setAttributeConfig('titlebar', {
|
|
904 value: false,
|
|
905 method: function(titlebar) {
|
|
906 if (titlebar) {
|
|
907 if (this._titlebar && this._titlebar.parentNode) {
|
|
908 this._titlebar.parentNode.removeChild(this._titlebar);
|
|
909 }
|
|
910 this._titlebar = document.createElement('DIV');
|
|
911 this._titlebar.tabIndex = '-1';
|
|
912 Event.on(this._titlebar, 'focus', function() {
|
|
913 this._handleFocus();
|
|
914 }, this, true);
|
|
915 Dom.addClass(this._titlebar, this.CLASS_PREFIX + '-titlebar');
|
|
916 if (Lang.isString(titlebar)) {
|
|
917 var h2 = document.createElement('h2');
|
|
918 h2.tabIndex = '-1';
|
|
919 h2.innerHTML = '<a href="#" tabIndex="0">' + titlebar + '</a>';
|
|
920 this._titlebar.appendChild(h2);
|
|
921 Event.on(h2.firstChild, 'click', function(ev) {
|
|
922 Event.stopEvent(ev);
|
|
923 });
|
|
924 Event.on([h2, h2.firstChild], 'focus', function() {
|
|
925 this._handleFocus();
|
|
926 }, this, true);
|
|
927 }
|
|
928 if (this.get('firstChild')) {
|
|
929 this.insertBefore(this._titlebar, this.get('firstChild'));
|
|
930 } else {
|
|
931 this.appendChild(this._titlebar);
|
|
932 }
|
|
933 if (this.get('collapse')) {
|
|
934 this.set('collapse', true);
|
|
935 }
|
|
936 } else if (this._titlebar) {
|
|
937 if (this._titlebar && this._titlebar.parentNode) {
|
|
938 this._titlebar.parentNode.removeChild(this._titlebar);
|
|
939 }
|
|
940 }
|
|
941 }
|
|
942 });
|
|
943
|
|
944
|
|
945 /**
|
|
946 * @attribute collapse
|
|
947 * @description Boolean indicating if the the titlebar should have a collapse button.
|
|
948 * The collapse button will not remove the toolbar, it will minimize it to the titlebar
|
|
949 * @default false
|
|
950 * @type Boolean
|
|
951 */
|
|
952 this.setAttributeConfig('collapse', {
|
|
953 value: false,
|
|
954 method: function(collapse) {
|
|
955 if (this._titlebar) {
|
|
956 var collapseEl = null;
|
|
957 var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
|
|
958 if (collapse) {
|
|
959 if (el.length > 0) {
|
|
960 //There is already a collapse button
|
|
961 return true;
|
|
962 }
|
|
963 collapseEl = document.createElement('SPAN');
|
|
964 collapseEl.innerHTML = 'X';
|
|
965 collapseEl.title = this.STR_COLLAPSE;
|
|
966
|
|
967 Dom.addClass(collapseEl, 'collapse');
|
|
968 this._titlebar.appendChild(collapseEl);
|
|
969 Event.addListener(collapseEl, 'click', function() {
|
|
970 if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
|
|
971 this.collapse(false); //Expand Toolbar
|
|
972 } else {
|
|
973 this.collapse(); //Collapse Toolbar
|
|
974 }
|
|
975 }, this, true);
|
|
976 } else {
|
|
977 collapseEl = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
|
|
978 if (collapseEl[0]) {
|
|
979 if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
|
|
980 //We are closed, reopen the titlebar..
|
|
981 this.collapse(false); //Expand Toolbar
|
|
982 }
|
|
983 collapseEl[0].parentNode.removeChild(collapseEl[0]);
|
|
984 }
|
|
985 }
|
|
986 }
|
|
987 }
|
|
988 });
|
|
989
|
|
990 /**
|
|
991 * @attribute draggable
|
|
992 * @description Boolean indicating if the toolbar should be draggable.
|
|
993 * @default false
|
|
994 * @type Boolean
|
|
995 */
|
|
996
|
|
997 this.setAttributeConfig('draggable', {
|
|
998 value: (attr.draggable || false),
|
|
999 method: function(draggable) {
|
|
1000 if (draggable && !this.get('titlebar')) {
|
|
1001 if (!this._dragHandle) {
|
|
1002 this._dragHandle = document.createElement('SPAN');
|
|
1003 this._dragHandle.innerHTML = '|';
|
|
1004 this._dragHandle.setAttribute('title', 'Click to drag the toolbar');
|
|
1005 this._dragHandle.id = this.get('id') + '_draghandle';
|
|
1006 Dom.addClass(this._dragHandle, this.CLASS_DRAGHANDLE);
|
|
1007 if (this.get('cont').hasChildNodes()) {
|
|
1008 this.get('cont').insertBefore(this._dragHandle, this.get('cont').firstChild);
|
|
1009 } else {
|
|
1010 this.get('cont').appendChild(this._dragHandle);
|
|
1011 }
|
|
1012 this.dd = new YAHOO.util.DD(this.get('id'));
|
|
1013 this.dd.setHandleElId(this._dragHandle.id);
|
|
1014
|
|
1015 }
|
|
1016 } else {
|
|
1017 if (this._dragHandle) {
|
|
1018 this._dragHandle.parentNode.removeChild(this._dragHandle);
|
|
1019 this._dragHandle = null;
|
|
1020 this.dd = null;
|
|
1021 }
|
|
1022 }
|
|
1023 if (this._titlebar) {
|
|
1024 if (draggable) {
|
|
1025 this.dd = new YAHOO.util.DD(this.get('id'));
|
|
1026 this.dd.setHandleElId(this._titlebar);
|
|
1027 Dom.addClass(this._titlebar, 'draggable');
|
|
1028 } else {
|
|
1029 Dom.removeClass(this._titlebar, 'draggable');
|
|
1030 if (this.dd) {
|
|
1031 this.dd.unreg();
|
|
1032 this.dd = null;
|
|
1033 }
|
|
1034 }
|
|
1035 }
|
|
1036 },
|
|
1037 validator: function(value) {
|
|
1038 var ret = true;
|
|
1039 if (!YAHOO.util.DD) {
|
|
1040 ret = false;
|
|
1041 }
|
|
1042 return ret;
|
|
1043 }
|
|
1044 });
|
|
1045
|
|
1046 },
|
|
1047 /**
|
|
1048 * @method addButtonGroup
|
|
1049 * @description Add a new button group to the toolbar. (uses addButton)
|
|
1050 * @param {Object} oGroup Object literal reference to the Groups Config (contains an array of button configs as well as the group label)
|
|
1051 */
|
|
1052 addButtonGroup: function(oGroup) {
|
|
1053 if (!this.get('element')) {
|
|
1054 this._queue[this._queue.length] = ['addButtonGroup', arguments];
|
|
1055 return false;
|
|
1056 }
|
|
1057
|
|
1058 if (!this.hasClass(this.CLASS_PREFIX + '-grouped')) {
|
|
1059 this.addClass(this.CLASS_PREFIX + '-grouped');
|
|
1060 }
|
|
1061 var div = document.createElement('DIV');
|
|
1062 Dom.addClass(div, this.CLASS_PREFIX + '-group');
|
|
1063 Dom.addClass(div, this.CLASS_PREFIX + '-group-' + oGroup.group);
|
|
1064 if (oGroup.label) {
|
|
1065 var label = document.createElement('h3');
|
|
1066 label.innerHTML = oGroup.label;
|
|
1067 div.appendChild(label);
|
|
1068 }
|
|
1069 if (!this.get('grouplabels')) {
|
|
1070 Dom.addClass(this.get('cont'), this.CLASS_PREFIX, '-nogrouplabels');
|
|
1071 }
|
|
1072
|
|
1073 this.get('cont').appendChild(div);
|
|
1074
|
|
1075 //For accessibility, let's put all of the group buttons in an Unordered List
|
|
1076 var ul = document.createElement('ul');
|
|
1077 div.appendChild(ul);
|
|
1078
|
|
1079 if (!this._buttonGroupList) {
|
|
1080 this._buttonGroupList = {};
|
|
1081 }
|
|
1082
|
|
1083 this._buttonGroupList[oGroup.group] = ul;
|
|
1084
|
|
1085 //An array of the button ids added to this group
|
|
1086 //This is used for destruction later...
|
|
1087 var addedButtons = [],
|
|
1088 button;
|
|
1089
|
|
1090
|
|
1091 for (var i = 0; i < oGroup.buttons.length; i++) {
|
|
1092 var li = document.createElement('li');
|
|
1093 li.className = this.CLASS_PREFIX + '-groupitem';
|
|
1094 ul.appendChild(li);
|
|
1095 if ((oGroup.buttons[i].type !== undefined) && oGroup.buttons[i].type == 'separator') {
|
|
1096 this.addSeparator(li);
|
|
1097 } else {
|
|
1098 oGroup.buttons[i].container = li;
|
|
1099 button = this.addButton(oGroup.buttons[i]);
|
|
1100 if (button) {
|
|
1101 addedButtons[addedButtons.length] = button.id;
|
|
1102 }
|
|
1103 }
|
|
1104 }
|
|
1105 return addedButtons;
|
|
1106 },
|
|
1107 /**
|
|
1108 * @method addButtonToGroup
|
|
1109 * @description Add a new button to a toolbar group. Buttons supported:
|
|
1110 * push, split, menu, select, color, spin
|
|
1111 * @param {Object} oButton Object literal reference to the Button's Config
|
|
1112 * @param {String} group The Group identifier passed into the initial config
|
|
1113 * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
|
|
1114 */
|
|
1115 addButtonToGroup: function(oButton, group, after) {
|
|
1116 var groupCont = this._buttonGroupList[group],
|
|
1117 li = document.createElement('li');
|
|
1118
|
|
1119 li.className = this.CLASS_PREFIX + '-groupitem';
|
|
1120 oButton.container = li;
|
|
1121 this.addButton(oButton, after);
|
|
1122 groupCont.appendChild(li);
|
|
1123 },
|
|
1124 /**
|
|
1125 * @method addButton
|
|
1126 * @description Add a new button to the toolbar. Buttons supported:
|
|
1127 * push, split, menu, select, color, spin
|
|
1128 * @param {Object} oButton Object literal reference to the Button's Config
|
|
1129 * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
|
|
1130 */
|
|
1131 addButton: function(oButton, after) {
|
|
1132 if (!this.get('element')) {
|
|
1133 this._queue[this._queue.length] = ['addButton', arguments];
|
|
1134 return false;
|
|
1135 }
|
|
1136 if (!this._buttonList) {
|
|
1137 this._buttonList = [];
|
|
1138 }
|
|
1139 if (!oButton.container) {
|
|
1140 oButton.container = this.get('cont');
|
|
1141 }
|
|
1142
|
|
1143 if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
|
|
1144 if (Lang.isArray(oButton.menu)) {
|
|
1145 for (var i in oButton.menu) {
|
|
1146 if (Lang.hasOwnProperty(oButton.menu, i)) {
|
|
1147 var funcObject = {
|
|
1148 fn: function(ev, x, oMenu) {
|
|
1149 if (!oButton.menucmd) {
|
|
1150 oButton.menucmd = oButton.value;
|
|
1151 }
|
|
1152 oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
|
|
1153 },
|
|
1154 scope: this
|
|
1155 };
|
|
1156 oButton.menu[i].onclick = funcObject;
|
|
1157 }
|
|
1158 }
|
|
1159 }
|
|
1160 }
|
|
1161 var _oButton = {}, skip = false;
|
|
1162 for (var o in oButton) {
|
|
1163 if (Lang.hasOwnProperty(oButton, o)) {
|
|
1164 if (!this._toolbarConfigs[o]) {
|
|
1165 _oButton[o] = oButton[o];
|
|
1166 }
|
|
1167 }
|
|
1168 }
|
|
1169 if (oButton.type == 'select') {
|
|
1170 _oButton.type = 'menu';
|
|
1171 }
|
|
1172 if (oButton.type == 'spin') {
|
|
1173 _oButton.type = 'push';
|
|
1174 }
|
|
1175 if (_oButton.type == 'color') {
|
|
1176 if (YAHOO.widget.Overlay) {
|
|
1177 _oButton = this._makeColorButton(_oButton);
|
|
1178 } else {
|
|
1179 skip = true;
|
|
1180 }
|
|
1181 }
|
|
1182 if (_oButton.menu) {
|
|
1183 if ((YAHOO.widget.Overlay) && (oButton.menu instanceof YAHOO.widget.Overlay)) {
|
|
1184 oButton.menu.showEvent.subscribe(function() {
|
|
1185 this._button = _oButton;
|
|
1186 });
|
|
1187 } else {
|
|
1188 for (var m = 0; m < _oButton.menu.length; m++) {
|
|
1189 if (!_oButton.menu[m].value) {
|
|
1190 _oButton.menu[m].value = _oButton.menu[m].text;
|
|
1191 }
|
|
1192 }
|
|
1193 if (this.browser.webkit) {
|
|
1194 _oButton.focusmenu = false;
|
|
1195 }
|
|
1196 }
|
|
1197 }
|
|
1198 if (skip) {
|
|
1199 oButton = false;
|
|
1200 } else {
|
|
1201 //Add to .get('buttons') manually
|
|
1202 this._configs.buttons.value[this._configs.buttons.value.length] = oButton;
|
|
1203
|
|
1204 var tmp = new this.buttonType(_oButton);
|
|
1205 tmp.get('element').tabIndex = '-1';
|
|
1206 tmp.get('element').setAttribute('role', 'button');
|
|
1207 tmp._selected = true;
|
|
1208
|
|
1209 if (this.get('disabled')) {
|
|
1210 //Toolbar is disabled, disable the new button too!
|
|
1211 tmp.set('disabled', true);
|
|
1212 }
|
|
1213 if (!oButton.id) {
|
|
1214 oButton.id = tmp.get('id');
|
|
1215 }
|
|
1216
|
|
1217 if (after) {
|
|
1218 var el = tmp.get('element');
|
|
1219 var nextSib = null;
|
|
1220 if (after.get) {
|
|
1221 nextSib = after.get('element').nextSibling;
|
|
1222 } else if (after.nextSibling) {
|
|
1223 nextSib = after.nextSibling;
|
|
1224 }
|
|
1225 if (nextSib) {
|
|
1226 nextSib.parentNode.insertBefore(el, nextSib);
|
|
1227 }
|
|
1228 }
|
|
1229 tmp.addClass(this.CLASS_PREFIX + '-' + tmp.get('value'));
|
|
1230
|
|
1231 var icon = document.createElement('span');
|
|
1232 icon.className = this.CLASS_PREFIX + '-icon';
|
|
1233 tmp.get('element').insertBefore(icon, tmp.get('firstChild'));
|
|
1234 if (tmp._button.tagName.toLowerCase() == 'button') {
|
|
1235 tmp.get('element').setAttribute('unselectable', 'on');
|
|
1236 //Replace the Button HTML Element with an a href if it exists
|
|
1237 var a = document.createElement('a');
|
|
1238 a.innerHTML = tmp._button.innerHTML;
|
|
1239 a.href = '#';
|
|
1240 a.tabIndex = '-1';
|
|
1241 Event.on(a, 'click', function(ev) {
|
|
1242 Event.stopEvent(ev);
|
|
1243 });
|
|
1244 tmp._button.parentNode.replaceChild(a, tmp._button);
|
|
1245 tmp._button = a;
|
|
1246 }
|
|
1247
|
|
1248 if (oButton.type == 'select') {
|
|
1249 if (tmp._button.tagName.toLowerCase() == 'select') {
|
|
1250 icon.parentNode.removeChild(icon);
|
|
1251 var iel = tmp._button,
|
|
1252 parEl = tmp.get('element');
|
|
1253 parEl.parentNode.replaceChild(iel, parEl);
|
|
1254 //The 'element' value is currently the orphaned element
|
|
1255 //In order for "destroy" to execute we need to get('element') to reference the correct node.
|
|
1256 //I'm not sure if there is a direct approach to setting this value.
|
|
1257 tmp._configs.element.value = iel;
|
|
1258 } else {
|
|
1259 //Don't put a class on it if it's a real select element
|
|
1260 tmp.addClass(this.CLASS_PREFIX + '-select');
|
|
1261 }
|
|
1262 }
|
|
1263 if (oButton.type == 'spin') {
|
|
1264 if (!Lang.isArray(oButton.range)) {
|
|
1265 oButton.range = [ 10, 100 ];
|
|
1266 }
|
|
1267 this._makeSpinButton(tmp, oButton);
|
|
1268 }
|
|
1269 tmp.get('element').setAttribute('title', tmp.get('label'));
|
|
1270 if (oButton.type != 'spin') {
|
|
1271 if ((YAHOO.widget.Overlay) && (_oButton.menu instanceof YAHOO.widget.Overlay)) {
|
|
1272 var showPicker = function(ev) {
|
|
1273 var exec = true;
|
|
1274 if (ev.keyCode && (ev.keyCode == 9)) {
|
|
1275 exec = false;
|
|
1276 }
|
|
1277 if (exec) {
|
|
1278 if (this._colorPicker) {
|
|
1279 this._colorPicker._button = oButton.value;
|
|
1280 }
|
|
1281 var menuEL = tmp.getMenu().element;
|
|
1282 if (Dom.getStyle(menuEL, 'visibility') == 'hidden') {
|
|
1283 tmp.getMenu().show();
|
|
1284 } else {
|
|
1285 tmp.getMenu().hide();
|
|
1286 }
|
|
1287 }
|
|
1288 YAHOO.util.Event.stopEvent(ev);
|
|
1289 };
|
|
1290 tmp.on('mousedown', showPicker, oButton, this);
|
|
1291 tmp.on('keydown', showPicker, oButton, this);
|
|
1292
|
|
1293 } else if ((oButton.type != 'menu') && (oButton.type != 'select')) {
|
|
1294 tmp.on('keypress', this._buttonClick, oButton, this);
|
|
1295 tmp.on('mousedown', function(ev) {
|
|
1296 YAHOO.util.Event.stopEvent(ev);
|
|
1297 this._buttonClick(ev, oButton);
|
|
1298 }, oButton, this);
|
|
1299 tmp.on('click', function(ev) {
|
|
1300 YAHOO.util.Event.stopEvent(ev);
|
|
1301 });
|
|
1302 } else {
|
|
1303 //Stop the mousedown event so we can trap the selection in the editor!
|
|
1304 tmp.on('mousedown', function(ev) {
|
|
1305 YAHOO.util.Event.stopEvent(ev);
|
|
1306 });
|
|
1307 tmp.on('click', function(ev) {
|
|
1308 YAHOO.util.Event.stopEvent(ev);
|
|
1309 });
|
|
1310 tmp.on('change', function(ev) {
|
|
1311 if (!ev.target) {
|
|
1312 if (!oButton.menucmd) {
|
|
1313 oButton.menucmd = oButton.value;
|
|
1314 }
|
|
1315 oButton.value = ev.value;
|
|
1316 this._buttonClick(ev, oButton);
|
|
1317 }
|
|
1318 }, this, true);
|
|
1319
|
|
1320 var self = this;
|
|
1321 //Hijack the mousedown event in the menu and make it fire a button click..
|
|
1322 tmp.on('appendTo', function() {
|
|
1323 var tmp = this;
|
|
1324 if (tmp.getMenu() && tmp.getMenu().mouseDownEvent) {
|
|
1325 tmp.getMenu().mouseDownEvent.subscribe(function(ev, args) {
|
|
1326 var oMenu = args[1];
|
|
1327 YAHOO.util.Event.stopEvent(args[0]);
|
|
1328 tmp._onMenuClick(args[0], tmp);
|
|
1329 if (!oButton.menucmd) {
|
|
1330 oButton.menucmd = oButton.value;
|
|
1331 }
|
|
1332 oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
|
|
1333 self._buttonClick.call(self, args[1], oButton);
|
|
1334 tmp._hideMenu();
|
|
1335 return false;
|
|
1336 });
|
|
1337 tmp.getMenu().clickEvent.subscribe(function(ev, args) {
|
|
1338 YAHOO.util.Event.stopEvent(args[0]);
|
|
1339 });
|
|
1340 tmp.getMenu().mouseUpEvent.subscribe(function(ev, args) {
|
|
1341 YAHOO.util.Event.stopEvent(args[0]);
|
|
1342 });
|
|
1343 }
|
|
1344 });
|
|
1345
|
|
1346 }
|
|
1347 } else {
|
|
1348 //Stop the mousedown event so we can trap the selection in the editor!
|
|
1349 tmp.on('mousedown', function(ev) {
|
|
1350 YAHOO.util.Event.stopEvent(ev);
|
|
1351 });
|
|
1352 tmp.on('click', function(ev) {
|
|
1353 YAHOO.util.Event.stopEvent(ev);
|
|
1354 });
|
|
1355 }
|
|
1356 if (this.browser.ie) {
|
|
1357 /*
|
|
1358 //Add a couple of new events for IE
|
|
1359 tmp.DOM_EVENTS.focusin = true;
|
|
1360 tmp.DOM_EVENTS.focusout = true;
|
|
1361
|
|
1362 //Stop them so we don't loose focus in the Editor
|
|
1363 tmp.on('focusin', function(ev) {
|
|
1364 YAHOO.util.Event.stopEvent(ev);
|
|
1365 }, oButton, this);
|
|
1366
|
|
1367 tmp.on('focusout', function(ev) {
|
|
1368 YAHOO.util.Event.stopEvent(ev);
|
|
1369 }, oButton, this);
|
|
1370 tmp.on('click', function(ev) {
|
|
1371 YAHOO.util.Event.stopEvent(ev);
|
|
1372 }, oButton, this);
|
|
1373 */
|
|
1374 }
|
|
1375 if (this.browser.webkit) {
|
|
1376 //This will keep the document from gaining focus and the editor from loosing it..
|
|
1377 //Forcefully remove the focus calls in button!
|
|
1378 tmp.hasFocus = function() {
|
|
1379 return true;
|
|
1380 };
|
|
1381 }
|
|
1382 this._buttonList[this._buttonList.length] = tmp;
|
|
1383 if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
|
|
1384 if (Lang.isArray(oButton.menu)) {
|
|
1385 var menu = tmp.getMenu();
|
|
1386 if (menu && menu.renderEvent) {
|
|
1387 menu.renderEvent.subscribe(this._addMenuClasses, tmp);
|
|
1388 if (oButton.renderer) {
|
|
1389 menu.renderEvent.subscribe(oButton.renderer, tmp);
|
|
1390 }
|
|
1391 }
|
|
1392 }
|
|
1393 }
|
|
1394 }
|
|
1395 return oButton;
|
|
1396 },
|
|
1397 /**
|
|
1398 * @method addSeparator
|
|
1399 * @description Add a new button separator to the toolbar.
|
|
1400 * @param {HTMLElement} cont Optional HTML element to insert this button into.
|
|
1401 * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
|
|
1402 */
|
|
1403 addSeparator: function(cont, after) {
|
|
1404 if (!this.get('element')) {
|
|
1405 this._queue[this._queue.length] = ['addSeparator', arguments];
|
|
1406 return false;
|
|
1407 }
|
|
1408 var sepCont = ((cont) ? cont : this.get('cont'));
|
|
1409 if (!this.get('element')) {
|
|
1410 this._queue[this._queue.length] = ['addSeparator', arguments];
|
|
1411 return false;
|
|
1412 }
|
|
1413 if (this._sepCount === null) {
|
|
1414 this._sepCount = 0;
|
|
1415 }
|
|
1416 if (!this._sep) {
|
|
1417 this._sep = document.createElement('SPAN');
|
|
1418 Dom.addClass(this._sep, this.CLASS_SEPARATOR);
|
|
1419 this._sep.innerHTML = '|';
|
|
1420 }
|
|
1421 var _sep = this._sep.cloneNode(true);
|
|
1422 this._sepCount++;
|
|
1423 Dom.addClass(_sep, this.CLASS_SEPARATOR + '-' + this._sepCount);
|
|
1424 if (after) {
|
|
1425 var nextSib = null;
|
|
1426 if (after.get) {
|
|
1427 nextSib = after.get('element').nextSibling;
|
|
1428 } else if (after.nextSibling) {
|
|
1429 nextSib = after.nextSibling;
|
|
1430 } else {
|
|
1431 nextSib = after;
|
|
1432 }
|
|
1433 if (nextSib) {
|
|
1434 if (nextSib == after) {
|
|
1435 nextSib.parentNode.appendChild(_sep);
|
|
1436 } else {
|
|
1437 nextSib.parentNode.insertBefore(_sep, nextSib);
|
|
1438 }
|
|
1439 }
|
|
1440 } else {
|
|
1441 sepCont.appendChild(_sep);
|
|
1442 }
|
|
1443 return _sep;
|
|
1444 },
|
|
1445 /**
|
|
1446 * @method _createColorPicker
|
|
1447 * @private
|
|
1448 * @description Creates the core DOM reference to the color picker menu item.
|
|
1449 * @param {String} id the id of the toolbar to prefix this DOM container with.
|
|
1450 */
|
|
1451 _createColorPicker: function(id) {
|
|
1452 if (Dom.get(id + '_colors')) {
|
|
1453 Dom.get(id + '_colors').parentNode.removeChild(Dom.get(id + '_colors'));
|
|
1454 }
|
|
1455 var picker = document.createElement('div');
|
|
1456 picker.className = 'yui-toolbar-colors';
|
|
1457 picker.id = id + '_colors';
|
|
1458 picker.style.display = 'none';
|
|
1459 Event.on(window, 'load', function() {
|
|
1460 document.body.appendChild(picker);
|
|
1461 }, this, true);
|
|
1462
|
|
1463 this._colorPicker = picker;
|
|
1464
|
|
1465 var html = '';
|
|
1466 for (var i in this._colorData) {
|
|
1467 if (Lang.hasOwnProperty(this._colorData, i)) {
|
|
1468 html += '<a style="background-color: ' + i + '" href="#">' + i.replace('#', '') + '</a>';
|
|
1469 }
|
|
1470 }
|
|
1471 html += '<span><em>X</em><strong></strong></span>';
|
|
1472 window.setTimeout(function() {
|
|
1473 picker.innerHTML = html;
|
|
1474 }, 0);
|
|
1475
|
|
1476 Event.on(picker, 'mouseover', function(ev) {
|
|
1477 var picker = this._colorPicker;
|
|
1478 var em = picker.getElementsByTagName('em')[0];
|
|
1479 var strong = picker.getElementsByTagName('strong')[0];
|
|
1480 var tar = Event.getTarget(ev);
|
|
1481 if (tar.tagName.toLowerCase() == 'a') {
|
|
1482 em.style.backgroundColor = tar.style.backgroundColor;
|
|
1483 strong.innerHTML = this._colorData['#' + tar.innerHTML] + '<br>' + tar.innerHTML;
|
|
1484 }
|
|
1485 }, this, true);
|
|
1486 Event.on(picker, 'focus', function(ev) {
|
|
1487 Event.stopEvent(ev);
|
|
1488 });
|
|
1489 Event.on(picker, 'click', function(ev) {
|
|
1490 Event.stopEvent(ev);
|
|
1491 });
|
|
1492 Event.on(picker, 'mousedown', function(ev) {
|
|
1493 Event.stopEvent(ev);
|
|
1494 var tar = Event.getTarget(ev);
|
|
1495 if (tar.tagName.toLowerCase() == 'a') {
|
|
1496 var retVal = this.fireEvent('colorPickerClicked', { type: 'colorPickerClicked', target: this, button: this._colorPicker._button, color: tar.innerHTML, colorName: this._colorData['#' + tar.innerHTML] } );
|
|
1497 if (retVal !== false) {
|
|
1498 var info = {
|
|
1499 color: tar.innerHTML,
|
|
1500 colorName: this._colorData['#' + tar.innerHTML],
|
|
1501 value: this._colorPicker._button
|
|
1502 };
|
|
1503
|
|
1504 this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
|
|
1505 }
|
|
1506 this.getButtonByValue(this._colorPicker._button).getMenu().hide();
|
|
1507 }
|
|
1508 }, this, true);
|
|
1509 },
|
|
1510 /**
|
|
1511 * @method _resetColorPicker
|
|
1512 * @private
|
|
1513 * @description Clears the currently selected color or mouseover color in the color picker.
|
|
1514 */
|
|
1515 _resetColorPicker: function() {
|
|
1516 var em = this._colorPicker.getElementsByTagName('em')[0];
|
|
1517 var strong = this._colorPicker.getElementsByTagName('strong')[0];
|
|
1518 em.style.backgroundColor = 'transparent';
|
|
1519 strong.innerHTML = '';
|
|
1520 },
|
|
1521 /**
|
|
1522 * @method _makeColorButton
|
|
1523 * @private
|
|
1524 * @description Called to turn a "color" button into a menu button with an Overlay for the menu.
|
|
1525 * @param {Object} _oButton <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
|
|
1526 */
|
|
1527 _makeColorButton: function(_oButton) {
|
|
1528 if (!this._colorPicker) {
|
|
1529 this._createColorPicker(this.get('id'));
|
|
1530 }
|
|
1531 _oButton.type = 'color';
|
|
1532 _oButton.menu = new YAHOO.widget.Overlay(this.get('id') + '_' + _oButton.value + '_menu', { visible: false, position: 'absolute', iframe: true });
|
|
1533 _oButton.menu.setBody('');
|
|
1534 _oButton.menu.render(this.get('cont'));
|
|
1535 Dom.addClass(_oButton.menu.element, 'yui-button-menu');
|
|
1536 Dom.addClass(_oButton.menu.element, 'yui-color-button-menu');
|
|
1537 _oButton.menu.beforeShowEvent.subscribe(function() {
|
|
1538 _oButton.menu.cfg.setProperty('zindex', 5); //Re Adjust the overlays zIndex.. not sure why.
|
|
1539 _oButton.menu.cfg.setProperty('context', [this.getButtonById(_oButton.id).get('element'), 'tl', 'bl']); //Re Adjust the overlay.. not sure why.
|
|
1540 //Move the DOM reference of the color picker to the Overlay that we are about to show.
|
|
1541 this._resetColorPicker();
|
|
1542 var _p = this._colorPicker;
|
|
1543 if (_p.parentNode) {
|
|
1544 _p.parentNode.removeChild(_p);
|
|
1545 }
|
|
1546 _oButton.menu.setBody('');
|
|
1547 _oButton.menu.appendToBody(_p);
|
|
1548 this._colorPicker.style.display = 'block';
|
|
1549 }, this, true);
|
|
1550 return _oButton;
|
|
1551 },
|
|
1552 /**
|
|
1553 * @private
|
|
1554 * @method _makeSpinButton
|
|
1555 * @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.
|
|
1556 * @param {Object} _button <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
|
|
1557 * @param {Object} oButton Object literal containing the buttons initial config
|
|
1558 */
|
|
1559 _makeSpinButton: function(_button, oButton) {
|
|
1560 _button.addClass(this.CLASS_PREFIX + '-spinbutton');
|
|
1561 var self = this,
|
|
1562 _par = _button._button.parentNode.parentNode, //parentNode of Button Element for appending child
|
|
1563 range = oButton.range,
|
|
1564 _b1 = document.createElement('a'),
|
|
1565 _b2 = document.createElement('a');
|
|
1566 _b1.href = '#';
|
|
1567 _b2.href = '#';
|
|
1568 _b1.tabIndex = '-1';
|
|
1569 _b2.tabIndex = '-1';
|
|
1570
|
|
1571 //Setup the up and down arrows
|
|
1572 _b1.className = 'up';
|
|
1573 _b1.title = this.STR_SPIN_UP;
|
|
1574 _b1.innerHTML = this.STR_SPIN_UP;
|
|
1575 _b2.className = 'down';
|
|
1576 _b2.title = this.STR_SPIN_DOWN;
|
|
1577 _b2.innerHTML = this.STR_SPIN_DOWN;
|
|
1578
|
|
1579 //Append them to the container
|
|
1580 _par.appendChild(_b1);
|
|
1581 _par.appendChild(_b2);
|
|
1582
|
|
1583 var label = YAHOO.lang.substitute(this.STR_SPIN_LABEL, { VALUE: _button.get('label') });
|
|
1584 _button.set('title', label);
|
|
1585
|
|
1586 var cleanVal = function(value) {
|
|
1587 value = ((value < range[0]) ? range[0] : value);
|
|
1588 value = ((value > range[1]) ? range[1] : value);
|
|
1589 return value;
|
|
1590 };
|
|
1591
|
|
1592 var br = this.browser;
|
|
1593 var tbar = false;
|
|
1594 var strLabel = this.STR_SPIN_LABEL;
|
|
1595 if (this._titlebar && this._titlebar.firstChild) {
|
|
1596 tbar = this._titlebar.firstChild;
|
|
1597 }
|
|
1598
|
|
1599 var _intUp = function(ev) {
|
|
1600 YAHOO.util.Event.stopEvent(ev);
|
|
1601 if (!_button.get('disabled') && (ev.keyCode != 9)) {
|
|
1602 var value = parseInt(_button.get('label'), 10);
|
|
1603 value++;
|
|
1604 value = cleanVal(value);
|
|
1605 _button.set('label', ''+value);
|
|
1606 var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
|
|
1607 _button.set('title', label);
|
|
1608 if (!br.webkit && tbar) {
|
|
1609 //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
|
|
1610 //_button.focus();
|
|
1611 }
|
|
1612 self._buttonClick(ev, oButton);
|
|
1613 }
|
|
1614 };
|
|
1615
|
|
1616 var _intDown = function(ev) {
|
|
1617 YAHOO.util.Event.stopEvent(ev);
|
|
1618 if (!_button.get('disabled') && (ev.keyCode != 9)) {
|
|
1619 var value = parseInt(_button.get('label'), 10);
|
|
1620 value--;
|
|
1621 value = cleanVal(value);
|
|
1622
|
|
1623 _button.set('label', ''+value);
|
|
1624 var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
|
|
1625 _button.set('title', label);
|
|
1626 if (!br.webkit && tbar) {
|
|
1627 //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
|
|
1628 //_button.focus();
|
|
1629 }
|
|
1630 self._buttonClick(ev, oButton);
|
|
1631 }
|
|
1632 };
|
|
1633
|
|
1634 var _intKeyUp = function(ev) {
|
|
1635 if (ev.keyCode == 38) {
|
|
1636 _intUp(ev);
|
|
1637 } else if (ev.keyCode == 40) {
|
|
1638 _intDown(ev);
|
|
1639 } else if (ev.keyCode == 107 && ev.shiftKey) { //Plus Key
|
|
1640 _intUp(ev);
|
|
1641 } else if (ev.keyCode == 109 && ev.shiftKey) { //Minus Key
|
|
1642 _intDown(ev);
|
|
1643 }
|
|
1644 };
|
|
1645
|
|
1646 //Handle arrow keys..
|
|
1647 _button.on('keydown', _intKeyUp, this, true);
|
|
1648
|
|
1649 //Listen for the click on the up button and act on it
|
|
1650 //Listen for the click on the down button and act on it
|
|
1651 Event.on(_b1, 'mousedown',function(ev) {
|
|
1652 Event.stopEvent(ev);
|
|
1653 }, this, true);
|
|
1654 Event.on(_b2, 'mousedown', function(ev) {
|
|
1655 Event.stopEvent(ev);
|
|
1656 }, this, true);
|
|
1657 Event.on(_b1, 'click', _intUp, this, true);
|
|
1658 Event.on(_b2, 'click', _intDown, this, true);
|
|
1659 },
|
|
1660 /**
|
|
1661 * @protected
|
|
1662 * @method _buttonClick
|
|
1663 * @description Click handler for all buttons in the toolbar.
|
|
1664 * @param {String} ev The event that was passed in.
|
|
1665 * @param {Object} info Object literal of information about the button that was clicked.
|
|
1666 */
|
|
1667 _buttonClick: function(ev, info) {
|
|
1668 var doEvent = true;
|
|
1669
|
|
1670 if (ev && ev.type == 'keypress') {
|
|
1671 if (ev.keyCode == 9) {
|
|
1672 doEvent = false;
|
|
1673 } else if ((ev.keyCode === 13) || (ev.keyCode === 0) || (ev.keyCode === 32)) {
|
|
1674 } else {
|
|
1675 doEvent = false;
|
|
1676 }
|
|
1677 }
|
|
1678
|
|
1679 if (doEvent) {
|
|
1680 var fireNextEvent = true,
|
|
1681 retValue = false;
|
|
1682
|
|
1683 info.isSelected = this.isSelected(info.id);
|
|
1684
|
|
1685 if (info.value) {
|
|
1686 retValue = this.fireEvent(info.value + 'Click', { type: info.value + 'Click', target: this.get('element'), button: info });
|
|
1687 if (retValue === false) {
|
|
1688 fireNextEvent = false;
|
|
1689 }
|
|
1690 }
|
|
1691
|
|
1692 if (info.menucmd && fireNextEvent) {
|
|
1693 retValue = this.fireEvent(info.menucmd + 'Click', { type: info.menucmd + 'Click', target: this.get('element'), button: info });
|
|
1694 if (retValue === false) {
|
|
1695 fireNextEvent = false;
|
|
1696 }
|
|
1697 }
|
|
1698 if (fireNextEvent) {
|
|
1699 this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
|
|
1700 }
|
|
1701
|
|
1702 if (info.type == 'select') {
|
|
1703 var button = this.getButtonById(info.id);
|
|
1704 if (button.buttonType == 'rich') {
|
|
1705 var txt = info.value;
|
|
1706 for (var i = 0; i < info.menu.length; i++) {
|
|
1707 if (info.menu[i].value == info.value) {
|
|
1708 txt = info.menu[i].text;
|
|
1709 break;
|
|
1710 }
|
|
1711 }
|
|
1712 button.set('label', '<span class="yui-toolbar-' + info.menucmd + '-' + (info.value).replace(/ /g, '-').toLowerCase() + '">' + txt + '</span>');
|
|
1713 var _items = button.getMenu().getItems();
|
|
1714 for (var m = 0; m < _items.length; m++) {
|
|
1715 if (_items[m].value.toLowerCase() == info.value.toLowerCase()) {
|
|
1716 _items[m].cfg.setProperty('checked', true);
|
|
1717 } else {
|
|
1718 _items[m].cfg.setProperty('checked', false);
|
|
1719 }
|
|
1720 }
|
|
1721 }
|
|
1722 }
|
|
1723 if (ev) {
|
|
1724 Event.stopEvent(ev);
|
|
1725 }
|
|
1726 }
|
|
1727 },
|
|
1728 /**
|
|
1729 * @private
|
|
1730 * @property _keyNav
|
|
1731 * @description Flag to determine if the arrow nav listeners have been attached
|
|
1732 * @type Boolean
|
|
1733 */
|
|
1734 _keyNav: null,
|
|
1735 /**
|
|
1736 * @private
|
|
1737 * @property _navCounter
|
|
1738 * @description Internal counter for walking the buttons in the toolbar with the arrow keys
|
|
1739 * @type Number
|
|
1740 */
|
|
1741 _navCounter: null,
|
|
1742 /**
|
|
1743 * @private
|
|
1744 * @method _navigateButtons
|
|
1745 * @description Handles the navigation/focus of toolbar buttons with the Arrow Keys
|
|
1746 * @param {Event} ev The Key Event
|
|
1747 */
|
|
1748 _navigateButtons: function(ev) {
|
|
1749 switch (ev.keyCode) {
|
|
1750 case 37:
|
|
1751 case 39:
|
|
1752 if (ev.keyCode == 37) {
|
|
1753 this._navCounter--;
|
|
1754 } else {
|
|
1755 this._navCounter++;
|
|
1756 }
|
|
1757 if (this._navCounter > (this._buttonList.length - 1)) {
|
|
1758 this._navCounter = 0;
|
|
1759 }
|
|
1760 if (this._navCounter < 0) {
|
|
1761 this._navCounter = (this._buttonList.length - 1);
|
|
1762 }
|
|
1763 if (this._buttonList[this._navCounter]) {
|
|
1764 var el = this._buttonList[this._navCounter].get('element');
|
|
1765 if (this.browser.ie) {
|
|
1766 el = this._buttonList[this._navCounter].get('element').getElementsByTagName('a')[0];
|
|
1767 }
|
|
1768 if (this._buttonList[this._navCounter].get('disabled')) {
|
|
1769 this._navigateButtons(ev);
|
|
1770 } else {
|
|
1771 el.focus();
|
|
1772 }
|
|
1773 }
|
|
1774 break;
|
|
1775 }
|
|
1776 },
|
|
1777 /**
|
|
1778 * @private
|
|
1779 * @method _handleFocus
|
|
1780 * @description Sets up the listeners for the arrow key navigation
|
|
1781 */
|
|
1782 _handleFocus: function() {
|
|
1783 if (!this._keyNav) {
|
|
1784 var ev = 'keypress';
|
|
1785 if (this.browser.ie) {
|
|
1786 ev = 'keydown';
|
|
1787 }
|
|
1788 Event.on(this.get('element'), ev, this._navigateButtons, this, true);
|
|
1789 this._keyNav = true;
|
|
1790 this._navCounter = -1;
|
|
1791 }
|
|
1792 },
|
|
1793 /**
|
|
1794 * @method getButtonById
|
|
1795 * @description Gets a button instance from the toolbar by is Dom id.
|
|
1796 * @param {String} id The Dom id to query for.
|
|
1797 * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
|
|
1798 */
|
|
1799 getButtonById: function(id) {
|
|
1800 var len = this._buttonList.length;
|
|
1801 for (var i = 0; i < len; i++) {
|
|
1802 if (this._buttonList[i] && this._buttonList[i].get('id') == id) {
|
|
1803 return this._buttonList[i];
|
|
1804 }
|
|
1805 }
|
|
1806 return false;
|
|
1807 },
|
|
1808 /**
|
|
1809 * @method getButtonByValue
|
|
1810 * @description Gets a button instance or a menuitem instance from the toolbar by it's value.
|
|
1811 * @param {String} value The button value to query for.
|
|
1812 * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> or <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>}
|
|
1813 */
|
|
1814 getButtonByValue: function(value) {
|
|
1815 var _buttons = this.get('buttons');
|
|
1816 if (!_buttons) {
|
|
1817 return false;
|
|
1818 }
|
|
1819 var len = _buttons.length;
|
|
1820 for (var i = 0; i < len; i++) {
|
|
1821 if (_buttons[i].group !== undefined) {
|
|
1822 for (var m = 0; m < _buttons[i].buttons.length; m++) {
|
|
1823 if ((_buttons[i].buttons[m].value == value) || (_buttons[i].buttons[m].menucmd == value)) {
|
|
1824 return this.getButtonById(_buttons[i].buttons[m].id);
|
|
1825 }
|
|
1826 if (_buttons[i].buttons[m].menu) { //Menu Button, loop through the values
|
|
1827 for (var s = 0; s < _buttons[i].buttons[m].menu.length; s++) {
|
|
1828 if (_buttons[i].buttons[m].menu[s].value == value) {
|
|
1829 return this.getButtonById(_buttons[i].buttons[m].id);
|
|
1830 }
|
|
1831 }
|
|
1832 }
|
|
1833 }
|
|
1834 } else {
|
|
1835 if ((_buttons[i].value == value) || (_buttons[i].menucmd == value)) {
|
|
1836 return this.getButtonById(_buttons[i].id);
|
|
1837 }
|
|
1838 if (_buttons[i].menu) { //Menu Button, loop through the values
|
|
1839 for (var j = 0; j < _buttons[i].menu.length; j++) {
|
|
1840 if (_buttons[i].menu[j].value == value) {
|
|
1841 return this.getButtonById(_buttons[i].id);
|
|
1842 }
|
|
1843 }
|
|
1844 }
|
|
1845 }
|
|
1846 }
|
|
1847 return false;
|
|
1848 },
|
|
1849 /**
|
|
1850 * @method getButtonByIndex
|
|
1851 * @description Gets a button instance from the toolbar by is index in _buttonList.
|
|
1852 * @param {Number} index The index of the button in _buttonList.
|
|
1853 * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
|
|
1854 */
|
|
1855 getButtonByIndex: function(index) {
|
|
1856 if (this._buttonList[index]) {
|
|
1857 return this._buttonList[index];
|
|
1858 } else {
|
|
1859 return false;
|
|
1860 }
|
|
1861 },
|
|
1862 /**
|
|
1863 * @method getButtons
|
|
1864 * @description Returns an array of buttons in the current toolbar
|
|
1865 * @return {Array}
|
|
1866 */
|
|
1867 getButtons: function() {
|
|
1868 return this._buttonList;
|
|
1869 },
|
|
1870 /**
|
|
1871 * @method disableButton
|
|
1872 * @description Disables a button in the toolbar.
|
|
1873 * @param {String/Number} id Disable a button by it's id, index or value.
|
|
1874 * @return {Boolean}
|
|
1875 */
|
|
1876 disableButton: function(id) {
|
|
1877 var button = getButton.call(this, id);
|
|
1878 if (button) {
|
|
1879 button.set('disabled', true);
|
|
1880 } else {
|
|
1881 return false;
|
|
1882 }
|
|
1883 },
|
|
1884 /**
|
|
1885 * @method enableButton
|
|
1886 * @description Enables a button in the toolbar.
|
|
1887 * @param {String/Number} id Enable a button by it's id, index or value.
|
|
1888 * @return {Boolean}
|
|
1889 */
|
|
1890 enableButton: function(id) {
|
|
1891 if (this.get('disabled')) {
|
|
1892 return false;
|
|
1893 }
|
|
1894 var button = getButton.call(this, id);
|
|
1895 if (button) {
|
|
1896 if (button.get('disabled')) {
|
|
1897 button.set('disabled', false);
|
|
1898 }
|
|
1899 } else {
|
|
1900 return false;
|
|
1901 }
|
|
1902 },
|
|
1903 /**
|
|
1904 * @method isSelected
|
|
1905 * @description Tells if a button is selected or not.
|
|
1906 * @param {String/Number} id A button by it's id, index or value.
|
|
1907 * @return {Boolean}
|
|
1908 */
|
|
1909 isSelected: function(id) {
|
|
1910 var button = getButton.call(this, id);
|
|
1911 if (button) {
|
|
1912 return button._selected;
|
|
1913 }
|
|
1914 return false;
|
|
1915 },
|
|
1916 /**
|
|
1917 * @method selectButton
|
|
1918 * @description Selects a button in the toolbar.
|
|
1919 * @param {String/Number} id Select a button by it's id, index or value.
|
|
1920 * @param {String} value If this is a Menu Button, check this item in the menu
|
|
1921 * @return {Boolean}
|
|
1922 */
|
|
1923 selectButton: function(id, value) {
|
|
1924 var button = getButton.call(this, id);
|
|
1925 if (button) {
|
|
1926 button.addClass('yui-button-selected');
|
|
1927 button.addClass('yui-button-' + button.get('value') + '-selected');
|
|
1928 button._selected = true;
|
|
1929 if (value) {
|
|
1930 if (button.buttonType == 'rich') {
|
|
1931 var _items = button.getMenu().getItems();
|
|
1932 for (var m = 0; m < _items.length; m++) {
|
|
1933 if (_items[m].value == value) {
|
|
1934 _items[m].cfg.setProperty('checked', true);
|
|
1935 button.set('label', '<span class="yui-toolbar-' + button.get('value') + '-' + (value).replace(/ /g, '-').toLowerCase() + '">' + _items[m]._oText.nodeValue + '</span>');
|
|
1936 } else {
|
|
1937 _items[m].cfg.setProperty('checked', false);
|
|
1938 }
|
|
1939 }
|
|
1940 }
|
|
1941 }
|
|
1942 } else {
|
|
1943 return false;
|
|
1944 }
|
|
1945 },
|
|
1946 /**
|
|
1947 * @method deselectButton
|
|
1948 * @description Deselects a button in the toolbar.
|
|
1949 * @param {String/Number} id Deselect a button by it's id, index or value.
|
|
1950 * @return {Boolean}
|
|
1951 */
|
|
1952 deselectButton: function(id) {
|
|
1953 var button = getButton.call(this, id);
|
|
1954 if (button) {
|
|
1955 button.removeClass('yui-button-selected');
|
|
1956 button.removeClass('yui-button-' + button.get('value') + '-selected');
|
|
1957 button.removeClass('yui-button-hover');
|
|
1958 button._selected = false;
|
|
1959 } else {
|
|
1960 return false;
|
|
1961 }
|
|
1962 },
|
|
1963 /**
|
|
1964 * @method deselectAllButtons
|
|
1965 * @description Deselects all buttons in the toolbar.
|
|
1966 * @return {Boolean}
|
|
1967 */
|
|
1968 deselectAllButtons: function() {
|
|
1969 var len = this._buttonList.length;
|
|
1970 for (var i = 0; i < len; i++) {
|
|
1971 this.deselectButton(this._buttonList[i]);
|
|
1972 }
|
|
1973 },
|
|
1974 /**
|
|
1975 * @method disableAllButtons
|
|
1976 * @description Disables all buttons in the toolbar.
|
|
1977 * @return {Boolean}
|
|
1978 */
|
|
1979 disableAllButtons: function() {
|
|
1980 if (this.get('disabled')) {
|
|
1981 return false;
|
|
1982 }
|
|
1983 var len = this._buttonList.length;
|
|
1984 for (var i = 0; i < len; i++) {
|
|
1985 this.disableButton(this._buttonList[i]);
|
|
1986 }
|
|
1987 },
|
|
1988 /**
|
|
1989 * @method enableAllButtons
|
|
1990 * @description Enables all buttons in the toolbar.
|
|
1991 * @return {Boolean}
|
|
1992 */
|
|
1993 enableAllButtons: function() {
|
|
1994 if (this.get('disabled')) {
|
|
1995 return false;
|
|
1996 }
|
|
1997 var len = this._buttonList.length;
|
|
1998 for (var i = 0; i < len; i++) {
|
|
1999 this.enableButton(this._buttonList[i]);
|
|
2000 }
|
|
2001 },
|
|
2002 /**
|
|
2003 * @method resetAllButtons
|
|
2004 * @description Resets all buttons to their initial state.
|
|
2005 * @param {Object} _ex Except these buttons
|
|
2006 * @return {Boolean}
|
|
2007 */
|
|
2008 resetAllButtons: function(_ex) {
|
|
2009 if (!Lang.isObject(_ex)) {
|
|
2010 _ex = {};
|
|
2011 }
|
|
2012 if (this.get('disabled') || !this._buttonList) {
|
|
2013 return false;
|
|
2014 }
|
|
2015 var len = this._buttonList.length;
|
|
2016 for (var i = 0; i < len; i++) {
|
|
2017 var _button = this._buttonList[i];
|
|
2018 if (_button) {
|
|
2019 var disabled = _button._configs.disabled._initialConfig.value;
|
|
2020 if (_ex[_button.get('id')]) {
|
|
2021 this.enableButton(_button);
|
|
2022 this.selectButton(_button);
|
|
2023 } else {
|
|
2024 if (disabled) {
|
|
2025 this.disableButton(_button);
|
|
2026 } else {
|
|
2027 this.enableButton(_button);
|
|
2028 }
|
|
2029 this.deselectButton(_button);
|
|
2030 }
|
|
2031 }
|
|
2032 }
|
|
2033 },
|
|
2034 /**
|
|
2035 * @method destroyButton
|
|
2036 * @description Destroy a button in the toolbar.
|
|
2037 * @param {String/Number} id Destroy a button by it's id or index.
|
|
2038 * @return {Boolean}
|
|
2039 */
|
|
2040 destroyButton: function(id) {
|
|
2041 var button = getButton.call(this, id);
|
|
2042 if (button) {
|
|
2043 var thisID = button.get('id'),
|
|
2044 new_list = [], i = 0,
|
|
2045 len = this._buttonList.length;
|
|
2046
|
|
2047 button.destroy();
|
|
2048
|
|
2049 for (i = 0; i < len; i++) {
|
|
2050 if (this._buttonList[i].get('id') != thisID) {
|
|
2051 new_list[new_list.length]= this._buttonList[i];
|
|
2052 }
|
|
2053 }
|
|
2054
|
|
2055 this._buttonList = new_list;
|
|
2056 } else {
|
|
2057 return false;
|
|
2058 }
|
|
2059 },
|
|
2060 /**
|
|
2061 * @method destroy
|
|
2062 * @description Destroys the toolbar, all of it's elements and objects.
|
|
2063 * @return {Boolean}
|
|
2064 */
|
|
2065 destroy: function() {
|
|
2066 var len = this._configuredButtons.length, j, i;
|
|
2067 for(b = 0; b < len; b++) {
|
|
2068 this.destroyButton(this._configuredButtons[b]);
|
|
2069 }
|
|
2070
|
|
2071 this._configuredButtons = null;
|
|
2072
|
|
2073 this.get('element').innerHTML = '';
|
|
2074 this.get('element').className = '';
|
|
2075 //Brutal Object Destroy
|
|
2076 for (i in this) {
|
|
2077 if (Lang.hasOwnProperty(this, i)) {
|
|
2078 this[i] = null;
|
|
2079 }
|
|
2080 }
|
|
2081 return true;
|
|
2082 },
|
|
2083 /**
|
|
2084 * @method collapse
|
|
2085 * @description Programatically collapse the toolbar.
|
|
2086 * @param {Boolean} collapse True to collapse, false to expand.
|
|
2087 */
|
|
2088 collapse: function(collapse) {
|
|
2089 var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
|
|
2090 if (collapse === false) {
|
|
2091 Dom.removeClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
|
|
2092 if (el[0]) {
|
|
2093 Dom.removeClass(el[0], 'collapsed');
|
|
2094 el[0].title = this.STR_COLLAPSE;
|
|
2095 }
|
|
2096 this.fireEvent('toolbarExpanded', { type: 'toolbarExpanded', target: this });
|
|
2097 } else {
|
|
2098 if (el[0]) {
|
|
2099 Dom.addClass(el[0], 'collapsed');
|
|
2100 el[0].title = this.STR_EXPAND;
|
|
2101 }
|
|
2102 Dom.addClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
|
|
2103 this.fireEvent('toolbarCollapsed', { type: 'toolbarCollapsed', target: this });
|
|
2104 }
|
|
2105 },
|
|
2106 /**
|
|
2107 * @method toString
|
|
2108 * @description Returns a string representing the toolbar.
|
|
2109 * @return {String}
|
|
2110 */
|
|
2111 toString: function() {
|
|
2112 return 'Toolbar (#' + this.get('element').id + ') with ' + this._buttonList.length + ' buttons.';
|
|
2113 }
|
|
2114 });
|
|
2115 /**
|
|
2116 * @event buttonClick
|
|
2117 * @param {Object} o The object passed to this handler is the button config used to create the button.
|
|
2118 * @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.
|
|
2119 * @type YAHOO.util.CustomEvent
|
|
2120 */
|
|
2121 /**
|
|
2122 * @event valueClick
|
|
2123 * @param {Object} o The object passed to this handler is the button config used to create the button.
|
|
2124 * @description This is a special dynamic event that is created and dispatched based on the value property
|
|
2125 * of the button config. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
2126 * Example:
|
|
2127 * <code><pre>
|
|
2128 * buttons : [
|
|
2129 * { type: 'button', value: 'test', value: 'testButton' }
|
|
2130 * ]</pre>
|
|
2131 * </code>
|
|
2132 * With the valueClick event you could subscribe to this buttons click event with this:
|
|
2133 * tbar.in('testButtonClick', function() { alert('test button clicked'); })
|
|
2134 * @type YAHOO.util.CustomEvent
|
|
2135 */
|
|
2136 /**
|
|
2137 * @event toolbarExpanded
|
|
2138 * @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.
|
|
2139 * @type YAHOO.util.CustomEvent
|
|
2140 */
|
|
2141 /**
|
|
2142 * @event toolbarCollapsed
|
|
2143 * @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.
|
|
2144 * @type YAHOO.util.CustomEvent
|
|
2145 */
|
|
2146 })();
|
|
2147 /**
|
|
2148 * @module editor
|
|
2149 * @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>
|
|
2150 * @namespace YAHOO.widget
|
|
2151 * @requires yahoo, dom, element, event, toolbar
|
|
2152 * @optional animation, container_core, resize, dragdrop
|
|
2153 */
|
|
2154
|
|
2155 (function() {
|
|
2156 var Dom = YAHOO.util.Dom,
|
|
2157 Event = YAHOO.util.Event,
|
|
2158 Lang = YAHOO.lang,
|
|
2159 Toolbar = YAHOO.widget.Toolbar;
|
|
2160
|
|
2161 /**
|
|
2162 * 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.
|
|
2163 * @constructor
|
|
2164 * @class SimpleEditor
|
|
2165 * @extends YAHOO.util.Element
|
|
2166 * @param {String/HTMLElement} el The textarea element to turn into an editor.
|
|
2167 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
2168 */
|
|
2169
|
|
2170 YAHOO.widget.SimpleEditor = function(el, attrs) {
|
|
2171
|
|
2172 var o = {};
|
|
2173 if (Lang.isObject(el) && (!el.tagName) && !attrs) {
|
|
2174 Lang.augmentObject(o, el); //Break the config reference
|
|
2175 el = document.createElement('textarea');
|
|
2176 this.DOMReady = true;
|
|
2177 if (o.container) {
|
|
2178 var c = Dom.get(o.container);
|
|
2179 c.appendChild(el);
|
|
2180 } else {
|
|
2181 document.body.appendChild(el);
|
|
2182 }
|
|
2183 } else {
|
|
2184 if (attrs) {
|
|
2185 Lang.augmentObject(o, attrs); //Break the config reference
|
|
2186 }
|
|
2187 }
|
|
2188
|
|
2189 var oConfig = {
|
|
2190 element: null,
|
|
2191 attributes: o
|
|
2192 }, id = null;
|
|
2193
|
|
2194 if (Lang.isString(el)) {
|
|
2195 id = el;
|
|
2196 } else {
|
|
2197 if (oConfig.attributes.id) {
|
|
2198 id = oConfig.attributes.id;
|
|
2199 } else {
|
|
2200 this.DOMReady = true;
|
|
2201 id = Dom.generateId(el);
|
|
2202 }
|
|
2203 }
|
|
2204 oConfig.element = el;
|
|
2205
|
|
2206 var element_cont = document.createElement('DIV');
|
|
2207 oConfig.attributes.element_cont = new YAHOO.util.Element(element_cont, {
|
|
2208 id: id + '_container'
|
|
2209 });
|
|
2210 var div = document.createElement('div');
|
|
2211 Dom.addClass(div, 'first-child');
|
|
2212 oConfig.attributes.element_cont.appendChild(div);
|
|
2213
|
|
2214 if (!oConfig.attributes.toolbar_cont) {
|
|
2215 oConfig.attributes.toolbar_cont = document.createElement('DIV');
|
|
2216 oConfig.attributes.toolbar_cont.id = id + '_toolbar';
|
|
2217 div.appendChild(oConfig.attributes.toolbar_cont);
|
|
2218 }
|
|
2219 var editorWrapper = document.createElement('DIV');
|
|
2220 div.appendChild(editorWrapper);
|
|
2221 oConfig.attributes.editor_wrapper = editorWrapper;
|
|
2222
|
|
2223 YAHOO.widget.SimpleEditor.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
|
|
2224 };
|
|
2225
|
|
2226
|
|
2227 YAHOO.extend(YAHOO.widget.SimpleEditor, YAHOO.util.Element, {
|
|
2228 /**
|
|
2229 * @private
|
|
2230 * @property _resizeConfig
|
|
2231 * @description The default config for the Resize Utility
|
|
2232 */
|
|
2233 _resizeConfig: {
|
|
2234 handles: ['br'],
|
|
2235 autoRatio: true,
|
|
2236 status: true,
|
|
2237 proxy: true,
|
|
2238 useShim: true,
|
|
2239 setSize: false
|
|
2240 },
|
|
2241 /**
|
|
2242 * @private
|
|
2243 * @method _setupResize
|
|
2244 * @description Creates the Resize instance and binds its events.
|
|
2245 */
|
|
2246 _setupResize: function() {
|
|
2247 if (!YAHOO.util.DD || !YAHOO.util.Resize) { return false; }
|
|
2248 if (this.get('resize')) {
|
|
2249 var config = {};
|
|
2250 Lang.augmentObject(config, this._resizeConfig); //Break the config reference
|
|
2251 this.resize = new YAHOO.util.Resize(this.get('element_cont').get('element'), config);
|
|
2252 this.resize.on('resize', function(args) {
|
|
2253 var anim = this.get('animate');
|
|
2254 this.set('animate', false);
|
|
2255 this.set('width', args.width + 'px');
|
|
2256 var h = args.height,
|
|
2257 th = (this.toolbar.get('element').clientHeight + 2),
|
|
2258 dh = 0;
|
|
2259 if (this.dompath) {
|
|
2260 dh = (this.dompath.clientHeight + 1); //It has a 1px top border..
|
|
2261 }
|
|
2262 var newH = (h - th - dh);
|
|
2263 this.set('height', newH + 'px');
|
|
2264 this.get('element_cont').setStyle('height', '');
|
|
2265 this.set('animate', anim);
|
|
2266 }, this, true);
|
|
2267 }
|
|
2268 },
|
|
2269 /**
|
|
2270 * @property resize
|
|
2271 * @description A reference to the Resize object
|
|
2272 * @type YAHOO.util.Resize
|
|
2273 */
|
|
2274 resize: null,
|
|
2275 /**
|
|
2276 * @private
|
|
2277 * @method _setupDD
|
|
2278 * @description Sets up the DD instance used from the 'drag' config option.
|
|
2279 */
|
|
2280 _setupDD: function() {
|
|
2281 if (!YAHOO.util.DD) { return false; }
|
|
2282 if (this.get('drag')) {
|
|
2283 var d = this.get('drag'),
|
|
2284 dd = YAHOO.util.DD;
|
|
2285 if (d === 'proxy') {
|
|
2286 dd = YAHOO.util.DDProxy;
|
|
2287 }
|
|
2288
|
|
2289 this.dd = new dd(this.get('element_cont').get('element'));
|
|
2290 this.toolbar.addClass('draggable');
|
|
2291 this.dd.setHandleElId(this.toolbar._titlebar);
|
|
2292 }
|
|
2293 },
|
|
2294 /**
|
|
2295 * @property dd
|
|
2296 * @description A reference to the DragDrop object.
|
|
2297 * @type YAHOO.util.DD/YAHOO.util.DDProxy
|
|
2298 */
|
|
2299 dd: null,
|
|
2300 /**
|
|
2301 * @private
|
|
2302 * @property _lastCommand
|
|
2303 * @description A cache of the last execCommand (used for Undo/Redo so they don't mark an undo level)
|
|
2304 * @type String
|
|
2305 */
|
|
2306 _lastCommand: null,
|
|
2307 _undoNodeChange: function() {},
|
|
2308 _storeUndo: function() {},
|
|
2309 /**
|
|
2310 * @private
|
|
2311 * @method _checkKey
|
|
2312 * @description Checks a keyMap entry against a key event
|
|
2313 * @param {Object} k The _keyMap object
|
|
2314 * @param {Event} e The Mouse Event
|
|
2315 * @return {Boolean}
|
|
2316 */
|
|
2317 _checkKey: function(k, e) {
|
|
2318 var ret = false;
|
|
2319 if ((e.keyCode === k.key)) {
|
|
2320 if (k.mods && (k.mods.length > 0)) {
|
|
2321 var val = 0;
|
|
2322 for (var i = 0; i < k.mods.length; i++) {
|
|
2323 if (this.browser.mac) {
|
|
2324 if (k.mods[i] == 'ctrl') {
|
|
2325 k.mods[i] = 'meta';
|
|
2326 }
|
|
2327 }
|
|
2328 if (e[k.mods[i] + 'Key'] === true) {
|
|
2329 val++;
|
|
2330 }
|
|
2331 }
|
|
2332 if (val === k.mods.length) {
|
|
2333 ret = true;
|
|
2334 }
|
|
2335 } else {
|
|
2336 ret = true;
|
|
2337 }
|
|
2338 }
|
|
2339 return ret;
|
|
2340 },
|
|
2341 /**
|
|
2342 * @private
|
|
2343 * @property _keyMap
|
|
2344 * @description Named key maps for various actions in the Editor. Example: <code>CLOSE_WINDOW: { key: 87, mods: ['shift', 'ctrl'] }</code>.
|
|
2345 * 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.
|
|
2346 * @type {Object/Mixed}
|
|
2347 */
|
|
2348 _keyMap: {
|
|
2349 SELECT_ALL: {
|
|
2350 key: 65, //A key
|
|
2351 mods: ['ctrl']
|
|
2352 },
|
|
2353 CLOSE_WINDOW: {
|
|
2354 key: 87, //W key
|
|
2355 mods: ['shift', 'ctrl']
|
|
2356 },
|
|
2357 FOCUS_TOOLBAR: {
|
|
2358 key: 27,
|
|
2359 mods: ['shift']
|
|
2360 },
|
|
2361 FOCUS_AFTER: {
|
|
2362 key: 27
|
|
2363 },
|
|
2364 FONT_SIZE_UP: {
|
|
2365 key: 38,
|
|
2366 mods: ['shift', 'ctrl']
|
|
2367 },
|
|
2368 FONT_SIZE_DOWN: {
|
|
2369 key: 40,
|
|
2370 mods: ['shift', 'ctrl']
|
|
2371 },
|
|
2372 CREATE_LINK: {
|
|
2373 key: 76,
|
|
2374 mods: ['shift', 'ctrl']
|
|
2375 },
|
|
2376 BOLD: {
|
|
2377 key: 66,
|
|
2378 mods: ['shift', 'ctrl']
|
|
2379 },
|
|
2380 ITALIC: {
|
|
2381 key: 73,
|
|
2382 mods: ['shift', 'ctrl']
|
|
2383 },
|
|
2384 UNDERLINE: {
|
|
2385 key: 85,
|
|
2386 mods: ['shift', 'ctrl']
|
|
2387 },
|
|
2388 UNDO: {
|
|
2389 key: 90,
|
|
2390 mods: ['ctrl']
|
|
2391 },
|
|
2392 REDO: {
|
|
2393 key: 90,
|
|
2394 mods: ['shift', 'ctrl']
|
|
2395 },
|
|
2396 JUSTIFY_LEFT: {
|
|
2397 key: 219,
|
|
2398 mods: ['shift', 'ctrl']
|
|
2399 },
|
|
2400 JUSTIFY_CENTER: {
|
|
2401 key: 220,
|
|
2402 mods: ['shift', 'ctrl']
|
|
2403 },
|
|
2404 JUSTIFY_RIGHT: {
|
|
2405 key: 221,
|
|
2406 mods: ['shift', 'ctrl']
|
|
2407 }
|
|
2408 },
|
|
2409 /**
|
|
2410 * @private
|
|
2411 * @method _cleanClassName
|
|
2412 * @description Makes a useable classname from dynamic data, by dropping it to lowercase and replacing spaces with -'s.
|
|
2413 * @param {String} str The classname to clean up
|
|
2414 * @return {String}
|
|
2415 */
|
|
2416 _cleanClassName: function(str) {
|
|
2417 return str.replace(/ /g, '-').toLowerCase();
|
|
2418 },
|
|
2419 /**
|
|
2420 * @property _textarea
|
|
2421 * @description Flag to determine if we are using a textarea or an HTML Node.
|
|
2422 * @type Boolean
|
|
2423 */
|
|
2424 _textarea: null,
|
|
2425 /**
|
|
2426 * @property _docType
|
|
2427 * @description The DOCTYPE to use in the editable container.
|
|
2428 * @type String
|
|
2429 */
|
|
2430 _docType: '<!DOCTYPE HTML PUBLIC "-/'+'/W3C/'+'/DTD HTML 4.01/'+'/EN" "http:/'+'/www.w3.org/TR/html4/strict.dtd">',
|
|
2431 /**
|
|
2432 * @property editorDirty
|
|
2433 * @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.
|
|
2434 * @type Boolean
|
|
2435 */
|
|
2436 editorDirty: null,
|
|
2437 /**
|
|
2438 * @property _defaultCSS
|
|
2439 * @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' }
|
|
2440 * @type String
|
|
2441 */
|
|
2442 _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; }',
|
|
2443 /**
|
|
2444 * @property _defaultToolbar
|
|
2445 * @private
|
|
2446 * @description Default toolbar config.
|
|
2447 * @type Object
|
|
2448 */
|
|
2449 _defaultToolbar: null,
|
|
2450 /**
|
|
2451 * @property _lastButton
|
|
2452 * @private
|
|
2453 * @description The last button pressed, so we don't disable it.
|
|
2454 * @type Object
|
|
2455 */
|
|
2456 _lastButton: null,
|
|
2457 /**
|
|
2458 * @property _baseHREF
|
|
2459 * @private
|
|
2460 * @description The base location of the editable page (this page) so that relative paths for image work.
|
|
2461 * @type String
|
|
2462 */
|
|
2463 _baseHREF: function() {
|
|
2464 var href = document.location.href;
|
|
2465 if (href.indexOf('?') !== -1) { //Remove the query string
|
|
2466 href = href.substring(0, href.indexOf('?'));
|
|
2467 }
|
|
2468 href = href.substring(0, href.lastIndexOf('/')) + '/';
|
|
2469 return href;
|
|
2470 }(),
|
|
2471 /**
|
|
2472 * @property _lastImage
|
|
2473 * @private
|
|
2474 * @description Safari reference for the last image selected (for styling as selected).
|
|
2475 * @type HTMLElement
|
|
2476 */
|
|
2477 _lastImage: null,
|
|
2478 /**
|
|
2479 * @property _blankImageLoaded
|
|
2480 * @private
|
|
2481 * @description Don't load the blank image more than once..
|
|
2482 * @type Boolean
|
|
2483 */
|
|
2484 _blankImageLoaded: null,
|
|
2485 /**
|
|
2486 * @property _fixNodesTimer
|
|
2487 * @private
|
|
2488 * @description Holder for the fixNodes timer
|
|
2489 * @type Date
|
|
2490 */
|
|
2491 _fixNodesTimer: null,
|
|
2492 /**
|
|
2493 * @property _nodeChangeTimer
|
|
2494 * @private
|
|
2495 * @description Holds a reference to the nodeChange setTimeout call
|
|
2496 * @type Number
|
|
2497 */
|
|
2498 _nodeChangeTimer: null,
|
|
2499 /**
|
|
2500 * @property _nodeChangeDelayTimer
|
|
2501 * @private
|
|
2502 * @description Holds a reference to the nodeChangeDelay setTimeout call
|
|
2503 * @type Number
|
|
2504 */
|
|
2505 _nodeChangeDelayTimer: null,
|
|
2506 /**
|
|
2507 * @property _lastNodeChangeEvent
|
|
2508 * @private
|
|
2509 * @description Flag to determine the last event that fired a node change
|
|
2510 * @type Event
|
|
2511 */
|
|
2512 _lastNodeChangeEvent: null,
|
|
2513 /**
|
|
2514 * @property _lastNodeChange
|
|
2515 * @private
|
|
2516 * @description Flag to determine when the last node change was fired
|
|
2517 * @type Date
|
|
2518 */
|
|
2519 _lastNodeChange: 0,
|
|
2520 /**
|
|
2521 * @property _rendered
|
|
2522 * @private
|
|
2523 * @description Flag to determine if editor has been rendered or not
|
|
2524 * @type Boolean
|
|
2525 */
|
|
2526 _rendered: null,
|
|
2527 /**
|
|
2528 * @property DOMReady
|
|
2529 * @private
|
|
2530 * @description Flag to determine if DOM is ready or not
|
|
2531 * @type Boolean
|
|
2532 */
|
|
2533 DOMReady: null,
|
|
2534 /**
|
|
2535 * @property _selection
|
|
2536 * @private
|
|
2537 * @description Holder for caching iframe selections
|
|
2538 * @type Object
|
|
2539 */
|
|
2540 _selection: null,
|
|
2541 /**
|
|
2542 * @property _mask
|
|
2543 * @private
|
|
2544 * @description DOM Element holder for the editor Mask when disabled
|
|
2545 * @type Object
|
|
2546 */
|
|
2547 _mask: null,
|
|
2548 /**
|
|
2549 * @property _showingHiddenElements
|
|
2550 * @private
|
|
2551 * @description Status of the hidden elements button
|
|
2552 * @type Boolean
|
|
2553 */
|
|
2554 _showingHiddenElements: null,
|
|
2555 /**
|
|
2556 * @property currentWindow
|
|
2557 * @description A reference to the currently open EditorWindow
|
|
2558 * @type Object
|
|
2559 */
|
|
2560 currentWindow: null,
|
|
2561 /**
|
|
2562 * @property currentEvent
|
|
2563 * @description A reference to the current editor event
|
|
2564 * @type Event
|
|
2565 */
|
|
2566 currentEvent: null,
|
|
2567 /**
|
|
2568 * @property operaEvent
|
|
2569 * @private
|
|
2570 * @description setTimeout holder for Opera and Image DoubleClick event..
|
|
2571 * @type Object
|
|
2572 */
|
|
2573 operaEvent: null,
|
|
2574 /**
|
|
2575 * @property currentFont
|
|
2576 * @description A reference to the last font selected from the Toolbar
|
|
2577 * @type HTMLElement
|
|
2578 */
|
|
2579 currentFont: null,
|
|
2580 /**
|
|
2581 * @property currentElement
|
|
2582 * @description A reference to the current working element in the editor
|
|
2583 * @type Array
|
|
2584 */
|
|
2585 currentElement: null,
|
|
2586 /**
|
|
2587 * @property dompath
|
|
2588 * @description A reference to the dompath container for writing the current working dom path to.
|
|
2589 * @type HTMLElement
|
|
2590 */
|
|
2591 dompath: null,
|
|
2592 /**
|
|
2593 * @property beforeElement
|
|
2594 * @description A reference to the H2 placed before the editor for Accessibilty.
|
|
2595 * @type HTMLElement
|
|
2596 */
|
|
2597 beforeElement: null,
|
|
2598 /**
|
|
2599 * @property afterElement
|
|
2600 * @description A reference to the H2 placed after the editor for Accessibilty.
|
|
2601 * @type HTMLElement
|
|
2602 */
|
|
2603 afterElement: null,
|
|
2604 /**
|
|
2605 * @property invalidHTML
|
|
2606 * @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.
|
|
2607 * @type Object
|
|
2608 */
|
|
2609 invalidHTML: {
|
|
2610 form: true,
|
|
2611 input: true,
|
|
2612 button: true,
|
|
2613 select: true,
|
|
2614 link: true,
|
|
2615 html: true,
|
|
2616 body: true,
|
|
2617 iframe: true,
|
|
2618 script: true,
|
|
2619 style: true,
|
|
2620 textarea: true
|
|
2621 },
|
|
2622 /**
|
|
2623 * @property toolbar
|
|
2624 * @description Local property containing the <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a> instance
|
|
2625 * @type <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>
|
|
2626 */
|
|
2627 toolbar: null,
|
|
2628 /**
|
|
2629 * @private
|
|
2630 * @property _contentTimer
|
|
2631 * @description setTimeout holder for documentReady check
|
|
2632 */
|
|
2633 _contentTimer: null,
|
|
2634 /**
|
|
2635 * @private
|
|
2636 * @property _contentTimerMax
|
|
2637 * @description The number of times the loaded content should be checked before giving up. Default: 500
|
|
2638 */
|
|
2639 _contentTimerMax: 500,
|
|
2640 /**
|
|
2641 * @private
|
|
2642 * @property _contentTimerCounter
|
|
2643 * @description Counter to check the number of times the body is polled for before giving up
|
|
2644 * @type Number
|
|
2645 */
|
|
2646 _contentTimerCounter: 0,
|
|
2647 /**
|
|
2648 * @private
|
|
2649 * @property _disabled
|
|
2650 * @description The Toolbar items that should be disabled if there is no selection present in the editor.
|
|
2651 * @type Array
|
|
2652 */
|
|
2653 _disabled: [ 'createlink', 'fontname', 'fontsize', 'forecolor', 'backcolor' ],
|
|
2654 /**
|
|
2655 * @private
|
|
2656 * @property _alwaysDisabled
|
|
2657 * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
|
|
2658 * @type Object
|
|
2659 */
|
|
2660 _alwaysDisabled: { undo: true, redo: true },
|
|
2661 /**
|
|
2662 * @private
|
|
2663 * @property _alwaysEnabled
|
|
2664 * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
|
|
2665 * @type Object
|
|
2666 */
|
|
2667 _alwaysEnabled: { },
|
|
2668 /**
|
|
2669 * @private
|
|
2670 * @property _semantic
|
|
2671 * @description The Toolbar commands that we should attempt to make tags out of instead of using styles.
|
|
2672 * @type Object
|
|
2673 */
|
|
2674 _semantic: { 'bold': true, 'italic' : true, 'underline' : true },
|
|
2675 /**
|
|
2676 * @private
|
|
2677 * @property _tag2cmd
|
|
2678 * @description A tag map of HTML tags to convert to the different types of commands so we can select the proper toolbar button.
|
|
2679 * @type Object
|
|
2680 */
|
|
2681 _tag2cmd: {
|
|
2682 'b': 'bold',
|
|
2683 'strong': 'bold',
|
|
2684 'i': 'italic',
|
|
2685 'em': 'italic',
|
|
2686 'u': 'underline',
|
|
2687 'sup': 'superscript',
|
|
2688 'sub': 'subscript',
|
|
2689 'img': 'insertimage',
|
|
2690 'a' : 'createlink',
|
|
2691 'ul' : 'insertunorderedlist',
|
|
2692 'ol' : 'insertorderedlist'
|
|
2693 },
|
|
2694
|
|
2695 /**
|
|
2696 * @private _createIframe
|
|
2697 * @description Creates the DOM and YUI Element for the iFrame editor area.
|
|
2698 * @param {String} id The string ID to prefix the iframe with
|
|
2699 * @return {Object} iFrame object
|
|
2700 */
|
|
2701 _createIframe: function() {
|
|
2702 var ifrmDom = document.createElement('iframe');
|
|
2703 ifrmDom.id = this.get('id') + '_editor';
|
|
2704 var config = {
|
|
2705 border: '0',
|
|
2706 frameBorder: '0',
|
|
2707 marginWidth: '0',
|
|
2708 marginHeight: '0',
|
|
2709 leftMargin: '0',
|
|
2710 topMargin: '0',
|
|
2711 allowTransparency: 'true',
|
|
2712 width: '100%'
|
|
2713 };
|
|
2714 if (this.get('autoHeight')) {
|
|
2715 config.scrolling = 'no';
|
|
2716 }
|
|
2717 for (var i in config) {
|
|
2718 if (Lang.hasOwnProperty(config, i)) {
|
|
2719 ifrmDom.setAttribute(i, config[i]);
|
|
2720 }
|
|
2721 }
|
|
2722 var isrc = 'javascript:;';
|
|
2723 if (this.browser.ie) {
|
|
2724 //isrc = 'about:blank';
|
|
2725 //TODO - Check this, I have changed it before..
|
|
2726 isrc = 'javascript:false;';
|
|
2727 }
|
|
2728 ifrmDom.setAttribute('src', isrc);
|
|
2729 var ifrm = new YAHOO.util.Element(ifrmDom);
|
|
2730 ifrm.setStyle('visibility', 'hidden');
|
|
2731 return ifrm;
|
|
2732 },
|
|
2733 /**
|
|
2734 * @private _isElement
|
|
2735 * @description Checks to see if an Element reference is a valid one and has a certain tag type
|
|
2736 * @param {HTMLElement} el The element to check
|
|
2737 * @param {String} tag The tag that the element needs to be
|
|
2738 * @return {Boolean}
|
|
2739 */
|
|
2740 _isElement: function(el, tag) {
|
|
2741 if (el && el.tagName && (el.tagName.toLowerCase() == tag)) {
|
|
2742 return true;
|
|
2743 }
|
|
2744 if (el && el.getAttribute && (el.getAttribute('tag') == tag)) {
|
|
2745 return true;
|
|
2746 }
|
|
2747 return false;
|
|
2748 },
|
|
2749 /**
|
|
2750 * @private _hasParent
|
|
2751 * @description Checks to see if an Element reference or one of it's parents is a valid one and has a certain tag type
|
|
2752 * @param {HTMLElement} el The element to check
|
|
2753 * @param {String} tag The tag that the element needs to be
|
|
2754 * @return HTMLElement
|
|
2755 */
|
|
2756 _hasParent: function(el, tag) {
|
|
2757 if (!el || !el.parentNode) {
|
|
2758 return false;
|
|
2759 }
|
|
2760
|
|
2761 while (el.parentNode) {
|
|
2762 if (this._isElement(el, tag)) {
|
|
2763 return el;
|
|
2764 }
|
|
2765 if (el.parentNode) {
|
|
2766 el = el.parentNode;
|
|
2767 } else {
|
|
2768 return false;
|
|
2769 }
|
|
2770 }
|
|
2771 return false;
|
|
2772 },
|
|
2773 /**
|
|
2774 * @private
|
|
2775 * @method _getDoc
|
|
2776 * @description Get the Document of the IFRAME
|
|
2777 * @return {Object}
|
|
2778 */
|
|
2779 _getDoc: function() {
|
|
2780 var value = false;
|
|
2781 try {
|
|
2782 if (this.get('iframe').get('element').contentWindow.document) {
|
|
2783 value = this.get('iframe').get('element').contentWindow.document;
|
|
2784 return value;
|
|
2785 }
|
|
2786 } catch (e) {
|
|
2787 return false;
|
|
2788 }
|
|
2789 },
|
|
2790 /**
|
|
2791 * @private
|
|
2792 * @method _getWindow
|
|
2793 * @description Get the Window of the IFRAME
|
|
2794 * @return {Object}
|
|
2795 */
|
|
2796 _getWindow: function() {
|
|
2797 return this.get('iframe').get('element').contentWindow;
|
|
2798 },
|
|
2799 /**
|
|
2800 * @method focus
|
|
2801 * @description Attempt to set the focus of the iframes window.
|
|
2802 */
|
|
2803 focus: function() {
|
|
2804 this._getWindow().focus();
|
|
2805 },
|
|
2806 /**
|
|
2807 * @private
|
|
2808 * @depreciated - This should not be used, moved to this.focus();
|
|
2809 * @method _focusWindow
|
|
2810 * @description Attempt to set the focus of the iframes window.
|
|
2811 */
|
|
2812 _focusWindow: function() {
|
|
2813 this.focus();
|
|
2814 },
|
|
2815 /**
|
|
2816 * @private
|
|
2817 * @method _hasSelection
|
|
2818 * @description Determines if there is a selection in the editor document.
|
|
2819 * @return {Boolean}
|
|
2820 */
|
|
2821 _hasSelection: function() {
|
|
2822 var sel = this._getSelection();
|
|
2823 var range = this._getRange();
|
|
2824 var hasSel = false;
|
|
2825
|
|
2826 if (!sel || !range) {
|
|
2827 return hasSel;
|
|
2828 }
|
|
2829
|
|
2830 //Internet Explorer
|
|
2831 if (this.browser.ie || this.browser.opera) {
|
|
2832 if (range.text) {
|
|
2833 hasSel = true;
|
|
2834 }
|
|
2835 if (range.html) {
|
|
2836 hasSel = true;
|
|
2837 }
|
|
2838 } else {
|
|
2839 if (this.browser.webkit) {
|
|
2840 if (sel+'' !== '') {
|
|
2841 hasSel = true;
|
|
2842 }
|
|
2843 } else {
|
|
2844 if (sel && (sel.toString() !== '') && (sel !== undefined)) {
|
|
2845 hasSel = true;
|
|
2846 }
|
|
2847 }
|
|
2848 }
|
|
2849 return hasSel;
|
|
2850 },
|
|
2851 /**
|
|
2852 * @private
|
|
2853 * @method _getSelection
|
|
2854 * @description Handles the different selection objects across the A-Grade list.
|
|
2855 * @return {Object} Selection Object
|
|
2856 */
|
|
2857 _getSelection: function() {
|
|
2858 var _sel = null;
|
|
2859 if (this._getDoc() && this._getWindow()) {
|
|
2860 if (this._getDoc().selection) {
|
|
2861 _sel = this._getDoc().selection;
|
|
2862 } else {
|
|
2863 _sel = this._getWindow().getSelection();
|
|
2864 }
|
|
2865 //Handle Safari's lack of Selection Object
|
|
2866 if (this.browser.webkit) {
|
|
2867 if (_sel.baseNode) {
|
|
2868 this._selection = {};
|
|
2869 this._selection.baseNode = _sel.baseNode;
|
|
2870 this._selection.baseOffset = _sel.baseOffset;
|
|
2871 this._selection.extentNode = _sel.extentNode;
|
|
2872 this._selection.extentOffset = _sel.extentOffset;
|
|
2873 } else if (this._selection !== null) {
|
|
2874 _sel = this._getWindow().getSelection();
|
|
2875 _sel.setBaseAndExtent(
|
|
2876 this._selection.baseNode,
|
|
2877 this._selection.baseOffset,
|
|
2878 this._selection.extentNode,
|
|
2879 this._selection.extentOffset);
|
|
2880 this._selection = null;
|
|
2881 }
|
|
2882 }
|
|
2883 }
|
|
2884 return _sel;
|
|
2885 },
|
|
2886 /**
|
|
2887 * @private
|
|
2888 * @method _selectNode
|
|
2889 * @description Places the highlight around a given node
|
|
2890 * @param {HTMLElement} node The node to select
|
|
2891 */
|
|
2892 _selectNode: function(node, collapse) {
|
|
2893 if (!node) {
|
|
2894 return false;
|
|
2895 }
|
|
2896 var sel = this._getSelection(),
|
|
2897 range = null;
|
|
2898
|
|
2899 if (this.browser.ie) {
|
|
2900 try { //IE freaks out here sometimes..
|
|
2901 range = this._getDoc().body.createTextRange();
|
|
2902 range.moveToElementText(node);
|
|
2903 range.select();
|
|
2904 } catch (e) {
|
|
2905 }
|
|
2906 } else if (this.browser.webkit) {
|
|
2907 if (collapse) {
|
|
2908 sel.setBaseAndExtent(node, 1, node, node.innerText.length);
|
|
2909 } else {
|
|
2910 sel.setBaseAndExtent(node, 0, node, node.innerText.length);
|
|
2911 }
|
|
2912 } else if (this.browser.opera) {
|
|
2913 sel = this._getWindow().getSelection();
|
|
2914 range = this._getDoc().createRange();
|
|
2915 range.selectNode(node);
|
|
2916 sel.removeAllRanges();
|
|
2917 sel.addRange(range);
|
|
2918 } else {
|
|
2919 range = this._getDoc().createRange();
|
|
2920 range.selectNodeContents(node);
|
|
2921 sel.removeAllRanges();
|
|
2922 sel.addRange(range);
|
|
2923 }
|
|
2924 //TODO - Check Performance
|
|
2925 this.nodeChange();
|
|
2926 },
|
|
2927 /**
|
|
2928 * @private
|
|
2929 * @method _getRange
|
|
2930 * @description Handles the different range objects across the A-Grade list.
|
|
2931 * @return {Object} Range Object
|
|
2932 */
|
|
2933 _getRange: function() {
|
|
2934 var sel = this._getSelection();
|
|
2935
|
|
2936 if (sel === null) {
|
|
2937 return null;
|
|
2938 }
|
|
2939
|
|
2940 if (this.browser.webkit && !sel.getRangeAt) {
|
|
2941 var _range = this._getDoc().createRange();
|
|
2942 try {
|
|
2943 _range.setStart(sel.anchorNode, sel.anchorOffset);
|
|
2944 _range.setEnd(sel.focusNode, sel.focusOffset);
|
|
2945 } catch (e) {
|
|
2946 _range = this._getWindow().getSelection()+'';
|
|
2947 }
|
|
2948 return _range;
|
|
2949 }
|
|
2950
|
|
2951 if (this.browser.ie || this.browser.opera) {
|
|
2952 try {
|
|
2953 return sel.createRange();
|
|
2954 } catch (e2) {
|
|
2955 return null;
|
|
2956 }
|
|
2957 }
|
|
2958
|
|
2959 if (sel.rangeCount > 0) {
|
|
2960 return sel.getRangeAt(0);
|
|
2961 }
|
|
2962 return null;
|
|
2963 },
|
|
2964 /**
|
|
2965 * @private
|
|
2966 * @method _setDesignMode
|
|
2967 * @description Sets the designMode property of the iFrame document's body.
|
|
2968 * @param {String} state This should be either on or off
|
|
2969 */
|
|
2970 _setDesignMode: function(state) {
|
|
2971 if (this.get('setDesignMode')) {
|
|
2972 try {
|
|
2973 this._getDoc().designMode = ((state.toLowerCase() == 'off') ? 'off' : 'on');
|
|
2974 } catch(e) { }
|
|
2975 }
|
|
2976 },
|
|
2977 /**
|
|
2978 * @private
|
|
2979 * @method _toggleDesignMode
|
|
2980 * @description Toggles the designMode property of the iFrame document on and off.
|
|
2981 * @return {String} The state that it was set to.
|
|
2982 */
|
|
2983 _toggleDesignMode: function() {
|
|
2984 var _dMode = this._getDoc().designMode,
|
|
2985 _state = ((_dMode.toLowerCase() == 'on') ? 'off' : 'on');
|
|
2986 this._setDesignMode(_state);
|
|
2987 return _state;
|
|
2988 },
|
|
2989 /**
|
|
2990 * @private
|
|
2991 * @property _focused
|
|
2992 * @description Holder for trapping focus/blur state and prevent double events
|
|
2993 * @type Boolean
|
|
2994 */
|
|
2995 _focused: null,
|
|
2996 /**
|
|
2997 * @private
|
|
2998 * @method _handleFocus
|
|
2999 * @description Handles the focus of the iframe. Note, this is window focus event, not an Editor focus event.
|
|
3000 * @param {Event} e The DOM Event
|
|
3001 */
|
|
3002 _handleFocus: function(e) {
|
|
3003 if (!this._focused) {
|
|
3004 this._focused = true;
|
|
3005 this.fireEvent('editorWindowFocus', { type: 'editorWindowFocus', target: this });
|
|
3006 }
|
|
3007 },
|
|
3008 /**
|
|
3009 * @private
|
|
3010 * @method _handleBlur
|
|
3011 * @description Handles the blur of the iframe. Note, this is window blur event, not an Editor blur event.
|
|
3012 * @param {Event} e The DOM Event
|
|
3013 */
|
|
3014 _handleBlur: function(e) {
|
|
3015 if (this._focused) {
|
|
3016 this._focused = false;
|
|
3017 this.fireEvent('editorWindowBlur', { type: 'editorWindowBlur', target: this });
|
|
3018 }
|
|
3019 },
|
|
3020 /**
|
|
3021 * @private
|
|
3022 * @method _initEditorEvents
|
|
3023 * @description This method sets up the listeners on the Editors document.
|
|
3024 */
|
|
3025 _initEditorEvents: function() {
|
|
3026 //Setup Listeners on iFrame
|
|
3027 var doc = this._getDoc(),
|
|
3028 win = this._getWindow();
|
|
3029
|
|
3030 Event.on(doc, 'mouseup', this._handleMouseUp, this, true);
|
|
3031 Event.on(doc, 'mousedown', this._handleMouseDown, this, true);
|
|
3032 Event.on(doc, 'click', this._handleClick, this, true);
|
|
3033 Event.on(doc, 'dblclick', this._handleDoubleClick, this, true);
|
|
3034 Event.on(doc, 'keypress', this._handleKeyPress, this, true);
|
|
3035 Event.on(doc, 'keyup', this._handleKeyUp, this, true);
|
|
3036 Event.on(doc, 'keydown', this._handleKeyDown, this, true);
|
|
3037 /* TODO -- Everyone but Opera works here..
|
|
3038 Event.on(doc, 'paste', function() {
|
|
3039 }, this, true);
|
|
3040 */
|
|
3041
|
|
3042 //Focus and blur..
|
|
3043 Event.on(win, 'focus', this._handleFocus, this, true);
|
|
3044 Event.on(win, 'blur', this._handleBlur, this, true);
|
|
3045 },
|
|
3046 /**
|
|
3047 * @private
|
|
3048 * @method _removeEditorEvents
|
|
3049 * @description This method removes the listeners on the Editors document (for disabling).
|
|
3050 */
|
|
3051 _removeEditorEvents: function() {
|
|
3052 //Remove Listeners on iFrame
|
|
3053 var doc = this._getDoc(),
|
|
3054 win = this._getWindow();
|
|
3055
|
|
3056 Event.removeListener(doc, 'mouseup', this._handleMouseUp, this, true);
|
|
3057 Event.removeListener(doc, 'mousedown', this._handleMouseDown, this, true);
|
|
3058 Event.removeListener(doc, 'click', this._handleClick, this, true);
|
|
3059 Event.removeListener(doc, 'dblclick', this._handleDoubleClick, this, true);
|
|
3060 Event.removeListener(doc, 'keypress', this._handleKeyPress, this, true);
|
|
3061 Event.removeListener(doc, 'keyup', this._handleKeyUp, this, true);
|
|
3062 Event.removeListener(doc, 'keydown', this._handleKeyDown, this, true);
|
|
3063
|
|
3064 //Focus and blur..
|
|
3065 Event.removeListener(win, 'focus', this._handleFocus, this, true);
|
|
3066 Event.removeListener(win, 'blur', this._handleBlur, this, true);
|
|
3067 },
|
|
3068 _fixWebkitDivs: function() {
|
|
3069 if (this.browser.webkit) {
|
|
3070 var divs = this._getDoc().body.getElementsByTagName('div');
|
|
3071 Dom.addClass(divs, 'yui-wk-div');
|
|
3072 }
|
|
3073 },
|
|
3074 /**
|
|
3075 * @private
|
|
3076 * @method _initEditor
|
|
3077 * @param {Boolean} raw Don't add events.
|
|
3078 * @description This method is fired from _checkLoaded when the document is ready. It turns on designMode and set's up the listeners.
|
|
3079 */
|
|
3080 _initEditor: function(raw) {
|
|
3081 if (this._editorInit) {
|
|
3082 return;
|
|
3083 }
|
|
3084 this._editorInit = true;
|
|
3085 if (this.browser.ie) {
|
|
3086 this._getDoc().body.style.margin = '0';
|
|
3087 }
|
|
3088 if (!this.get('disabled')) {
|
|
3089 this._setDesignMode('on');
|
|
3090 this._contentTimerCounter = 0;
|
|
3091 }
|
|
3092 if (!this._getDoc().body) {
|
|
3093 this._contentTimerCounter = 0;
|
|
3094 this._editorInit = false;
|
|
3095 this._checkLoaded();
|
|
3096 return false;
|
|
3097 }
|
|
3098
|
|
3099 if (!raw) {
|
|
3100 this.toolbar.on('buttonClick', this._handleToolbarClick, this, true);
|
|
3101 }
|
|
3102 if (!this.get('disabled')) {
|
|
3103 this._initEditorEvents();
|
|
3104 this.toolbar.set('disabled', false);
|
|
3105 }
|
|
3106
|
|
3107 if (raw) {
|
|
3108 this.fireEvent('editorContentReloaded', { type: 'editorreloaded', target: this });
|
|
3109 } else {
|
|
3110 this.fireEvent('editorContentLoaded', { type: 'editorLoaded', target: this });
|
|
3111 }
|
|
3112 this._fixWebkitDivs();
|
|
3113 if (this.get('dompath')) {
|
|
3114 var self = this;
|
|
3115 setTimeout(function() {
|
|
3116 self._writeDomPath.call(self);
|
|
3117 self._setupResize.call(self);
|
|
3118 }, 150);
|
|
3119 }
|
|
3120 var br = [];
|
|
3121 for (var i in this.browser) {
|
|
3122 if (this.browser[i]) {
|
|
3123 br.push(i);
|
|
3124 }
|
|
3125 }
|
|
3126 if (this.get('ptags')) {
|
|
3127 br.push('ptags');
|
|
3128 }
|
|
3129 Dom.addClass(this._getDoc().body, br.join(' '));
|
|
3130 this.nodeChange(true);
|
|
3131 },
|
|
3132 /**
|
|
3133 * @private
|
|
3134 * @method _checkLoaded
|
|
3135 * @param {Boolean} raw Don't add events.
|
|
3136 * @description Called from a setTimeout loop to check if the iframes body.onload event has fired, then it will init the editor.
|
|
3137 */
|
|
3138 _checkLoaded: function(raw) {
|
|
3139 this._editorInit = false;
|
|
3140 this._contentTimerCounter++;
|
|
3141 if (this._contentTimer) {
|
|
3142 clearTimeout(this._contentTimer);
|
|
3143 }
|
|
3144 if (this._contentTimerCounter > this._contentTimerMax) {
|
|
3145 return false;
|
|
3146 }
|
|
3147 var init = false;
|
|
3148 try {
|
|
3149 if (this._getDoc() && this._getDoc().body) {
|
|
3150 if (this.browser.ie) {
|
|
3151 if (this._getDoc().body.readyState == 'complete') {
|
|
3152 init = true;
|
|
3153 }
|
|
3154 } else {
|
|
3155 if (this._getDoc().body._rteLoaded === true) {
|
|
3156 init = true;
|
|
3157 }
|
|
3158 }
|
|
3159 }
|
|
3160 } catch (e) {
|
|
3161 init = false;
|
|
3162 }
|
|
3163
|
|
3164 if (init === true) {
|
|
3165 //The onload event has fired, clean up after ourselves and fire the _initEditor method
|
|
3166 this._initEditor(raw);
|
|
3167 } else {
|
|
3168 var self = this;
|
|
3169 this._contentTimer = setTimeout(function() {
|
|
3170 self._checkLoaded.call(self, raw);
|
|
3171 }, 20);
|
|
3172 }
|
|
3173 },
|
|
3174 /**
|
|
3175 * @private
|
|
3176 * @method _setInitialContent
|
|
3177 * @param {Boolean} raw Don't add events.
|
|
3178 * @description This method will open the iframes content document and write the textareas value into it, then start the body.onload checking.
|
|
3179 */
|
|
3180 _setInitialContent: function(raw) {
|
|
3181
|
|
3182 var value = ((this._textarea) ? this.get('element').value : this.get('element').innerHTML),
|
|
3183 doc = null;
|
|
3184
|
|
3185 if (value === '') {
|
|
3186 value = '<br>';
|
|
3187 }
|
|
3188
|
|
3189 var html = Lang.substitute(this.get('html'), {
|
|
3190 TITLE: this.STR_TITLE,
|
|
3191 CONTENT: this._cleanIncomingHTML(value),
|
|
3192 CSS: this.get('css'),
|
|
3193 HIDDEN_CSS: ((this.get('hiddencss')) ? this.get('hiddencss') : '/* No Hidden CSS */'),
|
|
3194 EXTRA_CSS: ((this.get('extracss')) ? this.get('extracss') : '/* No Extra CSS */')
|
|
3195 }),
|
|
3196 check = true;
|
|
3197
|
|
3198 html = html.replace(/RIGHT_BRACKET/gi, '{');
|
|
3199 html = html.replace(/LEFT_BRACKET/gi, '}');
|
|
3200
|
|
3201 if (document.compatMode != 'BackCompat') {
|
|
3202 html = this._docType + "\n" + html;
|
|
3203 } else {
|
|
3204 }
|
|
3205
|
|
3206 if (this.browser.ie || this.browser.webkit || this.browser.opera || (navigator.userAgent.indexOf('Firefox/1.5') != -1)) {
|
|
3207 //Firefox 1.5 doesn't like setting designMode on an document created with a data url
|
|
3208 try {
|
|
3209 //Adobe AIR Code
|
|
3210 if (this.browser.air) {
|
|
3211 doc = this._getDoc().implementation.createHTMLDocument();
|
|
3212 var origDoc = this._getDoc();
|
|
3213 origDoc.open();
|
|
3214 origDoc.close();
|
|
3215 doc.open();
|
|
3216 doc.write(html);
|
|
3217 doc.close();
|
|
3218 var node = origDoc.importNode(doc.getElementsByTagName("html")[0], true);
|
|
3219 origDoc.replaceChild(node, origDoc.getElementsByTagName("html")[0]);
|
|
3220 origDoc.body._rteLoaded = true;
|
|
3221 } else {
|
|
3222 doc = this._getDoc();
|
|
3223 doc.open();
|
|
3224 doc.write(html);
|
|
3225 doc.close();
|
|
3226 }
|
|
3227 } catch (e) {
|
|
3228 //Safari will only be here if we are hidden
|
|
3229 check = false;
|
|
3230 }
|
|
3231 } else {
|
|
3232 //This keeps Firefox 2 from writing the iframe to history preserving the back buttons functionality
|
|
3233 this.get('iframe').get('element').src = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
|
|
3234 }
|
|
3235 this.get('iframe').setStyle('visibility', '');
|
|
3236 if (check) {
|
|
3237 this._checkLoaded(raw);
|
|
3238 }
|
|
3239 },
|
|
3240 /**
|
|
3241 * @private
|
|
3242 * @method _setMarkupType
|
|
3243 * @param {String} action The action to take. Possible values are: css, default or semantic
|
|
3244 * @description This method will turn on/off the useCSS execCommand.
|
|
3245 */
|
|
3246 _setMarkupType: function(action) {
|
|
3247 switch (this.get('markup')) {
|
|
3248 case 'css':
|
|
3249 this._setEditorStyle(true);
|
|
3250 break;
|
|
3251 case 'default':
|
|
3252 this._setEditorStyle(false);
|
|
3253 break;
|
|
3254 case 'semantic':
|
|
3255 case 'xhtml':
|
|
3256 if (this._semantic[action]) {
|
|
3257 this._setEditorStyle(false);
|
|
3258 } else {
|
|
3259 this._setEditorStyle(true);
|
|
3260 }
|
|
3261 break;
|
|
3262 }
|
|
3263 },
|
|
3264 /**
|
|
3265 * Set the editor to use CSS instead of HTML
|
|
3266 * @param {Booleen} stat True/False
|
|
3267 */
|
|
3268 _setEditorStyle: function(stat) {
|
|
3269 try {
|
|
3270 this._getDoc().execCommand('useCSS', false, !stat);
|
|
3271 } catch (ex) {
|
|
3272 }
|
|
3273 },
|
|
3274 /**
|
|
3275 * @private
|
|
3276 * @method _getSelectedElement
|
|
3277 * @description This method will attempt to locate the element that was last interacted with, either via selection, location or event.
|
|
3278 * @return {HTMLElement} The currently selected element.
|
|
3279 */
|
|
3280 _getSelectedElement: function() {
|
|
3281 var doc = this._getDoc(),
|
|
3282 range = null,
|
|
3283 sel = null,
|
|
3284 elm = null,
|
|
3285 check = true;
|
|
3286
|
|
3287 if (this.browser.ie) {
|
|
3288 this.currentEvent = this._getWindow().event; //Event utility assumes window.event, so we need to reset it to this._getWindow().event;
|
|
3289 range = this._getRange();
|
|
3290 if (range) {
|
|
3291 elm = range.item ? range.item(0) : range.parentElement();
|
|
3292 if (this._hasSelection()) {
|
|
3293 //TODO
|
|
3294 //WTF.. Why can't I get an element reference here?!??!
|
|
3295 }
|
|
3296 if (elm === doc.body) {
|
|
3297 elm = null;
|
|
3298 }
|
|
3299 }
|
|
3300 if ((this.currentEvent !== null) && (this.currentEvent.keyCode === 0)) {
|
|
3301 elm = Event.getTarget(this.currentEvent);
|
|
3302 }
|
|
3303 } else {
|
|
3304 sel = this._getSelection();
|
|
3305 range = this._getRange();
|
|
3306
|
|
3307 if (!sel || !range) {
|
|
3308 return null;
|
|
3309 }
|
|
3310 //TODO
|
|
3311 if (!this._hasSelection() && this.browser.webkit3) {
|
|
3312 //check = false;
|
|
3313 }
|
|
3314 if (this.browser.gecko) {
|
|
3315 //Added in 2.6.0
|
|
3316 if (range.startContainer) {
|
|
3317 if (range.startContainer.nodeType === 3) {
|
|
3318 elm = range.startContainer.parentNode;
|
|
3319 } else if (range.startContainer.nodeType === 1) {
|
|
3320 elm = range.startContainer;
|
|
3321 }
|
|
3322 //Added in 2.7.0
|
|
3323 if (this.currentEvent) {
|
|
3324 var tar = Event.getTarget(this.currentEvent);
|
|
3325 if (!this._isElement(tar, 'html')) {
|
|
3326 if (elm !== tar) {
|
|
3327 elm = tar;
|
|
3328 }
|
|
3329 }
|
|
3330 }
|
|
3331 }
|
|
3332 }
|
|
3333
|
|
3334 if (check) {
|
|
3335 if (sel.anchorNode && (sel.anchorNode.nodeType == 3)) {
|
|
3336 if (sel.anchorNode.parentNode) { //next check parentNode
|
|
3337 elm = sel.anchorNode.parentNode;
|
|
3338 }
|
|
3339 if (sel.anchorNode.nextSibling != sel.focusNode.nextSibling) {
|
|
3340 elm = sel.anchorNode.nextSibling;
|
|
3341 }
|
|
3342 }
|
|
3343 if (this._isElement(elm, 'br')) {
|
|
3344 elm = null;
|
|
3345 }
|
|
3346 if (!elm) {
|
|
3347 elm = range.commonAncestorContainer;
|
|
3348 if (!range.collapsed) {
|
|
3349 if (range.startContainer == range.endContainer) {
|
|
3350 if (range.startOffset - range.endOffset < 2) {
|
|
3351 if (range.startContainer.hasChildNodes()) {
|
|
3352 elm = range.startContainer.childNodes[range.startOffset];
|
|
3353 }
|
|
3354 }
|
|
3355 }
|
|
3356 }
|
|
3357 }
|
|
3358 }
|
|
3359 }
|
|
3360
|
|
3361 if (this.currentEvent !== null) {
|
|
3362 try {
|
|
3363 switch (this.currentEvent.type) {
|
|
3364 case 'click':
|
|
3365 case 'mousedown':
|
|
3366 case 'mouseup':
|
|
3367 if (this.browser.webkit) {
|
|
3368 elm = Event.getTarget(this.currentEvent);
|
|
3369 }
|
|
3370 break;
|
|
3371 default:
|
|
3372 //Do nothing
|
|
3373 break;
|
|
3374 }
|
|
3375 } catch (e) {
|
|
3376 }
|
|
3377 } else if ((this.currentElement && this.currentElement[0]) && (!this.browser.ie)) {
|
|
3378 //TODO is this still needed?
|
|
3379 //elm = this.currentElement[0];
|
|
3380 }
|
|
3381
|
|
3382
|
|
3383 if (this.browser.opera || this.browser.webkit) {
|
|
3384 if (this.currentEvent && !elm) {
|
|
3385 elm = YAHOO.util.Event.getTarget(this.currentEvent);
|
|
3386 }
|
|
3387 }
|
|
3388 if (!elm || !elm.tagName) {
|
|
3389 elm = doc.body;
|
|
3390 }
|
|
3391 if (this._isElement(elm, 'html')) {
|
|
3392 //Safari sometimes gives us the HTML node back..
|
|
3393 elm = doc.body;
|
|
3394 }
|
|
3395 if (this._isElement(elm, 'body')) {
|
|
3396 //make sure that body means this body not the parent..
|
|
3397 elm = doc.body;
|
|
3398 }
|
|
3399 if (elm && !elm.parentNode) { //Not in document
|
|
3400 elm = doc.body;
|
|
3401 }
|
|
3402 if (elm === undefined) {
|
|
3403 elm = null;
|
|
3404 }
|
|
3405 return elm;
|
|
3406 },
|
|
3407 /**
|
|
3408 * @private
|
|
3409 * @method _getDomPath
|
|
3410 * @description This method will attempt to build the DOM path from the currently selected element.
|
|
3411 * @param HTMLElement el The element to start with, if not provided _getSelectedElement is used
|
|
3412 * @return {Array} An array of node references that will create the DOM Path.
|
|
3413 */
|
|
3414 _getDomPath: function(el) {
|
|
3415 if (!el) {
|
|
3416 el = this._getSelectedElement();
|
|
3417 }
|
|
3418 var domPath = [];
|
|
3419 while (el !== null) {
|
|
3420 if (el.ownerDocument != this._getDoc()) {
|
|
3421 el = null;
|
|
3422 break;
|
|
3423 }
|
|
3424 //Check to see if we get el.nodeName and nodeType
|
|
3425 if (el.nodeName && el.nodeType && (el.nodeType == 1)) {
|
|
3426 domPath[domPath.length] = el;
|
|
3427 }
|
|
3428
|
|
3429 if (this._isElement(el, 'body')) {
|
|
3430 break;
|
|
3431 }
|
|
3432
|
|
3433 el = el.parentNode;
|
|
3434 }
|
|
3435 if (domPath.length === 0) {
|
|
3436 if (this._getDoc() && this._getDoc().body) {
|
|
3437 domPath[0] = this._getDoc().body;
|
|
3438 }
|
|
3439 }
|
|
3440 return domPath.reverse();
|
|
3441 },
|
|
3442 /**
|
|
3443 * @private
|
|
3444 * @method _writeDomPath
|
|
3445 * @description Write the current DOM path out to the dompath container below the editor.
|
|
3446 */
|
|
3447 _writeDomPath: function() {
|
|
3448 var path = this._getDomPath(),
|
|
3449 pathArr = [],
|
|
3450 classPath = '',
|
|
3451 pathStr = '';
|
|
3452
|
|
3453 for (var i = 0; i < path.length; i++) {
|
|
3454 var tag = path[i].tagName.toLowerCase();
|
|
3455 if ((tag == 'ol') && (path[i].type)) {
|
|
3456 tag += ':' + path[i].type;
|
|
3457 }
|
|
3458 if (Dom.hasClass(path[i], 'yui-tag')) {
|
|
3459 tag = path[i].getAttribute('tag');
|
|
3460 }
|
|
3461 if ((this.get('markup') == 'semantic') || (this.get('markup') == 'xhtml')) {
|
|
3462 switch (tag) {
|
|
3463 case 'b': tag = 'strong'; break;
|
|
3464 case 'i': tag = 'em'; break;
|
|
3465 }
|
|
3466 }
|
|
3467 if (!Dom.hasClass(path[i], 'yui-non')) {
|
|
3468 if (Dom.hasClass(path[i], 'yui-tag')) {
|
|
3469 pathStr = tag;
|
|
3470 } else {
|
|
3471 classPath = ((path[i].className !== '') ? '.' + path[i].className.replace(/ /g, '.') : '');
|
|
3472 if ((classPath.indexOf('yui') != -1) || (classPath.toLowerCase().indexOf('apple-style-span') != -1)) {
|
|
3473 classPath = '';
|
|
3474 }
|
|
3475 pathStr = tag + ((path[i].id) ? '#' + path[i].id : '') + classPath;
|
|
3476 }
|
|
3477 switch (tag) {
|
|
3478 case 'body':
|
|
3479 pathStr = 'body';
|
|
3480 break;
|
|
3481 case 'a':
|
|
3482 if (path[i].getAttribute('href', 2)) {
|
|
3483 pathStr += ':' + path[i].getAttribute('href', 2).replace('mailto:', '').replace('http:/'+'/', '').replace('https:/'+'/', ''); //May need to add others here ftp
|
|
3484 }
|
|
3485 break;
|
|
3486 case 'img':
|
|
3487 var h = path[i].height;
|
|
3488 var w = path[i].width;
|
|
3489 if (path[i].style.height) {
|
|
3490 h = parseInt(path[i].style.height, 10);
|
|
3491 }
|
|
3492 if (path[i].style.width) {
|
|
3493 w = parseInt(path[i].style.width, 10);
|
|
3494 }
|
|
3495 pathStr += '(' + w + 'x' + h + ')';
|
|
3496 break;
|
|
3497 }
|
|
3498
|
|
3499 if (pathStr.length > 10) {
|
|
3500 pathStr = '<span title="' + pathStr + '">' + pathStr.substring(0, 10) + '...' + '</span>';
|
|
3501 } else {
|
|
3502 pathStr = '<span title="' + pathStr + '">' + pathStr + '</span>';
|
|
3503 }
|
|
3504 pathArr[pathArr.length] = pathStr;
|
|
3505 }
|
|
3506 }
|
|
3507 var str = pathArr.join(' ' + this.SEP_DOMPATH + ' ');
|
|
3508 //Prevent flickering
|
|
3509 if (this.dompath.innerHTML != str) {
|
|
3510 this.dompath.innerHTML = str;
|
|
3511 }
|
|
3512 },
|
|
3513 /**
|
|
3514 * @private
|
|
3515 * @method _fixNodes
|
|
3516 * @description Fix href and imgs as well as remove invalid HTML.
|
|
3517 */
|
|
3518 _fixNodes: function() {
|
|
3519 try {
|
|
3520 var doc = this._getDoc(),
|
|
3521 els = [];
|
|
3522
|
|
3523 for (var v in this.invalidHTML) {
|
|
3524 if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
|
|
3525 if (v.toLowerCase() != 'span') {
|
|
3526 var tags = doc.body.getElementsByTagName(v);
|
|
3527 if (tags.length) {
|
|
3528 for (var i = 0; i < tags.length; i++) {
|
|
3529 els.push(tags[i]);
|
|
3530 }
|
|
3531 }
|
|
3532 }
|
|
3533 }
|
|
3534 }
|
|
3535 for (var h = 0; h < els.length; h++) {
|
|
3536 if (els[h].parentNode) {
|
|
3537 if (Lang.isObject(this.invalidHTML[els[h].tagName.toLowerCase()]) && this.invalidHTML[els[h].tagName.toLowerCase()].keepContents) {
|
|
3538 this._swapEl(els[h], 'span', function(el) {
|
|
3539 el.className = 'yui-non';
|
|
3540 });
|
|
3541 } else {
|
|
3542 els[h].parentNode.removeChild(els[h]);
|
|
3543 }
|
|
3544 }
|
|
3545 }
|
|
3546 var imgs = this._getDoc().getElementsByTagName('img');
|
|
3547 Dom.addClass(imgs, 'yui-img');
|
|
3548 } catch(e) {}
|
|
3549 },
|
|
3550 /**
|
|
3551 * @private
|
|
3552 * @method _isNonEditable
|
|
3553 * @param Event ev The Dom event being checked
|
|
3554 * @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.
|
|
3555 * 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
|
|
3556 * disable and enable the Editor's toolbar based on the noedit state.
|
|
3557 * @return Boolean
|
|
3558 */
|
|
3559 _isNonEditable: function(ev) {
|
|
3560 if (this.get('allowNoEdit')) {
|
|
3561 var el = Event.getTarget(ev);
|
|
3562 if (this._isElement(el, 'html')) {
|
|
3563 el = null;
|
|
3564 }
|
|
3565 var path = this._getDomPath(el);
|
|
3566 for (var i = (path.length - 1); i > -1; i--) {
|
|
3567 if (Dom.hasClass(path[i], this.CLASS_NOEDIT)) {
|
|
3568 //if (this.toolbar.get('disabled') === false) {
|
|
3569 // this.toolbar.set('disabled', true);
|
|
3570 //}
|
|
3571 try {
|
|
3572 this._getDoc().execCommand('enableObjectResizing', false, 'false');
|
|
3573 } catch (e) {}
|
|
3574 this.nodeChange();
|
|
3575 Event.stopEvent(ev);
|
|
3576 return true;
|
|
3577 }
|
|
3578 }
|
|
3579 //if (this.toolbar.get('disabled') === true) {
|
|
3580 //Should only happen once..
|
|
3581 //this.toolbar.set('disabled', false);
|
|
3582 try {
|
|
3583 this._getDoc().execCommand('enableObjectResizing', false, 'true');
|
|
3584 } catch (e2) {}
|
|
3585 //}
|
|
3586 }
|
|
3587 return false;
|
|
3588 },
|
|
3589 /**
|
|
3590 * @private
|
|
3591 * @method _setCurrentEvent
|
|
3592 * @param {Event} ev The event to cache
|
|
3593 * @description Sets the current event property
|
|
3594 */
|
|
3595 _setCurrentEvent: function(ev) {
|
|
3596 this.currentEvent = ev;
|
|
3597 },
|
|
3598 /**
|
|
3599 * @private
|
|
3600 * @method _handleClick
|
|
3601 * @param {Event} ev The event we are working on.
|
|
3602 * @description Handles all click events inside the iFrame document.
|
|
3603 */
|
|
3604 _handleClick: function(ev) {
|
|
3605 var ret = this.fireEvent('beforeEditorClick', { type: 'beforeEditorClick', target: this, ev: ev });
|
|
3606 if (ret === false) {
|
|
3607 return false;
|
|
3608 }
|
|
3609 if (this._isNonEditable(ev)) {
|
|
3610 return false;
|
|
3611 }
|
|
3612 this._setCurrentEvent(ev);
|
|
3613 if (this.currentWindow) {
|
|
3614 this.closeWindow();
|
|
3615 }
|
|
3616 if (this.currentWindow) {
|
|
3617 this.closeWindow();
|
|
3618 }
|
|
3619 if (this.browser.webkit) {
|
|
3620 var tar =Event.getTarget(ev);
|
|
3621 if (this._isElement(tar, 'a') || this._isElement(tar.parentNode, 'a')) {
|
|
3622 Event.stopEvent(ev);
|
|
3623 this.nodeChange();
|
|
3624 }
|
|
3625 } else {
|
|
3626 this.nodeChange();
|
|
3627 }
|
|
3628 this.fireEvent('editorClick', { type: 'editorClick', target: this, ev: ev });
|
|
3629 },
|
|
3630 /**
|
|
3631 * @private
|
|
3632 * @method _handleMouseUp
|
|
3633 * @param {Event} ev The event we are working on.
|
|
3634 * @description Handles all mouseup events inside the iFrame document.
|
|
3635 */
|
|
3636 _handleMouseUp: function(ev) {
|
|
3637 var ret = this.fireEvent('beforeEditorMouseUp', { type: 'beforeEditorMouseUp', target: this, ev: ev });
|
|
3638 if (ret === false) {
|
|
3639 return false;
|
|
3640 }
|
|
3641 if (this._isNonEditable(ev)) {
|
|
3642 return false;
|
|
3643 }
|
|
3644 //Don't set current event for mouseup.
|
|
3645 //It get's fired after a menu is closed and gives up a bogus event to work with
|
|
3646 //this._setCurrentEvent(ev);
|
|
3647 var self = this;
|
|
3648 if (this.browser.opera) {
|
|
3649 /*
|
|
3650 * @knownissue Opera appears to stop the MouseDown, Click and DoubleClick events on an image inside of a document with designMode on..
|
|
3651 * @browser Opera
|
|
3652 * @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.
|
|
3653 */
|
|
3654 var sel = Event.getTarget(ev);
|
|
3655 if (this._isElement(sel, 'img')) {
|
|
3656 this.nodeChange();
|
|
3657 if (this.operaEvent) {
|
|
3658 clearTimeout(this.operaEvent);
|
|
3659 this.operaEvent = null;
|
|
3660 this._handleDoubleClick(ev);
|
|
3661 } else {
|
|
3662 this.operaEvent = window.setTimeout(function() {
|
|
3663 self.operaEvent = false;
|
|
3664 }, 700);
|
|
3665 }
|
|
3666 }
|
|
3667 }
|
|
3668 //This will stop Safari from selecting the entire document if you select all the text in the editor
|
|
3669 if (this.browser.webkit || this.browser.opera) {
|
|
3670 if (this.browser.webkit) {
|
|
3671 Event.stopEvent(ev);
|
|
3672 }
|
|
3673 }
|
|
3674 this.nodeChange();
|
|
3675 this.fireEvent('editorMouseUp', { type: 'editorMouseUp', target: this, ev: ev });
|
|
3676 },
|
|
3677 /**
|
|
3678 * @private
|
|
3679 * @method _handleMouseDown
|
|
3680 * @param {Event} ev The event we are working on.
|
|
3681 * @description Handles all mousedown events inside the iFrame document.
|
|
3682 */
|
|
3683 _handleMouseDown: function(ev) {
|
|
3684 var ret = this.fireEvent('beforeEditorMouseDown', { type: 'beforeEditorMouseDown', target: this, ev: ev });
|
|
3685 if (ret === false) {
|
|
3686 return false;
|
|
3687 }
|
|
3688 if (this._isNonEditable(ev)) {
|
|
3689 return false;
|
|
3690 }
|
|
3691 this._setCurrentEvent(ev);
|
|
3692 var sel = Event.getTarget(ev);
|
|
3693 if (this.browser.webkit && this._hasSelection()) {
|
|
3694 var _sel = this._getSelection();
|
|
3695 if (!this.browser.webkit3) {
|
|
3696 _sel.collapse(true);
|
|
3697 } else {
|
|
3698 _sel.collapseToStart();
|
|
3699 }
|
|
3700 }
|
|
3701 if (this.browser.webkit && this._lastImage) {
|
|
3702 Dom.removeClass(this._lastImage, 'selected');
|
|
3703 this._lastImage = null;
|
|
3704 }
|
|
3705 if (this._isElement(sel, 'img') || this._isElement(sel, 'a')) {
|
|
3706 if (this.browser.webkit) {
|
|
3707 Event.stopEvent(ev);
|
|
3708 if (this._isElement(sel, 'img')) {
|
|
3709 Dom.addClass(sel, 'selected');
|
|
3710 this._lastImage = sel;
|
|
3711 }
|
|
3712 }
|
|
3713 if (this.currentWindow) {
|
|
3714 this.closeWindow();
|
|
3715 }
|
|
3716 this.nodeChange();
|
|
3717 }
|
|
3718 this.fireEvent('editorMouseDown', { type: 'editorMouseDown', target: this, ev: ev });
|
|
3719 },
|
|
3720 /**
|
|
3721 * @private
|
|
3722 * @method _handleDoubleClick
|
|
3723 * @param {Event} ev The event we are working on.
|
|
3724 * @description Handles all doubleclick events inside the iFrame document.
|
|
3725 */
|
|
3726 _handleDoubleClick: function(ev) {
|
|
3727 var ret = this.fireEvent('beforeEditorDoubleClick', { type: 'beforeEditorDoubleClick', target: this, ev: ev });
|
|
3728 if (ret === false) {
|
|
3729 return false;
|
|
3730 }
|
|
3731 if (this._isNonEditable(ev)) {
|
|
3732 return false;
|
|
3733 }
|
|
3734 this._setCurrentEvent(ev);
|
|
3735 var sel = Event.getTarget(ev);
|
|
3736 if (this._isElement(sel, 'img')) {
|
|
3737 this.currentElement[0] = sel;
|
|
3738 this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
|
|
3739 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
3740 } else if (this._hasParent(sel, 'a')) { //Handle elements inside an a
|
|
3741 this.currentElement[0] = this._hasParent(sel, 'a');
|
|
3742 this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
|
|
3743 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
3744 }
|
|
3745 this.nodeChange();
|
|
3746 this.fireEvent('editorDoubleClick', { type: 'editorDoubleClick', target: this, ev: ev });
|
|
3747 },
|
|
3748 /**
|
|
3749 * @private
|
|
3750 * @method _handleKeyUp
|
|
3751 * @param {Event} ev The event we are working on.
|
|
3752 * @description Handles all keyup events inside the iFrame document.
|
|
3753 */
|
|
3754 _handleKeyUp: function(ev) {
|
|
3755 var ret = this.fireEvent('beforeEditorKeyUp', { type: 'beforeEditorKeyUp', target: this, ev: ev });
|
|
3756 if (ret === false) {
|
|
3757 return false;
|
|
3758 }
|
|
3759 if (this._isNonEditable(ev)) {
|
|
3760 return false;
|
|
3761 }
|
|
3762 this._storeUndo();
|
|
3763 this._setCurrentEvent(ev);
|
|
3764 switch (ev.keyCode) {
|
|
3765 case this._keyMap.SELECT_ALL.key:
|
|
3766 if (this._checkKey(this._keyMap.SELECT_ALL, ev)) {
|
|
3767 this.nodeChange();
|
|
3768 }
|
|
3769 break;
|
|
3770 case 32: //Space Bar
|
|
3771 case 35: //End
|
|
3772 case 36: //Home
|
|
3773 case 37: //Left Arrow
|
|
3774 case 38: //Up Arrow
|
|
3775 case 39: //Right Arrow
|
|
3776 case 40: //Down Arrow
|
|
3777 case 46: //Forward Delete
|
|
3778 case 8: //Delete
|
|
3779 case this._keyMap.CLOSE_WINDOW.key: //W key if window is open
|
|
3780 if ((ev.keyCode == this._keyMap.CLOSE_WINDOW.key) && this.currentWindow) {
|
|
3781 if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) {
|
|
3782 this.closeWindow();
|
|
3783 }
|
|
3784 } else {
|
|
3785 if (!this.browser.ie) {
|
|
3786 if (this._nodeChangeTimer) {
|
|
3787 clearTimeout(this._nodeChangeTimer);
|
|
3788 }
|
|
3789 var self = this;
|
|
3790 this._nodeChangeTimer = setTimeout(function() {
|
|
3791 self._nodeChangeTimer = null;
|
|
3792 self.nodeChange.call(self);
|
|
3793 }, 100);
|
|
3794 } else {
|
|
3795 this.nodeChange();
|
|
3796 }
|
|
3797 this.editorDirty = true;
|
|
3798 }
|
|
3799 break;
|
|
3800 }
|
|
3801 this.fireEvent('editorKeyUp', { type: 'editorKeyUp', target: this, ev: ev });
|
|
3802 },
|
|
3803 /**
|
|
3804 * @private
|
|
3805 * @method _handleKeyPress
|
|
3806 * @param {Event} ev The event we are working on.
|
|
3807 * @description Handles all keypress events inside the iFrame document.
|
|
3808 */
|
|
3809 _handleKeyPress: function(ev) {
|
|
3810 var ret = this.fireEvent('beforeEditorKeyPress', { type: 'beforeEditorKeyPress', target: this, ev: ev });
|
|
3811 if (ret === false) {
|
|
3812 return false;
|
|
3813 }
|
|
3814
|
|
3815 if (this.get('allowNoEdit')) {
|
|
3816 //if (ev && ev.keyCode && ((ev.keyCode == 46) || ev.keyCode == 63272)) {
|
|
3817 if (ev && ev.keyCode && (ev.keyCode == 63272)) {
|
|
3818 //Forward delete key
|
|
3819 Event.stopEvent(ev);
|
|
3820 }
|
|
3821 }
|
|
3822 if (this._isNonEditable(ev)) {
|
|
3823 return false;
|
|
3824 }
|
|
3825 this._setCurrentEvent(ev);
|
|
3826 this._storeUndo();
|
|
3827 if (this.browser.opera) {
|
|
3828 if (ev.keyCode === 13) {
|
|
3829 var tar = this._getSelectedElement();
|
|
3830 if (!this._isElement(tar, 'li')) {
|
|
3831 this.execCommand('inserthtml', '<br>');
|
|
3832 Event.stopEvent(ev);
|
|
3833 }
|
|
3834 }
|
|
3835 }
|
|
3836 if (this.browser.webkit) {
|
|
3837 if (!this.browser.webkit3) {
|
|
3838 if (ev.keyCode && (ev.keyCode == 122) && (ev.metaKey)) {
|
|
3839 //This is CMD + z (for undo)
|
|
3840 if (this._hasParent(this._getSelectedElement(), 'li')) {
|
|
3841 Event.stopEvent(ev);
|
|
3842 }
|
|
3843 }
|
|
3844 }
|
|
3845 this._listFix(ev);
|
|
3846 }
|
|
3847 this._fixListDupIds();
|
|
3848 this.fireEvent('editorKeyPress', { type: 'editorKeyPress', target: this, ev: ev });
|
|
3849 },
|
|
3850 /**
|
|
3851 * @private
|
|
3852 * @method _handleKeyDown
|
|
3853 * @param {Event} ev The event we are working on.
|
|
3854 * @description Handles all keydown events inside the iFrame document.
|
|
3855 */
|
|
3856 _handleKeyDown: function(ev) {
|
|
3857 var ret = this.fireEvent('beforeEditorKeyDown', { type: 'beforeEditorKeyDown', target: this, ev: ev });
|
|
3858 if (ret === false) {
|
|
3859 return false;
|
|
3860 }
|
|
3861 var tar = null, _range = null;
|
|
3862 if (this._isNonEditable(ev)) {
|
|
3863 return false;
|
|
3864 }
|
|
3865 this._setCurrentEvent(ev);
|
|
3866 if (this.currentWindow) {
|
|
3867 this.closeWindow();
|
|
3868 }
|
|
3869 if (this.currentWindow) {
|
|
3870 this.closeWindow();
|
|
3871 }
|
|
3872 var doExec = false,
|
|
3873 action = null,
|
|
3874 value = null,
|
|
3875 exec = false;
|
|
3876
|
|
3877
|
|
3878 switch (ev.keyCode) {
|
|
3879 case this._keyMap.FOCUS_TOOLBAR.key:
|
|
3880 if (this._checkKey(this._keyMap.FOCUS_TOOLBAR, ev)) {
|
|
3881 var h = this.toolbar.getElementsByTagName('h2')[0];
|
|
3882 if (h && h.firstChild) {
|
|
3883 h.firstChild.focus();
|
|
3884 }
|
|
3885 } else if (this._checkKey(this._keyMap.FOCUS_AFTER, ev)) {
|
|
3886 //Focus After Element - Esc
|
|
3887 this.afterElement.focus();
|
|
3888 }
|
|
3889 Event.stopEvent(ev);
|
|
3890 doExec = false;
|
|
3891 break;
|
|
3892 //case 76: //L
|
|
3893 case this._keyMap.CREATE_LINK.key: //L
|
|
3894 if (this._hasSelection()) {
|
|
3895 if (this._checkKey(this._keyMap.CREATE_LINK, ev)) {
|
|
3896 var makeLink = true;
|
|
3897 if (this.get('limitCommands')) {
|
|
3898 if (!this.toolbar.getButtonByValue('createlink')) {
|
|
3899 makeLink = false;
|
|
3900 }
|
|
3901 }
|
|
3902 if (makeLink) {
|
|
3903 this.execCommand('createlink', '');
|
|
3904 this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
|
|
3905 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
3906 doExec = false;
|
|
3907 }
|
|
3908 }
|
|
3909 }
|
|
3910 break;
|
|
3911 //case 90: //Z
|
|
3912 case this._keyMap.UNDO.key:
|
|
3913 case this._keyMap.REDO.key:
|
|
3914 if (this._checkKey(this._keyMap.REDO, ev)) {
|
|
3915 action = 'redo';
|
|
3916 doExec = true;
|
|
3917 } else if (this._checkKey(this._keyMap.UNDO, ev)) {
|
|
3918 action = 'undo';
|
|
3919 doExec = true;
|
|
3920 }
|
|
3921 break;
|
|
3922 //case 66: //B
|
|
3923 case this._keyMap.BOLD.key:
|
|
3924 if (this._checkKey(this._keyMap.BOLD, ev)) {
|
|
3925 action = 'bold';
|
|
3926 doExec = true;
|
|
3927 }
|
|
3928 break;
|
|
3929 case this._keyMap.FONT_SIZE_UP.key:
|
|
3930 case this._keyMap.FONT_SIZE_DOWN.key:
|
|
3931 var uk = false, dk = false;
|
|
3932 if (this._checkKey(this._keyMap.FONT_SIZE_UP, ev)) {
|
|
3933 uk = true;
|
|
3934 }
|
|
3935 if (this._checkKey(this._keyMap.FONT_SIZE_DOWN, ev)) {
|
|
3936 dk = true;
|
|
3937 }
|
|
3938 if (uk || dk) {
|
|
3939 var fs_button = this.toolbar.getButtonByValue('fontsize'),
|
|
3940 label = parseInt(fs_button.get('label'), 10),
|
|
3941 newValue = (label + 1);
|
|
3942
|
|
3943 if (dk) {
|
|
3944 newValue = (label - 1);
|
|
3945 }
|
|
3946
|
|
3947 action = 'fontsize';
|
|
3948 value = newValue + 'px';
|
|
3949 doExec = true;
|
|
3950 }
|
|
3951 break;
|
|
3952 //case 73: //I
|
|
3953 case this._keyMap.ITALIC.key:
|
|
3954 if (this._checkKey(this._keyMap.ITALIC, ev)) {
|
|
3955 action = 'italic';
|
|
3956 doExec = true;
|
|
3957 }
|
|
3958 break;
|
|
3959 //case 85: //U
|
|
3960 case this._keyMap.UNDERLINE.key:
|
|
3961 if (this._checkKey(this._keyMap.UNDERLINE, ev)) {
|
|
3962 action = 'underline';
|
|
3963 doExec = true;
|
|
3964 }
|
|
3965 break;
|
|
3966 case 9:
|
|
3967 if (this.browser.ie) {
|
|
3968 //Insert a tab in Internet Explorer
|
|
3969 _range = this._getRange();
|
|
3970 tar = this._getSelectedElement();
|
|
3971 if (!this._isElement(tar, 'li')) {
|
|
3972 if (_range) {
|
|
3973 _range.pasteHTML(' ');
|
|
3974 _range.collapse(false);
|
|
3975 _range.select();
|
|
3976 }
|
|
3977 Event.stopEvent(ev);
|
|
3978 }
|
|
3979 }
|
|
3980 //Firefox 3 code
|
|
3981 if (this.browser.gecko > 1.8) {
|
|
3982 tar = this._getSelectedElement();
|
|
3983 if (this._isElement(tar, 'li')) {
|
|
3984 if (ev.shiftKey) {
|
|
3985 this._getDoc().execCommand('outdent', null, '');
|
|
3986 } else {
|
|
3987 this._getDoc().execCommand('indent', null, '');
|
|
3988 }
|
|
3989
|
|
3990 } else if (!this._hasSelection()) {
|
|
3991 this.execCommand('inserthtml', ' ');
|
|
3992 }
|
|
3993 Event.stopEvent(ev);
|
|
3994 }
|
|
3995 break;
|
|
3996 case 13:
|
|
3997 var p = null, i = 0;
|
|
3998 if (this.get('ptags') && !ev.shiftKey) {
|
|
3999 if (this.browser.gecko) {
|
|
4000 tar = this._getSelectedElement();
|
|
4001 if (!this._hasParent(tar, 'li')) {
|
|
4002 if (this._hasParent(tar, 'p')) {
|
|
4003 p = this._getDoc().createElement('p');
|
|
4004 p.innerHTML = ' ';
|
|
4005 Dom.insertAfter(p, tar);
|
|
4006 this._selectNode(p.firstChild);
|
|
4007 } else if (this._isElement(tar, 'body')) {
|
|
4008 this.execCommand('insertparagraph', null);
|
|
4009 var ps = this._getDoc().body.getElementsByTagName('p');
|
|
4010 for (i = 0; i < ps.length; i++) {
|
|
4011 if (ps[i].getAttribute('_moz_dirty') !== null) {
|
|
4012 p = this._getDoc().createElement('p');
|
|
4013 p.innerHTML = ' ';
|
|
4014 Dom.insertAfter(p, ps[i]);
|
|
4015 this._selectNode(p.firstChild);
|
|
4016 ps[i].removeAttribute('_moz_dirty');
|
|
4017 }
|
|
4018 }
|
|
4019 } else {
|
|
4020 doExec = true;
|
|
4021 action = 'insertparagraph';
|
|
4022 }
|
|
4023 Event.stopEvent(ev);
|
|
4024 }
|
|
4025 }
|
|
4026 if (this.browser.webkit) {
|
|
4027 tar = this._getSelectedElement();
|
|
4028 if (!this._hasParent(tar, 'li')) {
|
|
4029 this.execCommand('insertparagraph', null);
|
|
4030 var divs = this._getDoc().body.getElementsByTagName('div');
|
|
4031 for (i = 0; i < divs.length; i++) {
|
|
4032 if (!Dom.hasClass(divs[i], 'yui-wk-div')) {
|
|
4033 Dom.addClass(divs[i], 'yui-wk-p');
|
|
4034 }
|
|
4035 }
|
|
4036 Event.stopEvent(ev);
|
|
4037 }
|
|
4038 }
|
|
4039 } else {
|
|
4040 if (this.browser.webkit) {
|
|
4041 tar = this._getSelectedElement();
|
|
4042 if (!this._hasParent(tar, 'li')) {
|
|
4043 if (this.browser.webkit4) {
|
|
4044 this.execCommand('insertlinebreak');
|
|
4045 } else {
|
|
4046 this.execCommand('inserthtml', '<var id="yui-br"></var>');
|
|
4047 var holder = this._getDoc().getElementById('yui-br'),
|
|
4048 br = this._getDoc().createElement('br'),
|
|
4049 caret = this._getDoc().createElement('span');
|
|
4050
|
|
4051 holder.parentNode.replaceChild(br, holder);
|
|
4052 caret.className = 'yui-non';
|
|
4053 caret.innerHTML = ' ';
|
|
4054 Dom.insertAfter(caret, br);
|
|
4055 this._selectNode(caret);
|
|
4056 }
|
|
4057 Event.stopEvent(ev);
|
|
4058 }
|
|
4059 }
|
|
4060 if (this.browser.ie) {
|
|
4061 //Insert a <br> instead of a <p></p> in Internet Explorer
|
|
4062 _range = this._getRange();
|
|
4063 tar = this._getSelectedElement();
|
|
4064 if (!this._isElement(tar, 'li')) {
|
|
4065 if (_range) {
|
|
4066 _range.pasteHTML('<br>');
|
|
4067 _range.collapse(false);
|
|
4068 _range.select();
|
|
4069 }
|
|
4070 Event.stopEvent(ev);
|
|
4071 }
|
|
4072 }
|
|
4073 }
|
|
4074 break;
|
|
4075 }
|
|
4076 if (this.browser.ie) {
|
|
4077 this._listFix(ev);
|
|
4078 }
|
|
4079 if (doExec && action) {
|
|
4080 this.execCommand(action, value);
|
|
4081 Event.stopEvent(ev);
|
|
4082 this.nodeChange();
|
|
4083 }
|
|
4084 this._storeUndo();
|
|
4085 this.fireEvent('editorKeyDown', { type: 'editorKeyDown', target: this, ev: ev });
|
|
4086 },
|
|
4087 /**
|
|
4088 * @private
|
|
4089 * @property _fixListRunning
|
|
4090 * @type Boolean
|
|
4091 * @description Keeps more than one _fixListDupIds from running at the same time.
|
|
4092 */
|
|
4093 _fixListRunning: null,
|
|
4094 /**
|
|
4095 * @private
|
|
4096 * @method _fixListDupIds
|
|
4097 * @description Some browsers will duplicate the id of an LI when created in designMode.
|
|
4098 * This method will fix the duplicate id issue. However it will only preserve the first element
|
|
4099 * in the document list with the unique id.
|
|
4100 */
|
|
4101 _fixListDupIds: function() {
|
|
4102 if (this._fixListRunning) {
|
|
4103 return false;
|
|
4104 }
|
|
4105 if (this._getDoc()) {
|
|
4106 this._fixListRunning = true;
|
|
4107 var lis = this._getDoc().body.getElementsByTagName('li'),
|
|
4108 i = 0, ids = {};
|
|
4109 for (i = 0; i < lis.length; i++) {
|
|
4110 if (lis[i].id) {
|
|
4111 if (ids[lis[i].id]) {
|
|
4112 lis[i].id = '';
|
|
4113 }
|
|
4114 ids[lis[i].id] = true;
|
|
4115 }
|
|
4116 }
|
|
4117 this._fixListRunning = false;
|
|
4118 }
|
|
4119 },
|
|
4120 /**
|
|
4121 * @private
|
|
4122 * @method _listFix
|
|
4123 * @param {Event} ev The event we are working on.
|
|
4124 * @description Handles the Enter key, Tab Key and Shift + Tab keys for List Items.
|
|
4125 */
|
|
4126 _listFix: function(ev) {
|
|
4127 var testLi = null, par = null, preContent = false, range = null;
|
|
4128 //Enter Key
|
|
4129 if (this.browser.webkit) {
|
|
4130 if (ev.keyCode && (ev.keyCode == 13)) {
|
|
4131 if (this._hasParent(this._getSelectedElement(), 'li')) {
|
|
4132 var tar = this._hasParent(this._getSelectedElement(), 'li');
|
|
4133 if (tar.previousSibling) {
|
|
4134 if (tar.firstChild && (tar.firstChild.length == 1)) {
|
|
4135 this._selectNode(tar);
|
|
4136 }
|
|
4137 }
|
|
4138 }
|
|
4139 }
|
|
4140 }
|
|
4141 //Shift + Tab Key
|
|
4142 if (ev.keyCode && ((!this.browser.webkit3 && (ev.keyCode == 25)) || ((this.browser.webkit3 || !this.browser.webkit) && ((ev.keyCode == 9) && ev.shiftKey)))) {
|
|
4143 testLi = this._getSelectedElement();
|
|
4144 if (this._hasParent(testLi, 'li')) {
|
|
4145 testLi = this._hasParent(testLi, 'li');
|
|
4146 if (this._hasParent(testLi, 'ul') || this._hasParent(testLi, 'ol')) {
|
|
4147 par = this._hasParent(testLi, 'ul');
|
|
4148 if (!par) {
|
|
4149 par = this._hasParent(testLi, 'ol');
|
|
4150 }
|
|
4151 if (this._isElement(par.previousSibling, 'li')) {
|
|
4152 par.removeChild(testLi);
|
|
4153 par.parentNode.insertBefore(testLi, par.nextSibling);
|
|
4154 if (this.browser.ie) {
|
|
4155 range = this._getDoc().body.createTextRange();
|
|
4156 range.moveToElementText(testLi);
|
|
4157 range.collapse(false);
|
|
4158 range.select();
|
|
4159 }
|
|
4160 if (this.browser.webkit) {
|
|
4161 this._selectNode(testLi.firstChild);
|
|
4162 }
|
|
4163 Event.stopEvent(ev);
|
|
4164 }
|
|
4165 }
|
|
4166 }
|
|
4167 }
|
|
4168 //Tab Key
|
|
4169 if (ev.keyCode && ((ev.keyCode == 9) && (!ev.shiftKey))) {
|
|
4170 var preLi = this._getSelectedElement();
|
|
4171 if (this._hasParent(preLi, 'li')) {
|
|
4172 preContent = this._hasParent(preLi, 'li').innerHTML;
|
|
4173 }
|
|
4174 if (this.browser.webkit) {
|
|
4175 this._getDoc().execCommand('inserttext', false, '\t');
|
|
4176 }
|
|
4177 testLi = this._getSelectedElement();
|
|
4178 if (this._hasParent(testLi, 'li')) {
|
|
4179 par = this._hasParent(testLi, 'li');
|
|
4180 var newUl = this._getDoc().createElement(par.parentNode.tagName.toLowerCase());
|
|
4181 if (this.browser.webkit) {
|
|
4182 var span = Dom.getElementsByClassName('Apple-tab-span', 'span', par);
|
|
4183 //Remove the span element that Safari puts in
|
|
4184 if (span[0]) {
|
|
4185 par.removeChild(span[0]);
|
|
4186 par.innerHTML = Lang.trim(par.innerHTML);
|
|
4187 //Put the HTML from the LI into this new LI
|
|
4188 if (preContent) {
|
|
4189 par.innerHTML = '<span class="yui-non">' + preContent + '</span> ';
|
|
4190 } else {
|
|
4191 par.innerHTML = '<span class="yui-non"> </span> ';
|
|
4192 }
|
|
4193 }
|
|
4194 } else {
|
|
4195 if (preContent) {
|
|
4196 par.innerHTML = preContent + ' ';
|
|
4197 } else {
|
|
4198 par.innerHTML = ' ';
|
|
4199 }
|
|
4200 }
|
|
4201
|
|
4202 par.parentNode.replaceChild(newUl, par);
|
|
4203 newUl.appendChild(par);
|
|
4204 if (this.browser.webkit) {
|
|
4205 this._getSelection().setBaseAndExtent(par.firstChild, 1, par.firstChild, par.firstChild.innerText.length);
|
|
4206 if (!this.browser.webkit3) {
|
|
4207 par.parentNode.parentNode.style.display = 'list-item';
|
|
4208 setTimeout(function() {
|
|
4209 par.parentNode.parentNode.style.display = 'block';
|
|
4210 }, 1);
|
|
4211 }
|
|
4212 } else if (this.browser.ie) {
|
|
4213 range = this._getDoc().body.createTextRange();
|
|
4214 range.moveToElementText(par);
|
|
4215 range.collapse(false);
|
|
4216 range.select();
|
|
4217 } else {
|
|
4218 this._selectNode(par);
|
|
4219 }
|
|
4220 Event.stopEvent(ev);
|
|
4221 }
|
|
4222 if (this.browser.webkit) {
|
|
4223 Event.stopEvent(ev);
|
|
4224 }
|
|
4225 this.nodeChange();
|
|
4226 }
|
|
4227 },
|
|
4228 /**
|
|
4229 * @method nodeChange
|
|
4230 * @param {Boolean} force Optional paramenter to skip the threshold counter
|
|
4231 * @description Handles setting up the toolbar buttons, getting the Dom path, fixing nodes.
|
|
4232 */
|
|
4233 nodeChange: function(force) {
|
|
4234 var NCself = this;
|
|
4235 this._storeUndo();
|
|
4236 if (this.get('nodeChangeDelay')) {
|
|
4237 this._nodeChangeDelayTimer = window.setTimeout(function() {
|
|
4238 NCself._nodeChangeDelayTimer = null;
|
|
4239 NCself._nodeChange.apply(NCself, arguments);
|
|
4240 }, 0);
|
|
4241 } else {
|
|
4242 this._nodeChange();
|
|
4243 }
|
|
4244 },
|
|
4245 /**
|
|
4246 * @private
|
|
4247 * @method _nodeChange
|
|
4248 * @param {Boolean} force Optional paramenter to skip the threshold counter
|
|
4249 * @description Fired from nodeChange in a setTimeout.
|
|
4250 */
|
|
4251 _nodeChange: function(force) {
|
|
4252 var threshold = parseInt(this.get('nodeChangeThreshold'), 10),
|
|
4253 thisNodeChange = Math.round(new Date().getTime() / 1000),
|
|
4254 self = this;
|
|
4255
|
|
4256 if (force === true) {
|
|
4257 this._lastNodeChange = 0;
|
|
4258 }
|
|
4259
|
|
4260 if ((this._lastNodeChange + threshold) < thisNodeChange) {
|
|
4261 if (this._fixNodesTimer === null) {
|
|
4262 this._fixNodesTimer = window.setTimeout(function() {
|
|
4263 self._fixNodes.call(self);
|
|
4264 self._fixNodesTimer = null;
|
|
4265 }, 0);
|
|
4266 }
|
|
4267 }
|
|
4268 this._lastNodeChange = thisNodeChange;
|
|
4269 if (this.currentEvent) {
|
|
4270 try {
|
|
4271 this._lastNodeChangeEvent = this.currentEvent.type;
|
|
4272 } catch (e) {}
|
|
4273 }
|
|
4274
|
|
4275 var beforeNodeChange = this.fireEvent('beforeNodeChange', { type: 'beforeNodeChange', target: this });
|
|
4276 if (beforeNodeChange === false) {
|
|
4277 return false;
|
|
4278 }
|
|
4279 if (this.get('dompath')) {
|
|
4280 window.setTimeout(function() {
|
|
4281 self._writeDomPath.call(self);
|
|
4282 }, 0);
|
|
4283 }
|
|
4284 //Check to see if we are disabled before continuing
|
|
4285 if (!this.get('disabled')) {
|
|
4286 if (this.STOP_NODE_CHANGE) {
|
|
4287 //Reset this var for next action
|
|
4288 this.STOP_NODE_CHANGE = false;
|
|
4289 return false;
|
|
4290 } else {
|
|
4291 var sel = this._getSelection(),
|
|
4292 range = this._getRange(),
|
|
4293 el = this._getSelectedElement(),
|
|
4294 fn_button = this.toolbar.getButtonByValue('fontname'),
|
|
4295 fs_button = this.toolbar.getButtonByValue('fontsize'),
|
|
4296 undo_button = this.toolbar.getButtonByValue('undo'),
|
|
4297 redo_button = this.toolbar.getButtonByValue('redo');
|
|
4298
|
|
4299 //Handle updating the toolbar with active buttons
|
|
4300 var _ex = {};
|
|
4301 if (this._lastButton) {
|
|
4302 _ex[this._lastButton.id] = true;
|
|
4303 //this._lastButton = null;
|
|
4304 }
|
|
4305 if (!this._isElement(el, 'body')) {
|
|
4306 if (fn_button) {
|
|
4307 _ex[fn_button.get('id')] = true;
|
|
4308 }
|
|
4309 if (fs_button) {
|
|
4310 _ex[fs_button.get('id')] = true;
|
|
4311 }
|
|
4312 }
|
|
4313 if (redo_button) {
|
|
4314 delete _ex[redo_button.get('id')];
|
|
4315 }
|
|
4316 this.toolbar.resetAllButtons(_ex);
|
|
4317
|
|
4318 //Handle disabled buttons
|
|
4319 for (var d = 0; d < this._disabled.length; d++) {
|
|
4320 var _button = this.toolbar.getButtonByValue(this._disabled[d]);
|
|
4321 if (_button && _button.get) {
|
|
4322 if (this._lastButton && (_button.get('id') === this._lastButton.id)) {
|
|
4323 //Skip
|
|
4324 } else {
|
|
4325 if (!this._hasSelection() && !this.get('insert')) {
|
|
4326 switch (this._disabled[d]) {
|
|
4327 case 'fontname':
|
|
4328 case 'fontsize':
|
|
4329 break;
|
|
4330 default:
|
|
4331 //No Selection - disable
|
|
4332 this.toolbar.disableButton(_button);
|
|
4333 }
|
|
4334 } else {
|
|
4335 if (!this._alwaysDisabled[this._disabled[d]]) {
|
|
4336 this.toolbar.enableButton(_button);
|
|
4337 }
|
|
4338 }
|
|
4339 if (!this._alwaysEnabled[this._disabled[d]]) {
|
|
4340 this.toolbar.deselectButton(_button);
|
|
4341 }
|
|
4342 }
|
|
4343 }
|
|
4344 }
|
|
4345 var path = this._getDomPath();
|
|
4346 var tag = null, cmd = null;
|
|
4347 for (var i = 0; i < path.length; i++) {
|
|
4348 tag = path[i].tagName.toLowerCase();
|
|
4349 if (path[i].getAttribute('tag')) {
|
|
4350 tag = path[i].getAttribute('tag').toLowerCase();
|
|
4351 }
|
|
4352 cmd = this._tag2cmd[tag];
|
|
4353 if (cmd === undefined) {
|
|
4354 cmd = [];
|
|
4355 }
|
|
4356 if (!Lang.isArray(cmd)) {
|
|
4357 cmd = [cmd];
|
|
4358 }
|
|
4359
|
|
4360 //Bold and Italic styles
|
|
4361 if (path[i].style.fontWeight.toLowerCase() == 'bold') {
|
|
4362 cmd[cmd.length] = 'bold';
|
|
4363 }
|
|
4364 if (path[i].style.fontStyle.toLowerCase() == 'italic') {
|
|
4365 cmd[cmd.length] = 'italic';
|
|
4366 }
|
|
4367 if (path[i].style.textDecoration.toLowerCase() == 'underline') {
|
|
4368 cmd[cmd.length] = 'underline';
|
|
4369 }
|
|
4370 if (path[i].style.textDecoration.toLowerCase() == 'line-through') {
|
|
4371 cmd[cmd.length] = 'strikethrough';
|
|
4372 }
|
|
4373 if (cmd.length > 0) {
|
|
4374 for (var j = 0; j < cmd.length; j++) {
|
|
4375 this.toolbar.selectButton(cmd[j]);
|
|
4376 this.toolbar.enableButton(cmd[j]);
|
|
4377 }
|
|
4378 }
|
|
4379 //Handle Alignment
|
|
4380 switch (path[i].style.textAlign.toLowerCase()) {
|
|
4381 case 'left':
|
|
4382 case 'right':
|
|
4383 case 'center':
|
|
4384 case 'justify':
|
|
4385 var alignType = path[i].style.textAlign.toLowerCase();
|
|
4386 if (path[i].style.textAlign.toLowerCase() == 'justify') {
|
|
4387 alignType = 'full';
|
|
4388 }
|
|
4389 this.toolbar.selectButton('justify' + alignType);
|
|
4390 this.toolbar.enableButton('justify' + alignType);
|
|
4391 break;
|
|
4392 }
|
|
4393 }
|
|
4394 //After for loop
|
|
4395
|
|
4396 //Reset Font Family and Size to the inital configs
|
|
4397 if (fn_button) {
|
|
4398 var family = fn_button._configs.label._initialConfig.value;
|
|
4399 fn_button.set('label', '<span class="yui-toolbar-fontname-' + this._cleanClassName(family) + '">' + family + '</span>');
|
|
4400 this._updateMenuChecked('fontname', family);
|
|
4401 }
|
|
4402
|
|
4403 if (fs_button) {
|
|
4404 fs_button.set('label', fs_button._configs.label._initialConfig.value);
|
|
4405 }
|
|
4406
|
|
4407 var hd_button = this.toolbar.getButtonByValue('heading');
|
|
4408 if (hd_button) {
|
|
4409 hd_button.set('label', hd_button._configs.label._initialConfig.value);
|
|
4410 this._updateMenuChecked('heading', 'none');
|
|
4411 }
|
|
4412 var img_button = this.toolbar.getButtonByValue('insertimage');
|
|
4413 if (img_button && this.currentWindow && (this.currentWindow.name == 'insertimage')) {
|
|
4414 this.toolbar.disableButton(img_button);
|
|
4415 }
|
|
4416 if (this._lastButton && this._lastButton.isSelected) {
|
|
4417 this.toolbar.deselectButton(this._lastButton.id);
|
|
4418 }
|
|
4419 this._undoNodeChange();
|
|
4420 }
|
|
4421 }
|
|
4422
|
|
4423 this.fireEvent('afterNodeChange', { type: 'afterNodeChange', target: this });
|
|
4424 },
|
|
4425 /**
|
|
4426 * @private
|
|
4427 * @method _updateMenuChecked
|
|
4428 * @param {Object} button The command identifier of the button you want to check
|
|
4429 * @param {String} value The value of the menu item you want to check
|
|
4430 * @param {<a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>} The Toolbar instance the button belongs to (defaults to this.toolbar)
|
|
4431 * @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.
|
|
4432 */
|
|
4433 _updateMenuChecked: function(button, value, tbar) {
|
|
4434 if (!tbar) {
|
|
4435 tbar = this.toolbar;
|
|
4436 }
|
|
4437 var _button = tbar.getButtonByValue(button);
|
|
4438 _button.checkValue(value);
|
|
4439 },
|
|
4440 /**
|
|
4441 * @private
|
|
4442 * @method _handleToolbarClick
|
|
4443 * @param {Event} ev The event that triggered the button click
|
|
4444 * @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.
|
|
4445 */
|
|
4446 _handleToolbarClick: function(ev) {
|
|
4447 var value = '';
|
|
4448 var str = '';
|
|
4449 var cmd = ev.button.value;
|
|
4450 if (ev.button.menucmd) {
|
|
4451 value = cmd;
|
|
4452 cmd = ev.button.menucmd;
|
|
4453 }
|
|
4454 this._lastButton = ev.button;
|
|
4455 if (this.STOP_EXEC_COMMAND) {
|
|
4456 this.STOP_EXEC_COMMAND = false;
|
|
4457 return false;
|
|
4458 } else {
|
|
4459 this.execCommand(cmd, value);
|
|
4460 if (!this.browser.webkit) {
|
|
4461 var Fself = this;
|
|
4462 setTimeout(function() {
|
|
4463 Fself.focus.call(Fself);
|
|
4464 }, 5);
|
|
4465 }
|
|
4466 }
|
|
4467 Event.stopEvent(ev);
|
|
4468 },
|
|
4469 /**
|
|
4470 * @private
|
|
4471 * @method _setupAfterElement
|
|
4472 * @description Creates the accessibility h2 header and places it after the iframe in the Dom for navigation.
|
|
4473 */
|
|
4474 _setupAfterElement: function() {
|
|
4475 if (!this.beforeElement) {
|
|
4476 this.beforeElement = document.createElement('h2');
|
|
4477 this.beforeElement.className = 'yui-editor-skipheader';
|
|
4478 this.beforeElement.tabIndex = '-1';
|
|
4479 this.beforeElement.innerHTML = this.STR_BEFORE_EDITOR;
|
|
4480 this.get('element_cont').get('firstChild').insertBefore(this.beforeElement, this.toolbar.get('nextSibling'));
|
|
4481 }
|
|
4482 if (!this.afterElement) {
|
|
4483 this.afterElement = document.createElement('h2');
|
|
4484 this.afterElement.className = 'yui-editor-skipheader';
|
|
4485 this.afterElement.tabIndex = '-1';
|
|
4486 this.afterElement.innerHTML = this.STR_LEAVE_EDITOR;
|
|
4487 this.get('element_cont').get('firstChild').appendChild(this.afterElement);
|
|
4488 }
|
|
4489 },
|
|
4490 /**
|
|
4491 * @private
|
|
4492 * @method _disableEditor
|
|
4493 * @param {Boolean} disabled Pass true to disable, false to enable
|
|
4494 * @description Creates a mask to place over the Editor.
|
|
4495 */
|
|
4496 _disableEditor: function(disabled) {
|
|
4497 var iframe, par, html, height;
|
|
4498 if (!this.get('disabled_iframe')) {
|
|
4499 iframe = this._createIframe();
|
|
4500 iframe.set('id', 'disabled_' + this.get('iframe').get('id'));
|
|
4501 iframe.setStyle('height', '100%');
|
|
4502 iframe.setStyle('display', 'none');
|
|
4503 iframe.setStyle('visibility', 'visible');
|
|
4504 this.set('disabled_iframe', iframe);
|
|
4505 par = this.get('iframe').get('parentNode');
|
|
4506 par.appendChild(iframe.get('element'));
|
|
4507 }
|
|
4508 if (!iframe) {
|
|
4509 iframe = this.get('disabled_iframe');
|
|
4510 }
|
|
4511 if (disabled) {
|
|
4512 this._orgIframe = this.get('iframe');
|
|
4513
|
|
4514 if (this.toolbar) {
|
|
4515 this.toolbar.set('disabled', true);
|
|
4516 }
|
|
4517
|
|
4518 html = this.getEditorHTML();
|
|
4519 height = this.get('iframe').get('offsetHeight');
|
|
4520 iframe.setStyle('visibility', '');
|
|
4521 iframe.setStyle('position', '');
|
|
4522 iframe.setStyle('top', '');
|
|
4523 iframe.setStyle('left', '');
|
|
4524 this._orgIframe.setStyle('visibility', 'hidden');
|
|
4525 this._orgIframe.setStyle('position', 'absolute');
|
|
4526 this._orgIframe.setStyle('top', '-99999px');
|
|
4527 this._orgIframe.setStyle('left', '-99999px');
|
|
4528 this.set('iframe', iframe);
|
|
4529 this._setInitialContent(true);
|
|
4530
|
|
4531 if (!this._mask) {
|
|
4532 this._mask = document.createElement('DIV');
|
|
4533 Dom.addClass(this._mask, 'yui-editor-masked');
|
|
4534 if (this.browser.ie) {
|
|
4535 this._mask.style.height = height + 'px';
|
|
4536 }
|
|
4537 this.get('iframe').get('parentNode').appendChild(this._mask);
|
|
4538 }
|
|
4539 this.on('editorContentReloaded', function() {
|
|
4540 this._getDoc().body._rteLoaded = false;
|
|
4541 this.setEditorHTML(html);
|
|
4542 iframe.setStyle('display', 'block');
|
|
4543 this.unsubscribeAll('editorContentReloaded');
|
|
4544 });
|
|
4545 } else {
|
|
4546 if (this._mask) {
|
|
4547 this._mask.parentNode.removeChild(this._mask);
|
|
4548 this._mask = null;
|
|
4549 if (this.toolbar) {
|
|
4550 this.toolbar.set('disabled', false);
|
|
4551 }
|
|
4552 iframe.setStyle('visibility', 'hidden');
|
|
4553 iframe.setStyle('position', 'absolute');
|
|
4554 iframe.setStyle('top', '-99999px');
|
|
4555 iframe.setStyle('left', '-99999px');
|
|
4556 this._orgIframe.setStyle('visibility', '');
|
|
4557 this._orgIframe.setStyle('position', '');
|
|
4558 this._orgIframe.setStyle('top', '');
|
|
4559 this._orgIframe.setStyle('left', '');
|
|
4560 this.set('iframe', this._orgIframe);
|
|
4561
|
|
4562 this.focus();
|
|
4563 var self = this;
|
|
4564 window.setTimeout(function() {
|
|
4565 self.nodeChange.call(self);
|
|
4566 }, 100);
|
|
4567 }
|
|
4568 }
|
|
4569 },
|
|
4570 /**
|
|
4571 * @property SEP_DOMPATH
|
|
4572 * @description The value to place in between the Dom path items
|
|
4573 * @type String
|
|
4574 */
|
|
4575 SEP_DOMPATH: '<',
|
|
4576 /**
|
|
4577 * @property STR_LEAVE_EDITOR
|
|
4578 * @description The accessibility string for the element after the iFrame
|
|
4579 * @type String
|
|
4580 */
|
|
4581 STR_LEAVE_EDITOR: 'You have left the Rich Text Editor.',
|
|
4582 /**
|
|
4583 * @property STR_BEFORE_EDITOR
|
|
4584 * @description The accessibility string for the element before the iFrame
|
|
4585 * @type String
|
|
4586 */
|
|
4587 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>',
|
|
4588 /**
|
|
4589 * @property STR_TITLE
|
|
4590 * @description The Title of the HTML document that is created in the iFrame
|
|
4591 * @type String
|
|
4592 */
|
|
4593 STR_TITLE: 'Rich Text Area.',
|
|
4594 /**
|
|
4595 * @property STR_IMAGE_HERE
|
|
4596 * @description The text to place in the URL textbox when using the blankimage.
|
|
4597 * @type String
|
|
4598 */
|
|
4599 STR_IMAGE_HERE: 'Image URL Here',
|
|
4600 /**
|
|
4601 * @property STR_IMAGE_URL
|
|
4602 * @description The label string for Image URL
|
|
4603 * @type String
|
|
4604 */
|
|
4605 STR_IMAGE_URL: 'Image URL',
|
|
4606 /**
|
|
4607 * @property STR_LINK_URL
|
|
4608 * @description The label string for the Link URL.
|
|
4609 * @type String
|
|
4610 */
|
|
4611 STR_LINK_URL: 'Link URL',
|
|
4612 /**
|
|
4613 * @protected
|
|
4614 * @property STOP_EXEC_COMMAND
|
|
4615 * @description Set to true when you want the default execCommand function to not process anything
|
|
4616 * @type Boolean
|
|
4617 */
|
|
4618 STOP_EXEC_COMMAND: false,
|
|
4619 /**
|
|
4620 * @protected
|
|
4621 * @property STOP_NODE_CHANGE
|
|
4622 * @description Set to true when you want the default nodeChange function to not process anything
|
|
4623 * @type Boolean
|
|
4624 */
|
|
4625 STOP_NODE_CHANGE: false,
|
|
4626 /**
|
|
4627 * @protected
|
|
4628 * @property CLASS_NOEDIT
|
|
4629 * @description CSS class applied to elements that are not editable.
|
|
4630 * @type String
|
|
4631 */
|
|
4632 CLASS_NOEDIT: 'yui-noedit',
|
|
4633 /**
|
|
4634 * @protected
|
|
4635 * @property CLASS_CONTAINER
|
|
4636 * @description Default CSS class to apply to the editors container element
|
|
4637 * @type String
|
|
4638 */
|
|
4639 CLASS_CONTAINER: 'yui-editor-container',
|
|
4640 /**
|
|
4641 * @protected
|
|
4642 * @property CLASS_EDITABLE
|
|
4643 * @description Default CSS class to apply to the editors iframe element
|
|
4644 * @type String
|
|
4645 */
|
|
4646 CLASS_EDITABLE: 'yui-editor-editable',
|
|
4647 /**
|
|
4648 * @protected
|
|
4649 * @property CLASS_EDITABLE_CONT
|
|
4650 * @description Default CSS class to apply to the editors iframe's parent element
|
|
4651 * @type String
|
|
4652 */
|
|
4653 CLASS_EDITABLE_CONT: 'yui-editor-editable-container',
|
|
4654 /**
|
|
4655 * @protected
|
|
4656 * @property CLASS_PREFIX
|
|
4657 * @description Default prefix for dynamically created class names
|
|
4658 * @type String
|
|
4659 */
|
|
4660 CLASS_PREFIX: 'yui-editor',
|
|
4661 /**
|
|
4662 * @property browser
|
|
4663 * @description Standard browser detection
|
|
4664 * @type Object
|
|
4665 */
|
|
4666 browser: function() {
|
|
4667 var br = YAHOO.env.ua;
|
|
4668 //Check for webkit3
|
|
4669 if (br.webkit >= 420) {
|
|
4670 br.webkit3 = br.webkit;
|
|
4671 } else {
|
|
4672 br.webkit3 = 0;
|
|
4673 }
|
|
4674 if (br.webkit >= 530) {
|
|
4675 br.webkit4 = br.webkit;
|
|
4676 } else {
|
|
4677 br.webkit4 = 0;
|
|
4678 }
|
|
4679 br.mac = false;
|
|
4680 //Check for Mac
|
|
4681 if (navigator.userAgent.indexOf('Macintosh') !== -1) {
|
|
4682 br.mac = true;
|
|
4683 }
|
|
4684
|
|
4685 return br;
|
|
4686 }(),
|
|
4687 /**
|
|
4688 * @method init
|
|
4689 * @description The Editor class' initialization method
|
|
4690 */
|
|
4691 init: function(p_oElement, p_oAttributes) {
|
|
4692
|
|
4693 if (!this._defaultToolbar) {
|
|
4694 this._defaultToolbar = {
|
|
4695 collapse: true,
|
|
4696 titlebar: 'Text Editing Tools',
|
|
4697 draggable: false,
|
|
4698 buttons: [
|
|
4699 { group: 'fontstyle', label: 'Font Name and Size',
|
|
4700 buttons: [
|
|
4701 { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
|
|
4702 menu: [
|
|
4703 { text: 'Arial', checked: true },
|
|
4704 { text: 'Arial Black' },
|
|
4705 { text: 'Comic Sans MS' },
|
|
4706 { text: 'Courier New' },
|
|
4707 { text: 'Lucida Console' },
|
|
4708 { text: 'Tahoma' },
|
|
4709 { text: 'Times New Roman' },
|
|
4710 { text: 'Trebuchet MS' },
|
|
4711 { text: 'Verdana' }
|
|
4712 ]
|
|
4713 },
|
|
4714 { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
|
|
4715 ]
|
|
4716 },
|
|
4717 { type: 'separator' },
|
|
4718 { group: 'textstyle', label: 'Font Style',
|
|
4719 buttons: [
|
|
4720 { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
|
|
4721 { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
|
|
4722 { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
|
|
4723 { type: 'push', label: 'Strike Through', value: 'strikethrough' },
|
|
4724 { type: 'separator' },
|
|
4725 { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
|
|
4726 { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }
|
|
4727
|
|
4728 ]
|
|
4729 },
|
|
4730 { type: 'separator' },
|
|
4731 { group: 'indentlist', label: 'Lists',
|
|
4732 buttons: [
|
|
4733 { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
|
|
4734 { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
|
|
4735 ]
|
|
4736 },
|
|
4737 { type: 'separator' },
|
|
4738 { group: 'insertitem', label: 'Insert Item',
|
|
4739 buttons: [
|
|
4740 { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
|
|
4741 { type: 'push', label: 'Insert Image', value: 'insertimage' }
|
|
4742 ]
|
|
4743 }
|
|
4744 ]
|
|
4745 };
|
|
4746 }
|
|
4747
|
|
4748 YAHOO.widget.SimpleEditor.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
4749 YAHOO.widget.EditorInfo._instances[this.get('id')] = this;
|
|
4750
|
|
4751
|
|
4752 this.currentElement = [];
|
|
4753 this.on('contentReady', function() {
|
|
4754 this.DOMReady = true;
|
|
4755 this.fireQueue();
|
|
4756 }, this, true);
|
|
4757
|
|
4758 },
|
|
4759 /**
|
|
4760 * @method initAttributes
|
|
4761 * @description Initializes all of the configuration attributes used to create
|
|
4762 * the editor.
|
|
4763 * @param {Object} attr Object literal specifying a set of
|
|
4764 * configuration attributes used to create the editor.
|
|
4765 */
|
|
4766 initAttributes: function(attr) {
|
|
4767 YAHOO.widget.SimpleEditor.superclass.initAttributes.call(this, attr);
|
|
4768 var self = this;
|
|
4769
|
|
4770 /**
|
|
4771 * @config setDesignMode
|
|
4772 * @description Should the Editor set designMode on the document. Default: true.
|
|
4773 * @default true
|
|
4774 * @type Boolean
|
|
4775 */
|
|
4776 this.setAttributeConfig('setDesignMode', {
|
|
4777 value: ((attr.setDesignMode === false) ? false : true)
|
|
4778 });
|
|
4779 /**
|
|
4780 * @config nodeChangeDelay
|
|
4781 * @description Do we wrap the nodeChange method in a timeout for performance. Default: true.
|
|
4782 * @default true
|
|
4783 * @type Boolean
|
|
4784 */
|
|
4785 this.setAttributeConfig('nodeChangeDelay', {
|
|
4786 value: ((attr.nodeChangeDelay === false) ? false : true)
|
|
4787 });
|
|
4788 /**
|
|
4789 * @config maxUndo
|
|
4790 * @description The max number of undo levels to store.
|
|
4791 * @default 30
|
|
4792 * @type Number
|
|
4793 */
|
|
4794 this.setAttributeConfig('maxUndo', {
|
|
4795 writeOnce: true,
|
|
4796 value: attr.maxUndo || 30
|
|
4797 });
|
|
4798
|
|
4799 /**
|
|
4800 * @config ptags
|
|
4801 * @description If true, the editor uses <P> tags instead of <br> tags. (Use Shift + Enter to get a <br>)
|
|
4802 * @default false
|
|
4803 * @type Boolean
|
|
4804 */
|
|
4805 this.setAttributeConfig('ptags', {
|
|
4806 writeOnce: true,
|
|
4807 value: attr.ptags || false
|
|
4808 });
|
|
4809 /**
|
|
4810 * @config insert
|
|
4811 * @description If true, selection is not required for: fontname, fontsize, forecolor, backcolor.
|
|
4812 * @default false
|
|
4813 * @type Boolean
|
|
4814 */
|
|
4815 this.setAttributeConfig('insert', {
|
|
4816 writeOnce: true,
|
|
4817 value: attr.insert || false,
|
|
4818 method: function(insert) {
|
|
4819 if (insert) {
|
|
4820 var buttons = {
|
|
4821 fontname: true,
|
|
4822 fontsize: true,
|
|
4823 forecolor: true,
|
|
4824 backcolor: true
|
|
4825 };
|
|
4826 var tmp = this._defaultToolbar.buttons;
|
|
4827 for (var i = 0; i < tmp.length; i++) {
|
|
4828 if (tmp[i].buttons) {
|
|
4829 for (var a = 0; a < tmp[i].buttons.length; a++) {
|
|
4830 if (tmp[i].buttons[a].value) {
|
|
4831 if (buttons[tmp[i].buttons[a].value]) {
|
|
4832 delete tmp[i].buttons[a].disabled;
|
|
4833 }
|
|
4834 }
|
|
4835 }
|
|
4836 }
|
|
4837 }
|
|
4838 }
|
|
4839 }
|
|
4840 });
|
|
4841 /**
|
|
4842 * @config container
|
|
4843 * @description Used when dynamically creating the Editor from Javascript with no default textarea.
|
|
4844 * We will create one and place it in this container. If no container is passed we will append to document.body.
|
|
4845 * @default false
|
|
4846 * @type HTMLElement
|
|
4847 */
|
|
4848 this.setAttributeConfig('container', {
|
|
4849 writeOnce: true,
|
|
4850 value: attr.container || false
|
|
4851 });
|
|
4852 /**
|
|
4853 * @config plainText
|
|
4854 * @description Process the inital textarea data as if it was plain text. Accounting for spaces, tabs and line feeds.
|
|
4855 * @default false
|
|
4856 * @type Boolean
|
|
4857 */
|
|
4858 this.setAttributeConfig('plainText', {
|
|
4859 writeOnce: true,
|
|
4860 value: attr.plainText || false
|
|
4861 });
|
|
4862 /**
|
|
4863 * @private
|
|
4864 * @config iframe
|
|
4865 * @description Internal config for holding the iframe element.
|
|
4866 * @default null
|
|
4867 * @type HTMLElement
|
|
4868 */
|
|
4869 this.setAttributeConfig('iframe', {
|
|
4870 value: null
|
|
4871 });
|
|
4872 /**
|
|
4873 * @private
|
|
4874 * @config disabled_iframe
|
|
4875 * @description Internal config for holding the iframe element used when disabling the Editor.
|
|
4876 * @default null
|
|
4877 * @type HTMLElement
|
|
4878 */
|
|
4879 this.setAttributeConfig('disabled_iframe', {
|
|
4880 value: null
|
|
4881 });
|
|
4882 /**
|
|
4883 * @private
|
|
4884 * @depreciated - No longer used, should use this.get('element')
|
|
4885 * @config textarea
|
|
4886 * @description Internal config for holding the textarea element (replaced with element).
|
|
4887 * @default null
|
|
4888 * @type HTMLElement
|
|
4889 */
|
|
4890 this.setAttributeConfig('textarea', {
|
|
4891 value: null,
|
|
4892 writeOnce: true
|
|
4893 });
|
|
4894 /**
|
|
4895 * @config nodeChangeThreshold
|
|
4896 * @description The number of seconds that need to be in between nodeChange processing
|
|
4897 * @default 3
|
|
4898 * @type Number
|
|
4899 */
|
|
4900 this.setAttributeConfig('nodeChangeThreshold', {
|
|
4901 value: attr.nodeChangeThreshold || 3,
|
|
4902 validator: YAHOO.lang.isNumber
|
|
4903 });
|
|
4904 /**
|
|
4905 * @config allowNoEdit
|
|
4906 * @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.
|
|
4907 * Such as highlighting an element below and above the content and hitting a toolbar button or a shortcut key.
|
|
4908 * @default false
|
|
4909 * @type Boolean
|
|
4910 */
|
|
4911 this.setAttributeConfig('allowNoEdit', {
|
|
4912 value: attr.allowNoEdit || false,
|
|
4913 validator: YAHOO.lang.isBoolean
|
|
4914 });
|
|
4915 /**
|
|
4916 * @config limitCommands
|
|
4917 * @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.
|
|
4918 * @default false
|
|
4919 * @type Boolean
|
|
4920 */
|
|
4921 this.setAttributeConfig('limitCommands', {
|
|
4922 value: attr.limitCommands || false,
|
|
4923 validator: YAHOO.lang.isBoolean
|
|
4924 });
|
|
4925 /**
|
|
4926 * @config element_cont
|
|
4927 * @description Internal config for the editors container
|
|
4928 * @default false
|
|
4929 * @type HTMLElement
|
|
4930 */
|
|
4931 this.setAttributeConfig('element_cont', {
|
|
4932 value: attr.element_cont
|
|
4933 });
|
|
4934 /**
|
|
4935 * @private
|
|
4936 * @config editor_wrapper
|
|
4937 * @description The outter wrapper for the entire editor.
|
|
4938 * @default null
|
|
4939 * @type HTMLElement
|
|
4940 */
|
|
4941 this.setAttributeConfig('editor_wrapper', {
|
|
4942 value: attr.editor_wrapper || null,
|
|
4943 writeOnce: true
|
|
4944 });
|
|
4945 /**
|
|
4946 * @attribute height
|
|
4947 * @description The height of the editor iframe container, not including the toolbar..
|
|
4948 * @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
|
|
4949 * @type String
|
|
4950 */
|
|
4951 this.setAttributeConfig('height', {
|
|
4952 value: attr.height || Dom.getStyle(self.get('element'), 'height'),
|
|
4953 method: function(height) {
|
|
4954 if (this._rendered) {
|
|
4955 //We have been rendered, change the height
|
|
4956 if (this.get('animate')) {
|
|
4957 var anim = new YAHOO.util.Anim(this.get('iframe').get('parentNode'), {
|
|
4958 height: {
|
|
4959 to: parseInt(height, 10)
|
|
4960 }
|
|
4961 }, 0.5);
|
|
4962 anim.animate();
|
|
4963 } else {
|
|
4964 Dom.setStyle(this.get('iframe').get('parentNode'), 'height', height);
|
|
4965 }
|
|
4966 }
|
|
4967 }
|
|
4968 });
|
|
4969 /**
|
|
4970 * @config autoHeight
|
|
4971 * @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.
|
|
4972 * @default false
|
|
4973 * @type Boolean || Number
|
|
4974 */
|
|
4975 this.setAttributeConfig('autoHeight', {
|
|
4976 value: attr.autoHeight || false,
|
|
4977 method: function(a) {
|
|
4978 if (a) {
|
|
4979 if (this.get('iframe')) {
|
|
4980 this.get('iframe').get('element').setAttribute('scrolling', 'no');
|
|
4981 }
|
|
4982 this.on('afterNodeChange', this._handleAutoHeight, this, true);
|
|
4983 this.on('editorKeyDown', this._handleAutoHeight, this, true);
|
|
4984 this.on('editorKeyPress', this._handleAutoHeight, this, true);
|
|
4985 } else {
|
|
4986 if (this.get('iframe')) {
|
|
4987 this.get('iframe').get('element').setAttribute('scrolling', 'auto');
|
|
4988 }
|
|
4989 this.unsubscribe('afterNodeChange', this._handleAutoHeight);
|
|
4990 this.unsubscribe('editorKeyDown', this._handleAutoHeight);
|
|
4991 this.unsubscribe('editorKeyPress', this._handleAutoHeight);
|
|
4992 }
|
|
4993 }
|
|
4994 });
|
|
4995 /**
|
|
4996 * @attribute width
|
|
4997 * @description The width of the editor container.
|
|
4998 * @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
|
|
4999 * @type String
|
|
5000 */
|
|
5001 this.setAttributeConfig('width', {
|
|
5002 value: attr.width || Dom.getStyle(this.get('element'), 'width'),
|
|
5003 method: function(width) {
|
|
5004 if (this._rendered) {
|
|
5005 //We have been rendered, change the width
|
|
5006 if (this.get('animate')) {
|
|
5007 var anim = new YAHOO.util.Anim(this.get('element_cont').get('element'), {
|
|
5008 width: {
|
|
5009 to: parseInt(width, 10)
|
|
5010 }
|
|
5011 }, 0.5);
|
|
5012 anim.animate();
|
|
5013 } else {
|
|
5014 this.get('element_cont').setStyle('width', width);
|
|
5015 }
|
|
5016 }
|
|
5017 }
|
|
5018 });
|
|
5019
|
|
5020 /**
|
|
5021 * @attribute blankimage
|
|
5022 * @description The URL for the image placeholder to put in when inserting an image.
|
|
5023 * @default The yahooapis.com address for the current release + 'assets/blankimage.png'
|
|
5024 * @type String
|
|
5025 */
|
|
5026 this.setAttributeConfig('blankimage', {
|
|
5027 value: attr.blankimage || this._getBlankImage()
|
|
5028 });
|
|
5029 /**
|
|
5030 * @attribute css
|
|
5031 * @description The Base CSS used to format the content of the editor
|
|
5032 * @default <code><pre>html {
|
|
5033 height: 95%;
|
|
5034 }
|
|
5035 body {
|
|
5036 height: 100%;
|
|
5037 padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;
|
|
5038 }
|
|
5039 a {
|
|
5040 color: blue;
|
|
5041 text-decoration: underline;
|
|
5042 cursor: pointer;
|
|
5043 }
|
|
5044 .warning-localfile {
|
|
5045 border-bottom: 1px dashed red !important;
|
|
5046 }
|
|
5047 .yui-busy {
|
|
5048 cursor: wait !important;
|
|
5049 }
|
|
5050 img.selected { //Safari image selection
|
|
5051 border: 2px dotted #808080;
|
|
5052 }
|
|
5053 img {
|
|
5054 cursor: pointer !important;
|
|
5055 border: none;
|
|
5056 }
|
|
5057 </pre></code>
|
|
5058 * @type String
|
|
5059 */
|
|
5060 this.setAttributeConfig('css', {
|
|
5061 value: attr.css || this._defaultCSS,
|
|
5062 writeOnce: true
|
|
5063 });
|
|
5064 /**
|
|
5065 * @attribute html
|
|
5066 * @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)
|
|
5067 * @default This HTML requires a few things if you are to override:
|
|
5068 <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>
|
|
5069 <p><code>onload="document.body._rteLoaded = true;"</code> : the onload statement must be there or the editor will not finish loading.</p>
|
|
5070 <code>
|
|
5071 <pre>
|
|
5072 <html>
|
|
5073 <head>
|
|
5074 <title>{TITLE}</title>
|
|
5075 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
5076 <style>
|
|
5077 {CSS}
|
|
5078 </style>
|
|
5079 <style>
|
|
5080 {HIDDEN_CSS}
|
|
5081 </style>
|
|
5082 <style>
|
|
5083 {EXTRA_CSS}
|
|
5084 </style>
|
|
5085 </head>
|
|
5086 <body onload="document.body._rteLoaded = true;">
|
|
5087 {CONTENT}
|
|
5088 </body>
|
|
5089 </html>
|
|
5090 </pre>
|
|
5091 </code>
|
|
5092 * @type String
|
|
5093 */
|
|
5094 this.setAttributeConfig('html', {
|
|
5095 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>',
|
|
5096 writeOnce: true
|
|
5097 });
|
|
5098
|
|
5099 /**
|
|
5100 * @attribute extracss
|
|
5101 * @description Extra user defined css to load after the default SimpleEditor CSS
|
|
5102 * @default ''
|
|
5103 * @type String
|
|
5104 */
|
|
5105 this.setAttributeConfig('extracss', {
|
|
5106 value: attr.extracss || '',
|
|
5107 writeOnce: true
|
|
5108 });
|
|
5109
|
|
5110 /**
|
|
5111 * @attribute handleSubmit
|
|
5112 * @description Config handles if the editor will attach itself to the textareas parent form's submit handler.
|
|
5113 If it is set to true, the editor will attempt to attach a submit listener to the textareas parent form.
|
|
5114 Then it will trigger the editors save handler and place the new content back into the text area before the form is submitted.
|
|
5115 * @default false
|
|
5116 * @type Boolean
|
|
5117 */
|
|
5118 this.setAttributeConfig('handleSubmit', {
|
|
5119 value: attr.handleSubmit || false,
|
|
5120 method: function(exec) {
|
|
5121 if (this.get('element').form) {
|
|
5122 if (!this._formButtons) {
|
|
5123 this._formButtons = [];
|
|
5124 }
|
|
5125 if (exec) {
|
|
5126 Event.on(this.get('element').form, 'submit', this._handleFormSubmit, this, true);
|
|
5127 var i = this.get('element').form.getElementsByTagName('input');
|
|
5128 for (var s = 0; s < i.length; s++) {
|
|
5129 var type = i[s].getAttribute('type');
|
|
5130 if (type && (type.toLowerCase() == 'submit')) {
|
|
5131 Event.on(i[s], 'click', this._handleFormButtonClick, this, true);
|
|
5132 this._formButtons[this._formButtons.length] = i[s];
|
|
5133 }
|
|
5134 }
|
|
5135 } else {
|
|
5136 Event.removeListener(this.get('element').form, 'submit', this._handleFormSubmit);
|
|
5137 if (this._formButtons) {
|
|
5138 Event.removeListener(this._formButtons, 'click', this._handleFormButtonClick);
|
|
5139 }
|
|
5140 }
|
|
5141 }
|
|
5142 }
|
|
5143 });
|
|
5144 /**
|
|
5145 * @attribute disabled
|
|
5146 * @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.
|
|
5147 All Toolbar buttons are also disabled so they cannot be used.
|
|
5148 * @default false
|
|
5149 * @type Boolean
|
|
5150 */
|
|
5151
|
|
5152 this.setAttributeConfig('disabled', {
|
|
5153 value: false,
|
|
5154 method: function(disabled) {
|
|
5155 if (this._rendered) {
|
|
5156 this._disableEditor(disabled);
|
|
5157 }
|
|
5158 }
|
|
5159 });
|
|
5160 /**
|
|
5161 * @config saveEl
|
|
5162 * @description When save HTML is called, this element will be updated as well as the source of data.
|
|
5163 * @default element
|
|
5164 * @type HTMLElement
|
|
5165 */
|
|
5166 this.setAttributeConfig('saveEl', {
|
|
5167 value: this.get('element')
|
|
5168 });
|
|
5169 /**
|
|
5170 * @config toolbar_cont
|
|
5171 * @description Internal config for the toolbars container
|
|
5172 * @default false
|
|
5173 * @type Boolean
|
|
5174 */
|
|
5175 this.setAttributeConfig('toolbar_cont', {
|
|
5176 value: null,
|
|
5177 writeOnce: true
|
|
5178 });
|
|
5179 /**
|
|
5180 * @attribute toolbar
|
|
5181 * @description The default toolbar config.
|
|
5182 * @type Object
|
|
5183 */
|
|
5184 this.setAttributeConfig('toolbar', {
|
|
5185 value: attr.toolbar || this._defaultToolbar,
|
|
5186 writeOnce: true,
|
|
5187 method: function(toolbar) {
|
|
5188 if (!toolbar.buttonType) {
|
|
5189 toolbar.buttonType = this._defaultToolbar.buttonType;
|
|
5190 }
|
|
5191 this._defaultToolbar = toolbar;
|
|
5192 }
|
|
5193 });
|
|
5194 /**
|
|
5195 * @attribute animate
|
|
5196 * @description Should the editor animate window movements
|
|
5197 * @default false unless Animation is found, then true
|
|
5198 * @type Boolean
|
|
5199 */
|
|
5200 this.setAttributeConfig('animate', {
|
|
5201 value: ((attr.animate) ? ((YAHOO.util.Anim) ? true : false) : false),
|
|
5202 validator: function(value) {
|
|
5203 var ret = true;
|
|
5204 if (!YAHOO.util.Anim) {
|
|
5205 ret = false;
|
|
5206 }
|
|
5207 return ret;
|
|
5208 }
|
|
5209 });
|
|
5210 /**
|
|
5211 * @config panel
|
|
5212 * @description A reference to the panel we are using for windows.
|
|
5213 * @default false
|
|
5214 * @type Boolean
|
|
5215 */
|
|
5216 this.setAttributeConfig('panel', {
|
|
5217 value: null,
|
|
5218 writeOnce: true,
|
|
5219 validator: function(value) {
|
|
5220 var ret = true;
|
|
5221 if (!YAHOO.widget.Overlay) {
|
|
5222 ret = false;
|
|
5223 }
|
|
5224 return ret;
|
|
5225 }
|
|
5226 });
|
|
5227 /**
|
|
5228 * @attribute focusAtStart
|
|
5229 * @description Should we focus the window when the content is ready?
|
|
5230 * @default false
|
|
5231 * @type Boolean
|
|
5232 */
|
|
5233 this.setAttributeConfig('focusAtStart', {
|
|
5234 value: attr.focusAtStart || false,
|
|
5235 writeOnce: true,
|
|
5236 method: function(fs) {
|
|
5237 if (fs) {
|
|
5238 this.on('editorContentLoaded', function() {
|
|
5239 var self = this;
|
|
5240 setTimeout(function() {
|
|
5241 self.focus.call(self);
|
|
5242 self.editorDirty = false;
|
|
5243 }, 400);
|
|
5244 }, this, true);
|
|
5245 }
|
|
5246 }
|
|
5247 });
|
|
5248 /**
|
|
5249 * @attribute dompath
|
|
5250 * @description Toggle the display of the current Dom path below the editor
|
|
5251 * @default false
|
|
5252 * @type Boolean
|
|
5253 */
|
|
5254 this.setAttributeConfig('dompath', {
|
|
5255 value: attr.dompath || false,
|
|
5256 method: function(dompath) {
|
|
5257 if (dompath && !this.dompath) {
|
|
5258 this.dompath = document.createElement('DIV');
|
|
5259 this.dompath.id = this.get('id') + '_dompath';
|
|
5260 Dom.addClass(this.dompath, 'dompath');
|
|
5261 this.get('element_cont').get('firstChild').appendChild(this.dompath);
|
|
5262 if (this.get('iframe')) {
|
|
5263 this._writeDomPath();
|
|
5264 }
|
|
5265 } else if (!dompath && this.dompath) {
|
|
5266 this.dompath.parentNode.removeChild(this.dompath);
|
|
5267 this.dompath = null;
|
|
5268 }
|
|
5269 }
|
|
5270 });
|
|
5271 /**
|
|
5272 * @attribute markup
|
|
5273 * @description Should we try to adjust the markup for the following types: semantic, css, default or xhtml
|
|
5274 * @default "semantic"
|
|
5275 * @type String
|
|
5276 */
|
|
5277 this.setAttributeConfig('markup', {
|
|
5278 value: attr.markup || 'semantic',
|
|
5279 validator: function(markup) {
|
|
5280 switch (markup.toLowerCase()) {
|
|
5281 case 'semantic':
|
|
5282 case 'css':
|
|
5283 case 'default':
|
|
5284 case 'xhtml':
|
|
5285 return true;
|
|
5286 }
|
|
5287 return false;
|
|
5288 }
|
|
5289 });
|
|
5290 /**
|
|
5291 * @attribute removeLineBreaks
|
|
5292 * @description Should we remove linebreaks and extra spaces on cleanup
|
|
5293 * @default false
|
|
5294 * @type Boolean
|
|
5295 */
|
|
5296 this.setAttributeConfig('removeLineBreaks', {
|
|
5297 value: attr.removeLineBreaks || false,
|
|
5298 validator: YAHOO.lang.isBoolean
|
|
5299 });
|
|
5300
|
|
5301 /**
|
|
5302 * @config drag
|
|
5303 * @description Set this config to make the Editor draggable, pass 'proxy' to make use YAHOO.util.DDProxy.
|
|
5304 * @type {Boolean/String}
|
|
5305 */
|
|
5306 this.setAttributeConfig('drag', {
|
|
5307 writeOnce: true,
|
|
5308 value: attr.drag || false
|
|
5309 });
|
|
5310
|
|
5311 /**
|
|
5312 * @config resize
|
|
5313 * @description Set this to true to make the Editor Resizable with YAHOO.util.Resize. The default config is available: myEditor._resizeConfig
|
|
5314 * Animation will be ignored while performing this resize to allow for the dynamic change in size of the toolbar.
|
|
5315 * @type Boolean
|
|
5316 */
|
|
5317 this.setAttributeConfig('resize', {
|
|
5318 writeOnce: true,
|
|
5319 value: attr.resize || false
|
|
5320 });
|
|
5321
|
|
5322 /**
|
|
5323 * @config filterWord
|
|
5324 * @description Attempt to filter out MS Word HTML from the Editor's output.
|
|
5325 * @type Boolean
|
|
5326 */
|
|
5327 this.setAttributeConfig('filterWord', {
|
|
5328 value: attr.filterWord || false,
|
|
5329 validator: YAHOO.lang.isBoolean
|
|
5330 });
|
|
5331
|
|
5332 },
|
|
5333 /**
|
|
5334 * @private
|
|
5335 * @method _getBlankImage
|
|
5336 * @description Retrieves the full url of the image to use as the blank image.
|
|
5337 * @return {String} The URL to the blank image
|
|
5338 */
|
|
5339 _getBlankImage: function() {
|
|
5340 if (!this.DOMReady) {
|
|
5341 this._queue[this._queue.length] = ['_getBlankImage', arguments];
|
|
5342 return '';
|
|
5343 }
|
|
5344 var img = '';
|
|
5345 if (!this._blankImageLoaded) {
|
|
5346 if (YAHOO.widget.EditorInfo.blankImage) {
|
|
5347 this.set('blankimage', YAHOO.widget.EditorInfo.blankImage);
|
|
5348 this._blankImageLoaded = true;
|
|
5349 } else {
|
|
5350 var div = document.createElement('div');
|
|
5351 div.style.position = 'absolute';
|
|
5352 div.style.top = '-9999px';
|
|
5353 div.style.left = '-9999px';
|
|
5354 div.className = this.CLASS_PREFIX + '-blankimage';
|
|
5355 document.body.appendChild(div);
|
|
5356 img = YAHOO.util.Dom.getStyle(div, 'background-image');
|
|
5357 img = img.replace('url(', '').replace(')', '').replace(/"/g, '');
|
|
5358 //Adobe AIR Code
|
|
5359 img = img.replace('app:/', '');
|
|
5360 this.set('blankimage', img);
|
|
5361 this._blankImageLoaded = true;
|
|
5362 div.parentNode.removeChild(div);
|
|
5363 YAHOO.widget.EditorInfo.blankImage = img;
|
|
5364 }
|
|
5365 } else {
|
|
5366 img = this.get('blankimage');
|
|
5367 }
|
|
5368 return img;
|
|
5369 },
|
|
5370 /**
|
|
5371 * @private
|
|
5372 * @method _handleAutoHeight
|
|
5373 * @description Handles resizing the editor's height based on the content
|
|
5374 */
|
|
5375 _handleAutoHeight: function() {
|
|
5376 var doc = this._getDoc(),
|
|
5377 body = doc.body,
|
|
5378 docEl = doc.documentElement;
|
|
5379
|
|
5380 var height = parseInt(Dom.getStyle(this.get('editor_wrapper'), 'height'), 10);
|
|
5381 var newHeight = body.scrollHeight;
|
|
5382 if (this.browser.webkit) {
|
|
5383 newHeight = docEl.scrollHeight;
|
|
5384 }
|
|
5385 if (newHeight < parseInt(this.get('height'), 10)) {
|
|
5386 newHeight = parseInt(this.get('height'), 10);
|
|
5387 }
|
|
5388 if ((height != newHeight) && (newHeight >= parseInt(this.get('height'), 10))) {
|
|
5389 var anim = this.get('animate');
|
|
5390 this.set('animate', false);
|
|
5391 this.set('height', newHeight + 'px');
|
|
5392 this.set('animate', anim);
|
|
5393 if (this.browser.ie) {
|
|
5394 //Internet Explorer needs this
|
|
5395 this.get('iframe').setStyle('height', '99%');
|
|
5396 this.get('iframe').setStyle('zoom', '1');
|
|
5397 var self = this;
|
|
5398 window.setTimeout(function() {
|
|
5399 self.get('iframe').setStyle('height', '100%');
|
|
5400 }, 1);
|
|
5401 }
|
|
5402 }
|
|
5403 },
|
|
5404 /**
|
|
5405 * @private
|
|
5406 * @property _formButtons
|
|
5407 * @description Array of buttons that are in the Editor's parent form (for handleSubmit)
|
|
5408 * @type Array
|
|
5409 */
|
|
5410 _formButtons: null,
|
|
5411 /**
|
|
5412 * @private
|
|
5413 * @property _formButtonClicked
|
|
5414 * @description The form button that was clicked to submit the form.
|
|
5415 * @type HTMLElement
|
|
5416 */
|
|
5417 _formButtonClicked: null,
|
|
5418 /**
|
|
5419 * @private
|
|
5420 * @method _handleFormButtonClick
|
|
5421 * @description The click listener assigned to each submit button in the Editor's parent form.
|
|
5422 * @param {Event} ev The click event
|
|
5423 */
|
|
5424 _handleFormButtonClick: function(ev) {
|
|
5425 var tar = Event.getTarget(ev);
|
|
5426 this._formButtonClicked = tar;
|
|
5427 },
|
|
5428 /**
|
|
5429 * @private
|
|
5430 * @method _handleFormSubmit
|
|
5431 * @description Handles the form submission.
|
|
5432 * @param {Object} ev The Form Submit Event
|
|
5433 */
|
|
5434 _handleFormSubmit: function(ev) {
|
|
5435 this.saveHTML();
|
|
5436
|
|
5437 var form = this.get('element').form,
|
|
5438 tar = this._formButtonClicked || false;
|
|
5439
|
|
5440 Event.removeListener(form, 'submit', this._handleFormSubmit);
|
|
5441 if (YAHOO.env.ua.ie) {
|
|
5442 //form.fireEvent("onsubmit");
|
|
5443 if (tar && !tar.disabled) {
|
|
5444 tar.click();
|
|
5445 }
|
|
5446 } else { // Gecko, Opera, and Safari
|
|
5447 if (tar && !tar.disabled) {
|
|
5448 tar.click();
|
|
5449 }
|
|
5450 var oEvent = document.createEvent("HTMLEvents");
|
|
5451 oEvent.initEvent("submit", true, true);
|
|
5452 form.dispatchEvent(oEvent);
|
|
5453 if (YAHOO.env.ua.webkit) {
|
|
5454 if (YAHOO.lang.isFunction(form.submit)) {
|
|
5455 form.submit();
|
|
5456 }
|
|
5457 }
|
|
5458 }
|
|
5459 //2.6.0
|
|
5460 //Removed this, not need since removing Safari 2.x
|
|
5461 //Event.stopEvent(ev);
|
|
5462 },
|
|
5463 /**
|
|
5464 * @private
|
|
5465 * @method _handleFontSize
|
|
5466 * @description Handles the font size button in the toolbar.
|
|
5467 * @param {Object} o Object returned from Toolbar's buttonClick Event
|
|
5468 */
|
|
5469 _handleFontSize: function(o) {
|
|
5470 var button = this.toolbar.getButtonById(o.button.id);
|
|
5471 var value = button.get('label') + 'px';
|
|
5472 this.execCommand('fontsize', value);
|
|
5473 return false;
|
|
5474 },
|
|
5475 /**
|
|
5476 * @private
|
|
5477 * @description Handles the colorpicker buttons in the toolbar.
|
|
5478 * @param {Object} o Object returned from Toolbar's buttonClick Event
|
|
5479 */
|
|
5480 _handleColorPicker: function(o) {
|
|
5481 var cmd = o.button;
|
|
5482 var value = '#' + o.color;
|
|
5483 if ((cmd == 'forecolor') || (cmd == 'backcolor')) {
|
|
5484 this.execCommand(cmd, value);
|
|
5485 }
|
|
5486 },
|
|
5487 /**
|
|
5488 * @private
|
|
5489 * @method _handleAlign
|
|
5490 * @description Handles the alignment buttons in the toolbar.
|
|
5491 * @param {Object} o Object returned from Toolbar's buttonClick Event
|
|
5492 */
|
|
5493 _handleAlign: function(o) {
|
|
5494 var cmd = null;
|
|
5495 for (var i = 0; i < o.button.menu.length; i++) {
|
|
5496 if (o.button.menu[i].value == o.button.value) {
|
|
5497 cmd = o.button.menu[i].value;
|
|
5498 }
|
|
5499 }
|
|
5500 var value = this._getSelection();
|
|
5501
|
|
5502 this.execCommand(cmd, value);
|
|
5503 return false;
|
|
5504 },
|
|
5505 /**
|
|
5506 * @private
|
|
5507 * @method _handleAfterNodeChange
|
|
5508 * @description Fires after a nodeChange happens to setup the things that where reset on the node change (button state).
|
|
5509 */
|
|
5510 _handleAfterNodeChange: function() {
|
|
5511 var path = this._getDomPath(),
|
|
5512 elm = null,
|
|
5513 family = null,
|
|
5514 fontsize = null,
|
|
5515 validFont = false,
|
|
5516 fn_button = this.toolbar.getButtonByValue('fontname'),
|
|
5517 fs_button = this.toolbar.getButtonByValue('fontsize'),
|
|
5518 hd_button = this.toolbar.getButtonByValue('heading');
|
|
5519
|
|
5520 for (var i = 0; i < path.length; i++) {
|
|
5521 elm = path[i];
|
|
5522
|
|
5523 var tag = elm.tagName.toLowerCase();
|
|
5524
|
|
5525
|
|
5526 if (elm.getAttribute('tag')) {
|
|
5527 tag = elm.getAttribute('tag');
|
|
5528 }
|
|
5529
|
|
5530 family = elm.getAttribute('face');
|
|
5531 if (Dom.getStyle(elm, 'font-family')) {
|
|
5532 family = Dom.getStyle(elm, 'font-family');
|
|
5533 //Adobe AIR Code
|
|
5534 family = family.replace(/'/g, '');
|
|
5535 }
|
|
5536
|
|
5537 if (tag.substring(0, 1) == 'h') {
|
|
5538 if (hd_button) {
|
|
5539 for (var h = 0; h < hd_button._configs.menu.value.length; h++) {
|
|
5540 if (hd_button._configs.menu.value[h].value.toLowerCase() == tag) {
|
|
5541 hd_button.set('label', hd_button._configs.menu.value[h].text);
|
|
5542 }
|
|
5543 }
|
|
5544 this._updateMenuChecked('heading', tag);
|
|
5545 }
|
|
5546 }
|
|
5547 }
|
|
5548
|
|
5549 if (fn_button) {
|
|
5550 for (var b = 0; b < fn_button._configs.menu.value.length; b++) {
|
|
5551 if (family && fn_button._configs.menu.value[b].text.toLowerCase() == family.toLowerCase()) {
|
|
5552 validFont = true;
|
|
5553 family = fn_button._configs.menu.value[b].text; //Put the proper menu name in the button
|
|
5554 }
|
|
5555 }
|
|
5556 if (!validFont) {
|
|
5557 family = fn_button._configs.label._initialConfig.value;
|
|
5558 }
|
|
5559 var familyLabel = '<span class="yui-toolbar-fontname-' + this._cleanClassName(family) + '">' + family + '</span>';
|
|
5560 if (fn_button.get('label') != familyLabel) {
|
|
5561 fn_button.set('label', familyLabel);
|
|
5562 this._updateMenuChecked('fontname', family);
|
|
5563 }
|
|
5564 }
|
|
5565
|
|
5566 if (fs_button) {
|
|
5567 fontsize = parseInt(Dom.getStyle(elm, 'fontSize'), 10);
|
|
5568 if ((fontsize === null) || isNaN(fontsize)) {
|
|
5569 fontsize = fs_button._configs.label._initialConfig.value;
|
|
5570 }
|
|
5571 fs_button.set('label', ''+fontsize);
|
|
5572 }
|
|
5573
|
|
5574 if (!this._isElement(elm, 'body') && !this._isElement(elm, 'img')) {
|
|
5575 this.toolbar.enableButton(fn_button);
|
|
5576 this.toolbar.enableButton(fs_button);
|
|
5577 this.toolbar.enableButton('forecolor');
|
|
5578 this.toolbar.enableButton('backcolor');
|
|
5579 }
|
|
5580 if (this._isElement(elm, 'img')) {
|
|
5581 if (YAHOO.widget.Overlay) {
|
|
5582 this.toolbar.enableButton('createlink');
|
|
5583 }
|
|
5584 }
|
|
5585 if (this._hasParent(elm, 'blockquote')) {
|
|
5586 this.toolbar.selectButton('indent');
|
|
5587 this.toolbar.disableButton('indent');
|
|
5588 this.toolbar.enableButton('outdent');
|
|
5589 }
|
|
5590 if (this._hasParent(elm, 'ol') || this._hasParent(elm, 'ul')) {
|
|
5591 this.toolbar.disableButton('indent');
|
|
5592 }
|
|
5593 this._lastButton = null;
|
|
5594
|
|
5595 },
|
|
5596 /**
|
|
5597 * @private
|
|
5598 * @method _handleInsertImageClick
|
|
5599 * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
|
|
5600 */
|
|
5601 _handleInsertImageClick: function() {
|
|
5602 if (this.get('limitCommands')) {
|
|
5603 if (!this.toolbar.getButtonByValue('insertimage')) {
|
|
5604 return false;
|
|
5605 }
|
|
5606 }
|
|
5607
|
|
5608 this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
|
|
5609 var _handleAEC = function() {
|
|
5610 var el = this.currentElement[0],
|
|
5611 src = 'http://';
|
|
5612 if (!el) {
|
|
5613 el = this._getSelectedElement();
|
|
5614 }
|
|
5615 if (el) {
|
|
5616 if (el.getAttribute('src')) {
|
|
5617 src = el.getAttribute('src', 2);
|
|
5618 if (src.indexOf(this.get('blankimage')) != -1) {
|
|
5619 src = this.STR_IMAGE_HERE;
|
|
5620 }
|
|
5621 }
|
|
5622 }
|
|
5623 var str = prompt(this.STR_IMAGE_URL + ': ', src);
|
|
5624 if ((str !== '') && (str !== null)) {
|
|
5625 el.setAttribute('src', str);
|
|
5626 } else if (str === '') {
|
|
5627 el.parentNode.removeChild(el);
|
|
5628 this.currentElement = [];
|
|
5629 this.nodeChange();
|
|
5630 } else if ((str === null)) {
|
|
5631 src = el.getAttribute('src', 2);
|
|
5632 if (src.indexOf(this.get('blankimage')) != -1) {
|
|
5633 el.parentNode.removeChild(el);
|
|
5634 this.currentElement = [];
|
|
5635 this.nodeChange();
|
|
5636 }
|
|
5637 }
|
|
5638 this.closeWindow();
|
|
5639 this.toolbar.set('disabled', false);
|
|
5640 this.unsubscribe('afterExecCommand', _handleAEC, this, true);
|
|
5641 };
|
|
5642 this.on('afterExecCommand', _handleAEC, this, true);
|
|
5643 },
|
|
5644 /**
|
|
5645 * @private
|
|
5646 * @method _handleInsertImageWindowClose
|
|
5647 * @description Handles the closing of the Image Properties Window.
|
|
5648 */
|
|
5649 _handleInsertImageWindowClose: function() {
|
|
5650 this.nodeChange();
|
|
5651 },
|
|
5652 /**
|
|
5653 * @private
|
|
5654 * @method _isLocalFile
|
|
5655 * @param {String} url THe url/string to check
|
|
5656 * @description Checks to see if a string (href or img src) is possibly a local file reference..
|
|
5657 */
|
|
5658 _isLocalFile: function(url) {
|
|
5659 if ((url) && (url !== '') && ((url.indexOf('file:/') != -1) || (url.indexOf(':\\') != -1))) {
|
|
5660 return true;
|
|
5661 }
|
|
5662 return false;
|
|
5663 },
|
|
5664 /**
|
|
5665 * @private
|
|
5666 * @method _handleCreateLinkClick
|
|
5667 * @description Handles the opening of the Link Properties Window when the Create Link button is clicked or an href is doubleclicked.
|
|
5668 */
|
|
5669 _handleCreateLinkClick: function() {
|
|
5670 if (this.get('limitCommands')) {
|
|
5671 if (!this.toolbar.getButtonByValue('createlink')) {
|
|
5672 return false;
|
|
5673 }
|
|
5674 }
|
|
5675
|
|
5676 this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
|
|
5677
|
|
5678 var _handleAEC = function() {
|
|
5679 var el = this.currentElement[0],
|
|
5680 url = '';
|
|
5681
|
|
5682 if (el) {
|
|
5683 if (el.getAttribute('href', 2) !== null) {
|
|
5684 url = el.getAttribute('href', 2);
|
|
5685 }
|
|
5686 }
|
|
5687 var str = prompt(this.STR_LINK_URL + ': ', url);
|
|
5688 if ((str !== '') && (str !== null)) {
|
|
5689 var urlValue = str;
|
|
5690 if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
5691 if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
5692 //Found an @ sign, prefix with mailto:
|
|
5693 urlValue = 'mailto:' + urlValue;
|
|
5694 } else {
|
|
5695 /* :// not found adding */
|
|
5696 if (urlValue.substring(0, 1) != '#') {
|
|
5697 //urlValue = 'http:/'+'/' + urlValue;
|
|
5698 }
|
|
5699 }
|
|
5700 }
|
|
5701 el.setAttribute('href', urlValue);
|
|
5702 } else if (str !== null) {
|
|
5703 var _span = this._getDoc().createElement('span');
|
|
5704 _span.innerHTML = el.innerHTML;
|
|
5705 Dom.addClass(_span, 'yui-non');
|
|
5706 el.parentNode.replaceChild(_span, el);
|
|
5707 }
|
|
5708 this.closeWindow();
|
|
5709 this.toolbar.set('disabled', false);
|
|
5710 this.unsubscribe('afterExecCommand', _handleAEC, this, true);
|
|
5711 };
|
|
5712 this.on('afterExecCommand', _handleAEC, this);
|
|
5713
|
|
5714 },
|
|
5715 /**
|
|
5716 * @private
|
|
5717 * @method _handleCreateLinkWindowClose
|
|
5718 * @description Handles the closing of the Link Properties Window.
|
|
5719 */
|
|
5720 _handleCreateLinkWindowClose: function() {
|
|
5721 this.nodeChange();
|
|
5722 this.currentElement = [];
|
|
5723 },
|
|
5724 /**
|
|
5725 * @method render
|
|
5726 * @description Calls the private method _render in a setTimeout to allow for other things on the page to continue to load.
|
|
5727 */
|
|
5728 render: function() {
|
|
5729 if (this._rendered) {
|
|
5730 return false;
|
|
5731 }
|
|
5732 if (!this.DOMReady) {
|
|
5733 this._queue[this._queue.length] = ['render', arguments];
|
|
5734 return false;
|
|
5735 }
|
|
5736 if (this.get('element')) {
|
|
5737 if (this.get('element').tagName) {
|
|
5738 this._textarea = true;
|
|
5739 if (this.get('element').tagName.toLowerCase() !== 'textarea') {
|
|
5740 this._textarea = false;
|
|
5741 }
|
|
5742 } else {
|
|
5743 return false;
|
|
5744 }
|
|
5745 } else {
|
|
5746 return false;
|
|
5747 }
|
|
5748 this._rendered = true;
|
|
5749 var self = this;
|
|
5750 window.setTimeout(function() {
|
|
5751 self._render.call(self);
|
|
5752 }, 4);
|
|
5753 },
|
|
5754 /**
|
|
5755 * @private
|
|
5756 * @method _render
|
|
5757 * @description Causes the toolbar and the editor to render and replace the textarea.
|
|
5758 */
|
|
5759 _render: function() {
|
|
5760 var self = this;
|
|
5761 this.set('textarea', this.get('element'));
|
|
5762
|
|
5763 this.get('element_cont').setStyle('display', 'none');
|
|
5764 this.get('element_cont').addClass(this.CLASS_CONTAINER);
|
|
5765
|
|
5766 this.set('iframe', this._createIframe());
|
|
5767
|
|
5768 window.setTimeout(function() {
|
|
5769 self._setInitialContent.call(self);
|
|
5770 }, 10);
|
|
5771
|
|
5772 this.get('editor_wrapper').appendChild(this.get('iframe').get('element'));
|
|
5773
|
|
5774 if (this.get('disabled')) {
|
|
5775 this._disableEditor(true);
|
|
5776 }
|
|
5777
|
|
5778 var tbarConf = this.get('toolbar');
|
|
5779 //Create Toolbar instance
|
|
5780 if (tbarConf instanceof Toolbar) {
|
|
5781 this.toolbar = tbarConf;
|
|
5782 //Set the toolbar to disabled until content is loaded
|
|
5783 this.toolbar.set('disabled', true);
|
|
5784 } else {
|
|
5785 //Set the toolbar to disabled until content is loaded
|
|
5786 tbarConf.disabled = true;
|
|
5787 this.toolbar = new Toolbar(this.get('toolbar_cont'), tbarConf);
|
|
5788 }
|
|
5789
|
|
5790 this.fireEvent('toolbarLoaded', { type: 'toolbarLoaded', target: this.toolbar });
|
|
5791
|
|
5792
|
|
5793 this.toolbar.on('toolbarCollapsed', function() {
|
|
5794 if (this.currentWindow) {
|
|
5795 this.moveWindow();
|
|
5796 }
|
|
5797 }, this, true);
|
|
5798 this.toolbar.on('toolbarExpanded', function() {
|
|
5799 if (this.currentWindow) {
|
|
5800 this.moveWindow();
|
|
5801 }
|
|
5802 }, this, true);
|
|
5803 this.toolbar.on('fontsizeClick', this._handleFontSize, this, true);
|
|
5804
|
|
5805 this.toolbar.on('colorPickerClicked', function(o) {
|
|
5806 this._handleColorPicker(o);
|
|
5807 return false; //Stop the buttonClick event
|
|
5808 }, this, true);
|
|
5809
|
|
5810 this.toolbar.on('alignClick', this._handleAlign, this, true);
|
|
5811 this.on('afterNodeChange', this._handleAfterNodeChange, this, true);
|
|
5812 this.toolbar.on('insertimageClick', this._handleInsertImageClick, this, true);
|
|
5813 this.on('windowinsertimageClose', this._handleInsertImageWindowClose, this, true);
|
|
5814 this.toolbar.on('createlinkClick', this._handleCreateLinkClick, this, true);
|
|
5815 this.on('windowcreatelinkClose', this._handleCreateLinkWindowClose, this, true);
|
|
5816
|
|
5817
|
|
5818 //Replace Textarea with editable area
|
|
5819 this.get('parentNode').replaceChild(this.get('element_cont').get('element'), this.get('element'));
|
|
5820
|
|
5821
|
|
5822 this.setStyle('visibility', 'hidden');
|
|
5823 this.setStyle('position', 'absolute');
|
|
5824 this.setStyle('top', '-9999px');
|
|
5825 this.setStyle('left', '-9999px');
|
|
5826 this.get('element_cont').appendChild(this.get('element'));
|
|
5827 this.get('element_cont').setStyle('display', 'block');
|
|
5828
|
|
5829
|
|
5830 Dom.addClass(this.get('iframe').get('parentNode'), this.CLASS_EDITABLE_CONT);
|
|
5831 this.get('iframe').addClass(this.CLASS_EDITABLE);
|
|
5832
|
|
5833 //Set height and width of editor container
|
|
5834 this.get('element_cont').setStyle('width', this.get('width'));
|
|
5835 Dom.setStyle(this.get('iframe').get('parentNode'), 'height', this.get('height'));
|
|
5836
|
|
5837 this.get('iframe').setStyle('width', '100%'); //WIDTH
|
|
5838 this.get('iframe').setStyle('height', '100%');
|
|
5839
|
|
5840 this._setupDD();
|
|
5841
|
|
5842 window.setTimeout(function() {
|
|
5843 self._setupAfterElement.call(self);
|
|
5844 }, 0);
|
|
5845 this.fireEvent('afterRender', { type: 'afterRender', target: this });
|
|
5846 },
|
|
5847 /**
|
|
5848 * @method execCommand
|
|
5849 * @param {String} action The "execCommand" action to try to execute (Example: bold, insertimage, inserthtml)
|
|
5850 * @param {String} value (optional) The value for a given action such as action: fontname value: 'Verdana'
|
|
5851 * @description This method attempts to try and level the differences in the various browsers and their support for execCommand actions
|
|
5852 */
|
|
5853 execCommand: function(action, value) {
|
|
5854 var beforeExec = this.fireEvent('beforeExecCommand', { type: 'beforeExecCommand', target: this, args: arguments });
|
|
5855 if ((beforeExec === false) || (this.STOP_EXEC_COMMAND)) {
|
|
5856 this.STOP_EXEC_COMMAND = false;
|
|
5857 return false;
|
|
5858 }
|
|
5859 this._lastCommand = action;
|
|
5860 this._setMarkupType(action);
|
|
5861 if (this.browser.ie) {
|
|
5862 this._getWindow().focus();
|
|
5863 }
|
|
5864 var exec = true;
|
|
5865
|
|
5866 if (this.get('limitCommands')) {
|
|
5867 if (!this.toolbar.getButtonByValue(action)) {
|
|
5868 exec = false;
|
|
5869 }
|
|
5870 }
|
|
5871
|
|
5872 this.editorDirty = true;
|
|
5873
|
|
5874 if ((typeof this['cmd_' + action.toLowerCase()] == 'function') && exec) {
|
|
5875 var retValue = this['cmd_' + action.toLowerCase()](value);
|
|
5876 exec = retValue[0];
|
|
5877 if (retValue[1]) {
|
|
5878 action = retValue[1];
|
|
5879 }
|
|
5880 if (retValue[2]) {
|
|
5881 value = retValue[2];
|
|
5882 }
|
|
5883 }
|
|
5884 if (exec) {
|
|
5885 try {
|
|
5886 this._getDoc().execCommand(action, false, value);
|
|
5887 } catch(e) {
|
|
5888 }
|
|
5889 } else {
|
|
5890 }
|
|
5891 this.on('afterExecCommand', function() {
|
|
5892 this.unsubscribeAll('afterExecCommand');
|
|
5893 this.nodeChange();
|
|
5894 }, this, true);
|
|
5895 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
5896
|
|
5897 },
|
|
5898 /* {{{ Command Overrides */
|
|
5899
|
|
5900 /**
|
|
5901 * @method cmd_bold
|
|
5902 * @param value Value passed from the execCommand method
|
|
5903 * @description This is an execCommand override method. It is called from execCommand when the execCommand('bold') is used.
|
|
5904 */
|
|
5905 cmd_bold: function(value) {
|
|
5906 if (!this.browser.webkit) {
|
|
5907 var el = this._getSelectedElement();
|
|
5908 if (el && this._isElement(el, 'span') && this._hasSelection()) {
|
|
5909 if (el.style.fontWeight == 'bold') {
|
|
5910 el.style.fontWeight = '';
|
|
5911 var b = this._getDoc().createElement('b'),
|
|
5912 par = el.parentNode;
|
|
5913 par.replaceChild(b, el);
|
|
5914 b.appendChild(el);
|
|
5915 }
|
|
5916 }
|
|
5917 }
|
|
5918 return [true];
|
|
5919 },
|
|
5920 /**
|
|
5921 * @method cmd_italic
|
|
5922 * @param value Value passed from the execCommand method
|
|
5923 * @description This is an execCommand override method. It is called from execCommand when the execCommand('italic') is used.
|
|
5924 */
|
|
5925
|
|
5926 cmd_italic: function(value) {
|
|
5927 if (!this.browser.webkit) {
|
|
5928 var el = this._getSelectedElement();
|
|
5929 if (el && this._isElement(el, 'span') && this._hasSelection()) {
|
|
5930 if (el.style.fontStyle == 'italic') {
|
|
5931 el.style.fontStyle = '';
|
|
5932 var i = this._getDoc().createElement('i'),
|
|
5933 par = el.parentNode;
|
|
5934 par.replaceChild(i, el);
|
|
5935 i.appendChild(el);
|
|
5936 }
|
|
5937 }
|
|
5938 }
|
|
5939 return [true];
|
|
5940 },
|
|
5941
|
|
5942
|
|
5943 /**
|
|
5944 * @method cmd_underline
|
|
5945 * @param value Value passed from the execCommand method
|
|
5946 * @description This is an execCommand override method. It is called from execCommand when the execCommand('underline') is used.
|
|
5947 */
|
|
5948 cmd_underline: function(value) {
|
|
5949 if (!this.browser.webkit) {
|
|
5950 var el = this._getSelectedElement();
|
|
5951 if (el && this._isElement(el, 'span')) {
|
|
5952 if (el.style.textDecoration == 'underline') {
|
|
5953 el.style.textDecoration = 'none';
|
|
5954 } else {
|
|
5955 el.style.textDecoration = 'underline';
|
|
5956 }
|
|
5957 return [false];
|
|
5958 }
|
|
5959 }
|
|
5960 return [true];
|
|
5961 },
|
|
5962 /**
|
|
5963 * @method cmd_backcolor
|
|
5964 * @param value Value passed from the execCommand method
|
|
5965 * @description This is an execCommand override method. It is called from execCommand when the execCommand('backcolor') is used.
|
|
5966 */
|
|
5967 cmd_backcolor: function(value) {
|
|
5968 var exec = true,
|
|
5969 el = this._getSelectedElement(),
|
|
5970 action = 'backcolor';
|
|
5971
|
|
5972 if (this.browser.gecko || this.browser.opera) {
|
|
5973 this._setEditorStyle(true);
|
|
5974 action = 'hilitecolor';
|
|
5975 }
|
|
5976
|
|
5977 if (!this._isElement(el, 'body') && !this._hasSelection()) {
|
|
5978 el.style.backgroundColor = value;
|
|
5979 this._selectNode(el);
|
|
5980 exec = false;
|
|
5981 } else {
|
|
5982 if (this.get('insert')) {
|
|
5983 el = this._createInsertElement({ backgroundColor: value });
|
|
5984 } else {
|
|
5985 this._createCurrentElement('span', { backgroundColor: value, color: el.style.color, fontSize: el.style.fontSize, fontFamily: el.style.fontFamily });
|
|
5986 this._selectNode(this.currentElement[0]);
|
|
5987 }
|
|
5988 exec = false;
|
|
5989 }
|
|
5990
|
|
5991 return [exec, action];
|
|
5992 },
|
|
5993 /**
|
|
5994 * @method cmd_forecolor
|
|
5995 * @param value Value passed from the execCommand method
|
|
5996 * @description This is an execCommand override method. It is called from execCommand when the execCommand('forecolor') is used.
|
|
5997 */
|
|
5998 cmd_forecolor: function(value) {
|
|
5999 var exec = true,
|
|
6000 el = this._getSelectedElement();
|
|
6001
|
|
6002 if (!this._isElement(el, 'body') && !this._hasSelection()) {
|
|
6003 Dom.setStyle(el, 'color', value);
|
|
6004 this._selectNode(el);
|
|
6005 exec = false;
|
|
6006 } else {
|
|
6007 if (this.get('insert')) {
|
|
6008 el = this._createInsertElement({ color: value });
|
|
6009 } else {
|
|
6010 this._createCurrentElement('span', { color: value, fontSize: el.style.fontSize, fontFamily: el.style.fontFamily, backgroundColor: el.style.backgroundColor });
|
|
6011 this._selectNode(this.currentElement[0]);
|
|
6012 }
|
|
6013 exec = false;
|
|
6014 }
|
|
6015 return [exec];
|
|
6016 },
|
|
6017 /**
|
|
6018 * @method cmd_unlink
|
|
6019 * @param value Value passed from the execCommand method
|
|
6020 * @description This is an execCommand override method. It is called from execCommand when the execCommand('unlink') is used.
|
|
6021 */
|
|
6022 cmd_unlink: function(value) {
|
|
6023 this._swapEl(this.currentElement[0], 'span', function(el) {
|
|
6024 el.className = 'yui-non';
|
|
6025 });
|
|
6026 return [false];
|
|
6027 },
|
|
6028 /**
|
|
6029 * @method cmd_createlink
|
|
6030 * @param value Value passed from the execCommand method
|
|
6031 * @description This is an execCommand override method. It is called from execCommand when the execCommand('createlink') is used.
|
|
6032 */
|
|
6033 cmd_createlink: function(value) {
|
|
6034 var el = this._getSelectedElement(), _a = null;
|
|
6035 if (this._hasParent(el, 'a')) {
|
|
6036 this.currentElement[0] = this._hasParent(el, 'a');
|
|
6037 } else if (this._isElement(el, 'li')) {
|
|
6038 _a = this._getDoc().createElement('a');
|
|
6039 _a.innerHTML = el.innerHTML;
|
|
6040 el.innerHTML = '';
|
|
6041 el.appendChild(_a);
|
|
6042 this.currentElement[0] = _a;
|
|
6043 } else if (!this._isElement(el, 'a')) {
|
|
6044 this._createCurrentElement('a');
|
|
6045 _a = this._swapEl(this.currentElement[0], 'a');
|
|
6046 this.currentElement[0] = _a;
|
|
6047 } else {
|
|
6048 this.currentElement[0] = el;
|
|
6049 }
|
|
6050 return [false];
|
|
6051 },
|
|
6052 /**
|
|
6053 * @method cmd_insertimage
|
|
6054 * @param value Value passed from the execCommand method
|
|
6055 * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertimage') is used.
|
|
6056 */
|
|
6057 cmd_insertimage: function(value) {
|
|
6058 var exec = true, _img = null, action = 'insertimage',
|
|
6059 el = this._getSelectedElement();
|
|
6060
|
|
6061 if (value === '') {
|
|
6062 value = this.get('blankimage');
|
|
6063 }
|
|
6064
|
|
6065 /*
|
|
6066 * @knownissue Safari Cursor Position
|
|
6067 * @browser Safari 2.x
|
|
6068 * @description The issue here is that we have no way of knowing where the cursor position is
|
|
6069 * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
|
|
6070 */
|
|
6071
|
|
6072 if (this._isElement(el, 'img')) {
|
|
6073 this.currentElement[0] = el;
|
|
6074 exec = false;
|
|
6075 } else {
|
|
6076 if (this._getDoc().queryCommandEnabled(action)) {
|
|
6077 this._getDoc().execCommand(action, false, value);
|
|
6078 var imgs = this._getDoc().getElementsByTagName('img');
|
|
6079 for (var i = 0; i < imgs.length; i++) {
|
|
6080 if (!YAHOO.util.Dom.hasClass(imgs[i], 'yui-img')) {
|
|
6081 YAHOO.util.Dom.addClass(imgs[i], 'yui-img');
|
|
6082 this.currentElement[0] = imgs[i];
|
|
6083 }
|
|
6084 }
|
|
6085 exec = false;
|
|
6086 } else {
|
|
6087 if (el == this._getDoc().body) {
|
|
6088 _img = this._getDoc().createElement('img');
|
|
6089 _img.setAttribute('src', value);
|
|
6090 YAHOO.util.Dom.addClass(_img, 'yui-img');
|
|
6091 this._getDoc().body.appendChild(_img);
|
|
6092 } else {
|
|
6093 this._createCurrentElement('img');
|
|
6094 _img = this._getDoc().createElement('img');
|
|
6095 _img.setAttribute('src', value);
|
|
6096 YAHOO.util.Dom.addClass(_img, 'yui-img');
|
|
6097 this.currentElement[0].parentNode.replaceChild(_img, this.currentElement[0]);
|
|
6098 }
|
|
6099 this.currentElement[0] = _img;
|
|
6100 exec = false;
|
|
6101 }
|
|
6102 }
|
|
6103 return [exec];
|
|
6104 },
|
|
6105 /**
|
|
6106 * @method cmd_inserthtml
|
|
6107 * @param value Value passed from the execCommand method
|
|
6108 * @description This is an execCommand override method. It is called from execCommand when the execCommand('inserthtml') is used.
|
|
6109 */
|
|
6110 cmd_inserthtml: function(value) {
|
|
6111 var exec = true, action = 'inserthtml', _span = null, _range = null;
|
|
6112 /*
|
|
6113 * @knownissue Safari cursor position
|
|
6114 * @browser Safari 2.x
|
|
6115 * @description The issue here is that we have no way of knowing where the cursor position is
|
|
6116 * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
|
|
6117 */
|
|
6118 if (this.browser.webkit && !this._getDoc().queryCommandEnabled(action)) {
|
|
6119 this._createCurrentElement('img');
|
|
6120 _span = this._getDoc().createElement('span');
|
|
6121 _span.innerHTML = value;
|
|
6122 this.currentElement[0].parentNode.replaceChild(_span, this.currentElement[0]);
|
|
6123 exec = false;
|
|
6124 } else if (this.browser.ie) {
|
|
6125 _range = this._getRange();
|
|
6126 if (_range.item) {
|
|
6127 _range.item(0).outerHTML = value;
|
|
6128 } else {
|
|
6129 _range.pasteHTML(value);
|
|
6130 }
|
|
6131 exec = false;
|
|
6132 }
|
|
6133 return [exec];
|
|
6134 },
|
|
6135 /**
|
|
6136 * @method cmd_list
|
|
6137 * @param tag The tag of the list you want to create (eg, ul or ol)
|
|
6138 * @description This is a combined execCommand override method. It is called from the cmd_insertorderedlist and cmd_insertunorderedlist methods.
|
|
6139 */
|
|
6140 cmd_list: function(tag) {
|
|
6141 var exec = true, list = null, li = 0, el = null, str = '',
|
|
6142 selEl = this._getSelectedElement(), action = 'insertorderedlist';
|
|
6143 if (tag == 'ul') {
|
|
6144 action = 'insertunorderedlist';
|
|
6145 }
|
|
6146 /*
|
|
6147 * @knownissue Safari 2.+ doesn't support ordered and unordered lists
|
|
6148 * @browser Safari 2.x
|
|
6149 * The issue with this workaround is that when applied to a set of text
|
|
6150 * that has BR's in it, Safari may or may not pick up the individual items as
|
|
6151 * list items. This is fixed in WebKit (Safari 3)
|
|
6152 * 2.6.0: Seems there are still some issues with List Creation and Safari 3, reverting to previously working Safari 2.x code
|
|
6153 */
|
|
6154 //if ((this.browser.webkit && !this._getDoc().queryCommandEnabled(action))) {
|
|
6155 if ((this.browser.webkit && !this.browser.webkit4) || (this.browser.opera)) {
|
|
6156 if (this._isElement(selEl, 'li') && this._isElement(selEl.parentNode, tag)) {
|
|
6157 el = selEl.parentNode;
|
|
6158 list = this._getDoc().createElement('span');
|
|
6159 YAHOO.util.Dom.addClass(list, 'yui-non');
|
|
6160 str = '';
|
|
6161 var lis = el.getElementsByTagName('li'), p_tag = ((this.browser.opera && this.get('ptags')) ? 'p' : 'div');
|
|
6162 for (li = 0; li < lis.length; li++) {
|
|
6163 str += '<' + p_tag + '>' + lis[li].innerHTML + '</' + p_tag + '>';
|
|
6164 }
|
|
6165 list.innerHTML = str;
|
|
6166 this.currentElement[0] = el;
|
|
6167 this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
|
|
6168 } else {
|
|
6169 this._createCurrentElement(tag.toLowerCase());
|
|
6170 list = this._getDoc().createElement(tag);
|
|
6171 for (li = 0; li < this.currentElement.length; li++) {
|
|
6172 var newli = this._getDoc().createElement('li');
|
|
6173 newli.innerHTML = this.currentElement[li].innerHTML + '<span class="yui-non"> </span> ';
|
|
6174 list.appendChild(newli);
|
|
6175 if (li > 0) {
|
|
6176 this.currentElement[li].parentNode.removeChild(this.currentElement[li]);
|
|
6177 }
|
|
6178 }
|
|
6179 var b_tag = ((this.browser.opera) ? '<BR>' : '<br>'),
|
|
6180 items = list.firstChild.innerHTML.split(b_tag), i, item;
|
|
6181 if (items.length > 0) {
|
|
6182 list.innerHTML = '';
|
|
6183 for (i = 0; i < items.length; i++) {
|
|
6184 item = this._getDoc().createElement('li');
|
|
6185 item.innerHTML = items[i];
|
|
6186 list.appendChild(item);
|
|
6187 }
|
|
6188 }
|
|
6189
|
|
6190 this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
|
|
6191 this.currentElement[0] = list;
|
|
6192 var _h = this.currentElement[0].firstChild;
|
|
6193 _h = Dom.getElementsByClassName('yui-non', 'span', _h)[0];
|
|
6194 if (this.browser.webkit) {
|
|
6195 this._getSelection().setBaseAndExtent(_h, 1, _h, _h.innerText.length);
|
|
6196 }
|
|
6197 }
|
|
6198 exec = false;
|
|
6199 } else {
|
|
6200 el = this._getSelectedElement();
|
|
6201 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..
|
|
6202 if (this.browser.ie) {
|
|
6203 if ((this.browser.ie && this._isElement(el, 'ul')) || (this.browser.ie && this._isElement(el, 'ol'))) {
|
|
6204 el = el.getElementsByTagName('li')[0];
|
|
6205 }
|
|
6206 str = '';
|
|
6207 var lis2 = el.parentNode.getElementsByTagName('li');
|
|
6208 for (var j = 0; j < lis2.length; j++) {
|
|
6209 str += lis2[j].innerHTML + '<br>';
|
|
6210 }
|
|
6211 var newEl = this._getDoc().createElement('span');
|
|
6212 newEl.innerHTML = str;
|
|
6213 el.parentNode.parentNode.replaceChild(newEl, el.parentNode);
|
|
6214 } else {
|
|
6215 this.nodeChange();
|
|
6216 this._getDoc().execCommand(action, '', el.parentNode);
|
|
6217 this.nodeChange();
|
|
6218 }
|
|
6219 exec = false;
|
|
6220 }
|
|
6221 if (this.browser.opera) {
|
|
6222 var self = this;
|
|
6223 window.setTimeout(function() {
|
|
6224 var liso = self._getDoc().getElementsByTagName('li');
|
|
6225 for (var i = 0; i < liso.length; i++) {
|
|
6226 if (liso[i].innerHTML.toLowerCase() == '<br>') {
|
|
6227 liso[i].parentNode.parentNode.removeChild(liso[i].parentNode);
|
|
6228 }
|
|
6229 }
|
|
6230 },30);
|
|
6231 }
|
|
6232 if (this.browser.ie && exec) {
|
|
6233 var html = '';
|
|
6234 if (this._getRange().html) {
|
|
6235 html = '<li>' + this._getRange().html+ '</li>';
|
|
6236 } else {
|
|
6237 var t = this._getRange().text.split('\n');
|
|
6238 if (t.length > 1) {
|
|
6239 html = '';
|
|
6240 for (var ie = 0; ie < t.length; ie++) {
|
|
6241 html += '<li>' + t[ie] + '</li>';
|
|
6242 }
|
|
6243 } else {
|
|
6244 var txt = this._getRange().text;
|
|
6245 if (txt === '') {
|
|
6246 html = '<li id="new_list_item">' + txt + '</li>';
|
|
6247 } else {
|
|
6248 html = '<li>' + txt + '</li>';
|
|
6249 }
|
|
6250 }
|
|
6251 }
|
|
6252 this._getRange().pasteHTML('<' + tag + '>' + html + '</' + tag + '>');
|
|
6253 var new_item = this._getDoc().getElementById('new_list_item');
|
|
6254 if (new_item) {
|
|
6255 var range = this._getDoc().body.createTextRange();
|
|
6256 range.moveToElementText(new_item);
|
|
6257 range.collapse(false);
|
|
6258 range.select();
|
|
6259 new_item.id = '';
|
|
6260 }
|
|
6261 exec = false;
|
|
6262 }
|
|
6263 }
|
|
6264 return exec;
|
|
6265 },
|
|
6266 /**
|
|
6267 * @method cmd_insertorderedlist
|
|
6268 * @param value Value passed from the execCommand method
|
|
6269 * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertorderedlist ') is used.
|
|
6270 */
|
|
6271 cmd_insertorderedlist: function(value) {
|
|
6272 return [this.cmd_list('ol')];
|
|
6273 },
|
|
6274 /**
|
|
6275 * @method cmd_insertunorderedlist
|
|
6276 * @param value Value passed from the execCommand method
|
|
6277 * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertunorderedlist') is used.
|
|
6278 */
|
|
6279 cmd_insertunorderedlist: function(value) {
|
|
6280 return [this.cmd_list('ul')];
|
|
6281 },
|
|
6282 /**
|
|
6283 * @method cmd_fontname
|
|
6284 * @param value Value passed from the execCommand method
|
|
6285 * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontname') is used.
|
|
6286 */
|
|
6287 cmd_fontname: function(value) {
|
|
6288 var exec = true,
|
|
6289 selEl = this._getSelectedElement();
|
|
6290
|
|
6291 this.currentFont = value;
|
|
6292 if (selEl && selEl.tagName && !this._hasSelection() && !this._isElement(selEl, 'body') && !this.get('insert')) {
|
|
6293 YAHOO.util.Dom.setStyle(selEl, 'font-family', value);
|
|
6294 exec = false;
|
|
6295 } else if (this.get('insert') && !this._hasSelection()) {
|
|
6296 var el = this._createInsertElement({ fontFamily: value });
|
|
6297 exec = false;
|
|
6298 }
|
|
6299 return [exec];
|
|
6300 },
|
|
6301 /**
|
|
6302 * @method cmd_fontsize
|
|
6303 * @param value Value passed from the execCommand method
|
|
6304 * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontsize') is used.
|
|
6305 */
|
|
6306 cmd_fontsize: function(value) {
|
|
6307 var el = null, go = true;
|
|
6308 el = this._getSelectedElement();
|
|
6309 if (this.browser.webkit) {
|
|
6310 if (this.currentElement[0]) {
|
|
6311 if (el == this.currentElement[0]) {
|
|
6312 go = false;
|
|
6313 YAHOO.util.Dom.setStyle(el, 'fontSize', value);
|
|
6314 this._selectNode(el);
|
|
6315 this.currentElement[0] = el;
|
|
6316 }
|
|
6317 }
|
|
6318 }
|
|
6319 if (go) {
|
|
6320 if (!this._isElement(this._getSelectedElement(), 'body') && (!this._hasSelection())) {
|
|
6321 el = this._getSelectedElement();
|
|
6322 YAHOO.util.Dom.setStyle(el, 'fontSize', value);
|
|
6323 if (this.get('insert') && this.browser.ie) {
|
|
6324 var r = this._getRange();
|
|
6325 r.collapse(false);
|
|
6326 r.select();
|
|
6327 } else {
|
|
6328 this._selectNode(el);
|
|
6329 }
|
|
6330 } else if (this.currentElement && (this.currentElement.length > 0) && (!this._hasSelection()) && (!this.get('insert'))) {
|
|
6331 YAHOO.util.Dom.setStyle(this.currentElement, 'fontSize', value);
|
|
6332 } else {
|
|
6333 if (this.get('insert') && !this._hasSelection()) {
|
|
6334 el = this._createInsertElement({ fontSize: value });
|
|
6335 this.currentElement[0] = el;
|
|
6336 this._selectNode(this.currentElement[0]);
|
|
6337 } else {
|
|
6338 this._createCurrentElement('span', {'fontSize': value, fontFamily: el.style.fontFamily, color: el.style.color, backgroundColor: el.style.backgroundColor });
|
|
6339 this._selectNode(this.currentElement[0]);
|
|
6340 }
|
|
6341 }
|
|
6342 }
|
|
6343 return [false];
|
|
6344 },
|
|
6345 /* }}} */
|
|
6346 /**
|
|
6347 * @private
|
|
6348 * @method _swapEl
|
|
6349 * @param {HTMLElement} el The element to swap with
|
|
6350 * @param {String} tagName The tagname of the element that you wish to create
|
|
6351 * @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.
|
|
6352 * @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.
|
|
6353 */
|
|
6354 _swapEl: function(el, tagName, callback) {
|
|
6355 var _el = this._getDoc().createElement(tagName);
|
|
6356 if (el) {
|
|
6357 _el.innerHTML = el.innerHTML;
|
|
6358 }
|
|
6359 if (typeof callback == 'function') {
|
|
6360 callback.call(this, _el);
|
|
6361 }
|
|
6362 if (el) {
|
|
6363 el.parentNode.replaceChild(_el, el);
|
|
6364 }
|
|
6365 return _el;
|
|
6366 },
|
|
6367 /**
|
|
6368 * @private
|
|
6369 * @method _createInsertElement
|
|
6370 * @description Creates a new "currentElement" then adds some text (and other things) to make it selectable and stylable. Then the user can continue typing.
|
|
6371 * @param {Object} css (optional) Object literal containing styles to apply to the new element.
|
|
6372 * @return {HTMLElement}
|
|
6373 */
|
|
6374 _createInsertElement: function(css) {
|
|
6375 this._createCurrentElement('span', css);
|
|
6376 var el = this.currentElement[0];
|
|
6377 if (this.browser.webkit) {
|
|
6378 //Little Safari Hackery here..
|
|
6379 el.innerHTML = '<span class="yui-non"> </span>';
|
|
6380 el = el.firstChild;
|
|
6381 this._getSelection().setBaseAndExtent(el, 1, el, el.innerText.length);
|
|
6382 } else if (this.browser.ie || this.browser.opera) {
|
|
6383 el.innerHTML = ' ';
|
|
6384 }
|
|
6385 this.focus();
|
|
6386 this._selectNode(el, true);
|
|
6387 return el;
|
|
6388 },
|
|
6389 /**
|
|
6390 * @private
|
|
6391 * @method _createCurrentElement
|
|
6392 * @param {String} tagName (optional defaults to a) The tagname of the element that you wish to create
|
|
6393 * @param {Object} tagStyle (optional) Object literal containing styles to apply to the new element.
|
|
6394 * @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.
|
|
6395 * 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
|
|
6396 * <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.
|
|
6397 */
|
|
6398 _createCurrentElement: function(tagName, tagStyle) {
|
|
6399 tagName = ((tagName) ? tagName : 'a');
|
|
6400 var tar = null,
|
|
6401 el = [],
|
|
6402 _doc = this._getDoc();
|
|
6403
|
|
6404 if (this.currentFont) {
|
|
6405 if (!tagStyle) {
|
|
6406 tagStyle = {};
|
|
6407 }
|
|
6408 tagStyle.fontFamily = this.currentFont;
|
|
6409 this.currentFont = null;
|
|
6410 }
|
|
6411 this.currentElement = [];
|
|
6412
|
|
6413 var _elCreate = function(tagName, tagStyle) {
|
|
6414 var el = null;
|
|
6415 tagName = ((tagName) ? tagName : 'span');
|
|
6416 tagName = tagName.toLowerCase();
|
|
6417 switch (tagName) {
|
|
6418 case 'h1':
|
|
6419 case 'h2':
|
|
6420 case 'h3':
|
|
6421 case 'h4':
|
|
6422 case 'h5':
|
|
6423 case 'h6':
|
|
6424 el = _doc.createElement(tagName);
|
|
6425 break;
|
|
6426 default:
|
|
6427 el = _doc.createElement(tagName);
|
|
6428 if (tagName === 'span') {
|
|
6429 YAHOO.util.Dom.addClass(el, 'yui-tag-' + tagName);
|
|
6430 YAHOO.util.Dom.addClass(el, 'yui-tag');
|
|
6431 el.setAttribute('tag', tagName);
|
|
6432 }
|
|
6433
|
|
6434 for (var k in tagStyle) {
|
|
6435 if (YAHOO.lang.hasOwnProperty(tagStyle, k)) {
|
|
6436 el.style[k] = tagStyle[k];
|
|
6437 }
|
|
6438 }
|
|
6439 break;
|
|
6440 }
|
|
6441 return el;
|
|
6442 };
|
|
6443
|
|
6444 if (!this._hasSelection()) {
|
|
6445 if (this._getDoc().queryCommandEnabled('insertimage')) {
|
|
6446 this._getDoc().execCommand('insertimage', false, 'yui-tmp-img');
|
|
6447 var imgs = this._getDoc().getElementsByTagName('img');
|
|
6448 for (var j = 0; j < imgs.length; j++) {
|
|
6449 if (imgs[j].getAttribute('src', 2) == 'yui-tmp-img') {
|
|
6450 el = _elCreate(tagName, tagStyle);
|
|
6451 imgs[j].parentNode.replaceChild(el, imgs[j]);
|
|
6452 this.currentElement[this.currentElement.length] = el;
|
|
6453 }
|
|
6454 }
|
|
6455 } else {
|
|
6456 if (this.currentEvent) {
|
|
6457 tar = YAHOO.util.Event.getTarget(this.currentEvent);
|
|
6458 } else {
|
|
6459 //For Safari..
|
|
6460 tar = this._getDoc().body;
|
|
6461 }
|
|
6462 }
|
|
6463 if (tar) {
|
|
6464 /*
|
|
6465 * @knownissue Safari Cursor Position
|
|
6466 * @browser Safari 2.x
|
|
6467 * @description The issue here is that we have no way of knowing where the cursor position is
|
|
6468 * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
|
|
6469 */
|
|
6470 el = _elCreate(tagName, tagStyle);
|
|
6471 if (this._isElement(tar, 'body') || this._isElement(tar, 'html')) {
|
|
6472 if (this._isElement(tar, 'html')) {
|
|
6473 tar = this._getDoc().body;
|
|
6474 }
|
|
6475 tar.appendChild(el);
|
|
6476 } else if (tar.nextSibling) {
|
|
6477 tar.parentNode.insertBefore(el, tar.nextSibling);
|
|
6478 } else {
|
|
6479 tar.parentNode.appendChild(el);
|
|
6480 }
|
|
6481 //this.currentElement = el;
|
|
6482 this.currentElement[this.currentElement.length] = el;
|
|
6483 this.currentEvent = null;
|
|
6484 if (this.browser.webkit) {
|
|
6485 //Force Safari to focus the new element
|
|
6486 this._getSelection().setBaseAndExtent(el, 0, el, 0);
|
|
6487 if (this.browser.webkit3) {
|
|
6488 this._getSelection().collapseToStart();
|
|
6489 } else {
|
|
6490 this._getSelection().collapse(true);
|
|
6491 }
|
|
6492 }
|
|
6493 }
|
|
6494 } else {
|
|
6495 //Force CSS Styling for this action...
|
|
6496 this._setEditorStyle(true);
|
|
6497 this._getDoc().execCommand('fontname', false, 'yui-tmp');
|
|
6498 var _tmp = [], __tmp, __els = ['font', 'span', 'i', 'b', 'u'];
|
|
6499
|
|
6500 if (!this._isElement(this._getSelectedElement(), 'body')) {
|
|
6501 __els[__els.length] = this._getDoc().getElementsByTagName(this._getSelectedElement().tagName);
|
|
6502 __els[__els.length] = this._getDoc().getElementsByTagName(this._getSelectedElement().parentNode.tagName);
|
|
6503 }
|
|
6504 for (var _els = 0; _els < __els.length; _els++) {
|
|
6505 var _tmp1 = this._getDoc().getElementsByTagName(__els[_els]);
|
|
6506 for (var e = 0; e < _tmp1.length; e++) {
|
|
6507 _tmp[_tmp.length] = _tmp1[e];
|
|
6508 }
|
|
6509 }
|
|
6510
|
|
6511
|
|
6512 for (var i = 0; i < _tmp.length; i++) {
|
|
6513 if ((YAHOO.util.Dom.getStyle(_tmp[i], 'font-family') == 'yui-tmp') || (_tmp[i].face && (_tmp[i].face == 'yui-tmp'))) {
|
|
6514 if (tagName !== 'span') {
|
|
6515 el = _elCreate(tagName, tagStyle);
|
|
6516 } else {
|
|
6517 el = _elCreate(_tmp[i].tagName, tagStyle);
|
|
6518 }
|
|
6519 el.innerHTML = _tmp[i].innerHTML;
|
|
6520 if (this._isElement(_tmp[i], 'ol') || (this._isElement(_tmp[i], 'ul'))) {
|
|
6521 var fc = _tmp[i].getElementsByTagName('li')[0];
|
|
6522 _tmp[i].style.fontFamily = 'inherit';
|
|
6523 fc.style.fontFamily = 'inherit';
|
|
6524 el.innerHTML = fc.innerHTML;
|
|
6525 fc.innerHTML = '';
|
|
6526 fc.appendChild(el);
|
|
6527 this.currentElement[this.currentElement.length] = el;
|
|
6528 } else if (this._isElement(_tmp[i], 'li')) {
|
|
6529 _tmp[i].innerHTML = '';
|
|
6530 _tmp[i].appendChild(el);
|
|
6531 _tmp[i].style.fontFamily = 'inherit';
|
|
6532 this.currentElement[this.currentElement.length] = el;
|
|
6533 } else {
|
|
6534 if (_tmp[i].parentNode) {
|
|
6535 _tmp[i].parentNode.replaceChild(el, _tmp[i]);
|
|
6536 this.currentElement[this.currentElement.length] = el;
|
|
6537 this.currentEvent = null;
|
|
6538 if (this.browser.webkit) {
|
|
6539 //Force Safari to focus the new element
|
|
6540 this._getSelection().setBaseAndExtent(el, 0, el, 0);
|
|
6541 if (this.browser.webkit3) {
|
|
6542 this._getSelection().collapseToStart();
|
|
6543 } else {
|
|
6544 this._getSelection().collapse(true);
|
|
6545 }
|
|
6546 }
|
|
6547 if (this.browser.ie && tagStyle && tagStyle.fontSize) {
|
|
6548 this._getSelection().empty();
|
|
6549 }
|
|
6550 if (this.browser.gecko) {
|
|
6551 this._getSelection().collapseToStart();
|
|
6552 }
|
|
6553 }
|
|
6554 }
|
|
6555 }
|
|
6556 }
|
|
6557 var len = this.currentElement.length;
|
|
6558 for (var o = 0; o < len; o++) {
|
|
6559 if ((o + 1) != len) { //Skip the last one in the list
|
|
6560 if (this.currentElement[o] && this.currentElement[o].nextSibling) {
|
|
6561 if (this._isElement(this.currentElement[o], 'br')) {
|
|
6562 this.currentElement[this.currentElement.length] = this.currentElement[o].nextSibling;
|
|
6563 }
|
|
6564 }
|
|
6565 }
|
|
6566 }
|
|
6567 }
|
|
6568 },
|
|
6569 /**
|
|
6570 * @method saveHTML
|
|
6571 * @description Cleans the HTML with the cleanHTML method then places that string back into the textarea.
|
|
6572 * @return String
|
|
6573 */
|
|
6574 saveHTML: function() {
|
|
6575 var html = this.cleanHTML();
|
|
6576 if (this._textarea) {
|
|
6577 this.get('element').value = html;
|
|
6578 } else {
|
|
6579 this.get('element').innerHTML = html;
|
|
6580 }
|
|
6581 if (this.get('saveEl') !== this.get('element')) {
|
|
6582 var out = this.get('saveEl');
|
|
6583 if (Lang.isString(out)) {
|
|
6584 out = Dom.get(out);
|
|
6585 }
|
|
6586 if (out) {
|
|
6587 if (out.tagName.toLowerCase() === 'textarea') {
|
|
6588 out.value = html;
|
|
6589 } else {
|
|
6590 out.innerHTML = html;
|
|
6591 }
|
|
6592 }
|
|
6593 }
|
|
6594 return html;
|
|
6595 },
|
|
6596 /**
|
|
6597 * @method setEditorHTML
|
|
6598 * @param {String} incomingHTML The html content to load into the editor
|
|
6599 * @description Loads HTML into the editors body
|
|
6600 */
|
|
6601 setEditorHTML: function(incomingHTML) {
|
|
6602 var html = this._cleanIncomingHTML(incomingHTML);
|
|
6603 html = html.replace(/RIGHT_BRACKET/gi, '{');
|
|
6604 html = html.replace(/LEFT_BRACKET/gi, '}');
|
|
6605 this._getDoc().body.innerHTML = html;
|
|
6606 this.nodeChange();
|
|
6607 },
|
|
6608 /**
|
|
6609 * @method getEditorHTML
|
|
6610 * @description Gets the unprocessed/unfiltered HTML from the editor
|
|
6611 */
|
|
6612 getEditorHTML: function() {
|
|
6613 try {
|
|
6614 var b = this._getDoc().body;
|
|
6615 if (b === null) {
|
|
6616 return null;
|
|
6617 }
|
|
6618 return this._getDoc().body.innerHTML;
|
|
6619 } catch (e) {
|
|
6620 return '';
|
|
6621 }
|
|
6622 },
|
|
6623 /**
|
|
6624 * @method show
|
|
6625 * @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.
|
|
6626 */
|
|
6627 show: function() {
|
|
6628 if (this.browser.gecko) {
|
|
6629 this._setDesignMode('on');
|
|
6630 this.focus();
|
|
6631 }
|
|
6632 if (this.browser.webkit) {
|
|
6633 var self = this;
|
|
6634 window.setTimeout(function() {
|
|
6635 self._setInitialContent.call(self);
|
|
6636 }, 10);
|
|
6637 }
|
|
6638 //Adding this will close all other Editor window's when showing this one.
|
|
6639 if (this.currentWindow) {
|
|
6640 this.closeWindow();
|
|
6641 }
|
|
6642 //Put the iframe back in place
|
|
6643 this.get('iframe').setStyle('position', 'static');
|
|
6644 this.get('iframe').setStyle('left', '');
|
|
6645 },
|
|
6646 /**
|
|
6647 * @method hide
|
|
6648 * @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.
|
|
6649 */
|
|
6650 hide: function() {
|
|
6651 //Adding this will close all other Editor window's.
|
|
6652 if (this.currentWindow) {
|
|
6653 this.closeWindow();
|
|
6654 }
|
|
6655 if (this._fixNodesTimer) {
|
|
6656 clearTimeout(this._fixNodesTimer);
|
|
6657 this._fixNodesTimer = null;
|
|
6658 }
|
|
6659 if (this._nodeChangeTimer) {
|
|
6660 clearTimeout(this._nodeChangeTimer);
|
|
6661 this._nodeChangeTimer = null;
|
|
6662 }
|
|
6663 this._lastNodeChange = 0;
|
|
6664 //Move the iframe off of the screen, so that in containers with visiblity hidden, IE will not cover other elements.
|
|
6665 this.get('iframe').setStyle('position', 'absolute');
|
|
6666 this.get('iframe').setStyle('left', '-9999px');
|
|
6667 },
|
|
6668 /**
|
|
6669 * @method _cleanIncomingHTML
|
|
6670 * @param {String} html The unfiltered HTML
|
|
6671 * @description Process the HTML with a few regexes to clean it up and stabilize the input
|
|
6672 * @return {String} The filtered HTML
|
|
6673 */
|
|
6674 _cleanIncomingHTML: function(html) {
|
|
6675 html = html.replace(/{/gi, 'RIGHT_BRACKET');
|
|
6676 html = html.replace(/}/gi, 'LEFT_BRACKET');
|
|
6677
|
|
6678 html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
|
|
6679 html = html.replace(/<\/strong>/gi, '</b>');
|
|
6680
|
|
6681 //replace embed before em check
|
|
6682 html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
|
|
6683 html = html.replace(/<\/embed>/gi, '</YUI_EMBED>');
|
|
6684
|
|
6685 html = html.replace(/<em([^>]*)>/gi, '<i$1>');
|
|
6686 html = html.replace(/<\/em>/gi, '</i>');
|
|
6687 html = html.replace(/_moz_dirty=""/gi, '');
|
|
6688
|
|
6689 //Put embed tags back in..
|
|
6690 html = html.replace(/<YUI_EMBED([^>]*)>/gi, '<embed$1>');
|
|
6691 html = html.replace(/<\/YUI_EMBED>/gi, '</embed>');
|
|
6692 if (this.get('plainText')) {
|
|
6693 html = html.replace(/\n/g, '<br>').replace(/\r/g, '<br>');
|
|
6694 html = html.replace(/ /gi, ' '); //Replace all double spaces
|
|
6695 html = html.replace(/\t/gi, ' '); //Replace all tabs
|
|
6696 }
|
|
6697 //Removing Script Tags from the Editor
|
|
6698 html = html.replace(/<script([^>]*)>/gi, '<bad>');
|
|
6699 html = html.replace(/<\/script([^>]*)>/gi, '</bad>');
|
|
6700 html = html.replace(/<script([^>]*)>/gi, '<bad>');
|
|
6701 html = html.replace(/<\/script([^>]*)>/gi, '</bad>');
|
|
6702 //Replace the line feeds
|
|
6703 html = html.replace(/\r\n/g, '<YUI_LF>').replace(/\n/g, '<YUI_LF>').replace(/\r/g, '<YUI_LF>');
|
|
6704
|
|
6705 //Remove Bad HTML elements (used to be script nodes)
|
|
6706 html = html.replace(new RegExp('<bad([^>]*)>(.*?)<\/bad>', 'gi'), '');
|
|
6707 //Replace the lines feeds
|
|
6708 html = html.replace(/<YUI_LF>/g, '\n');
|
|
6709 return html;
|
|
6710 },
|
|
6711 /**
|
|
6712 * @method cleanHTML
|
|
6713 * @param {String} html The unfiltered HTML
|
|
6714 * @description Process the HTML with a few regexes to clean it up and stabilize the output
|
|
6715 * @return {String} The filtered HTML
|
|
6716 */
|
|
6717 cleanHTML: function(html) {
|
|
6718 //Start Filtering Output
|
|
6719 //Begin RegExs..
|
|
6720 if (!html) {
|
|
6721 html = this.getEditorHTML();
|
|
6722 }
|
|
6723 var markup = this.get('markup');
|
|
6724 //Make some backups...
|
|
6725 html = this.pre_filter_linebreaks(html, markup);
|
|
6726
|
|
6727 //Filter MS Word
|
|
6728 html = this.filter_msword(html);
|
|
6729
|
|
6730 html = html.replace(/<img([^>]*)\/>/gi, '<YUI_IMG$1>');
|
|
6731 html = html.replace(/<img([^>]*)>/gi, '<YUI_IMG$1>');
|
|
6732
|
|
6733 html = html.replace(/<input([^>]*)\/>/gi, '<YUI_INPUT$1>');
|
|
6734 html = html.replace(/<input([^>]*)>/gi, '<YUI_INPUT$1>');
|
|
6735
|
|
6736 html = html.replace(/<ul([^>]*)>/gi, '<YUI_UL$1>');
|
|
6737 html = html.replace(/<\/ul>/gi, '<\/YUI_UL>');
|
|
6738 html = html.replace(/<blockquote([^>]*)>/gi, '<YUI_BQ$1>');
|
|
6739 html = html.replace(/<\/blockquote>/gi, '<\/YUI_BQ>');
|
|
6740
|
|
6741 html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
|
|
6742 html = html.replace(/<\/embed>/gi, '<\/YUI_EMBED>');
|
|
6743
|
|
6744 //Convert b and i tags to strong and em tags
|
|
6745 if ((markup == 'semantic') || (markup == 'xhtml')) {
|
|
6746 html = html.replace(/<i(\s+[^>]*)?>/gi, '<em$1>');
|
|
6747 html = html.replace(/<\/i>/gi, '</em>');
|
|
6748 html = html.replace(/<b(\s+[^>]*)?>/gi, '<strong$1>');
|
|
6749 html = html.replace(/<\/b>/gi, '</strong>');
|
|
6750 }
|
|
6751
|
|
6752 html = html.replace(/_moz_dirty=""/gi, '');
|
|
6753
|
|
6754 //normalize strikethrough
|
|
6755 html = html.replace(/<strike/gi, '<span style="text-decoration: line-through;"');
|
|
6756 html = html.replace(/\/strike>/gi, '/span>');
|
|
6757
|
|
6758
|
|
6759 //Case Changing
|
|
6760 if (this.browser.ie) {
|
|
6761 html = html.replace(/text-decoration/gi, 'text-decoration');
|
|
6762 html = html.replace(/font-weight/gi, 'font-weight');
|
|
6763 html = html.replace(/_width="([^>]*)"/gi, '');
|
|
6764 html = html.replace(/_height="([^>]*)"/gi, '');
|
|
6765 //Cleanup Image URL's
|
|
6766 var url = this._baseHREF.replace(/\//gi, '\\/'),
|
|
6767 re = new RegExp('src="' + url, 'gi');
|
|
6768 html = html.replace(re, 'src="');
|
|
6769 }
|
|
6770 html = html.replace(/<font/gi, '<font');
|
|
6771 html = html.replace(/<\/font>/gi, '</font>');
|
|
6772 html = html.replace(/<span/gi, '<span');
|
|
6773 html = html.replace(/<\/span>/gi, '</span>');
|
|
6774 if ((markup == 'semantic') || (markup == 'xhtml') || (markup == 'css')) {
|
|
6775 html = html.replace(new RegExp('<font([^>]*)face="([^>]*)">(.*?)<\/font>', 'gi'), '<span $1 style="font-family: $2;">$3</span>');
|
|
6776 html = html.replace(/<u/gi, '<span style="text-decoration: underline;"');
|
|
6777 if (this.browser.webkit) {
|
|
6778 html = html.replace(new RegExp('<span class="Apple-style-span" style="font-weight: bold;">([^>]*)<\/span>', 'gi'), '<strong>$1</strong>');
|
|
6779 html = html.replace(new RegExp('<span class="Apple-style-span" style="font-style: italic;">([^>]*)<\/span>', 'gi'), '<em>$1</em>');
|
|
6780 }
|
|
6781 html = html.replace(/\/u>/gi, '/span>');
|
|
6782 if (markup == 'css') {
|
|
6783 html = html.replace(/<em([^>]*)>/gi, '<i$1>');
|
|
6784 html = html.replace(/<\/em>/gi, '</i>');
|
|
6785 html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
|
|
6786 html = html.replace(/<\/strong>/gi, '</b>');
|
|
6787 html = html.replace(/<b/gi, '<span style="font-weight: bold;"');
|
|
6788 html = html.replace(/\/b>/gi, '/span>');
|
|
6789 html = html.replace(/<i/gi, '<span style="font-style: italic;"');
|
|
6790 html = html.replace(/\/i>/gi, '/span>');
|
|
6791 }
|
|
6792 html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single
|
|
6793 } else {
|
|
6794 html = html.replace(/<u/gi, '<u');
|
|
6795 html = html.replace(/\/u>/gi, '/u>');
|
|
6796 }
|
|
6797 html = html.replace(/<ol([^>]*)>/gi, '<ol$1>');
|
|
6798 html = html.replace(/\/ol>/gi, '/ol>');
|
|
6799 html = html.replace(/<li/gi, '<li');
|
|
6800 html = html.replace(/\/li>/gi, '/li>');
|
|
6801 html = this.filter_safari(html);
|
|
6802
|
|
6803 html = this.filter_internals(html);
|
|
6804
|
|
6805 html = this.filter_all_rgb(html);
|
|
6806
|
|
6807 //Replace our backups with the real thing
|
|
6808 html = this.post_filter_linebreaks(html, markup);
|
|
6809
|
|
6810 if (markup == 'xhtml') {
|
|
6811 html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1 />');
|
|
6812 html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1 />');
|
|
6813 } else {
|
|
6814 html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1>');
|
|
6815 html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1>');
|
|
6816 }
|
|
6817 html = html.replace(/<YUI_UL([^>]*)>/g, '<ul$1>');
|
|
6818 html = html.replace(/<\/YUI_UL>/g, '<\/ul>');
|
|
6819
|
|
6820 html = this.filter_invalid_lists(html);
|
|
6821
|
|
6822 html = html.replace(/<YUI_BQ([^>]*)>/g, '<blockquote$1>');
|
|
6823 html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>');
|
|
6824
|
|
6825 html = html.replace(/<YUI_EMBED([^>]*)>/g, '<embed$1>');
|
|
6826 html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>');
|
|
6827
|
|
6828 //This should fix &'s in URL's
|
|
6829 html = html.replace(/ & /gi, ' YUI_AMP ');
|
|
6830 html = html.replace(/ &/gi, ' YUI_AMP_F ');
|
|
6831 html = html.replace(/& /gi, ' YUI_AMP_R ');
|
|
6832 html = html.replace(/&/gi, '&');
|
|
6833 html = html.replace(/ YUI_AMP /gi, ' & ');
|
|
6834 html = html.replace(/ YUI_AMP_F /gi, ' &');
|
|
6835 html = html.replace(/ YUI_AMP_R /gi, '& ');
|
|
6836
|
|
6837 //Trim the output, removing whitespace from the beginning and end
|
|
6838 html = YAHOO.lang.trim(html);
|
|
6839
|
|
6840 if (this.get('removeLineBreaks')) {
|
|
6841 html = html.replace(/\n/g, '').replace(/\r/g, '');
|
|
6842 html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single
|
|
6843 }
|
|
6844
|
|
6845 for (var v in this.invalidHTML) {
|
|
6846 if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
|
|
6847 if (Lang.isObject(v) && v.keepContents) {
|
|
6848 html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1');
|
|
6849 } else {
|
|
6850 html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '');
|
|
6851 }
|
|
6852 }
|
|
6853 }
|
|
6854
|
|
6855 /* LATER -- Add DOM manipulation
|
|
6856 console.log(html);
|
|
6857 var frag = document.createDocumentFragment();
|
|
6858 frag.innerHTML = html;
|
|
6859
|
|
6860 var ps = frag.getElementsByTagName('p'),
|
|
6861 len = ps.length;
|
|
6862 for (var i = 0; i < len; i++) {
|
|
6863 var ps2 = ps[i].getElementsByTagName('p');
|
|
6864 if (ps2.length) {
|
|
6865
|
|
6866 }
|
|
6867
|
|
6868 }
|
|
6869 html = frag.innerHTML;
|
|
6870 console.log(html);
|
|
6871 */
|
|
6872
|
|
6873 this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html });
|
|
6874
|
|
6875 return html;
|
|
6876 },
|
|
6877 /**
|
|
6878 * @method filter_msword
|
|
6879 * @param String html The HTML string to filter
|
|
6880 * @description Filters out msword html attributes and other junk. Activate with filterWord: true in config
|
|
6881 */
|
|
6882 filter_msword: function(html) {
|
|
6883 if (!this.get('filterWord')) {
|
|
6884 return html;
|
|
6885 }
|
|
6886 //Remove the ms o: tags
|
|
6887 html = html.replace(/<o:p>\s*<\/o:p>/g, '');
|
|
6888 html = html.replace(/<o:p>[\s\S]*?<\/o:p>/g, ' ');
|
|
6889
|
|
6890 //Remove the ms w: tags
|
|
6891 html = html.replace( /<w:[^>]*>[\s\S]*?<\/w:[^>]*>/gi, '');
|
|
6892
|
|
6893 //Remove mso-? styles.
|
|
6894 html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '');
|
|
6895
|
|
6896 //Remove more bogus MS styles.
|
|
6897 html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*;/gi, '');
|
|
6898 html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*"/gi, "\"");
|
|
6899 html = html.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '');
|
|
6900 html = html.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"");
|
|
6901 html = html.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"");
|
|
6902 html = html.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" );
|
|
6903 html = html.replace( /\s*tab-stops:[^;"]*;?/gi, '');
|
|
6904 html = html.replace( /\s*tab-stops:[^"]*/gi, '');
|
|
6905
|
|
6906 //Remove XML declarations
|
|
6907 html = html.replace(/<\\?\?xml[^>]*>/gi, '');
|
|
6908
|
|
6909 //Remove lang
|
|
6910 html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
|
|
6911
|
|
6912 //Remove language tags
|
|
6913 html = html.replace( /<(\w[^>]*) language=([^ |>]*)([^>]*)/gi, "<$1$3");
|
|
6914
|
|
6915 //Remove onmouseover and onmouseout events (from MS Word comments effect)
|
|
6916 html = html.replace( /<(\w[^>]*) onmouseover="([^\"]*)"([^>]*)/gi, "<$1$3");
|
|
6917 html = html.replace( /<(\w[^>]*) onmouseout="([^\"]*)"([^>]*)/gi, "<$1$3");
|
|
6918
|
|
6919 return html;
|
|
6920 },
|
|
6921 /**
|
|
6922 * @method filter_invalid_lists
|
|
6923 * @param String html The HTML string to filter
|
|
6924 * @description Filters invalid ol and ul list markup, converts this: <li></li><ol>..</ol> to this: <li></li><li><ol>..</ol></li>
|
|
6925 */
|
|
6926 filter_invalid_lists: function(html) {
|
|
6927 html = html.replace(/<\/li>\n/gi, '</li>');
|
|
6928
|
|
6929 html = html.replace(/<\/li><ol>/gi, '</li><li><ol>');
|
|
6930 html = html.replace(/<\/ol>/gi, '</ol></li>');
|
|
6931 html = html.replace(/<\/ol><\/li>\n/gi, "</ol>");
|
|
6932
|
|
6933 html = html.replace(/<\/li><ul>/gi, '</li><li><ul>');
|
|
6934 html = html.replace(/<\/ul>/gi, '</ul></li>');
|
|
6935 html = html.replace(/<\/ul><\/li>\n?/gi, "</ul>");
|
|
6936
|
|
6937 html = html.replace(/<\/li>/gi, "</li>");
|
|
6938 html = html.replace(/<\/ol>/gi, "</ol>");
|
|
6939 html = html.replace(/<ol>/gi, "<ol>");
|
|
6940 html = html.replace(/<ul>/gi, "<ul>");
|
|
6941 return html;
|
|
6942 },
|
|
6943 /**
|
|
6944 * @method filter_safari
|
|
6945 * @param String html The HTML string to filter
|
|
6946 * @description Filters strings specific to Safari
|
|
6947 * @return String
|
|
6948 */
|
|
6949 filter_safari: function(html) {
|
|
6950 if (this.browser.webkit) {
|
|
6951 //<span class="Apple-tab-span" style="white-space:pre"> </span>
|
|
6952 html = html.replace(/<span class="Apple-tab-span" style="white-space:pre">([^>])<\/span>/gi, ' ');
|
|
6953 html = html.replace(/Apple-style-span/gi, '');
|
|
6954 html = html.replace(/style="line-height: normal;"/gi, '');
|
|
6955 html = html.replace(/yui-wk-div/gi, '');
|
|
6956 html = html.replace(/yui-wk-p/gi, '');
|
|
6957
|
|
6958
|
|
6959 //Remove bogus LI's
|
|
6960 html = html.replace(/<li><\/li>/gi, '');
|
|
6961 html = html.replace(/<li> <\/li>/gi, '');
|
|
6962 html = html.replace(/<li> <\/li>/gi, '');
|
|
6963 //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break
|
|
6964 if (this.get('ptags')) {
|
|
6965 html = html.replace(/<div([^>]*)>/g, '<p$1>');
|
|
6966 html = html.replace(/<\/div>/gi, '</p>');
|
|
6967 } else {
|
|
6968 //html = html.replace(/<div>/gi, '<br>');
|
|
6969 html = html.replace(/<div([^>]*)>([ tnr]*)<\/div>/gi, '<br>');
|
|
6970 html = html.replace(/<\/div>/gi, '');
|
|
6971 }
|
|
6972 }
|
|
6973 return html;
|
|
6974 },
|
|
6975 /**
|
|
6976 * @method filter_internals
|
|
6977 * @param String html The HTML string to filter
|
|
6978 * @description Filters internal RTE strings and bogus attrs we don't want
|
|
6979 * @return String
|
|
6980 */
|
|
6981 filter_internals: function(html) {
|
|
6982 html = html.replace(/\r/g, '');
|
|
6983 //Fix stuff we don't want
|
|
6984 html = html.replace(/<\/?(body|head|html)[^>]*>/gi, '');
|
|
6985 //Fix last BR in LI
|
|
6986 html = html.replace(/<YUI_BR><\/li>/gi, '</li>');
|
|
6987
|
|
6988 html = html.replace(/yui-tag-span/gi, '');
|
|
6989 html = html.replace(/yui-tag/gi, '');
|
|
6990 html = html.replace(/yui-non/gi, '');
|
|
6991 html = html.replace(/yui-img/gi, '');
|
|
6992 html = html.replace(/ tag="span"/gi, '');
|
|
6993 html = html.replace(/ class=""/gi, '');
|
|
6994 html = html.replace(/ style=""/gi, '');
|
|
6995 html = html.replace(/ class=" "/gi, '');
|
|
6996 html = html.replace(/ class=" "/gi, '');
|
|
6997 html = html.replace(/ target=""/gi, '');
|
|
6998 html = html.replace(/ title=""/gi, '');
|
|
6999
|
|
7000 if (this.browser.ie) {
|
|
7001 html = html.replace(/ class= /gi, '');
|
|
7002 html = html.replace(/ class= >/gi, '');
|
|
7003 }
|
|
7004
|
|
7005 return html;
|
|
7006 },
|
|
7007 /**
|
|
7008 * @method filter_all_rgb
|
|
7009 * @param String str The HTML string to filter
|
|
7010 * @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"
|
|
7011 * @return String
|
|
7012 */
|
|
7013 filter_all_rgb: function(str) {
|
|
7014 var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi");
|
|
7015 var arr = str.match(exp);
|
|
7016 if (Lang.isArray(arr)) {
|
|
7017 for (var i = 0; i < arr.length; i++) {
|
|
7018 var color = this.filter_rgb(arr[i]);
|
|
7019 str = str.replace(arr[i].toString(), color);
|
|
7020 }
|
|
7021 }
|
|
7022
|
|
7023 return str;
|
|
7024 },
|
|
7025 /**
|
|
7026 * @method filter_rgb
|
|
7027 * @param String css The CSS string containing rgb(#,#,#);
|
|
7028 * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00
|
|
7029 * @return String
|
|
7030 */
|
|
7031 filter_rgb: function(css) {
|
|
7032 if (css.toLowerCase().indexOf('rgb') != -1) {
|
|
7033 var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
|
|
7034 var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(',');
|
|
7035
|
|
7036 if (rgb.length == 5) {
|
|
7037 var r = parseInt(rgb[1], 10).toString(16);
|
|
7038 var g = parseInt(rgb[2], 10).toString(16);
|
|
7039 var b = parseInt(rgb[3], 10).toString(16);
|
|
7040
|
|
7041 r = r.length == 1 ? '0' + r : r;
|
|
7042 g = g.length == 1 ? '0' + g : g;
|
|
7043 b = b.length == 1 ? '0' + b : b;
|
|
7044
|
|
7045 css = "#" + r + g + b;
|
|
7046 }
|
|
7047 }
|
|
7048 return css;
|
|
7049 },
|
|
7050 /**
|
|
7051 * @method pre_filter_linebreaks
|
|
7052 * @param String html The HTML to filter
|
|
7053 * @param String markup The markup type to filter to
|
|
7054 * @description HTML Pre Filter
|
|
7055 * @return String
|
|
7056 */
|
|
7057 pre_filter_linebreaks: function(html, markup) {
|
|
7058 if (this.browser.webkit) {
|
|
7059 html = html.replace(/<br class="khtml-block-placeholder">/gi, '<YUI_BR>');
|
|
7060 html = html.replace(/<br class="webkit-block-placeholder">/gi, '<YUI_BR>');
|
|
7061 }
|
|
7062 html = html.replace(/<br>/gi, '<YUI_BR>');
|
|
7063 html = html.replace(/<br (.*?)>/gi, '<YUI_BR>');
|
|
7064 html = html.replace(/<br\/>/gi, '<YUI_BR>');
|
|
7065 html = html.replace(/<br \/>/gi, '<YUI_BR>');
|
|
7066 html = html.replace(/<div><YUI_BR><\/div>/gi, '<YUI_BR>');
|
|
7067 html = html.replace(/<p>( | )<\/p>/g, '<YUI_BR>');
|
|
7068 html = html.replace(/<p><br> <\/p>/gi, '<YUI_BR>');
|
|
7069 html = html.replace(/<p> <\/p>/gi, '<YUI_BR>');
|
|
7070 //Fix last BR
|
|
7071 html = html.replace(/<YUI_BR>$/, '');
|
|
7072 //Fix last BR in P
|
|
7073 html = html.replace(/<YUI_BR><\/p>/g, '</p>');
|
|
7074 if (this.browser.ie) {
|
|
7075 html = html.replace(/ /g, '\t');
|
|
7076 }
|
|
7077 return html;
|
|
7078 },
|
|
7079 /**
|
|
7080 * @method post_filter_linebreaks
|
|
7081 * @param String html The HTML to filter
|
|
7082 * @param String markup The markup type to filter to
|
|
7083 * @description HTML Pre Filter
|
|
7084 * @return String
|
|
7085 */
|
|
7086 post_filter_linebreaks: function(html, markup) {
|
|
7087 if (markup == 'xhtml') {
|
|
7088 html = html.replace(/<YUI_BR>/g, '<br />');
|
|
7089 } else {
|
|
7090 html = html.replace(/<YUI_BR>/g, '<br>');
|
|
7091 }
|
|
7092 return html;
|
|
7093 },
|
|
7094 /**
|
|
7095 * @method clearEditorDoc
|
|
7096 * @description Clear the doc of the Editor
|
|
7097 */
|
|
7098 clearEditorDoc: function() {
|
|
7099 this._getDoc().body.innerHTML = ' ';
|
|
7100 },
|
|
7101 /**
|
|
7102 * @method openWindow
|
|
7103 * @description Override Method for Advanced Editor
|
|
7104 */
|
|
7105 openWindow: function(win) {
|
|
7106 },
|
|
7107 /**
|
|
7108 * @method moveWindow
|
|
7109 * @description Override Method for Advanced Editor
|
|
7110 */
|
|
7111 moveWindow: function() {
|
|
7112 },
|
|
7113 /**
|
|
7114 * @private
|
|
7115 * @method _closeWindow
|
|
7116 * @description Override Method for Advanced Editor
|
|
7117 */
|
|
7118 _closeWindow: function() {
|
|
7119 },
|
|
7120 /**
|
|
7121 * @method closeWindow
|
|
7122 * @description Override Method for Advanced Editor
|
|
7123 */
|
|
7124 closeWindow: function() {
|
|
7125 //this.unsubscribeAll('afterExecCommand');
|
|
7126 this.toolbar.resetAllButtons();
|
|
7127 this.focus();
|
|
7128 },
|
|
7129 /**
|
|
7130 * @method destroy
|
|
7131 * @description Destroys the editor, all of it's elements and objects.
|
|
7132 * @return {Boolean}
|
|
7133 */
|
|
7134 destroy: function() {
|
|
7135 if (this._nodeChangeDelayTimer) {
|
|
7136 clearTimeout(this._nodeChangeDelayTimer);
|
|
7137 }
|
|
7138 this.hide();
|
|
7139
|
|
7140 if (this.resize) {
|
|
7141 this.resize.destroy();
|
|
7142 }
|
|
7143 if (this.dd) {
|
|
7144 this.dd.unreg();
|
|
7145 }
|
|
7146 if (this.get('panel')) {
|
|
7147 this.get('panel').destroy();
|
|
7148 }
|
|
7149 this.saveHTML();
|
|
7150 this.toolbar.destroy();
|
|
7151 this.setStyle('visibility', 'visible');
|
|
7152 this.setStyle('position', 'static');
|
|
7153 this.setStyle('top', '');
|
|
7154 this.setStyle('left', '');
|
|
7155 var textArea = this.get('element');
|
|
7156 this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element'));
|
|
7157 this.get('element_cont').get('element').innerHTML = '';
|
|
7158 this.set('handleSubmit', false); //Remove the submit handler
|
|
7159 return true;
|
|
7160 },
|
|
7161 /**
|
|
7162 * @method toString
|
|
7163 * @description Returns a string representing the editor.
|
|
7164 * @return {String}
|
|
7165 */
|
|
7166 toString: function() {
|
|
7167 var str = 'SimpleEditor';
|
|
7168 if (this.get && this.get('element_cont')) {
|
|
7169 str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
|
|
7170 }
|
|
7171 return str;
|
|
7172 }
|
|
7173 });
|
|
7174
|
|
7175 /**
|
|
7176 * @event toolbarLoaded
|
|
7177 * @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.
|
|
7178 * @type YAHOO.util.CustomEvent
|
|
7179 */
|
|
7180 /**
|
|
7181 * @event cleanHTML
|
|
7182 * @description Event is fired after the cleanHTML method is called.
|
|
7183 * @type YAHOO.util.CustomEvent
|
|
7184 */
|
|
7185 /**
|
|
7186 * @event afterRender
|
|
7187 * @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.
|
|
7188 * @type YAHOO.util.CustomEvent
|
|
7189 */
|
|
7190 /**
|
|
7191 * @event editorContentLoaded
|
|
7192 * @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.
|
|
7193 * @type YAHOO.util.CustomEvent
|
|
7194 */
|
|
7195 /**
|
|
7196 * @event beforeNodeChange
|
|
7197 * @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.
|
|
7198 * @type YAHOO.util.CustomEvent
|
|
7199 */
|
|
7200 /**
|
|
7201 * @event afterNodeChange
|
|
7202 * @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.
|
|
7203 * @type YAHOO.util.CustomEvent
|
|
7204 */
|
|
7205 /**
|
|
7206 * @event beforeExecCommand
|
|
7207 * @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.
|
|
7208 * @type YAHOO.util.CustomEvent
|
|
7209 */
|
|
7210 /**
|
|
7211 * @event afterExecCommand
|
|
7212 * @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.
|
|
7213 * @type YAHOO.util.CustomEvent
|
|
7214 */
|
|
7215 /**
|
|
7216 * @event editorMouseUp
|
|
7217 * @param {Event} ev The DOM Event that occured
|
|
7218 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7219 * @type YAHOO.util.CustomEvent
|
|
7220 */
|
|
7221 /**
|
|
7222 * @event editorMouseDown
|
|
7223 * @param {Event} ev The DOM Event that occured
|
|
7224 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7225 * @type YAHOO.util.CustomEvent
|
|
7226 */
|
|
7227 /**
|
|
7228 * @event editorDoubleClick
|
|
7229 * @param {Event} ev The DOM Event that occured
|
|
7230 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7231 * @type YAHOO.util.CustomEvent
|
|
7232 */
|
|
7233 /**
|
|
7234 * @event editorClick
|
|
7235 * @param {Event} ev The DOM Event that occured
|
|
7236 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7237 * @type YAHOO.util.CustomEvent
|
|
7238 */
|
|
7239 /**
|
|
7240 * @event editorKeyUp
|
|
7241 * @param {Event} ev The DOM Event that occured
|
|
7242 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7243 * @type YAHOO.util.CustomEvent
|
|
7244 */
|
|
7245 /**
|
|
7246 * @event editorKeyPress
|
|
7247 * @param {Event} ev The DOM Event that occured
|
|
7248 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7249 * @type YAHOO.util.CustomEvent
|
|
7250 */
|
|
7251 /**
|
|
7252 * @event editorKeyDown
|
|
7253 * @param {Event} ev The DOM Event that occured
|
|
7254 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7255 * @type YAHOO.util.CustomEvent
|
|
7256 */
|
|
7257 /**
|
|
7258 * @event beforeEditorMouseUp
|
|
7259 * @param {Event} ev The DOM Event that occured
|
|
7260 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7261 * @type YAHOO.util.CustomEvent
|
|
7262 */
|
|
7263 /**
|
|
7264 * @event beforeEditorMouseDown
|
|
7265 * @param {Event} ev The DOM Event that occured
|
|
7266 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7267 * @type YAHOO.util.CustomEvent
|
|
7268 */
|
|
7269 /**
|
|
7270 * @event beforeEditorDoubleClick
|
|
7271 * @param {Event} ev The DOM Event that occured
|
|
7272 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7273 * @type YAHOO.util.CustomEvent
|
|
7274 */
|
|
7275 /**
|
|
7276 * @event beforeEditorClick
|
|
7277 * @param {Event} ev The DOM Event that occured
|
|
7278 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7279 * @type YAHOO.util.CustomEvent
|
|
7280 */
|
|
7281 /**
|
|
7282 * @event beforeEditorKeyUp
|
|
7283 * @param {Event} ev The DOM Event that occured
|
|
7284 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7285 * @type YAHOO.util.CustomEvent
|
|
7286 */
|
|
7287 /**
|
|
7288 * @event beforeEditorKeyPress
|
|
7289 * @param {Event} ev The DOM Event that occured
|
|
7290 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7291 * @type YAHOO.util.CustomEvent
|
|
7292 */
|
|
7293 /**
|
|
7294 * @event beforeEditorKeyDown
|
|
7295 * @param {Event} ev The DOM Event that occured
|
|
7296 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7297 * @type YAHOO.util.CustomEvent
|
|
7298 */
|
|
7299
|
|
7300 /**
|
|
7301 * @event editorWindowFocus
|
|
7302 * @description Fires when the iframe is focused. Note, this is window focus event, not an Editor focus event.
|
|
7303 * @type YAHOO.util.CustomEvent
|
|
7304 */
|
|
7305 /**
|
|
7306 * @event editorWindowBlur
|
|
7307 * @description Fires when the iframe is blurred. Note, this is window blur event, not an Editor blur event.
|
|
7308 * @type YAHOO.util.CustomEvent
|
|
7309 */
|
|
7310
|
|
7311
|
|
7312 /**
|
|
7313 * @description Singleton object used to track the open window objects and panels across the various open editors
|
|
7314 * @class EditorInfo
|
|
7315 * @static
|
|
7316 */
|
|
7317 YAHOO.widget.EditorInfo = {
|
|
7318 /**
|
|
7319 * @private
|
|
7320 * @property _instances
|
|
7321 * @description A reference to all editors on the page.
|
|
7322 * @type Object
|
|
7323 */
|
|
7324 _instances: {},
|
|
7325 /**
|
|
7326 * @private
|
|
7327 * @property blankImage
|
|
7328 * @description A reference to the blankImage url
|
|
7329 * @type String
|
|
7330 */
|
|
7331 blankImage: '',
|
|
7332 /**
|
|
7333 * @private
|
|
7334 * @property window
|
|
7335 * @description A reference to the currently open window object in any editor on the page.
|
|
7336 * @type Object <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>
|
|
7337 */
|
|
7338 window: {},
|
|
7339 /**
|
|
7340 * @private
|
|
7341 * @property panel
|
|
7342 * @description A reference to the currently open panel in any editor on the page.
|
|
7343 * @type Object <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
|
|
7344 */
|
|
7345 panel: null,
|
|
7346 /**
|
|
7347 * @method getEditorById
|
|
7348 * @description Returns a reference to the Editor object associated with the given textarea
|
|
7349 * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of
|
|
7350 * @return Object <a href="YAHOO.widget.Editor.html">YAHOO.widget.Editor</a>
|
|
7351 */
|
|
7352 getEditorById: function(id) {
|
|
7353 if (!YAHOO.lang.isString(id)) {
|
|
7354 //Not a string, assume a node Reference
|
|
7355 id = id.id;
|
|
7356 }
|
|
7357 if (this._instances[id]) {
|
|
7358 return this._instances[id];
|
|
7359 }
|
|
7360 return false;
|
|
7361 },
|
|
7362 /**
|
|
7363 * @method saveAll
|
|
7364 * @description Saves all Editor instances on the page. If a form reference is passed, only Editor's bound to this form will be saved.
|
|
7365 * @param {HTMLElement} form The form to check if this Editor instance belongs to
|
|
7366 */
|
|
7367 saveAll: function(form) {
|
|
7368 var i, e, items = YAHOO.widget.EditorInfo._instances;
|
|
7369 if (form) {
|
|
7370 for (i in items) {
|
|
7371 if (Lang.hasOwnProperty(items, i)) {
|
|
7372 e = items[i];
|
|
7373 if (e.get('element').form && (e.get('element').form == form)) {
|
|
7374 e.saveHTML();
|
|
7375 }
|
|
7376 }
|
|
7377 }
|
|
7378 } else {
|
|
7379 for (i in items) {
|
|
7380 if (Lang.hasOwnProperty(items, i)) {
|
|
7381 items[i].saveHTML();
|
|
7382 }
|
|
7383 }
|
|
7384 }
|
|
7385 },
|
|
7386 /**
|
|
7387 * @method toString
|
|
7388 * @description Returns a string representing the EditorInfo.
|
|
7389 * @return {String}
|
|
7390 */
|
|
7391 toString: function() {
|
|
7392 var len = 0;
|
|
7393 for (var i in this._instances) {
|
|
7394 if (Lang.hasOwnProperty(this._instances, i)) {
|
|
7395 len++;
|
|
7396 }
|
|
7397 }
|
|
7398 return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')';
|
|
7399 }
|
|
7400 };
|
|
7401
|
|
7402
|
|
7403
|
|
7404
|
|
7405 })();
|
|
7406 /**
|
|
7407 * @module editor
|
|
7408 * @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>
|
|
7409 * @namespace YAHOO.widget
|
|
7410 * @requires yahoo, dom, element, event, container_core, simpleeditor
|
|
7411 * @optional dragdrop, animation, menu, button, resize
|
|
7412 */
|
|
7413
|
|
7414 (function() {
|
|
7415 var Dom = YAHOO.util.Dom,
|
|
7416 Event = YAHOO.util.Event,
|
|
7417 Lang = YAHOO.lang,
|
|
7418 Toolbar = YAHOO.widget.Toolbar;
|
|
7419
|
|
7420 /**
|
|
7421 * 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.
|
|
7422 * @constructor
|
|
7423 * @class Editor
|
|
7424 * @extends YAHOO.widget.SimpleEditor
|
|
7425 * @param {String/HTMLElement} el The textarea element to turn into an editor.
|
|
7426 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
7427 */
|
|
7428
|
|
7429 YAHOO.widget.Editor = function(el, attrs) {
|
|
7430 YAHOO.widget.Editor.superclass.constructor.call(this, el, attrs);
|
|
7431 };
|
|
7432
|
|
7433 YAHOO.extend(YAHOO.widget.Editor, YAHOO.widget.SimpleEditor, {
|
|
7434 /**
|
|
7435 * @private
|
|
7436 * @property _undoCache
|
|
7437 * @description An Array hash of the Undo Levels.
|
|
7438 * @type Array
|
|
7439 */
|
|
7440 _undoCache: null,
|
|
7441 /**
|
|
7442 * @private
|
|
7443 * @property _undoLevel
|
|
7444 * @description The index of the current undo state.
|
|
7445 * @type Number
|
|
7446 */
|
|
7447 _undoLevel: null,
|
|
7448 /**
|
|
7449 * @private
|
|
7450 * @method _hasUndoLevel
|
|
7451 * @description Checks to see if we have an undo level available
|
|
7452 * @return Boolean
|
|
7453 */
|
|
7454 _hasUndoLevel: function() {
|
|
7455 return ((this._undoCache.length > 1) && this._undoLevel);
|
|
7456 },
|
|
7457 /**
|
|
7458 * @private
|
|
7459 * @method _undoNodeChange
|
|
7460 * @description nodeChange listener for undo processing
|
|
7461 */
|
|
7462 _undoNodeChange: function() {
|
|
7463 var undo_button = this.toolbar.getButtonByValue('undo'),
|
|
7464 redo_button = this.toolbar.getButtonByValue('redo');
|
|
7465 if (undo_button && redo_button) {
|
|
7466 if (this._hasUndoLevel()) {
|
|
7467 this.toolbar.enableButton(undo_button);
|
|
7468 }
|
|
7469 if (this._undoLevel < this._undoCache.length) {
|
|
7470 this.toolbar.enableButton(redo_button);
|
|
7471 }
|
|
7472 }
|
|
7473 this._lastCommand = null;
|
|
7474 },
|
|
7475 /**
|
|
7476 * @private
|
|
7477 * @method _checkUndo
|
|
7478 * @description Prunes the undo cache when it reaches the maxUndo config
|
|
7479 */
|
|
7480 _checkUndo: function() {
|
|
7481 var len = this._undoCache.length,
|
|
7482 tmp = [];
|
|
7483 if (len >= this.get('maxUndo')) {
|
|
7484 for (var i = (len - this.get('maxUndo')); i < len; i++) {
|
|
7485 tmp.push(this._undoCache[i]);
|
|
7486 }
|
|
7487 this._undoCache = tmp;
|
|
7488 }
|
|
7489 },
|
|
7490 /**
|
|
7491 * @private
|
|
7492 * @method _putUndo
|
|
7493 * @description Puts the content of the Editor into the _undoCache.
|
|
7494 * //TODO Convert the hash to a series of TEXTAREAS to store state in.
|
|
7495 * @param {String} str The content of the Editor
|
|
7496 */
|
|
7497 _putUndo: function(str) {
|
|
7498 if (this._undoLevel === this._undoCache.length) {
|
|
7499 this._undoCache.push(str);
|
|
7500 this._undoLevel = this._undoCache.length;
|
|
7501 } else {
|
|
7502 var str = this.getEditorHTML();
|
|
7503 var last = this._undoCache[this._undoLevel];
|
|
7504 if (last) {
|
|
7505 if (str !== last) {
|
|
7506 this._undoCache = [];
|
|
7507 this._undoLevel = 0;
|
|
7508 }
|
|
7509 }
|
|
7510 }
|
|
7511 },
|
|
7512 /**
|
|
7513 * @private
|
|
7514 * @method _getUndo
|
|
7515 * @description Get's a level from the undo cache.
|
|
7516 * @param {Number} index The index of the undo level we want to get.
|
|
7517 * @return {String}
|
|
7518 */
|
|
7519 _getUndo: function(index) {
|
|
7520 this._undoLevel = index;
|
|
7521 return this._undoCache[index];
|
|
7522 },
|
|
7523 /**
|
|
7524 * @private
|
|
7525 * @method _storeUndo
|
|
7526 * @description Method to call when you want to store an undo state. Currently called from nodeChange and _handleKeyUp
|
|
7527 */
|
|
7528 _storeUndo: function() {
|
|
7529 if (this._lastCommand === 'undo' || this._lastCommand === 'redo') {
|
|
7530 return false;
|
|
7531 }
|
|
7532 if (!this._undoCache) {
|
|
7533 this._undoCache = [];
|
|
7534 this._undoLevel = 0;
|
|
7535 }
|
|
7536 this._checkUndo();
|
|
7537 var str = this.getEditorHTML();
|
|
7538 //var last = this._undoCache[this._undoCache.length - 1];
|
|
7539 var last = this._undoCache[this._undoLevel - 1];
|
|
7540 if (last) {
|
|
7541 if (str !== last) {
|
|
7542 this._putUndo(str);
|
|
7543 }
|
|
7544 } else {
|
|
7545 this._putUndo(str);
|
|
7546 }
|
|
7547 this._undoNodeChange();
|
|
7548 },
|
|
7549 /**
|
|
7550 * @property STR_BEFORE_EDITOR
|
|
7551 * @description The accessibility string for the element before the iFrame
|
|
7552 * @type String
|
|
7553 */
|
|
7554 STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names. <h4>Common formatting keyboard shortcuts:</h4><ul><li>Control Shift B sets text to bold</li> <li>Control Shift I sets text to italic</li> <li>Control Shift U underlines text</li> <li>Control Shift [ aligns text left</li> <li>Control Shift | centers text</li> <li>Control Shift ] aligns text right</li> <li>Control Shift L adds an HTML link</li> <li>To exit this text editor use the keyboard shortcut Control + Shift + ESC.</li></ul>',
|
|
7555 /**
|
|
7556 * @property STR_CLOSE_WINDOW
|
|
7557 * @description The Title of the close button in the Editor Window
|
|
7558 * @type String
|
|
7559 */
|
|
7560 STR_CLOSE_WINDOW: 'Close Window',
|
|
7561 /**
|
|
7562 * @property STR_CLOSE_WINDOW_NOTE
|
|
7563 * @description A note appearing in the Editor Window to tell the user that the Escape key will close the window
|
|
7564 * @type String
|
|
7565 */
|
|
7566 STR_CLOSE_WINDOW_NOTE: 'To close this window use the Control + Shift + W key',
|
|
7567 /**
|
|
7568 * @property STR_IMAGE_PROP_TITLE
|
|
7569 * @description The title for the Image Property Editor Window
|
|
7570 * @type String
|
|
7571 */
|
|
7572 STR_IMAGE_PROP_TITLE: 'Image Options',
|
|
7573 /**
|
|
7574 * @property STR_IMAGE_TITLE
|
|
7575 * @description The label string for Image Description
|
|
7576 * @type String
|
|
7577 */
|
|
7578 STR_IMAGE_TITLE: 'Description',
|
|
7579 /**
|
|
7580 * @property STR_IMAGE_SIZE
|
|
7581 * @description The label string for Image Size
|
|
7582 * @type String
|
|
7583 */
|
|
7584 STR_IMAGE_SIZE: 'Size',
|
|
7585 /**
|
|
7586 * @property STR_IMAGE_ORIG_SIZE
|
|
7587 * @description The label string for Original Image Size
|
|
7588 * @type String
|
|
7589 */
|
|
7590 STR_IMAGE_ORIG_SIZE: 'Original Size',
|
|
7591 /**
|
|
7592 * @property STR_IMAGE_COPY
|
|
7593 * @description The label string for the image copy and paste message for Opera and Safari
|
|
7594 * @type String
|
|
7595 */
|
|
7596 STR_IMAGE_COPY: '<span class="tip"><span class="icon icon-info"></span><strong>Note:</strong>To move this image just highlight it, cut, and paste where ever you\'d like.</span>',
|
|
7597 /**
|
|
7598 * @property STR_IMAGE_PADDING
|
|
7599 * @description The label string for the image padding.
|
|
7600 * @type String
|
|
7601 */
|
|
7602 STR_IMAGE_PADDING: 'Padding',
|
|
7603 /**
|
|
7604 * @property STR_IMAGE_BORDER
|
|
7605 * @description The label string for the image border.
|
|
7606 * @type String
|
|
7607 */
|
|
7608 STR_IMAGE_BORDER: 'Border',
|
|
7609 /**
|
|
7610 * @property STR_IMAGE_BORDER_SIZE
|
|
7611 * @description The label string for the image border size.
|
|
7612 * @type String
|
|
7613 */
|
|
7614 STR_IMAGE_BORDER_SIZE: 'Border Size',
|
|
7615 /**
|
|
7616 * @property STR_IMAGE_BORDER_TYPE
|
|
7617 * @description The label string for the image border type.
|
|
7618 * @type String
|
|
7619 */
|
|
7620 STR_IMAGE_BORDER_TYPE: 'Border Type',
|
|
7621 /**
|
|
7622 * @property STR_IMAGE_TEXTFLOW
|
|
7623 * @description The label string for the image text flow.
|
|
7624 * @type String
|
|
7625 */
|
|
7626 STR_IMAGE_TEXTFLOW: 'Text Flow',
|
|
7627 /**
|
|
7628 * @property STR_LOCAL_FILE_WARNING
|
|
7629 * @description The label string for the local file warning.
|
|
7630 * @type String
|
|
7631 */
|
|
7632 STR_LOCAL_FILE_WARNING: '<span class="tip"><span class="icon icon-warn"></span><strong>Note:</strong>This image/link points to a file on your computer and will not be accessible to others on the internet.</span>',
|
|
7633 /**
|
|
7634 * @property STR_LINK_PROP_TITLE
|
|
7635 * @description The label string for the Link Property Editor Window.
|
|
7636 * @type String
|
|
7637 */
|
|
7638 STR_LINK_PROP_TITLE: 'Link Options',
|
|
7639 /**
|
|
7640 * @property STR_LINK_PROP_REMOVE
|
|
7641 * @description The label string for the Remove link from text link inside the property editor.
|
|
7642 * @type String
|
|
7643 */
|
|
7644 STR_LINK_PROP_REMOVE: 'Remove link from text',
|
|
7645 /**
|
|
7646 * @property STR_LINK_NEW_WINDOW
|
|
7647 * @description The string for the open in a new window label.
|
|
7648 * @type String
|
|
7649 */
|
|
7650 STR_LINK_NEW_WINDOW: 'Open in a new window.',
|
|
7651 /**
|
|
7652 * @property STR_LINK_TITLE
|
|
7653 * @description The string for the link description.
|
|
7654 * @type String
|
|
7655 */
|
|
7656 STR_LINK_TITLE: 'Description',
|
|
7657 /**
|
|
7658 * @property STR_NONE
|
|
7659 * @description The string for the word none.
|
|
7660 * @type String
|
|
7661 */
|
|
7662 STR_NONE: 'none',
|
|
7663 /**
|
|
7664 * @protected
|
|
7665 * @property CLASS_LOCAL_FILE
|
|
7666 * @description CSS class applied to an element when it's found to have a local url.
|
|
7667 * @type String
|
|
7668 */
|
|
7669 CLASS_LOCAL_FILE: 'warning-localfile',
|
|
7670 /**
|
|
7671 * @protected
|
|
7672 * @property CLASS_HIDDEN
|
|
7673 * @description CSS class applied to the body when the hiddenelements button is pressed.
|
|
7674 * @type String
|
|
7675 */
|
|
7676 CLASS_HIDDEN: 'yui-hidden',
|
|
7677 /**
|
|
7678 * @method init
|
|
7679 * @description The Editor class' initialization method
|
|
7680 */
|
|
7681 init: function(p_oElement, p_oAttributes) {
|
|
7682
|
|
7683 this._windows = {};
|
|
7684 if (!this._defaultToolbar) {
|
|
7685 this._defaultToolbar = {
|
|
7686 collapse: true,
|
|
7687 titlebar: 'Text Editing Tools',
|
|
7688 draggable: false,
|
|
7689 buttonType: 'advanced',
|
|
7690 buttons: [
|
|
7691 { group: 'fontstyle', label: 'Font Name and Size',
|
|
7692 buttons: [
|
|
7693 { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
|
|
7694 menu: [
|
|
7695 { text: 'Arial', checked: true },
|
|
7696 { text: 'Arial Black' },
|
|
7697 { text: 'Comic Sans MS' },
|
|
7698 { text: 'Courier New' },
|
|
7699 { text: 'Lucida Console' },
|
|
7700 { text: 'Tahoma' },
|
|
7701 { text: 'Times New Roman' },
|
|
7702 { text: 'Trebuchet MS' },
|
|
7703 { text: 'Verdana' }
|
|
7704 ]
|
|
7705 },
|
|
7706 { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
|
|
7707 ]
|
|
7708 },
|
|
7709 { type: 'separator' },
|
|
7710 { group: 'textstyle', label: 'Font Style',
|
|
7711 buttons: [
|
|
7712 { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
|
|
7713 { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
|
|
7714 { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
|
|
7715 { type: 'separator' },
|
|
7716 { type: 'push', label: 'Subscript', value: 'subscript', disabled: true },
|
|
7717 { type: 'push', label: 'Superscript', value: 'superscript', disabled: true }
|
|
7718 ]
|
|
7719 },
|
|
7720 { type: 'separator' },
|
|
7721 { group: 'textstyle2', label: ' ',
|
|
7722 buttons: [
|
|
7723 { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
|
|
7724 { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true },
|
|
7725 { type: 'separator' },
|
|
7726 { type: 'push', label: 'Remove Formatting', value: 'removeformat', disabled: true },
|
|
7727 { type: 'push', label: 'Show/Hide Hidden Elements', value: 'hiddenelements' }
|
|
7728 ]
|
|
7729 },
|
|
7730 { type: 'separator' },
|
|
7731 { group: 'undoredo', label: 'Undo/Redo',
|
|
7732 buttons: [
|
|
7733 { type: 'push', label: 'Undo', value: 'undo', disabled: true },
|
|
7734 { type: 'push', label: 'Redo', value: 'redo', disabled: true }
|
|
7735
|
|
7736 ]
|
|
7737 },
|
|
7738 { type: 'separator' },
|
|
7739 { group: 'alignment', label: 'Alignment',
|
|
7740 buttons: [
|
|
7741 { type: 'push', label: 'Align Left CTRL + SHIFT + [', value: 'justifyleft' },
|
|
7742 { type: 'push', label: 'Align Center CTRL + SHIFT + |', value: 'justifycenter' },
|
|
7743 { type: 'push', label: 'Align Right CTRL + SHIFT + ]', value: 'justifyright' },
|
|
7744 { type: 'push', label: 'Justify', value: 'justifyfull' }
|
|
7745 ]
|
|
7746 },
|
|
7747 { type: 'separator' },
|
|
7748 { group: 'parastyle', label: 'Paragraph Style',
|
|
7749 buttons: [
|
|
7750 { type: 'select', label: 'Normal', value: 'heading', disabled: true,
|
|
7751 menu: [
|
|
7752 { text: 'Normal', value: 'none', checked: true },
|
|
7753 { text: 'Header 1', value: 'h1' },
|
|
7754 { text: 'Header 2', value: 'h2' },
|
|
7755 { text: 'Header 3', value: 'h3' },
|
|
7756 { text: 'Header 4', value: 'h4' },
|
|
7757 { text: 'Header 5', value: 'h5' },
|
|
7758 { text: 'Header 6', value: 'h6' }
|
|
7759 ]
|
|
7760 }
|
|
7761 ]
|
|
7762 },
|
|
7763 { type: 'separator' },
|
|
7764
|
|
7765 { group: 'indentlist2', label: 'Indenting and Lists',
|
|
7766 buttons: [
|
|
7767 { type: 'push', label: 'Indent', value: 'indent', disabled: true },
|
|
7768 { type: 'push', label: 'Outdent', value: 'outdent', disabled: true },
|
|
7769 { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
|
|
7770 { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
|
|
7771 ]
|
|
7772 },
|
|
7773 { type: 'separator' },
|
|
7774 { group: 'insertitem', label: 'Insert Item',
|
|
7775 buttons: [
|
|
7776 { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
|
|
7777 { type: 'push', label: 'Insert Image', value: 'insertimage' }
|
|
7778 ]
|
|
7779 }
|
|
7780 ]
|
|
7781 };
|
|
7782 }
|
|
7783
|
|
7784 if (!this._defaultImageToolbarConfig) {
|
|
7785 this._defaultImageToolbarConfig = {
|
|
7786 buttonType: this._defaultToolbar.buttonType,
|
|
7787 buttons: [
|
|
7788 { group: 'textflow', label: this.STR_IMAGE_TEXTFLOW + ':',
|
|
7789 buttons: [
|
|
7790 { type: 'push', label: 'Left', value: 'left' },
|
|
7791 { type: 'push', label: 'Inline', value: 'inline' },
|
|
7792 { type: 'push', label: 'Block', value: 'block' },
|
|
7793 { type: 'push', label: 'Right', value: 'right' }
|
|
7794 ]
|
|
7795 },
|
|
7796 { type: 'separator' },
|
|
7797 { group: 'padding', label: this.STR_IMAGE_PADDING + ':',
|
|
7798 buttons: [
|
|
7799 { type: 'spin', label: '0', value: 'padding', range: [0, 50] }
|
|
7800 ]
|
|
7801 },
|
|
7802 { type: 'separator' },
|
|
7803 { group: 'border', label: this.STR_IMAGE_BORDER + ':',
|
|
7804 buttons: [
|
|
7805 { type: 'select', label: this.STR_IMAGE_BORDER_SIZE, value: 'bordersize',
|
|
7806 menu: [
|
|
7807 { text: 'none', value: '0', checked: true },
|
|
7808 { text: '1px', value: '1' },
|
|
7809 { text: '2px', value: '2' },
|
|
7810 { text: '3px', value: '3' },
|
|
7811 { text: '4px', value: '4' },
|
|
7812 { text: '5px', value: '5' }
|
|
7813 ]
|
|
7814 },
|
|
7815 { type: 'select', label: this.STR_IMAGE_BORDER_TYPE, value: 'bordertype', disabled: true,
|
|
7816 menu: [
|
|
7817 { text: 'Solid', value: 'solid', checked: true },
|
|
7818 { text: 'Dashed', value: 'dashed' },
|
|
7819 { text: 'Dotted', value: 'dotted' }
|
|
7820 ]
|
|
7821 },
|
|
7822 { type: 'color', label: 'Border Color', value: 'bordercolor', disabled: true }
|
|
7823 ]
|
|
7824 }
|
|
7825 ]
|
|
7826 };
|
|
7827 }
|
|
7828
|
|
7829 YAHOO.widget.Editor.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
7830 },
|
|
7831 _render: function() {
|
|
7832 YAHOO.widget.Editor.superclass._render.apply(this, arguments);
|
|
7833 var self = this;
|
|
7834 //Render the panel in another thread and delay it a little..
|
|
7835 window.setTimeout(function() {
|
|
7836 self._renderPanel.call(self);
|
|
7837 }, 800);
|
|
7838 },
|
|
7839 /**
|
|
7840 * @method initAttributes
|
|
7841 * @description Initializes all of the configuration attributes used to create
|
|
7842 * the editor.
|
|
7843 * @param {Object} attr Object literal specifying a set of
|
|
7844 * configuration attributes used to create the editor.
|
|
7845 */
|
|
7846 initAttributes: function(attr) {
|
|
7847 YAHOO.widget.Editor.superclass.initAttributes.call(this, attr);
|
|
7848
|
|
7849 /**
|
|
7850 * @attribute localFileWarning
|
|
7851 * @description Should we throw the warning if we detect a file that is local to their machine?
|
|
7852 * @default true
|
|
7853 * @type Boolean
|
|
7854 */
|
|
7855 this.setAttributeConfig('localFileWarning', {
|
|
7856 value: attr.locaFileWarning || true
|
|
7857 });
|
|
7858
|
|
7859 /**
|
|
7860 * @attribute hiddencss
|
|
7861 * @description The CSS used to show/hide hidden elements on the page, these rules must be prefixed with the class provided in <code>this.CLASS_HIDDEN</code>
|
|
7862 * @default <code><pre>
|
|
7863 .yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u,
|
|
7864 .yui-hidden div, .yui-hidden p, .yui-hidden span, .yui-hidden img, .yui-hidden ul, .yui-hidden ol,
|
|
7865 .yui-hidden li, .yui-hidden table {
|
|
7866 border: 1px dotted #ccc;
|
|
7867 }
|
|
7868 .yui-hidden .yui-non {
|
|
7869 border: none;
|
|
7870 }
|
|
7871 .yui-hidden img {
|
|
7872 padding: 2px;
|
|
7873 }</pre></code>
|
|
7874 * @type String
|
|
7875 */
|
|
7876 this.setAttributeConfig('hiddencss', {
|
|
7877 value: attr.hiddencss || '.yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div,.yui-hidden p,.yui-hidden span,.yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table { border: 1px dotted #ccc; } .yui-hidden .yui-non { border: none; } .yui-hidden img { padding: 2px; }',
|
|
7878 writeOnce: true
|
|
7879 });
|
|
7880
|
|
7881 },
|
|
7882 /**
|
|
7883 * @private
|
|
7884 * @method _windows
|
|
7885 * @description A reference to the HTML elements used for the body of Editor Windows.
|
|
7886 */
|
|
7887 _windows: null,
|
|
7888 /**
|
|
7889 * @private
|
|
7890 * @method _defaultImageToolbar
|
|
7891 * @description A reference to the Toolbar Object inside Image Editor Window.
|
|
7892 */
|
|
7893 _defaultImageToolbar: null,
|
|
7894 /**
|
|
7895 * @private
|
|
7896 * @method _defaultImageToolbarConfig
|
|
7897 * @description Config to be used for the default Image Editor Window.
|
|
7898 */
|
|
7899 _defaultImageToolbarConfig: null,
|
|
7900 /**
|
|
7901 * @private
|
|
7902 * @method _fixNodes
|
|
7903 * @description Fix href and imgs as well as remove invalid HTML.
|
|
7904 */
|
|
7905 _fixNodes: function() {
|
|
7906 YAHOO.widget.Editor.superclass._fixNodes.call(this);
|
|
7907 try {
|
|
7908 var url = '';
|
|
7909
|
|
7910 var imgs = this._getDoc().getElementsByTagName('img');
|
|
7911 for (var im = 0; im < imgs.length; im++) {
|
|
7912 if (imgs[im].getAttribute('href', 2)) {
|
|
7913 url = imgs[im].getAttribute('src', 2);
|
|
7914 if (this._isLocalFile(url)) {
|
|
7915 Dom.addClass(imgs[im], this.CLASS_LOCAL_FILE);
|
|
7916 } else {
|
|
7917 Dom.removeClass(imgs[im], this.CLASS_LOCAL_FILE);
|
|
7918 }
|
|
7919 }
|
|
7920 }
|
|
7921 var fakeAs = this._getDoc().body.getElementsByTagName('a');
|
|
7922 for (var a = 0; a < fakeAs.length; a++) {
|
|
7923 if (fakeAs[a].getAttribute('href', 2)) {
|
|
7924 url = fakeAs[a].getAttribute('href', 2);
|
|
7925 if (this._isLocalFile(url)) {
|
|
7926 Dom.addClass(fakeAs[a], this.CLASS_LOCAL_FILE);
|
|
7927 } else {
|
|
7928 Dom.removeClass(fakeAs[a], this.CLASS_LOCAL_FILE);
|
|
7929 }
|
|
7930 }
|
|
7931 }
|
|
7932 } catch(e) {}
|
|
7933 },
|
|
7934 /**
|
|
7935 * @private
|
|
7936 * @property _disabled
|
|
7937 * @description The Toolbar items that should be disabled if there is no selection present in the editor.
|
|
7938 * @type Array
|
|
7939 */
|
|
7940 _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading', 'indent' ],
|
|
7941 /**
|
|
7942 * @private
|
|
7943 * @property _alwaysDisabled
|
|
7944 * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
|
|
7945 * @type Object
|
|
7946 */
|
|
7947 _alwaysDisabled: { 'outdent': true },
|
|
7948 /**
|
|
7949 * @private
|
|
7950 * @property _alwaysEnabled
|
|
7951 * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
|
|
7952 * @type Object
|
|
7953 */
|
|
7954 _alwaysEnabled: { hiddenelements: true },
|
|
7955 /**
|
|
7956 * @private
|
|
7957 * @method _handleKeyDown
|
|
7958 * @param {Event} ev The event we are working on.
|
|
7959 * @description Override method that handles some new keydown events inside the iFrame document.
|
|
7960 */
|
|
7961 _handleKeyDown: function(ev) {
|
|
7962 YAHOO.widget.Editor.superclass._handleKeyDown.call(this, ev);
|
|
7963 var doExec = false,
|
|
7964 action = null,
|
|
7965 exec = false;
|
|
7966
|
|
7967 switch (ev.keyCode) {
|
|
7968 //case 219: //Left
|
|
7969 case this._keyMap.JUSTIFY_LEFT.key: //Left
|
|
7970 if (this._checkKey(this._keyMap.JUSTIFY_LEFT, ev)) {
|
|
7971 action = 'justifyleft';
|
|
7972 doExec = true;
|
|
7973 }
|
|
7974 break;
|
|
7975 //case 220: //Center
|
|
7976 case this._keyMap.JUSTIFY_CENTER.key:
|
|
7977 if (this._checkKey(this._keyMap.JUSTIFY_CENTER, ev)) {
|
|
7978 action = 'justifycenter';
|
|
7979 doExec = true;
|
|
7980 }
|
|
7981 break;
|
|
7982 case 221: //Right
|
|
7983 case this._keyMap.JUSTIFY_RIGHT.key:
|
|
7984 if (this._checkKey(this._keyMap.JUSTIFY_RIGHT, ev)) {
|
|
7985 action = 'justifyright';
|
|
7986 doExec = true;
|
|
7987 }
|
|
7988 break;
|
|
7989 }
|
|
7990 if (doExec && action) {
|
|
7991 this.execCommand(action, null);
|
|
7992 Event.stopEvent(ev);
|
|
7993 this.nodeChange();
|
|
7994 }
|
|
7995 },
|
|
7996 /**
|
|
7997 * @private
|
|
7998 * @method _renderCreateLinkWindow
|
|
7999 * @description Pre renders the CreateLink window so we get faster window opening.
|
|
8000 */
|
|
8001 _renderCreateLinkWindow: function() {
|
|
8002 var str = '<label for="' + this.get('id') + '_createlink_url"><strong>' + this.STR_LINK_URL + ':</strong> <input type="text" name="' + this.get('id') + '_createlink_url" id="' + this.get('id') + '_createlink_url" value=""></label>';
|
|
8003 str += '<label for="' + this.get('id') + '_createlink_target"><strong> </strong><input type="checkbox" name="' + this.get('id') + '_createlink_target" id="' + this.get('id') + '_createlink_target" value="_blank" class="createlink_target"> ' + this.STR_LINK_NEW_WINDOW + '</label>';
|
|
8004 str += '<label for="' + this.get('id') + '_createlink_title"><strong>' + this.STR_LINK_TITLE + ':</strong> <input type="text" name="' + this.get('id') + '_createlink_title" id="' + this.get('id') + '_createlink_title" value=""></label>';
|
|
8005
|
|
8006 var body = document.createElement('div');
|
|
8007 body.innerHTML = str;
|
|
8008
|
|
8009 var unlinkCont = document.createElement('div');
|
|
8010 unlinkCont.className = 'removeLink';
|
|
8011 var unlink = document.createElement('a');
|
|
8012 unlink.href = '#';
|
|
8013 unlink.innerHTML = this.STR_LINK_PROP_REMOVE;
|
|
8014 unlink.title = this.STR_LINK_PROP_REMOVE;
|
|
8015 Event.on(unlink, 'click', function(ev) {
|
|
8016 Event.stopEvent(ev);
|
|
8017 this.unsubscribeAll('afterExecCommand');
|
|
8018 this.execCommand('unlink');
|
|
8019 this.closeWindow();
|
|
8020 }, this, true);
|
|
8021 unlinkCont.appendChild(unlink);
|
|
8022 body.appendChild(unlinkCont);
|
|
8023
|
|
8024 this._windows.createlink = {};
|
|
8025 this._windows.createlink.body = body;
|
|
8026 //body.style.display = 'none';
|
|
8027 Event.on(body, 'keyup', function(e) {
|
|
8028 Event.stopPropagation(e);
|
|
8029 });
|
|
8030 this.get('panel').editor_form.appendChild(body);
|
|
8031 this.fireEvent('windowCreateLinkRender', { type: 'windowCreateLinkRender', panel: this.get('panel'), body: body });
|
|
8032 return body;
|
|
8033 },
|
|
8034 _handleCreateLinkClick: function() {
|
|
8035 var el = this._getSelectedElement();
|
|
8036 if (this._isElement(el, 'img')) {
|
|
8037 this.STOP_EXEC_COMMAND = true;
|
|
8038 this.currentElement[0] = el;
|
|
8039 this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
|
|
8040 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
8041 return false;
|
|
8042 }
|
|
8043 if (this.get('limitCommands')) {
|
|
8044 if (!this.toolbar.getButtonByValue('createlink')) {
|
|
8045 return false;
|
|
8046 }
|
|
8047 }
|
|
8048
|
|
8049 this.on('afterExecCommand', function() {
|
|
8050 var win = new YAHOO.widget.EditorWindow('createlink', {
|
|
8051 width: '350px'
|
|
8052 });
|
|
8053
|
|
8054 var el = this.currentElement[0],
|
|
8055 url = '',
|
|
8056 title = '',
|
|
8057 target = '',
|
|
8058 localFile = false;
|
|
8059 if (el) {
|
|
8060 win.el = el;
|
|
8061 if (el.getAttribute('href', 2) !== null) {
|
|
8062 url = el.getAttribute('href', 2);
|
|
8063 if (this._isLocalFile(url)) {
|
|
8064 //Local File throw Warning
|
|
8065 win.setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8066 localFile = true;
|
|
8067 } else {
|
|
8068 win.setFooter(' ');
|
|
8069 }
|
|
8070 }
|
|
8071 if (el.getAttribute('title') !== null) {
|
|
8072 title = el.getAttribute('title');
|
|
8073 }
|
|
8074 if (el.getAttribute('target') !== null) {
|
|
8075 target = el.getAttribute('target');
|
|
8076 }
|
|
8077 }
|
|
8078 var body = null;
|
|
8079 if (this._windows.createlink && this._windows.createlink.body) {
|
|
8080 body = this._windows.createlink.body;
|
|
8081 } else {
|
|
8082 body = this._renderCreateLinkWindow();
|
|
8083 }
|
|
8084
|
|
8085 win.setHeader(this.STR_LINK_PROP_TITLE);
|
|
8086 win.setBody(body);
|
|
8087
|
|
8088 Event.purgeElement(this.get('id') + '_createlink_url');
|
|
8089
|
|
8090 Dom.get(this.get('id') + '_createlink_url').value = url;
|
|
8091 Dom.get(this.get('id') + '_createlink_title').value = title;
|
|
8092 Dom.get(this.get('id') + '_createlink_target').checked = ((target) ? true : false);
|
|
8093
|
|
8094
|
|
8095 Event.onAvailable(this.get('id') + '_createlink_url', function() {
|
|
8096 var id = this.get('id');
|
|
8097 window.setTimeout(function() {
|
|
8098 try {
|
|
8099 YAHOO.util.Dom.get(id + '_createlink_url').focus();
|
|
8100 } catch (e) {}
|
|
8101 }, 50);
|
|
8102
|
|
8103 if (this._isLocalFile(url)) {
|
|
8104 //Local File throw Warning
|
|
8105 Dom.addClass(this.get('id') + '_createlink_url', 'warning');
|
|
8106 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8107 } else {
|
|
8108 Dom.removeClass(this.get('id') + '_createlink_url', 'warning');
|
|
8109 this.get('panel').setFooter(' ');
|
|
8110 }
|
|
8111 Event.on(this.get('id') + '_createlink_url', 'blur', function() {
|
|
8112 var url = Dom.get(this.get('id') + '_createlink_url');
|
|
8113 if (this._isLocalFile(url.value)) {
|
|
8114 //Local File throw Warning
|
|
8115 Dom.addClass(url, 'warning');
|
|
8116 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8117 } else {
|
|
8118 Dom.removeClass(url, 'warning');
|
|
8119 this.get('panel').setFooter(' ');
|
|
8120 }
|
|
8121 }, this, true);
|
|
8122 }, this, true);
|
|
8123
|
|
8124 this.openWindow(win);
|
|
8125
|
|
8126 });
|
|
8127 },
|
|
8128 /**
|
|
8129 * @private
|
|
8130 * @method _handleCreateLinkWindowClose
|
|
8131 * @description Handles the closing of the Link Properties Window.
|
|
8132 */
|
|
8133 _handleCreateLinkWindowClose: function() {
|
|
8134
|
|
8135 var url = Dom.get(this.get('id') + '_createlink_url'),
|
|
8136 target = Dom.get(this.get('id') + '_createlink_target'),
|
|
8137 title = Dom.get(this.get('id') + '_createlink_title'),
|
|
8138 el = arguments[0].win.el,
|
|
8139 a = el;
|
|
8140
|
|
8141 if (url && url.value) {
|
|
8142 var urlValue = url.value;
|
|
8143 if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8144 if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8145 //Found an @ sign, prefix with mailto:
|
|
8146 urlValue = 'mailto:' + urlValue;
|
|
8147 } else {
|
|
8148 // :// not found adding
|
|
8149 if (urlValue.substring(0, 1) != '#') {
|
|
8150 urlValue = 'http:/'+'/' + urlValue;
|
|
8151 }
|
|
8152
|
|
8153 }
|
|
8154 }
|
|
8155 el.setAttribute('href', urlValue);
|
|
8156 if (target.checked) {
|
|
8157 el.setAttribute('target', target.value);
|
|
8158 } else {
|
|
8159 el.setAttribute('target', '');
|
|
8160 }
|
|
8161 el.setAttribute('title', ((title.value) ? title.value : ''));
|
|
8162
|
|
8163 } else {
|
|
8164 var _span = this._getDoc().createElement('span');
|
|
8165 _span.innerHTML = el.innerHTML;
|
|
8166 Dom.addClass(_span, 'yui-non');
|
|
8167 el.parentNode.replaceChild(_span, el);
|
|
8168 }
|
|
8169 Dom.removeClass(url, 'warning');
|
|
8170 Dom.get(this.get('id') + '_createlink_url').value = '';
|
|
8171 Dom.get(this.get('id') + '_createlink_title').value = '';
|
|
8172 Dom.get(this.get('id') + '_createlink_target').checked = false;
|
|
8173 this.nodeChange();
|
|
8174 this.currentElement = [];
|
|
8175
|
|
8176 },
|
|
8177 /**
|
|
8178 * @private
|
|
8179 * @method _renderInsertImageWindow
|
|
8180 * @description Pre renders the InsertImage window so we get faster window opening.
|
|
8181 */
|
|
8182 _renderInsertImageWindow: function() {
|
|
8183 var el = this.currentElement[0];
|
|
8184 var str = '<label for="' + this.get('id') + '_insertimage_url"><strong>' + this.STR_IMAGE_URL + ':</strong> <input type="text" id="' + this.get('id') + '_insertimage_url" value="" size="40"></label>';
|
|
8185 var body = document.createElement('div');
|
|
8186 body.innerHTML = str;
|
|
8187
|
|
8188 var tbarCont = document.createElement('div');
|
|
8189 tbarCont.id = this.get('id') + '_img_toolbar';
|
|
8190 body.appendChild(tbarCont);
|
|
8191
|
|
8192 var str2 = '<label for="' + this.get('id') + '_insertimage_title"><strong>' + this.STR_IMAGE_TITLE + ':</strong> <input type="text" id="' + this.get('id') + '_insertimage_title" value="" size="40"></label>';
|
|
8193 str2 += '<label for="' + this.get('id') + '_insertimage_link"><strong>' + this.STR_LINK_URL + ':</strong> <input type="text" name="' + this.get('id') + '_insertimage_link" id="' + this.get('id') + '_insertimage_link" value=""></label>';
|
|
8194 str2 += '<label for="' + this.get('id') + '_insertimage_target"><strong> </strong><input type="checkbox" name="' + this.get('id') + '_insertimage_target_" id="' + this.get('id') + '_insertimage_target" value="_blank" class="insertimage_target"> ' + this.STR_LINK_NEW_WINDOW + '</label>';
|
|
8195 var div = document.createElement('div');
|
|
8196 div.innerHTML = str2;
|
|
8197 body.appendChild(div);
|
|
8198
|
|
8199 var o = {};
|
|
8200 Lang.augmentObject(o, this._defaultImageToolbarConfig); //Break the config reference
|
|
8201
|
|
8202 var tbar = new YAHOO.widget.Toolbar(tbarCont, o);
|
|
8203 tbar.editor_el = el;
|
|
8204 this._defaultImageToolbar = tbar;
|
|
8205
|
|
8206 var cont = tbar.get('cont');
|
|
8207 var hw = document.createElement('div');
|
|
8208 hw.className = 'yui-toolbar-group yui-toolbar-group-height-width height-width';
|
|
8209 hw.innerHTML = '<h3>' + this.STR_IMAGE_SIZE + ':</h3>';
|
|
8210 hw.innerHTML += '<span tabIndex="-1"><input type="text" size="3" value="" id="' + this.get('id') + '_insertimage_width"> x <input type="text" size="3" value="" id="' + this.get('id') + '_insertimage_height"></span>';
|
|
8211 cont.insertBefore(hw, cont.firstChild);
|
|
8212
|
|
8213 Event.onAvailable(this.get('id') + '_insertimage_width', function() {
|
|
8214 Event.on(this.get('id') + '_insertimage_width', 'blur', function() {
|
|
8215 var value = parseInt(Dom.get(this.get('id') + '_insertimage_width').value, 10);
|
|
8216 if (value > 5) {
|
|
8217 this._defaultImageToolbar.editor_el.style.width = value + 'px';
|
|
8218 //Removed moveWindow call so the window doesn't jump
|
|
8219 //this.moveWindow();
|
|
8220 }
|
|
8221 }, this, true);
|
|
8222 }, this, true);
|
|
8223 Event.onAvailable(this.get('id') + '_insertimage_height', function() {
|
|
8224 Event.on(this.get('id') + '_insertimage_height', 'blur', function() {
|
|
8225 var value = parseInt(Dom.get(this.get('id') + '_insertimage_height').value, 10);
|
|
8226 if (value > 5) {
|
|
8227 this._defaultImageToolbar.editor_el.style.height = value + 'px';
|
|
8228 //Removed moveWindow call so the window doesn't jump
|
|
8229 //this.moveWindow();
|
|
8230 }
|
|
8231 }, this, true);
|
|
8232 }, this, true);
|
|
8233
|
|
8234
|
|
8235 tbar.on('colorPickerClicked', function(o) {
|
|
8236 var size = '1', type = 'solid', color = 'black', el = this._defaultImageToolbar.editor_el;
|
|
8237
|
|
8238 if (el.style.borderLeftWidth) {
|
|
8239 size = parseInt(el.style.borderLeftWidth, 10);
|
|
8240 }
|
|
8241 if (el.style.borderLeftStyle) {
|
|
8242 type = el.style.borderLeftStyle;
|
|
8243 }
|
|
8244 if (el.style.borderLeftColor) {
|
|
8245 color = el.style.borderLeftColor;
|
|
8246 }
|
|
8247 var borderString = size + 'px ' + type + ' #' + o.color;
|
|
8248 el.style.border = borderString;
|
|
8249 }, this, true);
|
|
8250
|
|
8251 tbar.on('buttonClick', function(o) {
|
|
8252 var value = o.button.value,
|
|
8253 el = this._defaultImageToolbar.editor_el,
|
|
8254 borderString = '';
|
|
8255 if (o.button.menucmd) {
|
|
8256 value = o.button.menucmd;
|
|
8257 }
|
|
8258 var size = '1', type = 'solid', color = 'black';
|
|
8259
|
|
8260 /* All border calcs are done on the left border
|
|
8261 since our default interface only supports
|
|
8262 one border size/type and color */
|
|
8263 if (el.style.borderLeftWidth) {
|
|
8264 size = parseInt(el.style.borderLeftWidth, 10);
|
|
8265 }
|
|
8266 if (el.style.borderLeftStyle) {
|
|
8267 type = el.style.borderLeftStyle;
|
|
8268 }
|
|
8269 if (el.style.borderLeftColor) {
|
|
8270 color = el.style.borderLeftColor;
|
|
8271 }
|
|
8272 switch(value) {
|
|
8273 case 'bordersize':
|
|
8274 if (this.browser.webkit && this._lastImage) {
|
|
8275 Dom.removeClass(this._lastImage, 'selected');
|
|
8276 this._lastImage = null;
|
|
8277 }
|
|
8278
|
|
8279 borderString = parseInt(o.button.value, 10) + 'px ' + type + ' ' + color;
|
|
8280 el.style.border = borderString;
|
|
8281 if (parseInt(o.button.value, 10) > 0) {
|
|
8282 tbar.enableButton('bordertype');
|
|
8283 tbar.enableButton('bordercolor');
|
|
8284 } else {
|
|
8285 tbar.disableButton('bordertype');
|
|
8286 tbar.disableButton('bordercolor');
|
|
8287 }
|
|
8288 break;
|
|
8289 case 'bordertype':
|
|
8290 if (this.browser.webkit && this._lastImage) {
|
|
8291 Dom.removeClass(this._lastImage, 'selected');
|
|
8292 this._lastImage = null;
|
|
8293 }
|
|
8294 borderString = size + 'px ' + o.button.value + ' ' + color;
|
|
8295 el.style.border = borderString;
|
|
8296 break;
|
|
8297 case 'right':
|
|
8298 case 'left':
|
|
8299 tbar.deselectAllButtons();
|
|
8300 el.style.display = '';
|
|
8301 el.align = o.button.value;
|
|
8302 break;
|
|
8303 case 'inline':
|
|
8304 tbar.deselectAllButtons();
|
|
8305 el.style.display = '';
|
|
8306 el.align = '';
|
|
8307 break;
|
|
8308 case 'block':
|
|
8309 tbar.deselectAllButtons();
|
|
8310 el.style.display = 'block';
|
|
8311 el.align = 'center';
|
|
8312 break;
|
|
8313 case 'padding':
|
|
8314 var _button = tbar.getButtonById(o.button.id);
|
|
8315 el.style.margin = _button.get('label') + 'px';
|
|
8316 break;
|
|
8317 }
|
|
8318 tbar.selectButton(o.button.value);
|
|
8319 if (value !== 'padding') {
|
|
8320 this.moveWindow();
|
|
8321 }
|
|
8322 }, this, true);
|
|
8323
|
|
8324
|
|
8325
|
|
8326 if (this.get('localFileWarning')) {
|
|
8327 Event.on(this.get('id') + '_insertimage_link', 'blur', function() {
|
|
8328 var url = Dom.get(this.get('id') + '_insertimage_link');
|
|
8329 if (this._isLocalFile(url.value)) {
|
|
8330 //Local File throw Warning
|
|
8331 Dom.addClass(url, 'warning');
|
|
8332 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8333 } else {
|
|
8334 Dom.removeClass(url, 'warning');
|
|
8335 this.get('panel').setFooter(' ');
|
|
8336 //Adobe AIR Code
|
|
8337 if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {
|
|
8338 this.get('panel').setFooter(this.STR_IMAGE_COPY);
|
|
8339 }
|
|
8340 }
|
|
8341 }, this, true);
|
|
8342 }
|
|
8343
|
|
8344 Event.on(this.get('id') + '_insertimage_url', 'blur', function() {
|
|
8345 var url = Dom.get(this.get('id') + '_insertimage_url'),
|
|
8346 el = this.currentElement[0];
|
|
8347
|
|
8348 if (url.value && el) {
|
|
8349 if (url.value == el.getAttribute('src', 2)) {
|
|
8350 return false;
|
|
8351 }
|
|
8352 }
|
|
8353 if (this._isLocalFile(url.value)) {
|
|
8354 //Local File throw Warning
|
|
8355 Dom.addClass(url, 'warning');
|
|
8356 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8357 } else if (this.currentElement[0]) {
|
|
8358 Dom.removeClass(url, 'warning');
|
|
8359 this.get('panel').setFooter(' ');
|
|
8360 //Adobe AIR Code
|
|
8361 if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {
|
|
8362 this.get('panel').setFooter(this.STR_IMAGE_COPY);
|
|
8363 }
|
|
8364
|
|
8365 if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
|
|
8366 this.currentElement[0].setAttribute('src', url.value);
|
|
8367 var self = this,
|
|
8368 img = new Image();
|
|
8369
|
|
8370 img.onerror = function() {
|
|
8371 url.value = self.STR_IMAGE_HERE;
|
|
8372 img.setAttribute('src', self.get('blankimage'));
|
|
8373 self.currentElement[0].setAttribute('src', self.get('blankimage'));
|
|
8374 YAHOO.util.Dom.get(self.get('id') + '_insertimage_height').value = img.height;
|
|
8375 YAHOO.util.Dom.get(self.get('id') + '_insertimage_width').value = img.width;
|
|
8376 };
|
|
8377 var id = this.get('id');
|
|
8378 window.setTimeout(function() {
|
|
8379 YAHOO.util.Dom.get(id + '_insertimage_height').value = img.height;
|
|
8380 YAHOO.util.Dom.get(id + '_insertimage_width').value = img.width;
|
|
8381 if (self.currentElement && self.currentElement[0]) {
|
|
8382 if (!self.currentElement[0]._height) {
|
|
8383 self.currentElement[0]._height = img.height;
|
|
8384 }
|
|
8385 if (!self.currentElement[0]._width) {
|
|
8386 self.currentElement[0]._width = img.width;
|
|
8387 }
|
|
8388 }
|
|
8389 //Removed moveWindow call so the window doesn't jump
|
|
8390 //self.moveWindow();
|
|
8391 }, 800); //Bumped the timeout up to account for larger images..
|
|
8392
|
|
8393 if (url.value != this.STR_IMAGE_HERE) {
|
|
8394 img.src = url.value;
|
|
8395 }
|
|
8396 }
|
|
8397 }
|
|
8398 }, this, true);
|
|
8399
|
|
8400
|
|
8401
|
|
8402 this._windows.insertimage = {};
|
|
8403 this._windows.insertimage.body = body;
|
|
8404 //body.style.display = 'none';
|
|
8405 this.get('panel').editor_form.appendChild(body);
|
|
8406 this.fireEvent('windowInsertImageRender', { type: 'windowInsertImageRender', panel: this.get('panel'), body: body, toolbar: tbar });
|
|
8407 return body;
|
|
8408 },
|
|
8409 /**
|
|
8410 * @private
|
|
8411 * @method _handleInsertImageClick
|
|
8412 * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
|
|
8413 */
|
|
8414 _handleInsertImageClick: function() {
|
|
8415 if (this.get('limitCommands')) {
|
|
8416 if (!this.toolbar.getButtonByValue('insertimage')) {
|
|
8417 return false;
|
|
8418 }
|
|
8419 }
|
|
8420 this.on('afterExecCommand', function() {
|
|
8421 var el = this.currentElement[0],
|
|
8422 body = null,
|
|
8423 link = '',
|
|
8424 target = '',
|
|
8425 tbar = null,
|
|
8426 title = '',
|
|
8427 src = '',
|
|
8428 align = '',
|
|
8429 height = 75,
|
|
8430 width = 75,
|
|
8431 padding = 0,
|
|
8432 oheight = 0,
|
|
8433 owidth = 0,
|
|
8434 blankimage = false,
|
|
8435 win = new YAHOO.widget.EditorWindow('insertimage', {
|
|
8436 width: '415px'
|
|
8437 });
|
|
8438
|
|
8439 if (!el) {
|
|
8440 el = this._getSelectedElement();
|
|
8441 }
|
|
8442 if (el) {
|
|
8443 win.el = el;
|
|
8444 if (el.getAttribute('src')) {
|
|
8445 src = el.getAttribute('src', 2);
|
|
8446 if (src.indexOf(this.get('blankimage')) != -1) {
|
|
8447 src = this.STR_IMAGE_HERE;
|
|
8448 blankimage = true;
|
|
8449 }
|
|
8450 }
|
|
8451 if (el.getAttribute('alt', 2)) {
|
|
8452 title = el.getAttribute('alt', 2);
|
|
8453 }
|
|
8454 if (el.getAttribute('title', 2)) {
|
|
8455 title = el.getAttribute('title', 2);
|
|
8456 }
|
|
8457
|
|
8458 if (el.parentNode && this._isElement(el.parentNode, 'a')) {
|
|
8459 link = el.parentNode.getAttribute('href', 2);
|
|
8460 if (el.parentNode.getAttribute('target') !== null) {
|
|
8461 target = el.parentNode.getAttribute('target');
|
|
8462 }
|
|
8463 }
|
|
8464 height = parseInt(el.height, 10);
|
|
8465 width = parseInt(el.width, 10);
|
|
8466 if (el.style.height) {
|
|
8467 height = parseInt(el.style.height, 10);
|
|
8468 }
|
|
8469 if (el.style.width) {
|
|
8470 width = parseInt(el.style.width, 10);
|
|
8471 }
|
|
8472 if (el.style.margin) {
|
|
8473 padding = parseInt(el.style.margin, 10);
|
|
8474 }
|
|
8475 if (!blankimage) {
|
|
8476 if (!el._height) {
|
|
8477 el._height = height;
|
|
8478 }
|
|
8479 if (!el._width) {
|
|
8480 el._width = width;
|
|
8481 }
|
|
8482 oheight = el._height;
|
|
8483 owidth = el._width;
|
|
8484 }
|
|
8485 }
|
|
8486 if (this._windows.insertimage && this._windows.insertimage.body) {
|
|
8487 body = this._windows.insertimage.body;
|
|
8488 this._defaultImageToolbar.resetAllButtons();
|
|
8489 } else {
|
|
8490 body = this._renderInsertImageWindow();
|
|
8491 }
|
|
8492
|
|
8493 tbar = this._defaultImageToolbar;
|
|
8494 tbar.editor_el = el;
|
|
8495
|
|
8496
|
|
8497 var bsize = '0',
|
|
8498 btype = 'solid';
|
|
8499
|
|
8500 if (el.style.borderLeftWidth) {
|
|
8501 bsize = parseInt(el.style.borderLeftWidth, 10);
|
|
8502 }
|
|
8503 if (el.style.borderLeftStyle) {
|
|
8504 btype = el.style.borderLeftStyle;
|
|
8505 }
|
|
8506 var bs_button = tbar.getButtonByValue('bordersize'),
|
|
8507 bSizeStr = ((parseInt(bsize, 10) > 0) ? '' : this.STR_NONE);
|
|
8508 bs_button.set('label', '<span class="yui-toolbar-bordersize-' + bsize + '">' + bSizeStr + '</span>');
|
|
8509 this._updateMenuChecked('bordersize', bsize, tbar);
|
|
8510
|
|
8511 var bt_button = tbar.getButtonByValue('bordertype');
|
|
8512 bt_button.set('label', '<span class="yui-toolbar-bordertype-' + btype + '">asdfa</span>');
|
|
8513 this._updateMenuChecked('bordertype', btype, tbar);
|
|
8514 if (parseInt(bsize, 10) > 0) {
|
|
8515 tbar.enableButton(bt_button);
|
|
8516 tbar.enableButton(bs_button);
|
|
8517 tbar.enableButton('bordercolor');
|
|
8518 }
|
|
8519
|
|
8520 if ((el.align == 'right') || (el.align == 'left')) {
|
|
8521 tbar.selectButton(el.align);
|
|
8522 } else if (el.style.display == 'block') {
|
|
8523 tbar.selectButton('block');
|
|
8524 } else {
|
|
8525 tbar.selectButton('inline');
|
|
8526 }
|
|
8527 if (parseInt(el.style.marginLeft, 10) > 0) {
|
|
8528 tbar.getButtonByValue('padding').set('label', ''+parseInt(el.style.marginLeft, 10));
|
|
8529 }
|
|
8530 if (el.style.borderSize) {
|
|
8531 tbar.selectButton('bordersize');
|
|
8532 tbar.selectButton(parseInt(el.style.borderSize, 10));
|
|
8533 }
|
|
8534 tbar.getButtonByValue('padding').set('label', ''+padding);
|
|
8535
|
|
8536
|
|
8537
|
|
8538 win.setHeader(this.STR_IMAGE_PROP_TITLE);
|
|
8539 win.setBody(body);
|
|
8540 //Adobe AIR Code
|
|
8541 if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {
|
|
8542 win.setFooter(this.STR_IMAGE_COPY);
|
|
8543 }
|
|
8544 this.openWindow(win);
|
|
8545 Dom.get(this.get('id') + '_insertimage_url').value = src;
|
|
8546 Dom.get(this.get('id') + '_insertimage_title').value = title;
|
|
8547 Dom.get(this.get('id') + '_insertimage_link').value = link;
|
|
8548 Dom.get(this.get('id') + '_insertimage_target').checked = ((target) ? true : false);
|
|
8549 Dom.get(this.get('id') + '_insertimage_width').value = width;
|
|
8550 Dom.get(this.get('id') + '_insertimage_height').value = height;
|
|
8551
|
|
8552
|
|
8553 if (((height != oheight) || (width != owidth)) && (!blankimage)) {
|
|
8554 var s = document.createElement('span');
|
|
8555 s.className = 'info';
|
|
8556 s.innerHTML = this.STR_IMAGE_ORIG_SIZE + ': ('+ owidth +' x ' + oheight + ')';
|
|
8557 if (Dom.get(this.get('id') + '_insertimage_height').nextSibling) {
|
|
8558 var old = Dom.get(this.get('id') + '_insertimage_height').nextSibling;
|
|
8559 old.parentNode.removeChild(old);
|
|
8560 }
|
|
8561 Dom.get(this.get('id') + '_insertimage_height').parentNode.appendChild(s);
|
|
8562 }
|
|
8563
|
|
8564 this.toolbar.selectButton('insertimage');
|
|
8565 var id = this.get('id');
|
|
8566 window.setTimeout(function() {
|
|
8567 try {
|
|
8568 YAHOO.util.Dom.get(id + '_insertimage_url').focus();
|
|
8569 if (blankimage) {
|
|
8570 YAHOO.util.Dom.get(id + '_insertimage_url').select();
|
|
8571 }
|
|
8572 } catch (e) {}
|
|
8573 }, 50);
|
|
8574
|
|
8575 });
|
|
8576 },
|
|
8577 /**
|
|
8578 * @private
|
|
8579 * @method _handleInsertImageWindowClose
|
|
8580 * @description Handles the closing of the Image Properties Window.
|
|
8581 */
|
|
8582 _handleInsertImageWindowClose: function() {
|
|
8583 var url = Dom.get(this.get('id') + '_insertimage_url'),
|
|
8584 title = Dom.get(this.get('id') + '_insertimage_title'),
|
|
8585 link = Dom.get(this.get('id') + '_insertimage_link'),
|
|
8586 target = Dom.get(this.get('id') + '_insertimage_target'),
|
|
8587 el = arguments[0].win.el;
|
|
8588
|
|
8589 if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
|
|
8590 el.setAttribute('src', url.value);
|
|
8591 el.setAttribute('title', title.value);
|
|
8592 el.setAttribute('alt', title.value);
|
|
8593 var par = el.parentNode;
|
|
8594 if (link.value) {
|
|
8595 var urlValue = link.value;
|
|
8596 if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8597 if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8598 //Found an @ sign, prefix with mailto:
|
|
8599 urlValue = 'mailto:' + urlValue;
|
|
8600 } else {
|
|
8601 // :// not found adding
|
|
8602 urlValue = 'http:/'+'/' + urlValue;
|
|
8603 }
|
|
8604 }
|
|
8605 if (par && this._isElement(par, 'a')) {
|
|
8606 par.setAttribute('href', urlValue);
|
|
8607 if (target.checked) {
|
|
8608 par.setAttribute('target', target.value);
|
|
8609 } else {
|
|
8610 par.setAttribute('target', '');
|
|
8611 }
|
|
8612 } else {
|
|
8613 var _a = this._getDoc().createElement('a');
|
|
8614 _a.setAttribute('href', urlValue);
|
|
8615 if (target.checked) {
|
|
8616 _a.setAttribute('target', target.value);
|
|
8617 } else {
|
|
8618 _a.setAttribute('target', '');
|
|
8619 }
|
|
8620 el.parentNode.replaceChild(_a, el);
|
|
8621 _a.appendChild(el);
|
|
8622 }
|
|
8623 } else {
|
|
8624 if (par && this._isElement(par, 'a')) {
|
|
8625 par.parentNode.replaceChild(el, par);
|
|
8626 }
|
|
8627 }
|
|
8628 } else {
|
|
8629 //No url/src given, remove the node from the document
|
|
8630 el.parentNode.removeChild(el);
|
|
8631 }
|
|
8632 Dom.get(this.get('id') + '_insertimage_url').value = '';
|
|
8633 Dom.get(this.get('id') + '_insertimage_title').value = '';
|
|
8634 Dom.get(this.get('id') + '_insertimage_link').value = '';
|
|
8635 Dom.get(this.get('id') + '_insertimage_target').checked = false;
|
|
8636 Dom.get(this.get('id') + '_insertimage_width').value = 0;
|
|
8637 Dom.get(this.get('id') + '_insertimage_height').value = 0;
|
|
8638 this._defaultImageToolbar.resetAllButtons();
|
|
8639 this.currentElement = [];
|
|
8640 this.nodeChange();
|
|
8641 },
|
|
8642 /**
|
|
8643 * @property EDITOR_PANEL_ID
|
|
8644 * @description HTML id to give the properties window in the DOM.
|
|
8645 * @type String
|
|
8646 */
|
|
8647 EDITOR_PANEL_ID: '-panel',
|
|
8648 /**
|
|
8649 * @private
|
|
8650 * @method _renderPanel
|
|
8651 * @description Renders the panel used for Editor Windows to the document so we can start using it..
|
|
8652 * @return {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>}
|
|
8653 */
|
|
8654 _renderPanel: function() {
|
|
8655 var panelEl = document.createElement('div');
|
|
8656 Dom.addClass(panelEl, 'yui-editor-panel');
|
|
8657 panelEl.id = this.get('id') + this.EDITOR_PANEL_ID;
|
|
8658 panelEl.style.position = 'absolute';
|
|
8659 panelEl.style.top = '-9999px';
|
|
8660 panelEl.style.left = '-9999px';
|
|
8661 document.body.appendChild(panelEl);
|
|
8662 this.get('element_cont').insertBefore(panelEl, this.get('element_cont').get('firstChild'));
|
|
8663
|
|
8664
|
|
8665
|
|
8666 var panel = new YAHOO.widget.Overlay(this.get('id') + this.EDITOR_PANEL_ID, {
|
|
8667 width: '300px',
|
|
8668 iframe: true,
|
|
8669 visible: false,
|
|
8670 underlay: 'none',
|
|
8671 draggable: false,
|
|
8672 close: false
|
|
8673 });
|
|
8674 this.set('panel', panel);
|
|
8675
|
|
8676 panel.setBody('---');
|
|
8677 panel.setHeader(' ');
|
|
8678 panel.setFooter(' ');
|
|
8679
|
|
8680
|
|
8681 var body = document.createElement('div');
|
|
8682 body.className = this.CLASS_PREFIX + '-body-cont';
|
|
8683 for (var b in this.browser) {
|
|
8684 if (this.browser[b]) {
|
|
8685 Dom.addClass(body, b);
|
|
8686 break;
|
|
8687 }
|
|
8688 }
|
|
8689 Dom.addClass(body, ((YAHOO.widget.Button && (this._defaultToolbar.buttonType == 'advanced')) ? 'good-button' : 'no-button'));
|
|
8690
|
|
8691 var _note = document.createElement('h3');
|
|
8692 _note.className = 'yui-editor-skipheader';
|
|
8693 _note.innerHTML = this.STR_CLOSE_WINDOW_NOTE;
|
|
8694 body.appendChild(_note);
|
|
8695 var form = document.createElement('fieldset');
|
|
8696 panel.editor_form = form;
|
|
8697
|
|
8698 body.appendChild(form);
|
|
8699 var _close = document.createElement('span');
|
|
8700 _close.innerHTML = 'X';
|
|
8701 _close.title = this.STR_CLOSE_WINDOW;
|
|
8702 _close.className = 'close';
|
|
8703
|
|
8704 Event.on(_close, 'click', this.closeWindow, this, true);
|
|
8705
|
|
8706 var _knob = document.createElement('span');
|
|
8707 _knob.innerHTML = '^';
|
|
8708 _knob.className = 'knob';
|
|
8709 panel.editor_knob = _knob;
|
|
8710
|
|
8711 var _header = document.createElement('h3');
|
|
8712 panel.editor_header = _header;
|
|
8713 _header.innerHTML = '<span></span>';
|
|
8714
|
|
8715 panel.setHeader(' '); //Clear the current header
|
|
8716 panel.appendToHeader(_header);
|
|
8717 _header.appendChild(_close);
|
|
8718 _header.appendChild(_knob);
|
|
8719 panel.setBody(' '); //Clear the current body
|
|
8720 panel.setFooter(' '); //Clear the current footer
|
|
8721 panel.appendToBody(body); //Append the new DOM node to it
|
|
8722
|
|
8723 Event.on(panel.element, 'click', function(ev) {
|
|
8724 Event.stopPropagation(ev);
|
|
8725 });
|
|
8726
|
|
8727 var fireShowEvent = function() {
|
|
8728 panel.bringToTop();
|
|
8729 YAHOO.util.Dom.setStyle(this.element, 'display', 'block');
|
|
8730 this._handleWindowInputs(false);
|
|
8731 };
|
|
8732 panel.showEvent.subscribe(fireShowEvent, this, true);
|
|
8733 panel.hideEvent.subscribe(function() {
|
|
8734 this._handleWindowInputs(true);
|
|
8735 }, this, true);
|
|
8736 panel.renderEvent.subscribe(function() {
|
|
8737 this._renderInsertImageWindow();
|
|
8738 this._renderCreateLinkWindow();
|
|
8739 this.fireEvent('windowRender', { type: 'windowRender', panel: panel });
|
|
8740 this._handleWindowInputs(true);
|
|
8741 }, this, true);
|
|
8742
|
|
8743 if (this.DOMReady) {
|
|
8744 this.get('panel').render();
|
|
8745 } else {
|
|
8746 Event.onDOMReady(function() {
|
|
8747 this.get('panel').render();
|
|
8748 }, this, true);
|
|
8749 }
|
|
8750 return this.get('panel');
|
|
8751 },
|
|
8752 /**
|
|
8753 * @method _handleWindowInputs
|
|
8754 * @param {Boolean} disable The state to set all inputs in all Editor windows to. Defaults to: false.
|
|
8755 * @description Disables/Enables all fields inside Editor windows. Used in show/hide events to keep window fields from submitting when the parent form is submitted.
|
|
8756 */
|
|
8757 _handleWindowInputs: function(disable) {
|
|
8758 if (!Lang.isBoolean(disable)) {
|
|
8759 disable = false;
|
|
8760 }
|
|
8761 var inputs = this.get('panel').element.getElementsByTagName('input');
|
|
8762 for (var i = 0; i < inputs.length; i++) {
|
|
8763 try {
|
|
8764 inputs[i].disabled = disable;
|
|
8765 } catch (e) {}
|
|
8766 }
|
|
8767 },
|
|
8768 /**
|
|
8769 * @method openWindow
|
|
8770 * @param {<a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>} win A <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a> instance
|
|
8771 * @description Opens a new "window/panel"
|
|
8772 */
|
|
8773 openWindow: function(win) {
|
|
8774
|
|
8775 var self = this;
|
|
8776 window.setTimeout(function() {
|
|
8777 self.toolbar.set('disabled', true); //Disable the toolbar when an editor window is open..
|
|
8778 }, 10);
|
|
8779 Event.on(document, 'keydown', this._closeWindow, this, true);
|
|
8780
|
|
8781 if (this.currentWindow) {
|
|
8782 this.closeWindow();
|
|
8783 }
|
|
8784
|
|
8785 var xy = Dom.getXY(this.currentElement[0]),
|
|
8786 elXY = Dom.getXY(this.get('iframe').get('element')),
|
|
8787 panel = this.get('panel'),
|
|
8788 newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
|
|
8789 wWidth = (parseInt(win.attrs.width, 10) / 2),
|
|
8790 align = 'center',
|
|
8791 body = null;
|
|
8792
|
|
8793 this.fireEvent('beforeOpenWindow', { type: 'beforeOpenWindow', win: win, panel: panel });
|
|
8794
|
|
8795 var form = panel.editor_form;
|
|
8796
|
|
8797 var wins = this._windows;
|
|
8798 for (var b in wins) {
|
|
8799 if (Lang.hasOwnProperty(wins, b)) {
|
|
8800 if (wins[b] && wins[b].body) {
|
|
8801 if (b == win.name) {
|
|
8802 Dom.setStyle(wins[b].body, 'display', 'block');
|
|
8803 } else {
|
|
8804 Dom.setStyle(wins[b].body, 'display', 'none');
|
|
8805 }
|
|
8806 }
|
|
8807 }
|
|
8808 }
|
|
8809
|
|
8810 if (this._windows[win.name].body) {
|
|
8811 Dom.setStyle(this._windows[win.name].body, 'display', 'block');
|
|
8812 form.appendChild(this._windows[win.name].body);
|
|
8813 } else {
|
|
8814 if (Lang.isObject(win.body)) { //Assume it's a reference
|
|
8815 form.appendChild(win.body);
|
|
8816 } else { //Assume it's a string
|
|
8817 var _tmp = document.createElement('div');
|
|
8818 _tmp.innerHTML = win.body;
|
|
8819 form.appendChild(_tmp);
|
|
8820 }
|
|
8821 }
|
|
8822 panel.editor_header.firstChild.innerHTML = win.header;
|
|
8823 if (win.footer !== null) {
|
|
8824 panel.setFooter(win.footer);
|
|
8825 }
|
|
8826 panel.cfg.setProperty('width', win.attrs.width);
|
|
8827
|
|
8828 this.currentWindow = win;
|
|
8829 this.moveWindow(true);
|
|
8830 panel.show();
|
|
8831 this.fireEvent('afterOpenWindow', { type: 'afterOpenWindow', win: win, panel: panel });
|
|
8832 },
|
|
8833 /**
|
|
8834 * @method moveWindow
|
|
8835 * @param {Boolean} force Boolean to tell it to move but not use any animation (Usually done the first time the window is loaded.)
|
|
8836 * @description Realign the window with the currentElement and reposition the knob above the panel.
|
|
8837 */
|
|
8838 moveWindow: function(force) {
|
|
8839 if (!this.currentWindow) {
|
|
8840 return false;
|
|
8841 }
|
|
8842 var win = this.currentWindow,
|
|
8843 xy = Dom.getXY(this.currentElement[0]),
|
|
8844 elXY = Dom.getXY(this.get('iframe').get('element')),
|
|
8845 panel = this.get('panel'),
|
|
8846 //newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
|
|
8847 newXY = [(xy[0] + elXY[0]), (xy[1] + elXY[1])],
|
|
8848 wWidth = (parseInt(win.attrs.width, 10) / 2),
|
|
8849 align = 'center',
|
|
8850 orgXY = panel.cfg.getProperty('xy') || [0,0],
|
|
8851 _knob = panel.editor_knob,
|
|
8852 xDiff = 0,
|
|
8853 yDiff = 0,
|
|
8854 anim = false;
|
|
8855
|
|
8856
|
|
8857 newXY[0] = ((newXY[0] - wWidth) + 20);
|
|
8858 //Account for the Scroll bars in a scrolled editor window.
|
|
8859 newXY[0] = newXY[0] - Dom.getDocumentScrollLeft(this._getDoc());
|
|
8860 newXY[1] = newXY[1] - Dom.getDocumentScrollTop(this._getDoc());
|
|
8861
|
|
8862 if (this._isElement(this.currentElement[0], 'img')) {
|
|
8863 if (this.currentElement[0].src.indexOf(this.get('blankimage')) != -1) {
|
|
8864 newXY[0] = (newXY[0] + (75 / 2)); //Placeholder size
|
|
8865 newXY[1] = (newXY[1] + 75); //Placeholder sizea
|
|
8866 } else {
|
|
8867 var w = parseInt(this.currentElement[0].width, 10);
|
|
8868 var h = parseInt(this.currentElement[0].height, 10);
|
|
8869 newXY[0] = (newXY[0] + (w / 2));
|
|
8870 newXY[1] = (newXY[1] + h);
|
|
8871 }
|
|
8872 newXY[1] = newXY[1] + 15;
|
|
8873 } else {
|
|
8874 var fs = Dom.getStyle(this.currentElement[0], 'fontSize');
|
|
8875 if (fs && fs.indexOf && fs.indexOf('px') != -1) {
|
|
8876 newXY[1] = newXY[1] + parseInt(Dom.getStyle(this.currentElement[0], 'fontSize'), 10) + 5;
|
|
8877 } else {
|
|
8878 newXY[1] = newXY[1] + 20;
|
|
8879 }
|
|
8880 }
|
|
8881 if (newXY[0] < elXY[0]) {
|
|
8882 newXY[0] = elXY[0] + 5;
|
|
8883 align = 'left';
|
|
8884 }
|
|
8885
|
|
8886 if ((newXY[0] + (wWidth * 2)) > (elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10))) {
|
|
8887 newXY[0] = ((elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10)) - (wWidth * 2) - 5);
|
|
8888 align = 'right';
|
|
8889 }
|
|
8890
|
|
8891 try {
|
|
8892 xDiff = (newXY[0] - orgXY[0]);
|
|
8893 yDiff = (newXY[1] - orgXY[1]);
|
|
8894 } catch (e) {}
|
|
8895
|
|
8896
|
|
8897 var iTop = elXY[1] + parseInt(this.get('height'), 10);
|
|
8898 var iLeft = elXY[0] + parseInt(this.get('width'), 10);
|
|
8899 if (newXY[1] > iTop) {
|
|
8900 newXY[1] = iTop;
|
|
8901 }
|
|
8902 if (newXY[0] > iLeft) {
|
|
8903 newXY[0] = (iLeft / 2);
|
|
8904 }
|
|
8905
|
|
8906 //Convert negative numbers to positive so we can get the difference in distance
|
|
8907 xDiff = ((xDiff < 0) ? (xDiff * -1) : xDiff);
|
|
8908 yDiff = ((yDiff < 0) ? (yDiff * -1) : yDiff);
|
|
8909
|
|
8910 if (((xDiff > 10) || (yDiff > 10)) || force) { //Only move the window if it's supposed to move more than 10px or force was passed (new window)
|
|
8911 var _knobLeft = 0,
|
|
8912 elW = 0;
|
|
8913
|
|
8914 if (this.currentElement[0].width) {
|
|
8915 elW = (parseInt(this.currentElement[0].width, 10) / 2);
|
|
8916 }
|
|
8917
|
|
8918 var leftOffset = xy[0] + elXY[0] + elW;
|
|
8919 _knobLeft = leftOffset - newXY[0];
|
|
8920 //Check to see if the knob will go off either side & reposition it
|
|
8921 if (_knobLeft > (parseInt(win.attrs.width, 10) - 1)) {
|
|
8922 _knobLeft = ((parseInt(win.attrs.width, 10) - 30) - 1);
|
|
8923 } else if (_knobLeft < 40) {
|
|
8924 _knobLeft = 1;
|
|
8925 }
|
|
8926 if (isNaN(_knobLeft)) {
|
|
8927 _knobLeft = 1;
|
|
8928 }
|
|
8929 if (force) {
|
|
8930 if (_knob) {
|
|
8931 _knob.style.left = _knobLeft + 'px';
|
|
8932 }
|
|
8933 //Removed Animation from a forced move..
|
|
8934 panel.cfg.setProperty('xy', newXY);
|
|
8935 } else {
|
|
8936 if (this.get('animate')) {
|
|
8937 anim = new YAHOO.util.Anim(panel.element, {}, 0.5, YAHOO.util.Easing.easeOut);
|
|
8938 anim.attributes = {
|
|
8939 top: {
|
|
8940 to: newXY[1]
|
|
8941 },
|
|
8942 left: {
|
|
8943 to: newXY[0]
|
|
8944 }
|
|
8945 };
|
|
8946 anim.onComplete.subscribe(function() {
|
|
8947 panel.cfg.setProperty('xy', newXY);
|
|
8948 });
|
|
8949 //We have to animate the iframe shim at the same time as the panel or we get scrollbar bleed ..
|
|
8950 var iframeAnim = new YAHOO.util.Anim(panel.iframe, anim.attributes, 0.5, YAHOO.util.Easing.easeOut);
|
|
8951
|
|
8952 var _knobAnim = new YAHOO.util.Anim(_knob, {
|
|
8953 left: {
|
|
8954 to: _knobLeft
|
|
8955 }
|
|
8956 }, 0.6, YAHOO.util.Easing.easeOut);
|
|
8957 anim.animate();
|
|
8958 iframeAnim.animate();
|
|
8959 _knobAnim.animate();
|
|
8960 } else {
|
|
8961 _knob.style.left = _knobLeft + 'px';
|
|
8962 panel.cfg.setProperty('xy', newXY);
|
|
8963 }
|
|
8964 }
|
|
8965 }
|
|
8966 },
|
|
8967 /**
|
|
8968 * @private
|
|
8969 * @method _closeWindow
|
|
8970 * @description Close the currently open EditorWindow with the Escape key.
|
|
8971 * @param {Event} ev The keypress Event that we are trapping
|
|
8972 */
|
|
8973 _closeWindow: function(ev) {
|
|
8974 //if ((ev.charCode == 87) && ev.shiftKey && ev.ctrlKey) {
|
|
8975 if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) {
|
|
8976 if (this.currentWindow) {
|
|
8977 this.closeWindow();
|
|
8978 }
|
|
8979 }
|
|
8980 },
|
|
8981 /**
|
|
8982 * @method closeWindow
|
|
8983 * @description Close the currently open EditorWindow.
|
|
8984 */
|
|
8985 closeWindow: function(keepOpen) {
|
|
8986 this.fireEvent('window' + this.currentWindow.name + 'Close', { type: 'window' + this.currentWindow.name + 'Close', win: this.currentWindow, el: this.currentElement[0] });
|
|
8987 this.fireEvent('closeWindow', { type: 'closeWindow', win: this.currentWindow });
|
|
8988 this.currentWindow = null;
|
|
8989 this.get('panel').hide();
|
|
8990 this.get('panel').cfg.setProperty('xy', [-900,-900]);
|
|
8991 this.get('panel').syncIframe(); //Needed to move the iframe with the hidden panel
|
|
8992 this.unsubscribeAll('afterExecCommand');
|
|
8993 this.toolbar.set('disabled', false); //enable the toolbar now that the window is closed
|
|
8994 this.toolbar.resetAllButtons();
|
|
8995 this.focus();
|
|
8996 Event.removeListener(document, 'keydown', this._closeWindow);
|
|
8997 },
|
|
8998
|
|
8999 /* {{{ Command Overrides - These commands are only over written when we are using the advanced version */
|
|
9000
|
|
9001 /**
|
|
9002 * @method cmd_undo
|
|
9003 * @description Pulls an item from the Undo stack and updates the Editor
|
|
9004 * @param value Value passed from the execCommand method
|
|
9005 */
|
|
9006 cmd_undo: function(value) {
|
|
9007 if (this._hasUndoLevel()) {
|
|
9008 var c_html = this.getEditorHTML(), html;
|
|
9009 if (!this._undoLevel) {
|
|
9010 this._undoLevel = this._undoCache.length;
|
|
9011 }
|
|
9012 this._undoLevel = (this._undoLevel - 1);
|
|
9013 if (this._undoCache[this._undoLevel]) {
|
|
9014 html = this._getUndo(this._undoLevel);
|
|
9015 if (html != c_html) {
|
|
9016 this.setEditorHTML(html);
|
|
9017 } else {
|
|
9018 this._undoLevel = (this._undoLevel - 1);
|
|
9019 html = this._getUndo(this._undoLevel);
|
|
9020 if (html != c_html) {
|
|
9021 this.setEditorHTML(html);
|
|
9022 }
|
|
9023 }
|
|
9024 } else {
|
|
9025 this._undoLevel = 0;
|
|
9026 this.toolbar.disableButton('undo');
|
|
9027 }
|
|
9028 }
|
|
9029 return [false];
|
|
9030 },
|
|
9031
|
|
9032 /**
|
|
9033 * @method cmd_redo
|
|
9034 * @description Pulls an item from the Undo stack and updates the Editor
|
|
9035 * @param value Value passed from the execCommand method
|
|
9036 */
|
|
9037 cmd_redo: function(value) {
|
|
9038 this._undoLevel = this._undoLevel + 1;
|
|
9039 if (this._undoLevel >= this._undoCache.length) {
|
|
9040 this._undoLevel = this._undoCache.length;
|
|
9041 }
|
|
9042 if (this._undoCache[this._undoLevel]) {
|
|
9043 var html = this._getUndo(this._undoLevel);
|
|
9044 this.setEditorHTML(html);
|
|
9045 } else {
|
|
9046 this.toolbar.disableButton('redo');
|
|
9047 }
|
|
9048 return [false];
|
|
9049 },
|
|
9050
|
|
9051 /**
|
|
9052 * @method cmd_heading
|
|
9053 * @param value Value passed from the execCommand method
|
|
9054 * @description This is an execCommand override method. It is called from execCommand when the execCommand('heading') is used.
|
|
9055 */
|
|
9056 cmd_heading: function(value) {
|
|
9057 var exec = true,
|
|
9058 el = null,
|
|
9059 action = 'heading',
|
|
9060 _sel = this._getSelection(),
|
|
9061 _selEl = this._getSelectedElement();
|
|
9062
|
|
9063 if (_selEl) {
|
|
9064 _sel = _selEl;
|
|
9065 }
|
|
9066
|
|
9067 if (this.browser.ie) {
|
|
9068 action = 'formatblock';
|
|
9069 }
|
|
9070 if (value == this.STR_NONE) {
|
|
9071 if ((_sel && _sel.tagName && (_sel.tagName.toLowerCase().substring(0,1) == 'h')) || (_sel && _sel.parentNode && _sel.parentNode.tagName && (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h'))) {
|
|
9072 if (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h') {
|
|
9073 _sel = _sel.parentNode;
|
|
9074 }
|
|
9075 if (this._isElement(_sel, 'html')) {
|
|
9076 return [false];
|
|
9077 }
|
|
9078 el = this._swapEl(_selEl, 'span', function(el) {
|
|
9079 el.className = 'yui-non';
|
|
9080 });
|
|
9081 this._selectNode(el);
|
|
9082 this.currentElement[0] = el;
|
|
9083 }
|
|
9084 exec = false;
|
|
9085 } else {
|
|
9086 if (this._isElement(_selEl, 'h1') || this._isElement(_selEl, 'h2') || this._isElement(_selEl, 'h3') || this._isElement(_selEl, 'h4') || this._isElement(_selEl, 'h5') || this._isElement(_selEl, 'h6')) {
|
|
9087 el = this._swapEl(_selEl, value);
|
|
9088 this._selectNode(el);
|
|
9089 this.currentElement[0] = el;
|
|
9090 } else {
|
|
9091 this._createCurrentElement(value);
|
|
9092 this._selectNode(this.currentElement[0]);
|
|
9093 }
|
|
9094 exec = false;
|
|
9095 }
|
|
9096 return [exec, action];
|
|
9097 },
|
|
9098 /**
|
|
9099 * @method cmd_hiddenelements
|
|
9100 * @param value Value passed from the execCommand method
|
|
9101 * @description This is an execCommand override method. It is called from execCommand when the execCommand('hiddenelements') is used.
|
|
9102 */
|
|
9103 cmd_hiddenelements: function(value) {
|
|
9104 if (this._showingHiddenElements) {
|
|
9105 //Don't auto highlight the hidden button
|
|
9106 this._lastButton = null;
|
|
9107 this._showingHiddenElements = false;
|
|
9108 this.toolbar.deselectButton('hiddenelements');
|
|
9109 Dom.removeClass(this._getDoc().body, this.CLASS_HIDDEN);
|
|
9110 } else {
|
|
9111 this._showingHiddenElements = true;
|
|
9112 Dom.addClass(this._getDoc().body, this.CLASS_HIDDEN);
|
|
9113 this.toolbar.selectButton('hiddenelements');
|
|
9114 }
|
|
9115 return [false];
|
|
9116 },
|
|
9117 /**
|
|
9118 * @method cmd_removeformat
|
|
9119 * @param value Value passed from the execCommand method
|
|
9120 * @description This is an execCommand override method. It is called from execCommand when the execCommand('removeformat') is used.
|
|
9121 */
|
|
9122 cmd_removeformat: function(value) {
|
|
9123 var exec = true;
|
|
9124 /*
|
|
9125 * @knownissue Remove Format issue
|
|
9126 * @browser Safari 2.x
|
|
9127 * @description There is an issue here with Safari, that it may not always remove the format of the item that is selected.
|
|
9128 * Due to the way that Safari 2.x handles ranges, it is very difficult to determine what the selection holds.
|
|
9129 * So here we are making the best possible guess and acting on it.
|
|
9130 */
|
|
9131 if (this.browser.webkit && !this._getDoc().queryCommandEnabled('removeformat')) {
|
|
9132 var _txt = this._getSelection()+'';
|
|
9133 this._createCurrentElement('span');
|
|
9134 this.currentElement[0].className = 'yui-non';
|
|
9135 this.currentElement[0].innerHTML = _txt;
|
|
9136 for (var i = 1; i < this.currentElement.length; i++) {
|
|
9137 this.currentElement[i].parentNode.removeChild(this.currentElement[i]);
|
|
9138 }
|
|
9139
|
|
9140 exec = false;
|
|
9141 }
|
|
9142 return [exec];
|
|
9143 },
|
|
9144 /**
|
|
9145 * @method cmd_script
|
|
9146 * @param action action passed from the execCommand method
|
|
9147 * @param value Value passed from the execCommand method
|
|
9148 * @description This is a combined execCommand override method. It is called from the cmd_superscript and cmd_subscript methods.
|
|
9149 */
|
|
9150 cmd_script: function(action, value) {
|
|
9151 var exec = true, tag = action.toLowerCase().substring(0, 3),
|
|
9152 _span = null, _selEl = this._getSelectedElement();
|
|
9153
|
|
9154 if (this.browser.webkit) {
|
|
9155 if (this._isElement(_selEl, tag)) {
|
|
9156 _span = this._swapEl(this.currentElement[0], 'span', function(el) {
|
|
9157 el.className = 'yui-non';
|
|
9158 });
|
|
9159 this._selectNode(_span);
|
|
9160 } else {
|
|
9161 this._createCurrentElement(tag);
|
|
9162 var _sub = this._swapEl(this.currentElement[0], tag);
|
|
9163 this._selectNode(_sub);
|
|
9164 this.currentElement[0] = _sub;
|
|
9165 }
|
|
9166 exec = false;
|
|
9167 }
|
|
9168 return exec;
|
|
9169 },
|
|
9170 /**
|
|
9171 * @method cmd_superscript
|
|
9172 * @param value Value passed from the execCommand method
|
|
9173 * @description This is an execCommand override method. It is called from execCommand when the execCommand('superscript') is used.
|
|
9174 */
|
|
9175 cmd_superscript: function(value) {
|
|
9176 return [this.cmd_script('superscript', value)];
|
|
9177 },
|
|
9178 /**
|
|
9179 * @method cmd_subscript
|
|
9180 * @param value Value passed from the execCommand method
|
|
9181 * @description This is an execCommand override method. It is called from execCommand when the execCommand('subscript') is used.
|
|
9182 */
|
|
9183 cmd_subscript: function(value) {
|
|
9184 return [this.cmd_script('subscript', value)];
|
|
9185 },
|
|
9186 /**
|
|
9187 * @method cmd_indent
|
|
9188 * @param value Value passed from the execCommand method
|
|
9189 * @description This is an execCommand override method. It is called from execCommand when the execCommand('indent') is used.
|
|
9190 */
|
|
9191 cmd_indent: function(value) {
|
|
9192 var exec = true, selEl = this._getSelectedElement(), _bq = null;
|
|
9193
|
|
9194 //if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
|
|
9195 //if (this.browser.webkit || this.browser.ie) {
|
|
9196 if (this.browser.ie) {
|
|
9197 if (this._isElement(selEl, 'blockquote')) {
|
|
9198 _bq = this._getDoc().createElement('blockquote');
|
|
9199 _bq.innerHTML = selEl.innerHTML;
|
|
9200 selEl.innerHTML = '';
|
|
9201 selEl.appendChild(_bq);
|
|
9202 this._selectNode(_bq);
|
|
9203 } else {
|
|
9204 _bq = this._getDoc().createElement('blockquote');
|
|
9205 var html = this._getRange().htmlText;
|
|
9206 _bq.innerHTML = html;
|
|
9207 this._createCurrentElement('blockquote');
|
|
9208 /*
|
|
9209 for (var i = 0; i < this.currentElement.length; i++) {
|
|
9210 _bq = this._getDoc().createElement('blockquote');
|
|
9211 _bq.innerHTML = this.currentElement[i].innerHTML;
|
|
9212 this.currentElement[i].parentNode.replaceChild(_bq, this.currentElement[i]);
|
|
9213 this.currentElement[i] = _bq;
|
|
9214 }
|
|
9215 */
|
|
9216 this.currentElement[0].parentNode.replaceChild(_bq, this.currentElement[0]);
|
|
9217 this.currentElement[0] = _bq;
|
|
9218 this._selectNode(this.currentElement[0]);
|
|
9219 }
|
|
9220 exec = false;
|
|
9221 } else {
|
|
9222 value = 'blockquote';
|
|
9223 }
|
|
9224 return [exec, 'formatblock', value];
|
|
9225 },
|
|
9226 /**
|
|
9227 * @method cmd_outdent
|
|
9228 * @param value Value passed from the execCommand method
|
|
9229 * @description This is an execCommand override method. It is called from execCommand when the execCommand('outdent') is used.
|
|
9230 */
|
|
9231 cmd_outdent: function(value) {
|
|
9232 var exec = true, selEl = this._getSelectedElement(), _bq = null, _span = null;
|
|
9233 //if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
|
|
9234 if (this.browser.webkit || this.browser.ie) {
|
|
9235 //if (this.browser.ie) {
|
|
9236 selEl = this._getSelectedElement();
|
|
9237 if (this._isElement(selEl, 'blockquote')) {
|
|
9238 var par = selEl.parentNode;
|
|
9239 if (this._isElement(selEl.parentNode, 'blockquote')) {
|
|
9240 par.innerHTML = selEl.innerHTML;
|
|
9241 this._selectNode(par);
|
|
9242 } else {
|
|
9243 _span = this._getDoc().createElement('span');
|
|
9244 _span.innerHTML = selEl.innerHTML;
|
|
9245 YAHOO.util.Dom.addClass(_span, 'yui-non');
|
|
9246 par.replaceChild(_span, selEl);
|
|
9247 this._selectNode(_span);
|
|
9248 }
|
|
9249 } else {
|
|
9250 }
|
|
9251 exec = false;
|
|
9252 } else {
|
|
9253 value = false;
|
|
9254 }
|
|
9255 return [exec, 'outdent', value];
|
|
9256 },
|
|
9257 /**
|
|
9258 * @method cmd_justify
|
|
9259 * @param dir The direction to justify
|
|
9260 * @description This is a factory method for the justify family of commands.
|
|
9261 */
|
|
9262 cmd_justify: function(dir) {
|
|
9263 if (this.browser.ie) {
|
|
9264 if (this._hasSelection()) {
|
|
9265 this._createCurrentElement('span');
|
|
9266 this._swapEl(this.currentElement[0], 'div', function(el) {
|
|
9267 el.style.textAlign = dir;
|
|
9268 });
|
|
9269
|
|
9270 return [false];
|
|
9271 }
|
|
9272 }
|
|
9273 return [true, 'justify' + dir, ''];
|
|
9274 },
|
|
9275 /**
|
|
9276 * @method cmd_justifycenter
|
|
9277 * @param value Value passed from the execCommand method
|
|
9278 * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifycenter') is used.
|
|
9279 */
|
|
9280 cmd_justifycenter: function() {
|
|
9281 return [this.cmd_justify('center')];
|
|
9282 },
|
|
9283 /**
|
|
9284 * @method cmd_justifyleft
|
|
9285 * @param value Value passed from the execCommand method
|
|
9286 * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyleft') is used.
|
|
9287 */
|
|
9288 cmd_justifyleft: function() {
|
|
9289 return [this.cmd_justify('left')];
|
|
9290 },
|
|
9291 /**
|
|
9292 * @method cmd_justifyright
|
|
9293 * @param value Value passed from the execCommand method
|
|
9294 * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyright') is used.
|
|
9295 */
|
|
9296 cmd_justifyright: function() {
|
|
9297 return [this.cmd_justify('right')];
|
|
9298 },
|
|
9299 /* }}}*/
|
|
9300 /**
|
|
9301 * @method toString
|
|
9302 * @description Returns a string representing the editor.
|
|
9303 * @return {String}
|
|
9304 */
|
|
9305 toString: function() {
|
|
9306 var str = 'Editor';
|
|
9307 if (this.get && this.get('element_cont')) {
|
|
9308 str = 'Editor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
|
|
9309 }
|
|
9310 return str;
|
|
9311 }
|
|
9312 });
|
|
9313 /**
|
|
9314 * @event beforeOpenWindow
|
|
9315 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9316 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9317 * @description Event fires before an Editor Window is opened. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
9318 * @type YAHOO.util.CustomEvent
|
|
9319 */
|
|
9320 /**
|
|
9321 * @event afterOpenWindow
|
|
9322 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9323 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9324 * @description Event fires after an Editor Window is opened. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
9325 * @type YAHOO.util.CustomEvent
|
|
9326 */
|
|
9327 /**
|
|
9328 * @event closeWindow
|
|
9329 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9330 * @description Event fires after an Editor Window is closed. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
9331 * @type YAHOO.util.CustomEvent
|
|
9332 */
|
|
9333 /**
|
|
9334 * @event windowCMDOpen
|
|
9335 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9336 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9337 * @description Dynamic event fired when an <a href="YAHOO.widget.EditorWindow.html">EditorWindow</a> is opened.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkOpen event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
9338 * @type YAHOO.util.CustomEvent
|
|
9339 */
|
|
9340 /**
|
|
9341 * @event windowCMDClose
|
|
9342 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9343 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9344 * @description Dynamic event fired when an <a href="YAHOO.widget.EditorWindow.html">EditorWindow</a> is closed.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkClose event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
9345 * @type YAHOO.util.CustomEvent
|
|
9346 */
|
|
9347 /**
|
|
9348 * @event windowRender
|
|
9349 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9350 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9351 * @description Event fired when the initial Overlay is rendered. Can be used to manipulate the content of the panel.
|
|
9352 * @type YAHOO.util.CustomEvent
|
|
9353 */
|
|
9354 /**
|
|
9355 * @event windowInsertImageRender
|
|
9356 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9357 * @param {HTMLElement} body The HTML element used as the body of the window..
|
|
9358 * @param {Toolbar} toolbar A reference to the toolbar object used inside this window.
|
|
9359 * @description Event fired when the pre render of the Insert Image window has finished.
|
|
9360 * @type YAHOO.util.CustomEvent
|
|
9361 */
|
|
9362 /**
|
|
9363 * @event windowCreateLinkRender
|
|
9364 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9365 * @param {HTMLElement} body The HTML element used as the body of the window..
|
|
9366 * @description Event fired when the pre render of the Create Link window has finished.
|
|
9367 * @type YAHOO.util.CustomEvent
|
|
9368 */
|
|
9369
|
|
9370
|
|
9371
|
|
9372 /**
|
|
9373 * @description Class to hold Window information between uses. We use the same panel to show the windows, so using this will allow you to configure a window before it is shown.
|
|
9374 * This is what you pass to Editor.openWindow();. These parameters will not take effect until the openWindow() is called in the editor.
|
|
9375 * @class EditorWindow
|
|
9376 * @param {String} name The name of the window.
|
|
9377 * @param {Object} attrs Attributes for the window. Current attributes used are : height and width
|
|
9378 */
|
|
9379 YAHOO.widget.EditorWindow = function(name, attrs) {
|
|
9380 /**
|
|
9381 * @private
|
|
9382 * @property name
|
|
9383 * @description A unique name for the window
|
|
9384 */
|
|
9385 this.name = name.replace(' ', '_');
|
|
9386 /**
|
|
9387 * @private
|
|
9388 * @property attrs
|
|
9389 * @description The window attributes
|
|
9390 */
|
|
9391 this.attrs = attrs;
|
|
9392 };
|
|
9393
|
|
9394 YAHOO.widget.EditorWindow.prototype = {
|
|
9395 /**
|
|
9396 * @private
|
|
9397 * @property header
|
|
9398 * @description Holder for the header of the window, used in Editor.openWindow
|
|
9399 */
|
|
9400 header: null,
|
|
9401 /**
|
|
9402 * @private
|
|
9403 * @property body
|
|
9404 * @description Holder for the body of the window, used in Editor.openWindow
|
|
9405 */
|
|
9406 body: null,
|
|
9407 /**
|
|
9408 * @private
|
|
9409 * @property footer
|
|
9410 * @description Holder for the footer of the window, used in Editor.openWindow
|
|
9411 */
|
|
9412 footer: null,
|
|
9413 /**
|
|
9414 * @method setHeader
|
|
9415 * @description Sets the header for the window.
|
|
9416 * @param {String/HTMLElement} str The string or DOM reference to be used as the windows header.
|
|
9417 */
|
|
9418 setHeader: function(str) {
|
|
9419 this.header = str;
|
|
9420 },
|
|
9421 /**
|
|
9422 * @method setBody
|
|
9423 * @description Sets the body for the window.
|
|
9424 * @param {String/HTMLElement} str The string or DOM reference to be used as the windows body.
|
|
9425 */
|
|
9426 setBody: function(str) {
|
|
9427 this.body = str;
|
|
9428 },
|
|
9429 /**
|
|
9430 * @method setFooter
|
|
9431 * @description Sets the footer for the window.
|
|
9432 * @param {String/HTMLElement} str The string or DOM reference to be used as the windows footer.
|
|
9433 */
|
|
9434 setFooter: function(str) {
|
|
9435 this.footer = str;
|
|
9436 },
|
|
9437 /**
|
|
9438 * @method toString
|
|
9439 * @description Returns a string representing the EditorWindow.
|
|
9440 * @return {String}
|
|
9441 */
|
|
9442 toString: function() {
|
|
9443 return 'Editor Window (' + this.name + ')';
|
|
9444 }
|
|
9445 };
|
|
9446 })();
|
|
9447 YAHOO.register("editor", YAHOO.widget.Editor, {version: "2.8.0r4", build: "2449"});
|