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 YAHOO.log('ToolbarButton Initalizing', 'info', 'ToolbarButton');
|
|
70 YAHOO.log(arguments.length + ' arguments passed to constructor', 'info', 'Toolbar');
|
|
71
|
|
72 if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
|
|
73 attrs = el;
|
|
74 }
|
|
75 var local_attrs = (attrs || {});
|
|
76
|
|
77 var oConfig = {
|
|
78 element: null,
|
|
79 attributes: local_attrs
|
|
80 };
|
|
81
|
|
82 if (!oConfig.attributes.type) {
|
|
83 oConfig.attributes.type = 'push';
|
|
84 }
|
|
85
|
|
86 oConfig.element = document.createElement('span');
|
|
87 oConfig.element.setAttribute('unselectable', 'on');
|
|
88 oConfig.element.className = 'yui-button yui-' + oConfig.attributes.type + '-button';
|
|
89 oConfig.element.innerHTML = '<span class="first-child"><a href="#">LABEL</a></span>';
|
|
90 oConfig.element.firstChild.firstChild.tabIndex = '-1';
|
|
91 oConfig.attributes.id = (oConfig.attributes.id || Dom.generateId());
|
|
92 oConfig.element.id = oConfig.attributes.id;
|
|
93
|
|
94 YAHOO.widget.ToolbarButton.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
|
|
95 };
|
|
96
|
|
97 YAHOO.extend(YAHOO.widget.ToolbarButton, YAHOO.util.Element, {
|
|
98 /**
|
|
99 * @property buttonType
|
|
100 * @private
|
|
101 * @description Tells if the Button is a Rich Button or a Simple Button
|
|
102 */
|
|
103 buttonType: 'normal',
|
|
104 /**
|
|
105 * @method _handleMouseOver
|
|
106 * @private
|
|
107 * @description Adds classes to the button elements on mouseover (hover)
|
|
108 */
|
|
109 _handleMouseOver: function() {
|
|
110 if (!this.get('disabled')) {
|
|
111 this.addClass('yui-button-hover');
|
|
112 this.addClass('yui-' + this.get('type') + '-button-hover');
|
|
113 }
|
|
114 },
|
|
115 /**
|
|
116 * @method _handleMouseOut
|
|
117 * @private
|
|
118 * @description Removes classes from the button elements on mouseout (hover)
|
|
119 */
|
|
120 _handleMouseOut: function() {
|
|
121 this.removeClass('yui-button-hover');
|
|
122 this.removeClass('yui-' + this.get('type') + '-button-hover');
|
|
123 },
|
|
124 /**
|
|
125 * @method checkValue
|
|
126 * @param {String} value The value of the option that we want to mark as selected
|
|
127 * @description Select an option by value
|
|
128 */
|
|
129 checkValue: function(value) {
|
|
130 if (this.get('type') == 'menu') {
|
|
131 var opts = this._button.options;
|
|
132 for (var i = 0; i < opts.length; i++) {
|
|
133 if (opts[i].value == value) {
|
|
134 opts.selectedIndex = i;
|
|
135 }
|
|
136 }
|
|
137 }
|
|
138 },
|
|
139 /**
|
|
140 * @method init
|
|
141 * @description The ToolbarButton class's initialization method
|
|
142 */
|
|
143 init: function(p_oElement, p_oAttributes) {
|
|
144 YAHOO.widget.ToolbarButton.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
145
|
|
146 this.on('mouseover', this._handleMouseOver, this, true);
|
|
147 this.on('mouseout', this._handleMouseOut, this, true);
|
|
148 this.on('click', function(ev) {
|
|
149 Event.stopEvent(ev);
|
|
150 return false;
|
|
151 }, this, true);
|
|
152 },
|
|
153 /**
|
|
154 * @method initAttributes
|
|
155 * @description Initializes all of the configuration attributes used to create
|
|
156 * the toolbar.
|
|
157 * @param {Object} attr Object literal specifying a set of
|
|
158 * configuration attributes used to create the toolbar.
|
|
159 */
|
|
160 initAttributes: function(attr) {
|
|
161 YAHOO.widget.ToolbarButton.superclass.initAttributes.call(this, attr);
|
|
162 /**
|
|
163 * @attribute value
|
|
164 * @description The value of the button
|
|
165 * @type String
|
|
166 */
|
|
167 this.setAttributeConfig('value', {
|
|
168 value: attr.value
|
|
169 });
|
|
170 /**
|
|
171 * @attribute menu
|
|
172 * @description The menu attribute, see YAHOO.widget.Button
|
|
173 * @type Object
|
|
174 */
|
|
175 this.setAttributeConfig('menu', {
|
|
176 value: attr.menu || false
|
|
177 });
|
|
178 /**
|
|
179 * @attribute type
|
|
180 * @description The type of button to create: push, menu, color, select, spin
|
|
181 * @type String
|
|
182 */
|
|
183 this.setAttributeConfig('type', {
|
|
184 value: attr.type,
|
|
185 writeOnce: true,
|
|
186 method: function(type) {
|
|
187 var el, opt;
|
|
188 if (!this._button) {
|
|
189 this._button = this.get('element').getElementsByTagName('a')[0];
|
|
190 }
|
|
191 switch (type) {
|
|
192 case 'select':
|
|
193 case 'menu':
|
|
194 el = document.createElement('select');
|
|
195 el.id = this.get('id');
|
|
196 var menu = this.get('menu');
|
|
197 for (var i = 0; i < menu.length; i++) {
|
|
198 opt = document.createElement('option');
|
|
199 opt.innerHTML = menu[i].text;
|
|
200 opt.value = menu[i].value;
|
|
201 if (menu[i].checked) {
|
|
202 opt.selected = true;
|
|
203 }
|
|
204 el.appendChild(opt);
|
|
205 }
|
|
206 this._button.parentNode.replaceChild(el, this._button);
|
|
207 Event.on(el, 'change', this._handleSelect, this, true);
|
|
208 this._button = el;
|
|
209 break;
|
|
210 }
|
|
211 }
|
|
212 });
|
|
213
|
|
214 /**
|
|
215 * @attribute disabled
|
|
216 * @description Set the button into a disabled state
|
|
217 * @type String
|
|
218 */
|
|
219 this.setAttributeConfig('disabled', {
|
|
220 value: attr.disabled || false,
|
|
221 method: function(disabled) {
|
|
222 if (disabled) {
|
|
223 this.addClass('yui-button-disabled');
|
|
224 this.addClass('yui-' + this.get('type') + '-button-disabled');
|
|
225 } else {
|
|
226 this.removeClass('yui-button-disabled');
|
|
227 this.removeClass('yui-' + this.get('type') + '-button-disabled');
|
|
228 }
|
|
229 if ((this.get('type') == 'menu') || (this.get('type') == 'select')) {
|
|
230 this._button.disabled = disabled;
|
|
231 }
|
|
232 }
|
|
233 });
|
|
234
|
|
235 /**
|
|
236 * @attribute label
|
|
237 * @description The text label for the button
|
|
238 * @type String
|
|
239 */
|
|
240 this.setAttributeConfig('label', {
|
|
241 value: attr.label,
|
|
242 method: function(label) {
|
|
243 if (!this._button) {
|
|
244 this._button = this.get('element').getElementsByTagName('a')[0];
|
|
245 }
|
|
246 if (this.get('type') == 'push') {
|
|
247 this._button.innerHTML = label;
|
|
248 }
|
|
249 }
|
|
250 });
|
|
251
|
|
252 /**
|
|
253 * @attribute title
|
|
254 * @description The title of the button
|
|
255 * @type String
|
|
256 */
|
|
257 this.setAttributeConfig('title', {
|
|
258 value: attr.title
|
|
259 });
|
|
260
|
|
261 /**
|
|
262 * @config container
|
|
263 * @description The container that the button is rendered to, handled by Toolbar
|
|
264 * @type String
|
|
265 */
|
|
266 this.setAttributeConfig('container', {
|
|
267 value: null,
|
|
268 writeOnce: true,
|
|
269 method: function(cont) {
|
|
270 this.appendTo(cont);
|
|
271 }
|
|
272 });
|
|
273
|
|
274 },
|
|
275 /**
|
|
276 * @private
|
|
277 * @method _handleSelect
|
|
278 * @description The event fired when a change event gets fired on a select element
|
|
279 * @param {Event} ev The change event.
|
|
280 */
|
|
281 _handleSelect: function(ev) {
|
|
282 var tar = Event.getTarget(ev);
|
|
283 var value = tar.options[tar.selectedIndex].value;
|
|
284 this.fireEvent('change', {type: 'change', value: value });
|
|
285 },
|
|
286 /**
|
|
287 * @method getMenu
|
|
288 * @description A stub function to mimic YAHOO.widget.Button's getMenu method
|
|
289 */
|
|
290 getMenu: function() {
|
|
291 return this.get('menu');
|
|
292 },
|
|
293 /**
|
|
294 * @method destroy
|
|
295 * @description Destroy the button
|
|
296 */
|
|
297 destroy: function() {
|
|
298 Event.purgeElement(this.get('element'), true);
|
|
299 this.get('element').parentNode.removeChild(this.get('element'));
|
|
300 //Brutal Object Destroy
|
|
301 for (var i in this) {
|
|
302 if (Lang.hasOwnProperty(this, i)) {
|
|
303 this[i] = null;
|
|
304 }
|
|
305 }
|
|
306 },
|
|
307 /**
|
|
308 * @method fireEvent
|
|
309 * @description Overridden fireEvent method to prevent DOM events from firing if the button is disabled.
|
|
310 */
|
|
311 fireEvent: function(p_sType, p_aArgs) {
|
|
312 // Disabled buttons should not respond to DOM events
|
|
313 if (this.DOM_EVENTS[p_sType] && this.get('disabled')) {
|
|
314 Event.stopEvent(p_aArgs);
|
|
315 return;
|
|
316 }
|
|
317
|
|
318 YAHOO.widget.ToolbarButton.superclass.fireEvent.call(this, p_sType, p_aArgs);
|
|
319 },
|
|
320 /**
|
|
321 * @method toString
|
|
322 * @description Returns a string representing the toolbar.
|
|
323 * @return {String}
|
|
324 */
|
|
325 toString: function() {
|
|
326 return 'ToolbarButton (' + this.get('id') + ')';
|
|
327 }
|
|
328
|
|
329 });
|
|
330 })();
|
|
331 /**
|
|
332 * @module editor
|
|
333 * @description <p>Creates a rich Toolbar widget based on Button. Primarily used with the Rich Text Editor</p>
|
|
334 * @namespace YAHOO.widget
|
|
335 * @requires yahoo, dom, element, event, toolbarbutton
|
|
336 * @optional container_core, dragdrop
|
|
337 */
|
|
338 (function() {
|
|
339 var Dom = YAHOO.util.Dom,
|
|
340 Event = YAHOO.util.Event,
|
|
341 Lang = YAHOO.lang;
|
|
342
|
|
343 var getButton = function(id) {
|
|
344 var button = id;
|
|
345 if (Lang.isString(id)) {
|
|
346 button = this.getButtonById(id);
|
|
347 }
|
|
348 if (Lang.isNumber(id)) {
|
|
349 button = this.getButtonByIndex(id);
|
|
350 }
|
|
351 if ((!(button instanceof YAHOO.widget.ToolbarButton)) && (!(button instanceof YAHOO.widget.ToolbarButtonAdvanced))) {
|
|
352 button = this.getButtonByValue(id);
|
|
353 }
|
|
354 if ((button instanceof YAHOO.widget.ToolbarButton) || (button instanceof YAHOO.widget.ToolbarButtonAdvanced)) {
|
|
355 return button;
|
|
356 }
|
|
357 return false;
|
|
358 };
|
|
359
|
|
360 /**
|
|
361 * Provides a rich toolbar widget based on the button and menu widgets
|
|
362 * @constructor
|
|
363 * @class Toolbar
|
|
364 * @extends YAHOO.util.Element
|
|
365 * @param {String/HTMLElement} el The element to turn into a toolbar.
|
|
366 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
367 */
|
|
368 YAHOO.widget.Toolbar = function(el, attrs) {
|
|
369 YAHOO.log('Toolbar Initalizing', 'info', 'Toolbar');
|
|
370 YAHOO.log(arguments.length + ' arguments passed to constructor', 'info', 'Toolbar');
|
|
371
|
|
372 if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
|
|
373 attrs = el;
|
|
374 }
|
|
375 var local_attrs = {};
|
|
376 if (attrs) {
|
|
377 Lang.augmentObject(local_attrs, attrs); //Break the config reference
|
|
378 }
|
|
379
|
|
380
|
|
381 var oConfig = {
|
|
382 element: null,
|
|
383 attributes: local_attrs
|
|
384 };
|
|
385
|
|
386
|
|
387 if (Lang.isString(el) && Dom.get(el)) {
|
|
388 oConfig.element = Dom.get(el);
|
|
389 } else if (Lang.isObject(el) && Dom.get(el) && Dom.get(el).nodeType) {
|
|
390 oConfig.element = Dom.get(el);
|
|
391 }
|
|
392
|
|
393
|
|
394 if (!oConfig.element) {
|
|
395 YAHOO.log('No element defined, creating toolbar container', 'warn', 'Toolbar');
|
|
396 oConfig.element = document.createElement('DIV');
|
|
397 oConfig.element.id = Dom.generateId();
|
|
398
|
|
399 if (local_attrs.container && Dom.get(local_attrs.container)) {
|
|
400 YAHOO.log('Container found in config appending to it (' + Dom.get(local_attrs.container).id + ')', 'info', 'Toolbar');
|
|
401 Dom.get(local_attrs.container).appendChild(oConfig.element);
|
|
402 }
|
|
403 }
|
|
404
|
|
405
|
|
406 if (!oConfig.element.id) {
|
|
407 oConfig.element.id = ((Lang.isString(el)) ? el : Dom.generateId());
|
|
408 YAHOO.log('No element ID defined for toolbar container, creating..', 'warn', 'Toolbar');
|
|
409 }
|
|
410 YAHOO.log('Initing toolbar with id: ' + oConfig.element.id, 'info', 'Toolbar');
|
|
411
|
|
412 var fs = document.createElement('fieldset');
|
|
413 var lg = document.createElement('legend');
|
|
414 lg.innerHTML = 'Toolbar';
|
|
415 fs.appendChild(lg);
|
|
416
|
|
417 var cont = document.createElement('DIV');
|
|
418 oConfig.attributes.cont = cont;
|
|
419 Dom.addClass(cont, 'yui-toolbar-subcont');
|
|
420 fs.appendChild(cont);
|
|
421 oConfig.element.appendChild(fs);
|
|
422
|
|
423 oConfig.element.tabIndex = -1;
|
|
424
|
|
425
|
|
426 oConfig.attributes.element = oConfig.element;
|
|
427 oConfig.attributes.id = oConfig.element.id;
|
|
428
|
|
429 this._configuredButtons = [];
|
|
430
|
|
431 YAHOO.widget.Toolbar.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
|
|
432
|
|
433 };
|
|
434
|
|
435 YAHOO.extend(YAHOO.widget.Toolbar, YAHOO.util.Element, {
|
|
436 /**
|
|
437 * @protected
|
|
438 * @property _configuredButtons
|
|
439 * @type Array
|
|
440 */
|
|
441 _configuredButtons: null,
|
|
442 /**
|
|
443 * @method _addMenuClasses
|
|
444 * @private
|
|
445 * @description This method is called from Menu's renderEvent to add a few more classes to the menu items
|
|
446 * @param {String} ev The event that fired.
|
|
447 * @param {Array} na Array of event information.
|
|
448 * @param {Object} o Button config object.
|
|
449 */
|
|
450 _addMenuClasses: function(ev, na, o) {
|
|
451 Dom.addClass(this.element, 'yui-toolbar-' + o.get('value') + '-menu');
|
|
452 if (Dom.hasClass(o._button.parentNode.parentNode, 'yui-toolbar-select')) {
|
|
453 Dom.addClass(this.element, 'yui-toolbar-select-menu');
|
|
454 }
|
|
455 var items = this.getItems();
|
|
456 for (var i = 0; i < items.length; i++) {
|
|
457 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()));
|
|
458 Dom.addClass(items[i].element, 'yui-toolbar-' + o.get('value') + '-' + ((items[i].value) ? items[i].value.replace(/ /g, '-') : items[i]._oText.nodeValue.replace(/ /g, '-')));
|
|
459 }
|
|
460 },
|
|
461 /**
|
|
462 * @property buttonType
|
|
463 * @description The default button to use
|
|
464 * @type Object
|
|
465 */
|
|
466 buttonType: YAHOO.widget.ToolbarButton,
|
|
467 /**
|
|
468 * @property dd
|
|
469 * @description The DragDrop instance associated with the Toolbar
|
|
470 * @type Object
|
|
471 */
|
|
472 dd: null,
|
|
473 /**
|
|
474 * @property _colorData
|
|
475 * @description Object reference containing colors hex and text values.
|
|
476 * @type Object
|
|
477 */
|
|
478 _colorData: {
|
|
479 /* {{{ _colorData */
|
|
480 '#111111': 'Obsidian',
|
|
481 '#2D2D2D': 'Dark Gray',
|
|
482 '#434343': 'Shale',
|
|
483 '#5B5B5B': 'Flint',
|
|
484 '#737373': 'Gray',
|
|
485 '#8B8B8B': 'Concrete',
|
|
486 '#A2A2A2': 'Gray',
|
|
487 '#B9B9B9': 'Titanium',
|
|
488 '#000000': 'Black',
|
|
489 '#D0D0D0': 'Light Gray',
|
|
490 '#E6E6E6': 'Silver',
|
|
491 '#FFFFFF': 'White',
|
|
492 '#BFBF00': 'Pumpkin',
|
|
493 '#FFFF00': 'Yellow',
|
|
494 '#FFFF40': 'Banana',
|
|
495 '#FFFF80': 'Pale Yellow',
|
|
496 '#FFFFBF': 'Butter',
|
|
497 '#525330': 'Raw Siena',
|
|
498 '#898A49': 'Mildew',
|
|
499 '#AEA945': 'Olive',
|
|
500 '#7F7F00': 'Paprika',
|
|
501 '#C3BE71': 'Earth',
|
|
502 '#E0DCAA': 'Khaki',
|
|
503 '#FCFAE1': 'Cream',
|
|
504 '#60BF00': 'Cactus',
|
|
505 '#80FF00': 'Chartreuse',
|
|
506 '#A0FF40': 'Green',
|
|
507 '#C0FF80': 'Pale Lime',
|
|
508 '#DFFFBF': 'Light Mint',
|
|
509 '#3B5738': 'Green',
|
|
510 '#668F5A': 'Lime Gray',
|
|
511 '#7F9757': 'Yellow',
|
|
512 '#407F00': 'Clover',
|
|
513 '#8A9B55': 'Pistachio',
|
|
514 '#B7C296': 'Light Jade',
|
|
515 '#E6EBD5': 'Breakwater',
|
|
516 '#00BF00': 'Spring Frost',
|
|
517 '#00FF80': 'Pastel Green',
|
|
518 '#40FFA0': 'Light Emerald',
|
|
519 '#80FFC0': 'Sea Foam',
|
|
520 '#BFFFDF': 'Sea Mist',
|
|
521 '#033D21': 'Dark Forrest',
|
|
522 '#438059': 'Moss',
|
|
523 '#7FA37C': 'Medium Green',
|
|
524 '#007F40': 'Pine',
|
|
525 '#8DAE94': 'Yellow Gray Green',
|
|
526 '#ACC6B5': 'Aqua Lung',
|
|
527 '#DDEBE2': 'Sea Vapor',
|
|
528 '#00BFBF': 'Fog',
|
|
529 '#00FFFF': 'Cyan',
|
|
530 '#40FFFF': 'Turquoise Blue',
|
|
531 '#80FFFF': 'Light Aqua',
|
|
532 '#BFFFFF': 'Pale Cyan',
|
|
533 '#033D3D': 'Dark Teal',
|
|
534 '#347D7E': 'Gray Turquoise',
|
|
535 '#609A9F': 'Green Blue',
|
|
536 '#007F7F': 'Seaweed',
|
|
537 '#96BDC4': 'Green Gray',
|
|
538 '#B5D1D7': 'Soapstone',
|
|
539 '#E2F1F4': 'Light Turquoise',
|
|
540 '#0060BF': 'Summer Sky',
|
|
541 '#0080FF': 'Sky Blue',
|
|
542 '#40A0FF': 'Electric Blue',
|
|
543 '#80C0FF': 'Light Azure',
|
|
544 '#BFDFFF': 'Ice Blue',
|
|
545 '#1B2C48': 'Navy',
|
|
546 '#385376': 'Biscay',
|
|
547 '#57708F': 'Dusty Blue',
|
|
548 '#00407F': 'Sea Blue',
|
|
549 '#7792AC': 'Sky Blue Gray',
|
|
550 '#A8BED1': 'Morning Sky',
|
|
551 '#DEEBF6': 'Vapor',
|
|
552 '#0000BF': 'Deep Blue',
|
|
553 '#0000FF': 'Blue',
|
|
554 '#4040FF': 'Cerulean Blue',
|
|
555 '#8080FF': 'Evening Blue',
|
|
556 '#BFBFFF': 'Light Blue',
|
|
557 '#212143': 'Deep Indigo',
|
|
558 '#373E68': 'Sea Blue',
|
|
559 '#444F75': 'Night Blue',
|
|
560 '#00007F': 'Indigo Blue',
|
|
561 '#585E82': 'Dockside',
|
|
562 '#8687A4': 'Blue Gray',
|
|
563 '#D2D1E1': 'Light Blue Gray',
|
|
564 '#6000BF': 'Neon Violet',
|
|
565 '#8000FF': 'Blue Violet',
|
|
566 '#A040FF': 'Violet Purple',
|
|
567 '#C080FF': 'Violet Dusk',
|
|
568 '#DFBFFF': 'Pale Lavender',
|
|
569 '#302449': 'Cool Shale',
|
|
570 '#54466F': 'Dark Indigo',
|
|
571 '#655A7F': 'Dark Violet',
|
|
572 '#40007F': 'Violet',
|
|
573 '#726284': 'Smoky Violet',
|
|
574 '#9E8FA9': 'Slate Gray',
|
|
575 '#DCD1DF': 'Violet White',
|
|
576 '#BF00BF': 'Royal Violet',
|
|
577 '#FF00FF': 'Fuchsia',
|
|
578 '#FF40FF': 'Magenta',
|
|
579 '#FF80FF': 'Orchid',
|
|
580 '#FFBFFF': 'Pale Magenta',
|
|
581 '#4A234A': 'Dark Purple',
|
|
582 '#794A72': 'Medium Purple',
|
|
583 '#936386': 'Cool Granite',
|
|
584 '#7F007F': 'Purple',
|
|
585 '#9D7292': 'Purple Moon',
|
|
586 '#C0A0B6': 'Pale Purple',
|
|
587 '#ECDAE5': 'Pink Cloud',
|
|
588 '#BF005F': 'Hot Pink',
|
|
589 '#FF007F': 'Deep Pink',
|
|
590 '#FF409F': 'Grape',
|
|
591 '#FF80BF': 'Electric Pink',
|
|
592 '#FFBFDF': 'Pink',
|
|
593 '#451528': 'Purple Red',
|
|
594 '#823857': 'Purple Dino',
|
|
595 '#A94A76': 'Purple Gray',
|
|
596 '#7F003F': 'Rose',
|
|
597 '#BC6F95': 'Antique Mauve',
|
|
598 '#D8A5BB': 'Cool Marble',
|
|
599 '#F7DDE9': 'Pink Granite',
|
|
600 '#C00000': 'Apple',
|
|
601 '#FF0000': 'Fire Truck',
|
|
602 '#FF4040': 'Pale Red',
|
|
603 '#FF8080': 'Salmon',
|
|
604 '#FFC0C0': 'Warm Pink',
|
|
605 '#441415': 'Sepia',
|
|
606 '#82393C': 'Rust',
|
|
607 '#AA4D4E': 'Brick',
|
|
608 '#800000': 'Brick Red',
|
|
609 '#BC6E6E': 'Mauve',
|
|
610 '#D8A3A4': 'Shrimp Pink',
|
|
611 '#F8DDDD': 'Shell Pink',
|
|
612 '#BF5F00': 'Dark Orange',
|
|
613 '#FF7F00': 'Orange',
|
|
614 '#FF9F40': 'Grapefruit',
|
|
615 '#FFBF80': 'Canteloupe',
|
|
616 '#FFDFBF': 'Wax',
|
|
617 '#482C1B': 'Dark Brick',
|
|
618 '#855A40': 'Dirt',
|
|
619 '#B27C51': 'Tan',
|
|
620 '#7F3F00': 'Nutmeg',
|
|
621 '#C49B71': 'Mustard',
|
|
622 '#E1C4A8': 'Pale Tan',
|
|
623 '#FDEEE0': 'Marble'
|
|
624 /* }}} */
|
|
625 },
|
|
626 /**
|
|
627 * @property _colorPicker
|
|
628 * @description The HTML Element containing the colorPicker
|
|
629 * @type HTMLElement
|
|
630 */
|
|
631 _colorPicker: null,
|
|
632 /**
|
|
633 * @property STR_COLLAPSE
|
|
634 * @description String for Toolbar Collapse Button
|
|
635 * @type String
|
|
636 */
|
|
637 STR_COLLAPSE: 'Collapse Toolbar',
|
|
638 /**
|
|
639 * @property STR_EXPAND
|
|
640 * @description String for Toolbar Collapse Button - Expand
|
|
641 * @type String
|
|
642 */
|
|
643 STR_EXPAND: 'Expand Toolbar',
|
|
644 /**
|
|
645 * @property STR_SPIN_LABEL
|
|
646 * @description String for spinbutton dynamic label. Note the {VALUE} will be replaced with YAHOO.lang.substitute
|
|
647 * @type String
|
|
648 */
|
|
649 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.',
|
|
650 /**
|
|
651 * @property STR_SPIN_UP
|
|
652 * @description String for spinbutton up
|
|
653 * @type String
|
|
654 */
|
|
655 STR_SPIN_UP: 'Click to increase the value of this input',
|
|
656 /**
|
|
657 * @property STR_SPIN_DOWN
|
|
658 * @description String for spinbutton down
|
|
659 * @type String
|
|
660 */
|
|
661 STR_SPIN_DOWN: 'Click to decrease the value of this input',
|
|
662 /**
|
|
663 * @property _titlebar
|
|
664 * @description Object reference to the titlebar
|
|
665 * @type HTMLElement
|
|
666 */
|
|
667 _titlebar: null,
|
|
668 /**
|
|
669 * @property browser
|
|
670 * @description Standard browser detection
|
|
671 * @type Object
|
|
672 */
|
|
673 browser: YAHOO.env.ua,
|
|
674 /**
|
|
675 * @protected
|
|
676 * @property _buttonList
|
|
677 * @description Internal property list of current buttons in the toolbar
|
|
678 * @type Array
|
|
679 */
|
|
680 _buttonList: null,
|
|
681 /**
|
|
682 * @protected
|
|
683 * @property _buttonGroupList
|
|
684 * @description Internal property list of current button groups in the toolbar
|
|
685 * @type Array
|
|
686 */
|
|
687 _buttonGroupList: null,
|
|
688 /**
|
|
689 * @protected
|
|
690 * @property _sep
|
|
691 * @description Internal reference to the separator HTML Element for cloning
|
|
692 * @type HTMLElement
|
|
693 */
|
|
694 _sep: null,
|
|
695 /**
|
|
696 * @protected
|
|
697 * @property _sepCount
|
|
698 * @description Internal refernce for counting separators, so we can give them a useful class name for styling
|
|
699 * @type Number
|
|
700 */
|
|
701 _sepCount: null,
|
|
702 /**
|
|
703 * @protected
|
|
704 * @property draghandle
|
|
705 * @type HTMLElement
|
|
706 */
|
|
707 _dragHandle: null,
|
|
708 /**
|
|
709 * @protected
|
|
710 * @property _toolbarConfigs
|
|
711 * @type Object
|
|
712 */
|
|
713 _toolbarConfigs: {
|
|
714 renderer: true
|
|
715 },
|
|
716 /**
|
|
717 * @protected
|
|
718 * @property CLASS_CONTAINER
|
|
719 * @description Default CSS class to apply to the toolbar container element
|
|
720 * @type String
|
|
721 */
|
|
722 CLASS_CONTAINER: 'yui-toolbar-container',
|
|
723 /**
|
|
724 * @protected
|
|
725 * @property CLASS_DRAGHANDLE
|
|
726 * @description Default CSS class to apply to the toolbar's drag handle element
|
|
727 * @type String
|
|
728 */
|
|
729 CLASS_DRAGHANDLE: 'yui-toolbar-draghandle',
|
|
730 /**
|
|
731 * @protected
|
|
732 * @property CLASS_SEPARATOR
|
|
733 * @description Default CSS class to apply to all separators in the toolbar
|
|
734 * @type String
|
|
735 */
|
|
736 CLASS_SEPARATOR: 'yui-toolbar-separator',
|
|
737 /**
|
|
738 * @protected
|
|
739 * @property CLASS_DISABLED
|
|
740 * @description Default CSS class to apply when the toolbar is disabled
|
|
741 * @type String
|
|
742 */
|
|
743 CLASS_DISABLED: 'yui-toolbar-disabled',
|
|
744 /**
|
|
745 * @protected
|
|
746 * @property CLASS_PREFIX
|
|
747 * @description Default prefix for dynamically created class names
|
|
748 * @type String
|
|
749 */
|
|
750 CLASS_PREFIX: 'yui-toolbar',
|
|
751 /**
|
|
752 * @method init
|
|
753 * @description The Toolbar class's initialization method
|
|
754 */
|
|
755 init: function(p_oElement, p_oAttributes) {
|
|
756 YAHOO.widget.Toolbar.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
757 },
|
|
758 /**
|
|
759 * @method initAttributes
|
|
760 * @description Initializes all of the configuration attributes used to create
|
|
761 * the toolbar.
|
|
762 * @param {Object} attr Object literal specifying a set of
|
|
763 * configuration attributes used to create the toolbar.
|
|
764 */
|
|
765 initAttributes: function(attr) {
|
|
766 YAHOO.widget.Toolbar.superclass.initAttributes.call(this, attr);
|
|
767 this.addClass(this.CLASS_CONTAINER);
|
|
768
|
|
769 /**
|
|
770 * @attribute buttonType
|
|
771 * @description The buttonType to use (advanced or basic)
|
|
772 * @type String
|
|
773 */
|
|
774 this.setAttributeConfig('buttonType', {
|
|
775 value: attr.buttonType || 'basic',
|
|
776 writeOnce: true,
|
|
777 validator: function(type) {
|
|
778 switch (type) {
|
|
779 case 'advanced':
|
|
780 case 'basic':
|
|
781 return true;
|
|
782 }
|
|
783 return false;
|
|
784 },
|
|
785 method: function(type) {
|
|
786 if (type == 'advanced') {
|
|
787 if (YAHOO.widget.Button) {
|
|
788 this.buttonType = YAHOO.widget.ToolbarButtonAdvanced;
|
|
789 } else {
|
|
790 YAHOO.log('Can not find YAHOO.widget.Button', 'error', 'Toolbar');
|
|
791 this.buttonType = YAHOO.widget.ToolbarButton;
|
|
792 }
|
|
793 } else {
|
|
794 this.buttonType = YAHOO.widget.ToolbarButton;
|
|
795 }
|
|
796 }
|
|
797 });
|
|
798
|
|
799
|
|
800 /**
|
|
801 * @attribute buttons
|
|
802 * @description Object specifying the buttons to include in the toolbar
|
|
803 * Example:
|
|
804 * <code><pre>
|
|
805 * {
|
|
806 * { id: 'b3', type: 'button', label: 'Underline', value: 'underline' },
|
|
807 * { type: 'separator' },
|
|
808 * { id: 'b4', type: 'menu', label: 'Align', value: 'align',
|
|
809 * menu: [
|
|
810 * { text: "Left", value: 'alignleft' },
|
|
811 * { text: "Center", value: 'aligncenter' },
|
|
812 * { text: "Right", value: 'alignright' }
|
|
813 * ]
|
|
814 * }
|
|
815 * }
|
|
816 * </pre></code>
|
|
817 * @type Array
|
|
818 */
|
|
819
|
|
820 this.setAttributeConfig('buttons', {
|
|
821 value: [],
|
|
822 writeOnce: true,
|
|
823 method: function(data) {
|
|
824 var i, button, buttons, len, b;
|
|
825 for (i in data) {
|
|
826 if (Lang.hasOwnProperty(data, i)) {
|
|
827 if (data[i].type == 'separator') {
|
|
828 this.addSeparator();
|
|
829 } else if (data[i].group !== undefined) {
|
|
830 buttons = this.addButtonGroup(data[i]);
|
|
831 if (buttons) {
|
|
832 len = buttons.length;
|
|
833 for(b = 0; b < len; b++) {
|
|
834 if (buttons[b]) {
|
|
835 this._configuredButtons[this._configuredButtons.length] = buttons[b].id;
|
|
836 }
|
|
837 }
|
|
838 }
|
|
839
|
|
840 } else {
|
|
841 button = this.addButton(data[i]);
|
|
842 if (button) {
|
|
843 this._configuredButtons[this._configuredButtons.length] = button.id;
|
|
844 }
|
|
845 }
|
|
846 }
|
|
847 }
|
|
848 }
|
|
849 });
|
|
850
|
|
851 /**
|
|
852 * @attribute disabled
|
|
853 * @description Boolean indicating if the toolbar should be disabled. It will also disable the draggable attribute if it is on.
|
|
854 * @default false
|
|
855 * @type Boolean
|
|
856 */
|
|
857 this.setAttributeConfig('disabled', {
|
|
858 value: false,
|
|
859 method: function(disabled) {
|
|
860 if (this.get('disabled') === disabled) {
|
|
861 return false;
|
|
862 }
|
|
863 if (disabled) {
|
|
864 this.addClass(this.CLASS_DISABLED);
|
|
865 this.set('draggable', false);
|
|
866 this.disableAllButtons();
|
|
867 } else {
|
|
868 this.removeClass(this.CLASS_DISABLED);
|
|
869 if (this._configs.draggable._initialConfig.value) {
|
|
870 //Draggable by default, set it back
|
|
871 this.set('draggable', true);
|
|
872 }
|
|
873 this.resetAllButtons();
|
|
874 }
|
|
875 }
|
|
876 });
|
|
877
|
|
878 /**
|
|
879 * @config cont
|
|
880 * @description The container for the toolbar.
|
|
881 * @type HTMLElement
|
|
882 */
|
|
883 this.setAttributeConfig('cont', {
|
|
884 value: attr.cont,
|
|
885 readOnly: true
|
|
886 });
|
|
887
|
|
888
|
|
889 /**
|
|
890 * @attribute grouplabels
|
|
891 * @description Boolean indicating if the toolbar should show the group label's text string.
|
|
892 * @default true
|
|
893 * @type Boolean
|
|
894 */
|
|
895 this.setAttributeConfig('grouplabels', {
|
|
896 value: ((attr.grouplabels === false) ? false : true),
|
|
897 method: function(grouplabels) {
|
|
898 if (grouplabels) {
|
|
899 Dom.removeClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
|
|
900 } else {
|
|
901 Dom.addClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
|
|
902 }
|
|
903 }
|
|
904 });
|
|
905 /**
|
|
906 * @attribute titlebar
|
|
907 * @description Boolean indicating if the toolbar should have a titlebar. If
|
|
908 * passed a string, it will use that as the titlebar text
|
|
909 * @default false
|
|
910 * @type Boolean or String
|
|
911 */
|
|
912 this.setAttributeConfig('titlebar', {
|
|
913 value: false,
|
|
914 method: function(titlebar) {
|
|
915 if (titlebar) {
|
|
916 if (this._titlebar && this._titlebar.parentNode) {
|
|
917 this._titlebar.parentNode.removeChild(this._titlebar);
|
|
918 }
|
|
919 this._titlebar = document.createElement('DIV');
|
|
920 this._titlebar.tabIndex = '-1';
|
|
921 Event.on(this._titlebar, 'focus', function() {
|
|
922 this._handleFocus();
|
|
923 }, this, true);
|
|
924 Dom.addClass(this._titlebar, this.CLASS_PREFIX + '-titlebar');
|
|
925 if (Lang.isString(titlebar)) {
|
|
926 var h2 = document.createElement('h2');
|
|
927 h2.tabIndex = '-1';
|
|
928 h2.innerHTML = '<a href="#" tabIndex="0">' + titlebar + '</a>';
|
|
929 this._titlebar.appendChild(h2);
|
|
930 Event.on(h2.firstChild, 'click', function(ev) {
|
|
931 Event.stopEvent(ev);
|
|
932 });
|
|
933 Event.on([h2, h2.firstChild], 'focus', function() {
|
|
934 this._handleFocus();
|
|
935 }, this, true);
|
|
936 }
|
|
937 if (this.get('firstChild')) {
|
|
938 this.insertBefore(this._titlebar, this.get('firstChild'));
|
|
939 } else {
|
|
940 this.appendChild(this._titlebar);
|
|
941 }
|
|
942 if (this.get('collapse')) {
|
|
943 this.set('collapse', true);
|
|
944 }
|
|
945 } else if (this._titlebar) {
|
|
946 if (this._titlebar && this._titlebar.parentNode) {
|
|
947 this._titlebar.parentNode.removeChild(this._titlebar);
|
|
948 }
|
|
949 }
|
|
950 }
|
|
951 });
|
|
952
|
|
953
|
|
954 /**
|
|
955 * @attribute collapse
|
|
956 * @description Boolean indicating if the the titlebar should have a collapse button.
|
|
957 * The collapse button will not remove the toolbar, it will minimize it to the titlebar
|
|
958 * @default false
|
|
959 * @type Boolean
|
|
960 */
|
|
961 this.setAttributeConfig('collapse', {
|
|
962 value: false,
|
|
963 method: function(collapse) {
|
|
964 if (this._titlebar) {
|
|
965 var collapseEl = null;
|
|
966 var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
|
|
967 if (collapse) {
|
|
968 if (el.length > 0) {
|
|
969 //There is already a collapse button
|
|
970 return true;
|
|
971 }
|
|
972 collapseEl = document.createElement('SPAN');
|
|
973 collapseEl.innerHTML = 'X';
|
|
974 collapseEl.title = this.STR_COLLAPSE;
|
|
975
|
|
976 Dom.addClass(collapseEl, 'collapse');
|
|
977 this._titlebar.appendChild(collapseEl);
|
|
978 Event.addListener(collapseEl, 'click', function() {
|
|
979 if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
|
|
980 this.collapse(false); //Expand Toolbar
|
|
981 } else {
|
|
982 this.collapse(); //Collapse Toolbar
|
|
983 }
|
|
984 }, this, true);
|
|
985 } else {
|
|
986 collapseEl = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
|
|
987 if (collapseEl[0]) {
|
|
988 if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
|
|
989 //We are closed, reopen the titlebar..
|
|
990 this.collapse(false); //Expand Toolbar
|
|
991 }
|
|
992 collapseEl[0].parentNode.removeChild(collapseEl[0]);
|
|
993 }
|
|
994 }
|
|
995 }
|
|
996 }
|
|
997 });
|
|
998
|
|
999 /**
|
|
1000 * @attribute draggable
|
|
1001 * @description Boolean indicating if the toolbar should be draggable.
|
|
1002 * @default false
|
|
1003 * @type Boolean
|
|
1004 */
|
|
1005
|
|
1006 this.setAttributeConfig('draggable', {
|
|
1007 value: (attr.draggable || false),
|
|
1008 method: function(draggable) {
|
|
1009 if (draggable && !this.get('titlebar')) {
|
|
1010 YAHOO.log('Dragging enabled', 'info', 'Toolbar');
|
|
1011 if (!this._dragHandle) {
|
|
1012 this._dragHandle = document.createElement('SPAN');
|
|
1013 this._dragHandle.innerHTML = '|';
|
|
1014 this._dragHandle.setAttribute('title', 'Click to drag the toolbar');
|
|
1015 this._dragHandle.id = this.get('id') + '_draghandle';
|
|
1016 Dom.addClass(this._dragHandle, this.CLASS_DRAGHANDLE);
|
|
1017 if (this.get('cont').hasChildNodes()) {
|
|
1018 this.get('cont').insertBefore(this._dragHandle, this.get('cont').firstChild);
|
|
1019 } else {
|
|
1020 this.get('cont').appendChild(this._dragHandle);
|
|
1021 }
|
|
1022 this.dd = new YAHOO.util.DD(this.get('id'));
|
|
1023 this.dd.setHandleElId(this._dragHandle.id);
|
|
1024
|
|
1025 }
|
|
1026 } else {
|
|
1027 YAHOO.log('Dragging disabled', 'info', 'Toolbar');
|
|
1028 if (this._dragHandle) {
|
|
1029 this._dragHandle.parentNode.removeChild(this._dragHandle);
|
|
1030 this._dragHandle = null;
|
|
1031 this.dd = null;
|
|
1032 }
|
|
1033 }
|
|
1034 if (this._titlebar) {
|
|
1035 if (draggable) {
|
|
1036 this.dd = new YAHOO.util.DD(this.get('id'));
|
|
1037 this.dd.setHandleElId(this._titlebar);
|
|
1038 Dom.addClass(this._titlebar, 'draggable');
|
|
1039 } else {
|
|
1040 Dom.removeClass(this._titlebar, 'draggable');
|
|
1041 if (this.dd) {
|
|
1042 this.dd.unreg();
|
|
1043 this.dd = null;
|
|
1044 }
|
|
1045 }
|
|
1046 }
|
|
1047 },
|
|
1048 validator: function(value) {
|
|
1049 var ret = true;
|
|
1050 if (!YAHOO.util.DD) {
|
|
1051 ret = false;
|
|
1052 }
|
|
1053 return ret;
|
|
1054 }
|
|
1055 });
|
|
1056
|
|
1057 },
|
|
1058 /**
|
|
1059 * @method addButtonGroup
|
|
1060 * @description Add a new button group to the toolbar. (uses addButton)
|
|
1061 * @param {Object} oGroup Object literal reference to the Groups Config (contains an array of button configs as well as the group label)
|
|
1062 */
|
|
1063 addButtonGroup: function(oGroup) {
|
|
1064 if (!this.get('element')) {
|
|
1065 this._queue[this._queue.length] = ['addButtonGroup', arguments];
|
|
1066 return false;
|
|
1067 }
|
|
1068
|
|
1069 if (!this.hasClass(this.CLASS_PREFIX + '-grouped')) {
|
|
1070 this.addClass(this.CLASS_PREFIX + '-grouped');
|
|
1071 }
|
|
1072 var div = document.createElement('DIV');
|
|
1073 Dom.addClass(div, this.CLASS_PREFIX + '-group');
|
|
1074 Dom.addClass(div, this.CLASS_PREFIX + '-group-' + oGroup.group);
|
|
1075 if (oGroup.label) {
|
|
1076 var label = document.createElement('h3');
|
|
1077 label.innerHTML = oGroup.label;
|
|
1078 div.appendChild(label);
|
|
1079 }
|
|
1080 if (!this.get('grouplabels')) {
|
|
1081 Dom.addClass(this.get('cont'), this.CLASS_PREFIX, '-nogrouplabels');
|
|
1082 }
|
|
1083
|
|
1084 this.get('cont').appendChild(div);
|
|
1085
|
|
1086 //For accessibility, let's put all of the group buttons in an Unordered List
|
|
1087 var ul = document.createElement('ul');
|
|
1088 div.appendChild(ul);
|
|
1089
|
|
1090 if (!this._buttonGroupList) {
|
|
1091 this._buttonGroupList = {};
|
|
1092 }
|
|
1093
|
|
1094 this._buttonGroupList[oGroup.group] = ul;
|
|
1095
|
|
1096 //An array of the button ids added to this group
|
|
1097 //This is used for destruction later...
|
|
1098 var addedButtons = [],
|
|
1099 button;
|
|
1100
|
|
1101
|
|
1102 for (var i = 0; i < oGroup.buttons.length; i++) {
|
|
1103 var li = document.createElement('li');
|
|
1104 li.className = this.CLASS_PREFIX + '-groupitem';
|
|
1105 ul.appendChild(li);
|
|
1106 if ((oGroup.buttons[i].type !== undefined) && oGroup.buttons[i].type == 'separator') {
|
|
1107 this.addSeparator(li);
|
|
1108 } else {
|
|
1109 oGroup.buttons[i].container = li;
|
|
1110 button = this.addButton(oGroup.buttons[i]);
|
|
1111 if (button) {
|
|
1112 addedButtons[addedButtons.length] = button.id;
|
|
1113 }
|
|
1114 }
|
|
1115 }
|
|
1116 return addedButtons;
|
|
1117 },
|
|
1118 /**
|
|
1119 * @method addButtonToGroup
|
|
1120 * @description Add a new button to a toolbar group. Buttons supported:
|
|
1121 * push, split, menu, select, color, spin
|
|
1122 * @param {Object} oButton Object literal reference to the Button's Config
|
|
1123 * @param {String} group The Group identifier passed into the initial config
|
|
1124 * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
|
|
1125 */
|
|
1126 addButtonToGroup: function(oButton, group, after) {
|
|
1127 var groupCont = this._buttonGroupList[group],
|
|
1128 li = document.createElement('li');
|
|
1129
|
|
1130 li.className = this.CLASS_PREFIX + '-groupitem';
|
|
1131 oButton.container = li;
|
|
1132 this.addButton(oButton, after);
|
|
1133 groupCont.appendChild(li);
|
|
1134 },
|
|
1135 /**
|
|
1136 * @method addButton
|
|
1137 * @description Add a new button to the toolbar. Buttons supported:
|
|
1138 * push, split, menu, select, color, spin
|
|
1139 * @param {Object} oButton Object literal reference to the Button's Config
|
|
1140 * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
|
|
1141 */
|
|
1142 addButton: function(oButton, after) {
|
|
1143 if (!this.get('element')) {
|
|
1144 this._queue[this._queue.length] = ['addButton', arguments];
|
|
1145 return false;
|
|
1146 }
|
|
1147 if (!this._buttonList) {
|
|
1148 this._buttonList = [];
|
|
1149 }
|
|
1150 YAHOO.log('Adding button of type: ' + oButton.type, 'info', 'Toolbar');
|
|
1151 if (!oButton.container) {
|
|
1152 oButton.container = this.get('cont');
|
|
1153 }
|
|
1154
|
|
1155 if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
|
|
1156 if (Lang.isArray(oButton.menu)) {
|
|
1157 for (var i in oButton.menu) {
|
|
1158 if (Lang.hasOwnProperty(oButton.menu, i)) {
|
|
1159 var funcObject = {
|
|
1160 fn: function(ev, x, oMenu) {
|
|
1161 if (!oButton.menucmd) {
|
|
1162 oButton.menucmd = oButton.value;
|
|
1163 }
|
|
1164 oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
|
|
1165 },
|
|
1166 scope: this
|
|
1167 };
|
|
1168 oButton.menu[i].onclick = funcObject;
|
|
1169 }
|
|
1170 }
|
|
1171 }
|
|
1172 }
|
|
1173 var _oButton = {}, skip = false;
|
|
1174 for (var o in oButton) {
|
|
1175 if (Lang.hasOwnProperty(oButton, o)) {
|
|
1176 if (!this._toolbarConfigs[o]) {
|
|
1177 _oButton[o] = oButton[o];
|
|
1178 }
|
|
1179 }
|
|
1180 }
|
|
1181 if (oButton.type == 'select') {
|
|
1182 _oButton.type = 'menu';
|
|
1183 }
|
|
1184 if (oButton.type == 'spin') {
|
|
1185 _oButton.type = 'push';
|
|
1186 }
|
|
1187 if (_oButton.type == 'color') {
|
|
1188 if (YAHOO.widget.Overlay) {
|
|
1189 _oButton = this._makeColorButton(_oButton);
|
|
1190 } else {
|
|
1191 skip = true;
|
|
1192 }
|
|
1193 }
|
|
1194 if (_oButton.menu) {
|
|
1195 if ((YAHOO.widget.Overlay) && (oButton.menu instanceof YAHOO.widget.Overlay)) {
|
|
1196 oButton.menu.showEvent.subscribe(function() {
|
|
1197 this._button = _oButton;
|
|
1198 });
|
|
1199 } else {
|
|
1200 for (var m = 0; m < _oButton.menu.length; m++) {
|
|
1201 if (!_oButton.menu[m].value) {
|
|
1202 _oButton.menu[m].value = _oButton.menu[m].text;
|
|
1203 }
|
|
1204 }
|
|
1205 if (this.browser.webkit) {
|
|
1206 _oButton.focusmenu = false;
|
|
1207 }
|
|
1208 }
|
|
1209 }
|
|
1210 if (skip) {
|
|
1211 oButton = false;
|
|
1212 } else {
|
|
1213 //Add to .get('buttons') manually
|
|
1214 this._configs.buttons.value[this._configs.buttons.value.length] = oButton;
|
|
1215
|
|
1216 var tmp = new this.buttonType(_oButton);
|
|
1217 tmp.get('element').tabIndex = '-1';
|
|
1218 tmp.get('element').setAttribute('role', 'button');
|
|
1219 tmp._selected = true;
|
|
1220
|
|
1221 if (this.get('disabled')) {
|
|
1222 //Toolbar is disabled, disable the new button too!
|
|
1223 tmp.set('disabled', true);
|
|
1224 }
|
|
1225 if (!oButton.id) {
|
|
1226 oButton.id = tmp.get('id');
|
|
1227 }
|
|
1228 YAHOO.log('Button created (' + oButton.type + ')', 'info', 'Toolbar');
|
|
1229
|
|
1230 if (after) {
|
|
1231 var el = tmp.get('element');
|
|
1232 var nextSib = null;
|
|
1233 if (after.get) {
|
|
1234 nextSib = after.get('element').nextSibling;
|
|
1235 } else if (after.nextSibling) {
|
|
1236 nextSib = after.nextSibling;
|
|
1237 }
|
|
1238 if (nextSib) {
|
|
1239 nextSib.parentNode.insertBefore(el, nextSib);
|
|
1240 }
|
|
1241 }
|
|
1242 tmp.addClass(this.CLASS_PREFIX + '-' + tmp.get('value'));
|
|
1243
|
|
1244 var icon = document.createElement('span');
|
|
1245 icon.className = this.CLASS_PREFIX + '-icon';
|
|
1246 tmp.get('element').insertBefore(icon, tmp.get('firstChild'));
|
|
1247 if (tmp._button.tagName.toLowerCase() == 'button') {
|
|
1248 tmp.get('element').setAttribute('unselectable', 'on');
|
|
1249 //Replace the Button HTML Element with an a href if it exists
|
|
1250 var a = document.createElement('a');
|
|
1251 a.innerHTML = tmp._button.innerHTML;
|
|
1252 a.href = '#';
|
|
1253 a.tabIndex = '-1';
|
|
1254 Event.on(a, 'click', function(ev) {
|
|
1255 Event.stopEvent(ev);
|
|
1256 });
|
|
1257 tmp._button.parentNode.replaceChild(a, tmp._button);
|
|
1258 tmp._button = a;
|
|
1259 }
|
|
1260
|
|
1261 if (oButton.type == 'select') {
|
|
1262 if (tmp._button.tagName.toLowerCase() == 'select') {
|
|
1263 icon.parentNode.removeChild(icon);
|
|
1264 var iel = tmp._button,
|
|
1265 parEl = tmp.get('element');
|
|
1266 parEl.parentNode.replaceChild(iel, parEl);
|
|
1267 //The 'element' value is currently the orphaned element
|
|
1268 //In order for "destroy" to execute we need to get('element') to reference the correct node.
|
|
1269 //I'm not sure if there is a direct approach to setting this value.
|
|
1270 tmp._configs.element.value = iel;
|
|
1271 } else {
|
|
1272 //Don't put a class on it if it's a real select element
|
|
1273 tmp.addClass(this.CLASS_PREFIX + '-select');
|
|
1274 }
|
|
1275 }
|
|
1276 if (oButton.type == 'spin') {
|
|
1277 if (!Lang.isArray(oButton.range)) {
|
|
1278 oButton.range = [ 10, 100 ];
|
|
1279 }
|
|
1280 this._makeSpinButton(tmp, oButton);
|
|
1281 }
|
|
1282 tmp.get('element').setAttribute('title', tmp.get('label'));
|
|
1283 if (oButton.type != 'spin') {
|
|
1284 if ((YAHOO.widget.Overlay) && (_oButton.menu instanceof YAHOO.widget.Overlay)) {
|
|
1285 var showPicker = function(ev) {
|
|
1286 var exec = true;
|
|
1287 if (ev.keyCode && (ev.keyCode == 9)) {
|
|
1288 exec = false;
|
|
1289 }
|
|
1290 if (exec) {
|
|
1291 if (this._colorPicker) {
|
|
1292 this._colorPicker._button = oButton.value;
|
|
1293 }
|
|
1294 var menuEL = tmp.getMenu().element;
|
|
1295 if (Dom.getStyle(menuEL, 'visibility') == 'hidden') {
|
|
1296 tmp.getMenu().show();
|
|
1297 } else {
|
|
1298 tmp.getMenu().hide();
|
|
1299 }
|
|
1300 }
|
|
1301 YAHOO.util.Event.stopEvent(ev);
|
|
1302 };
|
|
1303 tmp.on('mousedown', showPicker, oButton, this);
|
|
1304 tmp.on('keydown', showPicker, oButton, this);
|
|
1305
|
|
1306 } else if ((oButton.type != 'menu') && (oButton.type != 'select')) {
|
|
1307 tmp.on('keypress', this._buttonClick, oButton, this);
|
|
1308 tmp.on('mousedown', function(ev) {
|
|
1309 YAHOO.util.Event.stopEvent(ev);
|
|
1310 this._buttonClick(ev, oButton);
|
|
1311 }, oButton, this);
|
|
1312 tmp.on('click', function(ev) {
|
|
1313 YAHOO.util.Event.stopEvent(ev);
|
|
1314 });
|
|
1315 } else {
|
|
1316 //Stop the mousedown event so we can trap the selection in the editor!
|
|
1317 tmp.on('mousedown', function(ev) {
|
|
1318 YAHOO.util.Event.stopEvent(ev);
|
|
1319 });
|
|
1320 tmp.on('click', function(ev) {
|
|
1321 YAHOO.util.Event.stopEvent(ev);
|
|
1322 });
|
|
1323 tmp.on('change', function(ev) {
|
|
1324 if (!ev.target) {
|
|
1325 if (!oButton.menucmd) {
|
|
1326 oButton.menucmd = oButton.value;
|
|
1327 }
|
|
1328 oButton.value = ev.value;
|
|
1329 this._buttonClick(ev, oButton);
|
|
1330 }
|
|
1331 }, this, true);
|
|
1332
|
|
1333 var self = this;
|
|
1334 //Hijack the mousedown event in the menu and make it fire a button click..
|
|
1335 tmp.on('appendTo', function() {
|
|
1336 var tmp = this;
|
|
1337 if (tmp.getMenu() && tmp.getMenu().mouseDownEvent) {
|
|
1338 tmp.getMenu().mouseDownEvent.subscribe(function(ev, args) {
|
|
1339 YAHOO.log('mouseDownEvent', 'warn', 'Toolbar');
|
|
1340 var oMenu = args[1];
|
|
1341 YAHOO.util.Event.stopEvent(args[0]);
|
|
1342 tmp._onMenuClick(args[0], tmp);
|
|
1343 if (!oButton.menucmd) {
|
|
1344 oButton.menucmd = oButton.value;
|
|
1345 }
|
|
1346 oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
|
|
1347 self._buttonClick.call(self, args[1], oButton);
|
|
1348 tmp._hideMenu();
|
|
1349 return false;
|
|
1350 });
|
|
1351 tmp.getMenu().clickEvent.subscribe(function(ev, args) {
|
|
1352 YAHOO.log('clickEvent', 'warn', 'Toolbar');
|
|
1353 YAHOO.util.Event.stopEvent(args[0]);
|
|
1354 });
|
|
1355 tmp.getMenu().mouseUpEvent.subscribe(function(ev, args) {
|
|
1356 YAHOO.log('mouseUpEvent', 'warn', 'Toolbar');
|
|
1357 YAHOO.util.Event.stopEvent(args[0]);
|
|
1358 });
|
|
1359 }
|
|
1360 });
|
|
1361
|
|
1362 }
|
|
1363 } else {
|
|
1364 //Stop the mousedown event so we can trap the selection in the editor!
|
|
1365 tmp.on('mousedown', function(ev) {
|
|
1366 YAHOO.util.Event.stopEvent(ev);
|
|
1367 });
|
|
1368 tmp.on('click', function(ev) {
|
|
1369 YAHOO.util.Event.stopEvent(ev);
|
|
1370 });
|
|
1371 }
|
|
1372 if (this.browser.ie) {
|
|
1373 /*
|
|
1374 //Add a couple of new events for IE
|
|
1375 tmp.DOM_EVENTS.focusin = true;
|
|
1376 tmp.DOM_EVENTS.focusout = true;
|
|
1377
|
|
1378 //Stop them so we don't loose focus in the Editor
|
|
1379 tmp.on('focusin', function(ev) {
|
|
1380 YAHOO.util.Event.stopEvent(ev);
|
|
1381 }, oButton, this);
|
|
1382
|
|
1383 tmp.on('focusout', function(ev) {
|
|
1384 YAHOO.util.Event.stopEvent(ev);
|
|
1385 }, oButton, this);
|
|
1386 tmp.on('click', function(ev) {
|
|
1387 YAHOO.util.Event.stopEvent(ev);
|
|
1388 }, oButton, this);
|
|
1389 */
|
|
1390 }
|
|
1391 if (this.browser.webkit) {
|
|
1392 //This will keep the document from gaining focus and the editor from loosing it..
|
|
1393 //Forcefully remove the focus calls in button!
|
|
1394 tmp.hasFocus = function() {
|
|
1395 return true;
|
|
1396 };
|
|
1397 }
|
|
1398 this._buttonList[this._buttonList.length] = tmp;
|
|
1399 if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
|
|
1400 if (Lang.isArray(oButton.menu)) {
|
|
1401 YAHOO.log('Button type is (' + oButton.type + '), doing extra renderer work.', 'info', 'Toolbar');
|
|
1402 var menu = tmp.getMenu();
|
|
1403 if (menu && menu.renderEvent) {
|
|
1404 menu.renderEvent.subscribe(this._addMenuClasses, tmp);
|
|
1405 if (oButton.renderer) {
|
|
1406 menu.renderEvent.subscribe(oButton.renderer, tmp);
|
|
1407 }
|
|
1408 }
|
|
1409 }
|
|
1410 }
|
|
1411 }
|
|
1412 return oButton;
|
|
1413 },
|
|
1414 /**
|
|
1415 * @method addSeparator
|
|
1416 * @description Add a new button separator to the toolbar.
|
|
1417 * @param {HTMLElement} cont Optional HTML element to insert this button into.
|
|
1418 * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
|
|
1419 */
|
|
1420 addSeparator: function(cont, after) {
|
|
1421 if (!this.get('element')) {
|
|
1422 this._queue[this._queue.length] = ['addSeparator', arguments];
|
|
1423 return false;
|
|
1424 }
|
|
1425 var sepCont = ((cont) ? cont : this.get('cont'));
|
|
1426 if (!this.get('element')) {
|
|
1427 this._queue[this._queue.length] = ['addSeparator', arguments];
|
|
1428 return false;
|
|
1429 }
|
|
1430 if (this._sepCount === null) {
|
|
1431 this._sepCount = 0;
|
|
1432 }
|
|
1433 if (!this._sep) {
|
|
1434 YAHOO.log('Separator does not yet exist, creating', 'info', 'Toolbar');
|
|
1435 this._sep = document.createElement('SPAN');
|
|
1436 Dom.addClass(this._sep, this.CLASS_SEPARATOR);
|
|
1437 this._sep.innerHTML = '|';
|
|
1438 }
|
|
1439 YAHOO.log('Separator does exist, cloning', 'info', 'Toolbar');
|
|
1440 var _sep = this._sep.cloneNode(true);
|
|
1441 this._sepCount++;
|
|
1442 Dom.addClass(_sep, this.CLASS_SEPARATOR + '-' + this._sepCount);
|
|
1443 if (after) {
|
|
1444 var nextSib = null;
|
|
1445 if (after.get) {
|
|
1446 nextSib = after.get('element').nextSibling;
|
|
1447 } else if (after.nextSibling) {
|
|
1448 nextSib = after.nextSibling;
|
|
1449 } else {
|
|
1450 nextSib = after;
|
|
1451 }
|
|
1452 if (nextSib) {
|
|
1453 if (nextSib == after) {
|
|
1454 nextSib.parentNode.appendChild(_sep);
|
|
1455 } else {
|
|
1456 nextSib.parentNode.insertBefore(_sep, nextSib);
|
|
1457 }
|
|
1458 }
|
|
1459 } else {
|
|
1460 sepCont.appendChild(_sep);
|
|
1461 }
|
|
1462 return _sep;
|
|
1463 },
|
|
1464 /**
|
|
1465 * @method _createColorPicker
|
|
1466 * @private
|
|
1467 * @description Creates the core DOM reference to the color picker menu item.
|
|
1468 * @param {String} id the id of the toolbar to prefix this DOM container with.
|
|
1469 */
|
|
1470 _createColorPicker: function(id) {
|
|
1471 if (Dom.get(id + '_colors')) {
|
|
1472 Dom.get(id + '_colors').parentNode.removeChild(Dom.get(id + '_colors'));
|
|
1473 }
|
|
1474 var picker = document.createElement('div');
|
|
1475 picker.className = 'yui-toolbar-colors';
|
|
1476 picker.id = id + '_colors';
|
|
1477 picker.style.display = 'none';
|
|
1478 Event.on(window, 'load', function() {
|
|
1479 document.body.appendChild(picker);
|
|
1480 }, this, true);
|
|
1481
|
|
1482 this._colorPicker = picker;
|
|
1483
|
|
1484 var html = '';
|
|
1485 for (var i in this._colorData) {
|
|
1486 if (Lang.hasOwnProperty(this._colorData, i)) {
|
|
1487 html += '<a style="background-color: ' + i + '" href="#">' + i.replace('#', '') + '</a>';
|
|
1488 }
|
|
1489 }
|
|
1490 html += '<span><em>X</em><strong></strong></span>';
|
|
1491 window.setTimeout(function() {
|
|
1492 picker.innerHTML = html;
|
|
1493 }, 0);
|
|
1494
|
|
1495 Event.on(picker, 'mouseover', function(ev) {
|
|
1496 var picker = this._colorPicker;
|
|
1497 var em = picker.getElementsByTagName('em')[0];
|
|
1498 var strong = picker.getElementsByTagName('strong')[0];
|
|
1499 var tar = Event.getTarget(ev);
|
|
1500 if (tar.tagName.toLowerCase() == 'a') {
|
|
1501 em.style.backgroundColor = tar.style.backgroundColor;
|
|
1502 strong.innerHTML = this._colorData['#' + tar.innerHTML] + '<br>' + tar.innerHTML;
|
|
1503 }
|
|
1504 }, this, true);
|
|
1505 Event.on(picker, 'focus', function(ev) {
|
|
1506 Event.stopEvent(ev);
|
|
1507 });
|
|
1508 Event.on(picker, 'click', function(ev) {
|
|
1509 Event.stopEvent(ev);
|
|
1510 });
|
|
1511 Event.on(picker, 'mousedown', function(ev) {
|
|
1512 Event.stopEvent(ev);
|
|
1513 var tar = Event.getTarget(ev);
|
|
1514 if (tar.tagName.toLowerCase() == 'a') {
|
|
1515 var retVal = this.fireEvent('colorPickerClicked', { type: 'colorPickerClicked', target: this, button: this._colorPicker._button, color: tar.innerHTML, colorName: this._colorData['#' + tar.innerHTML] } );
|
|
1516 if (retVal !== false) {
|
|
1517 var info = {
|
|
1518 color: tar.innerHTML,
|
|
1519 colorName: this._colorData['#' + tar.innerHTML],
|
|
1520 value: this._colorPicker._button
|
|
1521 };
|
|
1522
|
|
1523 this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
|
|
1524 }
|
|
1525 this.getButtonByValue(this._colorPicker._button).getMenu().hide();
|
|
1526 }
|
|
1527 }, this, true);
|
|
1528 },
|
|
1529 /**
|
|
1530 * @method _resetColorPicker
|
|
1531 * @private
|
|
1532 * @description Clears the currently selected color or mouseover color in the color picker.
|
|
1533 */
|
|
1534 _resetColorPicker: function() {
|
|
1535 var em = this._colorPicker.getElementsByTagName('em')[0];
|
|
1536 var strong = this._colorPicker.getElementsByTagName('strong')[0];
|
|
1537 em.style.backgroundColor = 'transparent';
|
|
1538 strong.innerHTML = '';
|
|
1539 },
|
|
1540 /**
|
|
1541 * @method _makeColorButton
|
|
1542 * @private
|
|
1543 * @description Called to turn a "color" button into a menu button with an Overlay for the menu.
|
|
1544 * @param {Object} _oButton <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
|
|
1545 */
|
|
1546 _makeColorButton: function(_oButton) {
|
|
1547 if (!this._colorPicker) {
|
|
1548 this._createColorPicker(this.get('id'));
|
|
1549 }
|
|
1550 _oButton.type = 'color';
|
|
1551 _oButton.menu = new YAHOO.widget.Overlay(this.get('id') + '_' + _oButton.value + '_menu', { visible: false, position: 'absolute', iframe: true });
|
|
1552 _oButton.menu.setBody('');
|
|
1553 _oButton.menu.render(this.get('cont'));
|
|
1554 Dom.addClass(_oButton.menu.element, 'yui-button-menu');
|
|
1555 Dom.addClass(_oButton.menu.element, 'yui-color-button-menu');
|
|
1556 _oButton.menu.beforeShowEvent.subscribe(function() {
|
|
1557 _oButton.menu.cfg.setProperty('zindex', 5); //Re Adjust the overlays zIndex.. not sure why.
|
|
1558 _oButton.menu.cfg.setProperty('context', [this.getButtonById(_oButton.id).get('element'), 'tl', 'bl']); //Re Adjust the overlay.. not sure why.
|
|
1559 //Move the DOM reference of the color picker to the Overlay that we are about to show.
|
|
1560 this._resetColorPicker();
|
|
1561 var _p = this._colorPicker;
|
|
1562 if (_p.parentNode) {
|
|
1563 _p.parentNode.removeChild(_p);
|
|
1564 }
|
|
1565 _oButton.menu.setBody('');
|
|
1566 _oButton.menu.appendToBody(_p);
|
|
1567 this._colorPicker.style.display = 'block';
|
|
1568 }, this, true);
|
|
1569 return _oButton;
|
|
1570 },
|
|
1571 /**
|
|
1572 * @private
|
|
1573 * @method _makeSpinButton
|
|
1574 * @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.
|
|
1575 * @param {Object} _button <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
|
|
1576 * @param {Object} oButton Object literal containing the buttons initial config
|
|
1577 */
|
|
1578 _makeSpinButton: function(_button, oButton) {
|
|
1579 _button.addClass(this.CLASS_PREFIX + '-spinbutton');
|
|
1580 var self = this,
|
|
1581 _par = _button._button.parentNode.parentNode, //parentNode of Button Element for appending child
|
|
1582 range = oButton.range,
|
|
1583 _b1 = document.createElement('a'),
|
|
1584 _b2 = document.createElement('a');
|
|
1585 _b1.href = '#';
|
|
1586 _b2.href = '#';
|
|
1587 _b1.tabIndex = '-1';
|
|
1588 _b2.tabIndex = '-1';
|
|
1589
|
|
1590 //Setup the up and down arrows
|
|
1591 _b1.className = 'up';
|
|
1592 _b1.title = this.STR_SPIN_UP;
|
|
1593 _b1.innerHTML = this.STR_SPIN_UP;
|
|
1594 _b2.className = 'down';
|
|
1595 _b2.title = this.STR_SPIN_DOWN;
|
|
1596 _b2.innerHTML = this.STR_SPIN_DOWN;
|
|
1597
|
|
1598 //Append them to the container
|
|
1599 _par.appendChild(_b1);
|
|
1600 _par.appendChild(_b2);
|
|
1601
|
|
1602 var label = YAHOO.lang.substitute(this.STR_SPIN_LABEL, { VALUE: _button.get('label') });
|
|
1603 _button.set('title', label);
|
|
1604
|
|
1605 var cleanVal = function(value) {
|
|
1606 value = ((value < range[0]) ? range[0] : value);
|
|
1607 value = ((value > range[1]) ? range[1] : value);
|
|
1608 return value;
|
|
1609 };
|
|
1610
|
|
1611 var br = this.browser;
|
|
1612 var tbar = false;
|
|
1613 var strLabel = this.STR_SPIN_LABEL;
|
|
1614 if (this._titlebar && this._titlebar.firstChild) {
|
|
1615 tbar = this._titlebar.firstChild;
|
|
1616 }
|
|
1617
|
|
1618 var _intUp = function(ev) {
|
|
1619 YAHOO.util.Event.stopEvent(ev);
|
|
1620 if (!_button.get('disabled') && (ev.keyCode != 9)) {
|
|
1621 var value = parseInt(_button.get('label'), 10);
|
|
1622 value++;
|
|
1623 value = cleanVal(value);
|
|
1624 _button.set('label', ''+value);
|
|
1625 var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
|
|
1626 _button.set('title', label);
|
|
1627 if (!br.webkit && tbar) {
|
|
1628 //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
|
|
1629 //_button.focus();
|
|
1630 }
|
|
1631 self._buttonClick(ev, oButton);
|
|
1632 }
|
|
1633 };
|
|
1634
|
|
1635 var _intDown = function(ev) {
|
|
1636 YAHOO.util.Event.stopEvent(ev);
|
|
1637 if (!_button.get('disabled') && (ev.keyCode != 9)) {
|
|
1638 var value = parseInt(_button.get('label'), 10);
|
|
1639 value--;
|
|
1640 value = cleanVal(value);
|
|
1641
|
|
1642 _button.set('label', ''+value);
|
|
1643 var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
|
|
1644 _button.set('title', label);
|
|
1645 if (!br.webkit && tbar) {
|
|
1646 //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
|
|
1647 //_button.focus();
|
|
1648 }
|
|
1649 self._buttonClick(ev, oButton);
|
|
1650 }
|
|
1651 };
|
|
1652
|
|
1653 var _intKeyUp = function(ev) {
|
|
1654 if (ev.keyCode == 38) {
|
|
1655 _intUp(ev);
|
|
1656 } else if (ev.keyCode == 40) {
|
|
1657 _intDown(ev);
|
|
1658 } else if (ev.keyCode == 107 && ev.shiftKey) { //Plus Key
|
|
1659 _intUp(ev);
|
|
1660 } else if (ev.keyCode == 109 && ev.shiftKey) { //Minus Key
|
|
1661 _intDown(ev);
|
|
1662 }
|
|
1663 };
|
|
1664
|
|
1665 //Handle arrow keys..
|
|
1666 _button.on('keydown', _intKeyUp, this, true);
|
|
1667
|
|
1668 //Listen for the click on the up button and act on it
|
|
1669 //Listen for the click on the down button and act on it
|
|
1670 Event.on(_b1, 'mousedown',function(ev) {
|
|
1671 Event.stopEvent(ev);
|
|
1672 }, this, true);
|
|
1673 Event.on(_b2, 'mousedown', function(ev) {
|
|
1674 Event.stopEvent(ev);
|
|
1675 }, this, true);
|
|
1676 Event.on(_b1, 'click', _intUp, this, true);
|
|
1677 Event.on(_b2, 'click', _intDown, this, true);
|
|
1678 },
|
|
1679 /**
|
|
1680 * @protected
|
|
1681 * @method _buttonClick
|
|
1682 * @description Click handler for all buttons in the toolbar.
|
|
1683 * @param {String} ev The event that was passed in.
|
|
1684 * @param {Object} info Object literal of information about the button that was clicked.
|
|
1685 */
|
|
1686 _buttonClick: function(ev, info) {
|
|
1687 var doEvent = true;
|
|
1688
|
|
1689 if (ev && ev.type == 'keypress') {
|
|
1690 if (ev.keyCode == 9) {
|
|
1691 doEvent = false;
|
|
1692 } else if ((ev.keyCode === 13) || (ev.keyCode === 0) || (ev.keyCode === 32)) {
|
|
1693 } else {
|
|
1694 doEvent = false;
|
|
1695 }
|
|
1696 }
|
|
1697
|
|
1698 if (doEvent) {
|
|
1699 var fireNextEvent = true,
|
|
1700 retValue = false;
|
|
1701
|
|
1702 info.isSelected = this.isSelected(info.id);
|
|
1703
|
|
1704 if (info.value) {
|
|
1705 YAHOO.log('fireEvent::' + info.value + 'Click', 'info', 'Toolbar');
|
|
1706 retValue = this.fireEvent(info.value + 'Click', { type: info.value + 'Click', target: this.get('element'), button: info });
|
|
1707 if (retValue === false) {
|
|
1708 fireNextEvent = false;
|
|
1709 }
|
|
1710 }
|
|
1711
|
|
1712 if (info.menucmd && fireNextEvent) {
|
|
1713 YAHOO.log('fireEvent::' + info.menucmd + 'Click', 'info', 'Toolbar');
|
|
1714 retValue = this.fireEvent(info.menucmd + 'Click', { type: info.menucmd + 'Click', target: this.get('element'), button: info });
|
|
1715 if (retValue === false) {
|
|
1716 fireNextEvent = false;
|
|
1717 }
|
|
1718 }
|
|
1719 if (fireNextEvent) {
|
|
1720 YAHOO.log('fireEvent::buttonClick', 'info', 'Toolbar');
|
|
1721 this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
|
|
1722 }
|
|
1723
|
|
1724 if (info.type == 'select') {
|
|
1725 var button = this.getButtonById(info.id);
|
|
1726 if (button.buttonType == 'rich') {
|
|
1727 var txt = info.value;
|
|
1728 for (var i = 0; i < info.menu.length; i++) {
|
|
1729 if (info.menu[i].value == info.value) {
|
|
1730 txt = info.menu[i].text;
|
|
1731 break;
|
|
1732 }
|
|
1733 }
|
|
1734 button.set('label', '<span class="yui-toolbar-' + info.menucmd + '-' + (info.value).replace(/ /g, '-').toLowerCase() + '">' + txt + '</span>');
|
|
1735 var _items = button.getMenu().getItems();
|
|
1736 for (var m = 0; m < _items.length; m++) {
|
|
1737 if (_items[m].value.toLowerCase() == info.value.toLowerCase()) {
|
|
1738 _items[m].cfg.setProperty('checked', true);
|
|
1739 } else {
|
|
1740 _items[m].cfg.setProperty('checked', false);
|
|
1741 }
|
|
1742 }
|
|
1743 }
|
|
1744 }
|
|
1745 if (ev) {
|
|
1746 Event.stopEvent(ev);
|
|
1747 }
|
|
1748 }
|
|
1749 },
|
|
1750 /**
|
|
1751 * @private
|
|
1752 * @property _keyNav
|
|
1753 * @description Flag to determine if the arrow nav listeners have been attached
|
|
1754 * @type Boolean
|
|
1755 */
|
|
1756 _keyNav: null,
|
|
1757 /**
|
|
1758 * @private
|
|
1759 * @property _navCounter
|
|
1760 * @description Internal counter for walking the buttons in the toolbar with the arrow keys
|
|
1761 * @type Number
|
|
1762 */
|
|
1763 _navCounter: null,
|
|
1764 /**
|
|
1765 * @private
|
|
1766 * @method _navigateButtons
|
|
1767 * @description Handles the navigation/focus of toolbar buttons with the Arrow Keys
|
|
1768 * @param {Event} ev The Key Event
|
|
1769 */
|
|
1770 _navigateButtons: function(ev) {
|
|
1771 switch (ev.keyCode) {
|
|
1772 case 37:
|
|
1773 case 39:
|
|
1774 if (ev.keyCode == 37) {
|
|
1775 this._navCounter--;
|
|
1776 } else {
|
|
1777 this._navCounter++;
|
|
1778 }
|
|
1779 if (this._navCounter > (this._buttonList.length - 1)) {
|
|
1780 this._navCounter = 0;
|
|
1781 }
|
|
1782 if (this._navCounter < 0) {
|
|
1783 this._navCounter = (this._buttonList.length - 1);
|
|
1784 }
|
|
1785 if (this._buttonList[this._navCounter]) {
|
|
1786 var el = this._buttonList[this._navCounter].get('element');
|
|
1787 if (this.browser.ie) {
|
|
1788 el = this._buttonList[this._navCounter].get('element').getElementsByTagName('a')[0];
|
|
1789 }
|
|
1790 if (this._buttonList[this._navCounter].get('disabled')) {
|
|
1791 this._navigateButtons(ev);
|
|
1792 } else {
|
|
1793 el.focus();
|
|
1794 }
|
|
1795 }
|
|
1796 break;
|
|
1797 }
|
|
1798 },
|
|
1799 /**
|
|
1800 * @private
|
|
1801 * @method _handleFocus
|
|
1802 * @description Sets up the listeners for the arrow key navigation
|
|
1803 */
|
|
1804 _handleFocus: function() {
|
|
1805 if (!this._keyNav) {
|
|
1806 var ev = 'keypress';
|
|
1807 if (this.browser.ie) {
|
|
1808 ev = 'keydown';
|
|
1809 }
|
|
1810 Event.on(this.get('element'), ev, this._navigateButtons, this, true);
|
|
1811 this._keyNav = true;
|
|
1812 this._navCounter = -1;
|
|
1813 }
|
|
1814 },
|
|
1815 /**
|
|
1816 * @method getButtonById
|
|
1817 * @description Gets a button instance from the toolbar by is Dom id.
|
|
1818 * @param {String} id The Dom id to query for.
|
|
1819 * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
|
|
1820 */
|
|
1821 getButtonById: function(id) {
|
|
1822 var len = this._buttonList.length;
|
|
1823 for (var i = 0; i < len; i++) {
|
|
1824 if (this._buttonList[i] && this._buttonList[i].get('id') == id) {
|
|
1825 return this._buttonList[i];
|
|
1826 }
|
|
1827 }
|
|
1828 return false;
|
|
1829 },
|
|
1830 /**
|
|
1831 * @method getButtonByValue
|
|
1832 * @description Gets a button instance or a menuitem instance from the toolbar by it's value.
|
|
1833 * @param {String} value The button value to query for.
|
|
1834 * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> or <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>}
|
|
1835 */
|
|
1836 getButtonByValue: function(value) {
|
|
1837 var _buttons = this.get('buttons');
|
|
1838 if (!_buttons) {
|
|
1839 return false;
|
|
1840 }
|
|
1841 var len = _buttons.length;
|
|
1842 for (var i = 0; i < len; i++) {
|
|
1843 if (_buttons[i].group !== undefined) {
|
|
1844 for (var m = 0; m < _buttons[i].buttons.length; m++) {
|
|
1845 if ((_buttons[i].buttons[m].value == value) || (_buttons[i].buttons[m].menucmd == value)) {
|
|
1846 return this.getButtonById(_buttons[i].buttons[m].id);
|
|
1847 }
|
|
1848 if (_buttons[i].buttons[m].menu) { //Menu Button, loop through the values
|
|
1849 for (var s = 0; s < _buttons[i].buttons[m].menu.length; s++) {
|
|
1850 if (_buttons[i].buttons[m].menu[s].value == value) {
|
|
1851 return this.getButtonById(_buttons[i].buttons[m].id);
|
|
1852 }
|
|
1853 }
|
|
1854 }
|
|
1855 }
|
|
1856 } else {
|
|
1857 if ((_buttons[i].value == value) || (_buttons[i].menucmd == value)) {
|
|
1858 return this.getButtonById(_buttons[i].id);
|
|
1859 }
|
|
1860 if (_buttons[i].menu) { //Menu Button, loop through the values
|
|
1861 for (var j = 0; j < _buttons[i].menu.length; j++) {
|
|
1862 if (_buttons[i].menu[j].value == value) {
|
|
1863 return this.getButtonById(_buttons[i].id);
|
|
1864 }
|
|
1865 }
|
|
1866 }
|
|
1867 }
|
|
1868 }
|
|
1869 return false;
|
|
1870 },
|
|
1871 /**
|
|
1872 * @method getButtonByIndex
|
|
1873 * @description Gets a button instance from the toolbar by is index in _buttonList.
|
|
1874 * @param {Number} index The index of the button in _buttonList.
|
|
1875 * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
|
|
1876 */
|
|
1877 getButtonByIndex: function(index) {
|
|
1878 if (this._buttonList[index]) {
|
|
1879 return this._buttonList[index];
|
|
1880 } else {
|
|
1881 return false;
|
|
1882 }
|
|
1883 },
|
|
1884 /**
|
|
1885 * @method getButtons
|
|
1886 * @description Returns an array of buttons in the current toolbar
|
|
1887 * @return {Array}
|
|
1888 */
|
|
1889 getButtons: function() {
|
|
1890 return this._buttonList;
|
|
1891 },
|
|
1892 /**
|
|
1893 * @method disableButton
|
|
1894 * @description Disables a button in the toolbar.
|
|
1895 * @param {String/Number} id Disable a button by it's id, index or value.
|
|
1896 * @return {Boolean}
|
|
1897 */
|
|
1898 disableButton: function(id) {
|
|
1899 var button = getButton.call(this, id);
|
|
1900 if (button) {
|
|
1901 button.set('disabled', true);
|
|
1902 } else {
|
|
1903 return false;
|
|
1904 }
|
|
1905 },
|
|
1906 /**
|
|
1907 * @method enableButton
|
|
1908 * @description Enables a button in the toolbar.
|
|
1909 * @param {String/Number} id Enable a button by it's id, index or value.
|
|
1910 * @return {Boolean}
|
|
1911 */
|
|
1912 enableButton: function(id) {
|
|
1913 if (this.get('disabled')) {
|
|
1914 return false;
|
|
1915 }
|
|
1916 var button = getButton.call(this, id);
|
|
1917 if (button) {
|
|
1918 if (button.get('disabled')) {
|
|
1919 button.set('disabled', false);
|
|
1920 }
|
|
1921 } else {
|
|
1922 return false;
|
|
1923 }
|
|
1924 },
|
|
1925 /**
|
|
1926 * @method isSelected
|
|
1927 * @description Tells if a button is selected or not.
|
|
1928 * @param {String/Number} id A button by it's id, index or value.
|
|
1929 * @return {Boolean}
|
|
1930 */
|
|
1931 isSelected: function(id) {
|
|
1932 var button = getButton.call(this, id);
|
|
1933 if (button) {
|
|
1934 return button._selected;
|
|
1935 }
|
|
1936 return false;
|
|
1937 },
|
|
1938 /**
|
|
1939 * @method selectButton
|
|
1940 * @description Selects a button in the toolbar.
|
|
1941 * @param {String/Number} id Select a button by it's id, index or value.
|
|
1942 * @param {String} value If this is a Menu Button, check this item in the menu
|
|
1943 * @return {Boolean}
|
|
1944 */
|
|
1945 selectButton: function(id, value) {
|
|
1946 var button = getButton.call(this, id);
|
|
1947 if (button) {
|
|
1948 button.addClass('yui-button-selected');
|
|
1949 button.addClass('yui-button-' + button.get('value') + '-selected');
|
|
1950 button._selected = true;
|
|
1951 if (value) {
|
|
1952 if (button.buttonType == 'rich') {
|
|
1953 var _items = button.getMenu().getItems();
|
|
1954 for (var m = 0; m < _items.length; m++) {
|
|
1955 if (_items[m].value == value) {
|
|
1956 _items[m].cfg.setProperty('checked', true);
|
|
1957 button.set('label', '<span class="yui-toolbar-' + button.get('value') + '-' + (value).replace(/ /g, '-').toLowerCase() + '">' + _items[m]._oText.nodeValue + '</span>');
|
|
1958 } else {
|
|
1959 _items[m].cfg.setProperty('checked', false);
|
|
1960 }
|
|
1961 }
|
|
1962 }
|
|
1963 }
|
|
1964 } else {
|
|
1965 return false;
|
|
1966 }
|
|
1967 },
|
|
1968 /**
|
|
1969 * @method deselectButton
|
|
1970 * @description Deselects a button in the toolbar.
|
|
1971 * @param {String/Number} id Deselect a button by it's id, index or value.
|
|
1972 * @return {Boolean}
|
|
1973 */
|
|
1974 deselectButton: function(id) {
|
|
1975 var button = getButton.call(this, id);
|
|
1976 if (button) {
|
|
1977 button.removeClass('yui-button-selected');
|
|
1978 button.removeClass('yui-button-' + button.get('value') + '-selected');
|
|
1979 button.removeClass('yui-button-hover');
|
|
1980 button._selected = false;
|
|
1981 } else {
|
|
1982 return false;
|
|
1983 }
|
|
1984 },
|
|
1985 /**
|
|
1986 * @method deselectAllButtons
|
|
1987 * @description Deselects all buttons in the toolbar.
|
|
1988 * @return {Boolean}
|
|
1989 */
|
|
1990 deselectAllButtons: function() {
|
|
1991 var len = this._buttonList.length;
|
|
1992 for (var i = 0; i < len; i++) {
|
|
1993 this.deselectButton(this._buttonList[i]);
|
|
1994 }
|
|
1995 },
|
|
1996 /**
|
|
1997 * @method disableAllButtons
|
|
1998 * @description Disables all buttons in the toolbar.
|
|
1999 * @return {Boolean}
|
|
2000 */
|
|
2001 disableAllButtons: function() {
|
|
2002 if (this.get('disabled')) {
|
|
2003 return false;
|
|
2004 }
|
|
2005 var len = this._buttonList.length;
|
|
2006 for (var i = 0; i < len; i++) {
|
|
2007 this.disableButton(this._buttonList[i]);
|
|
2008 }
|
|
2009 },
|
|
2010 /**
|
|
2011 * @method enableAllButtons
|
|
2012 * @description Enables all buttons in the toolbar.
|
|
2013 * @return {Boolean}
|
|
2014 */
|
|
2015 enableAllButtons: function() {
|
|
2016 if (this.get('disabled')) {
|
|
2017 return false;
|
|
2018 }
|
|
2019 var len = this._buttonList.length;
|
|
2020 for (var i = 0; i < len; i++) {
|
|
2021 this.enableButton(this._buttonList[i]);
|
|
2022 }
|
|
2023 },
|
|
2024 /**
|
|
2025 * @method resetAllButtons
|
|
2026 * @description Resets all buttons to their initial state.
|
|
2027 * @param {Object} _ex Except these buttons
|
|
2028 * @return {Boolean}
|
|
2029 */
|
|
2030 resetAllButtons: function(_ex) {
|
|
2031 if (!Lang.isObject(_ex)) {
|
|
2032 _ex = {};
|
|
2033 }
|
|
2034 if (this.get('disabled') || !this._buttonList) {
|
|
2035 return false;
|
|
2036 }
|
|
2037 var len = this._buttonList.length;
|
|
2038 for (var i = 0; i < len; i++) {
|
|
2039 var _button = this._buttonList[i];
|
|
2040 if (_button) {
|
|
2041 var disabled = _button._configs.disabled._initialConfig.value;
|
|
2042 if (_ex[_button.get('id')]) {
|
|
2043 this.enableButton(_button);
|
|
2044 this.selectButton(_button);
|
|
2045 } else {
|
|
2046 if (disabled) {
|
|
2047 this.disableButton(_button);
|
|
2048 } else {
|
|
2049 this.enableButton(_button);
|
|
2050 }
|
|
2051 this.deselectButton(_button);
|
|
2052 }
|
|
2053 }
|
|
2054 }
|
|
2055 },
|
|
2056 /**
|
|
2057 * @method destroyButton
|
|
2058 * @description Destroy a button in the toolbar.
|
|
2059 * @param {String/Number} id Destroy a button by it's id or index.
|
|
2060 * @return {Boolean}
|
|
2061 */
|
|
2062 destroyButton: function(id) {
|
|
2063 var button = getButton.call(this, id);
|
|
2064 if (button) {
|
|
2065 var thisID = button.get('id'),
|
|
2066 new_list = [], i = 0,
|
|
2067 len = this._buttonList.length;
|
|
2068
|
|
2069 button.destroy();
|
|
2070
|
|
2071 for (i = 0; i < len; i++) {
|
|
2072 if (this._buttonList[i].get('id') != thisID) {
|
|
2073 new_list[new_list.length]= this._buttonList[i];
|
|
2074 }
|
|
2075 }
|
|
2076
|
|
2077 this._buttonList = new_list;
|
|
2078 } else {
|
|
2079 return false;
|
|
2080 }
|
|
2081 },
|
|
2082 /**
|
|
2083 * @method destroy
|
|
2084 * @description Destroys the toolbar, all of it's elements and objects.
|
|
2085 * @return {Boolean}
|
|
2086 */
|
|
2087 destroy: function() {
|
|
2088 var len = this._configuredButtons.length, j, i;
|
|
2089 for(b = 0; b < len; b++) {
|
|
2090 this.destroyButton(this._configuredButtons[b]);
|
|
2091 }
|
|
2092
|
|
2093 this._configuredButtons = null;
|
|
2094
|
|
2095 this.get('element').innerHTML = '';
|
|
2096 this.get('element').className = '';
|
|
2097 //Brutal Object Destroy
|
|
2098 for (i in this) {
|
|
2099 if (Lang.hasOwnProperty(this, i)) {
|
|
2100 this[i] = null;
|
|
2101 }
|
|
2102 }
|
|
2103 return true;
|
|
2104 },
|
|
2105 /**
|
|
2106 * @method collapse
|
|
2107 * @description Programatically collapse the toolbar.
|
|
2108 * @param {Boolean} collapse True to collapse, false to expand.
|
|
2109 */
|
|
2110 collapse: function(collapse) {
|
|
2111 var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
|
|
2112 if (collapse === false) {
|
|
2113 Dom.removeClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
|
|
2114 if (el[0]) {
|
|
2115 Dom.removeClass(el[0], 'collapsed');
|
|
2116 el[0].title = this.STR_COLLAPSE;
|
|
2117 }
|
|
2118 this.fireEvent('toolbarExpanded', { type: 'toolbarExpanded', target: this });
|
|
2119 } else {
|
|
2120 if (el[0]) {
|
|
2121 Dom.addClass(el[0], 'collapsed');
|
|
2122 el[0].title = this.STR_EXPAND;
|
|
2123 }
|
|
2124 Dom.addClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
|
|
2125 this.fireEvent('toolbarCollapsed', { type: 'toolbarCollapsed', target: this });
|
|
2126 }
|
|
2127 },
|
|
2128 /**
|
|
2129 * @method toString
|
|
2130 * @description Returns a string representing the toolbar.
|
|
2131 * @return {String}
|
|
2132 */
|
|
2133 toString: function() {
|
|
2134 return 'Toolbar (#' + this.get('element').id + ') with ' + this._buttonList.length + ' buttons.';
|
|
2135 }
|
|
2136 });
|
|
2137 /**
|
|
2138 * @event buttonClick
|
|
2139 * @param {Object} o The object passed to this handler is the button config used to create the button.
|
|
2140 * @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.
|
|
2141 * @type YAHOO.util.CustomEvent
|
|
2142 */
|
|
2143 /**
|
|
2144 * @event valueClick
|
|
2145 * @param {Object} o The object passed to this handler is the button config used to create the button.
|
|
2146 * @description This is a special dynamic event that is created and dispatched based on the value property
|
|
2147 * of the button config. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
2148 * Example:
|
|
2149 * <code><pre>
|
|
2150 * buttons : [
|
|
2151 * { type: 'button', value: 'test', value: 'testButton' }
|
|
2152 * ]</pre>
|
|
2153 * </code>
|
|
2154 * With the valueClick event you could subscribe to this buttons click event with this:
|
|
2155 * tbar.in('testButtonClick', function() { alert('test button clicked'); })
|
|
2156 * @type YAHOO.util.CustomEvent
|
|
2157 */
|
|
2158 /**
|
|
2159 * @event toolbarExpanded
|
|
2160 * @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.
|
|
2161 * @type YAHOO.util.CustomEvent
|
|
2162 */
|
|
2163 /**
|
|
2164 * @event toolbarCollapsed
|
|
2165 * @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.
|
|
2166 * @type YAHOO.util.CustomEvent
|
|
2167 */
|
|
2168 })();
|
|
2169 /**
|
|
2170 * @module editor
|
|
2171 * @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>
|
|
2172 * @namespace YAHOO.widget
|
|
2173 * @requires yahoo, dom, element, event, toolbar
|
|
2174 * @optional animation, container_core, resize, dragdrop
|
|
2175 */
|
|
2176
|
|
2177 (function() {
|
|
2178 var Dom = YAHOO.util.Dom,
|
|
2179 Event = YAHOO.util.Event,
|
|
2180 Lang = YAHOO.lang,
|
|
2181 Toolbar = YAHOO.widget.Toolbar;
|
|
2182
|
|
2183 /**
|
|
2184 * 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.
|
|
2185 * @constructor
|
|
2186 * @class SimpleEditor
|
|
2187 * @extends YAHOO.util.Element
|
|
2188 * @param {String/HTMLElement} el The textarea element to turn into an editor.
|
|
2189 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
2190 */
|
|
2191
|
|
2192 YAHOO.widget.SimpleEditor = function(el, attrs) {
|
|
2193 YAHOO.log('SimpleEditor Initalizing', 'info', 'SimpleEditor');
|
|
2194
|
|
2195 var o = {};
|
|
2196 if (Lang.isObject(el) && (!el.tagName) && !attrs) {
|
|
2197 Lang.augmentObject(o, el); //Break the config reference
|
|
2198 el = document.createElement('textarea');
|
|
2199 this.DOMReady = true;
|
|
2200 if (o.container) {
|
|
2201 var c = Dom.get(o.container);
|
|
2202 c.appendChild(el);
|
|
2203 } else {
|
|
2204 document.body.appendChild(el);
|
|
2205 }
|
|
2206 } else {
|
|
2207 if (attrs) {
|
|
2208 Lang.augmentObject(o, attrs); //Break the config reference
|
|
2209 }
|
|
2210 }
|
|
2211
|
|
2212 var oConfig = {
|
|
2213 element: null,
|
|
2214 attributes: o
|
|
2215 }, id = null;
|
|
2216
|
|
2217 if (Lang.isString(el)) {
|
|
2218 id = el;
|
|
2219 } else {
|
|
2220 if (oConfig.attributes.id) {
|
|
2221 id = oConfig.attributes.id;
|
|
2222 } else {
|
|
2223 this.DOMReady = true;
|
|
2224 id = Dom.generateId(el);
|
|
2225 }
|
|
2226 }
|
|
2227 oConfig.element = el;
|
|
2228
|
|
2229 var element_cont = document.createElement('DIV');
|
|
2230 oConfig.attributes.element_cont = new YAHOO.util.Element(element_cont, {
|
|
2231 id: id + '_container'
|
|
2232 });
|
|
2233 var div = document.createElement('div');
|
|
2234 Dom.addClass(div, 'first-child');
|
|
2235 oConfig.attributes.element_cont.appendChild(div);
|
|
2236
|
|
2237 if (!oConfig.attributes.toolbar_cont) {
|
|
2238 oConfig.attributes.toolbar_cont = document.createElement('DIV');
|
|
2239 oConfig.attributes.toolbar_cont.id = id + '_toolbar';
|
|
2240 div.appendChild(oConfig.attributes.toolbar_cont);
|
|
2241 }
|
|
2242 var editorWrapper = document.createElement('DIV');
|
|
2243 div.appendChild(editorWrapper);
|
|
2244 oConfig.attributes.editor_wrapper = editorWrapper;
|
|
2245
|
|
2246 YAHOO.widget.SimpleEditor.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
|
|
2247 };
|
|
2248
|
|
2249
|
|
2250 YAHOO.extend(YAHOO.widget.SimpleEditor, YAHOO.util.Element, {
|
|
2251 /**
|
|
2252 * @private
|
|
2253 * @property _resizeConfig
|
|
2254 * @description The default config for the Resize Utility
|
|
2255 */
|
|
2256 _resizeConfig: {
|
|
2257 handles: ['br'],
|
|
2258 autoRatio: true,
|
|
2259 status: true,
|
|
2260 proxy: true,
|
|
2261 useShim: true,
|
|
2262 setSize: false
|
|
2263 },
|
|
2264 /**
|
|
2265 * @private
|
|
2266 * @method _setupResize
|
|
2267 * @description Creates the Resize instance and binds its events.
|
|
2268 */
|
|
2269 _setupResize: function() {
|
|
2270 if (!YAHOO.util.DD || !YAHOO.util.Resize) { return false; }
|
|
2271 if (this.get('resize')) {
|
|
2272 var config = {};
|
|
2273 Lang.augmentObject(config, this._resizeConfig); //Break the config reference
|
|
2274 this.resize = new YAHOO.util.Resize(this.get('element_cont').get('element'), config);
|
|
2275 this.resize.on('resize', function(args) {
|
|
2276 var anim = this.get('animate');
|
|
2277 this.set('animate', false);
|
|
2278 this.set('width', args.width + 'px');
|
|
2279 var h = args.height,
|
|
2280 th = (this.toolbar.get('element').clientHeight + 2),
|
|
2281 dh = 0;
|
|
2282 if (this.dompath) {
|
|
2283 dh = (this.dompath.clientHeight + 1); //It has a 1px top border..
|
|
2284 }
|
|
2285 var newH = (h - th - dh);
|
|
2286 this.set('height', newH + 'px');
|
|
2287 this.get('element_cont').setStyle('height', '');
|
|
2288 this.set('animate', anim);
|
|
2289 }, this, true);
|
|
2290 }
|
|
2291 },
|
|
2292 /**
|
|
2293 * @property resize
|
|
2294 * @description A reference to the Resize object
|
|
2295 * @type YAHOO.util.Resize
|
|
2296 */
|
|
2297 resize: null,
|
|
2298 /**
|
|
2299 * @private
|
|
2300 * @method _setupDD
|
|
2301 * @description Sets up the DD instance used from the 'drag' config option.
|
|
2302 */
|
|
2303 _setupDD: function() {
|
|
2304 if (!YAHOO.util.DD) { return false; }
|
|
2305 if (this.get('drag')) {
|
|
2306 YAHOO.log('Attaching DD instance to Editor', 'info', 'SimpleEditor');
|
|
2307 var d = this.get('drag'),
|
|
2308 dd = YAHOO.util.DD;
|
|
2309 if (d === 'proxy') {
|
|
2310 dd = YAHOO.util.DDProxy;
|
|
2311 }
|
|
2312
|
|
2313 this.dd = new dd(this.get('element_cont').get('element'));
|
|
2314 this.toolbar.addClass('draggable');
|
|
2315 this.dd.setHandleElId(this.toolbar._titlebar);
|
|
2316 }
|
|
2317 },
|
|
2318 /**
|
|
2319 * @property dd
|
|
2320 * @description A reference to the DragDrop object.
|
|
2321 * @type YAHOO.util.DD/YAHOO.util.DDProxy
|
|
2322 */
|
|
2323 dd: null,
|
|
2324 /**
|
|
2325 * @private
|
|
2326 * @property _lastCommand
|
|
2327 * @description A cache of the last execCommand (used for Undo/Redo so they don't mark an undo level)
|
|
2328 * @type String
|
|
2329 */
|
|
2330 _lastCommand: null,
|
|
2331 _undoNodeChange: function() {},
|
|
2332 _storeUndo: function() {},
|
|
2333 /**
|
|
2334 * @private
|
|
2335 * @method _checkKey
|
|
2336 * @description Checks a keyMap entry against a key event
|
|
2337 * @param {Object} k The _keyMap object
|
|
2338 * @param {Event} e The Mouse Event
|
|
2339 * @return {Boolean}
|
|
2340 */
|
|
2341 _checkKey: function(k, e) {
|
|
2342 var ret = false;
|
|
2343 if ((e.keyCode === k.key)) {
|
|
2344 if (k.mods && (k.mods.length > 0)) {
|
|
2345 var val = 0;
|
|
2346 for (var i = 0; i < k.mods.length; i++) {
|
|
2347 if (this.browser.mac) {
|
|
2348 if (k.mods[i] == 'ctrl') {
|
|
2349 k.mods[i] = 'meta';
|
|
2350 }
|
|
2351 }
|
|
2352 if (e[k.mods[i] + 'Key'] === true) {
|
|
2353 val++;
|
|
2354 }
|
|
2355 }
|
|
2356 if (val === k.mods.length) {
|
|
2357 ret = true;
|
|
2358 }
|
|
2359 } else {
|
|
2360 ret = true;
|
|
2361 }
|
|
2362 }
|
|
2363 //YAHOO.log('Shortcut Key Check: (' + k.key + ') return: ' + ret, 'info', 'SimpleEditor');
|
|
2364 return ret;
|
|
2365 },
|
|
2366 /**
|
|
2367 * @private
|
|
2368 * @property _keyMap
|
|
2369 * @description Named key maps for various actions in the Editor. Example: <code>CLOSE_WINDOW: { key: 87, mods: ['shift', 'ctrl'] }</code>.
|
|
2370 * 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.
|
|
2371 * @type {Object/Mixed}
|
|
2372 */
|
|
2373 _keyMap: {
|
|
2374 SELECT_ALL: {
|
|
2375 key: 65, //A key
|
|
2376 mods: ['ctrl']
|
|
2377 },
|
|
2378 CLOSE_WINDOW: {
|
|
2379 key: 87, //W key
|
|
2380 mods: ['shift', 'ctrl']
|
|
2381 },
|
|
2382 FOCUS_TOOLBAR: {
|
|
2383 key: 27,
|
|
2384 mods: ['shift']
|
|
2385 },
|
|
2386 FOCUS_AFTER: {
|
|
2387 key: 27
|
|
2388 },
|
|
2389 FONT_SIZE_UP: {
|
|
2390 key: 38,
|
|
2391 mods: ['shift', 'ctrl']
|
|
2392 },
|
|
2393 FONT_SIZE_DOWN: {
|
|
2394 key: 40,
|
|
2395 mods: ['shift', 'ctrl']
|
|
2396 },
|
|
2397 CREATE_LINK: {
|
|
2398 key: 76,
|
|
2399 mods: ['shift', 'ctrl']
|
|
2400 },
|
|
2401 BOLD: {
|
|
2402 key: 66,
|
|
2403 mods: ['shift', 'ctrl']
|
|
2404 },
|
|
2405 ITALIC: {
|
|
2406 key: 73,
|
|
2407 mods: ['shift', 'ctrl']
|
|
2408 },
|
|
2409 UNDERLINE: {
|
|
2410 key: 85,
|
|
2411 mods: ['shift', 'ctrl']
|
|
2412 },
|
|
2413 UNDO: {
|
|
2414 key: 90,
|
|
2415 mods: ['ctrl']
|
|
2416 },
|
|
2417 REDO: {
|
|
2418 key: 90,
|
|
2419 mods: ['shift', 'ctrl']
|
|
2420 },
|
|
2421 JUSTIFY_LEFT: {
|
|
2422 key: 219,
|
|
2423 mods: ['shift', 'ctrl']
|
|
2424 },
|
|
2425 JUSTIFY_CENTER: {
|
|
2426 key: 220,
|
|
2427 mods: ['shift', 'ctrl']
|
|
2428 },
|
|
2429 JUSTIFY_RIGHT: {
|
|
2430 key: 221,
|
|
2431 mods: ['shift', 'ctrl']
|
|
2432 }
|
|
2433 },
|
|
2434 /**
|
|
2435 * @private
|
|
2436 * @method _cleanClassName
|
|
2437 * @description Makes a useable classname from dynamic data, by dropping it to lowercase and replacing spaces with -'s.
|
|
2438 * @param {String} str The classname to clean up
|
|
2439 * @return {String}
|
|
2440 */
|
|
2441 _cleanClassName: function(str) {
|
|
2442 return str.replace(/ /g, '-').toLowerCase();
|
|
2443 },
|
|
2444 /**
|
|
2445 * @property _textarea
|
|
2446 * @description Flag to determine if we are using a textarea or an HTML Node.
|
|
2447 * @type Boolean
|
|
2448 */
|
|
2449 _textarea: null,
|
|
2450 /**
|
|
2451 * @property _docType
|
|
2452 * @description The DOCTYPE to use in the editable container.
|
|
2453 * @type String
|
|
2454 */
|
|
2455 _docType: '<!DOCTYPE HTML PUBLIC "-/'+'/W3C/'+'/DTD HTML 4.01/'+'/EN" "http:/'+'/www.w3.org/TR/html4/strict.dtd">',
|
|
2456 /**
|
|
2457 * @property editorDirty
|
|
2458 * @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.
|
|
2459 * @type Boolean
|
|
2460 */
|
|
2461 editorDirty: null,
|
|
2462 /**
|
|
2463 * @property _defaultCSS
|
|
2464 * @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' }
|
|
2465 * @type String
|
|
2466 */
|
|
2467 _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; }',
|
|
2468 /**
|
|
2469 * @property _defaultToolbar
|
|
2470 * @private
|
|
2471 * @description Default toolbar config.
|
|
2472 * @type Object
|
|
2473 */
|
|
2474 _defaultToolbar: null,
|
|
2475 /**
|
|
2476 * @property _lastButton
|
|
2477 * @private
|
|
2478 * @description The last button pressed, so we don't disable it.
|
|
2479 * @type Object
|
|
2480 */
|
|
2481 _lastButton: null,
|
|
2482 /**
|
|
2483 * @property _baseHREF
|
|
2484 * @private
|
|
2485 * @description The base location of the editable page (this page) so that relative paths for image work.
|
|
2486 * @type String
|
|
2487 */
|
|
2488 _baseHREF: function() {
|
|
2489 var href = document.location.href;
|
|
2490 if (href.indexOf('?') !== -1) { //Remove the query string
|
|
2491 href = href.substring(0, href.indexOf('?'));
|
|
2492 }
|
|
2493 href = href.substring(0, href.lastIndexOf('/')) + '/';
|
|
2494 return href;
|
|
2495 }(),
|
|
2496 /**
|
|
2497 * @property _lastImage
|
|
2498 * @private
|
|
2499 * @description Safari reference for the last image selected (for styling as selected).
|
|
2500 * @type HTMLElement
|
|
2501 */
|
|
2502 _lastImage: null,
|
|
2503 /**
|
|
2504 * @property _blankImageLoaded
|
|
2505 * @private
|
|
2506 * @description Don't load the blank image more than once..
|
|
2507 * @type Boolean
|
|
2508 */
|
|
2509 _blankImageLoaded: null,
|
|
2510 /**
|
|
2511 * @property _fixNodesTimer
|
|
2512 * @private
|
|
2513 * @description Holder for the fixNodes timer
|
|
2514 * @type Date
|
|
2515 */
|
|
2516 _fixNodesTimer: null,
|
|
2517 /**
|
|
2518 * @property _nodeChangeTimer
|
|
2519 * @private
|
|
2520 * @description Holds a reference to the nodeChange setTimeout call
|
|
2521 * @type Number
|
|
2522 */
|
|
2523 _nodeChangeTimer: null,
|
|
2524 /**
|
|
2525 * @property _nodeChangeDelayTimer
|
|
2526 * @private
|
|
2527 * @description Holds a reference to the nodeChangeDelay setTimeout call
|
|
2528 * @type Number
|
|
2529 */
|
|
2530 _nodeChangeDelayTimer: null,
|
|
2531 /**
|
|
2532 * @property _lastNodeChangeEvent
|
|
2533 * @private
|
|
2534 * @description Flag to determine the last event that fired a node change
|
|
2535 * @type Event
|
|
2536 */
|
|
2537 _lastNodeChangeEvent: null,
|
|
2538 /**
|
|
2539 * @property _lastNodeChange
|
|
2540 * @private
|
|
2541 * @description Flag to determine when the last node change was fired
|
|
2542 * @type Date
|
|
2543 */
|
|
2544 _lastNodeChange: 0,
|
|
2545 /**
|
|
2546 * @property _rendered
|
|
2547 * @private
|
|
2548 * @description Flag to determine if editor has been rendered or not
|
|
2549 * @type Boolean
|
|
2550 */
|
|
2551 _rendered: null,
|
|
2552 /**
|
|
2553 * @property DOMReady
|
|
2554 * @private
|
|
2555 * @description Flag to determine if DOM is ready or not
|
|
2556 * @type Boolean
|
|
2557 */
|
|
2558 DOMReady: null,
|
|
2559 /**
|
|
2560 * @property _selection
|
|
2561 * @private
|
|
2562 * @description Holder for caching iframe selections
|
|
2563 * @type Object
|
|
2564 */
|
|
2565 _selection: null,
|
|
2566 /**
|
|
2567 * @property _mask
|
|
2568 * @private
|
|
2569 * @description DOM Element holder for the editor Mask when disabled
|
|
2570 * @type Object
|
|
2571 */
|
|
2572 _mask: null,
|
|
2573 /**
|
|
2574 * @property _showingHiddenElements
|
|
2575 * @private
|
|
2576 * @description Status of the hidden elements button
|
|
2577 * @type Boolean
|
|
2578 */
|
|
2579 _showingHiddenElements: null,
|
|
2580 /**
|
|
2581 * @property currentWindow
|
|
2582 * @description A reference to the currently open EditorWindow
|
|
2583 * @type Object
|
|
2584 */
|
|
2585 currentWindow: null,
|
|
2586 /**
|
|
2587 * @property currentEvent
|
|
2588 * @description A reference to the current editor event
|
|
2589 * @type Event
|
|
2590 */
|
|
2591 currentEvent: null,
|
|
2592 /**
|
|
2593 * @property operaEvent
|
|
2594 * @private
|
|
2595 * @description setTimeout holder for Opera and Image DoubleClick event..
|
|
2596 * @type Object
|
|
2597 */
|
|
2598 operaEvent: null,
|
|
2599 /**
|
|
2600 * @property currentFont
|
|
2601 * @description A reference to the last font selected from the Toolbar
|
|
2602 * @type HTMLElement
|
|
2603 */
|
|
2604 currentFont: null,
|
|
2605 /**
|
|
2606 * @property currentElement
|
|
2607 * @description A reference to the current working element in the editor
|
|
2608 * @type Array
|
|
2609 */
|
|
2610 currentElement: null,
|
|
2611 /**
|
|
2612 * @property dompath
|
|
2613 * @description A reference to the dompath container for writing the current working dom path to.
|
|
2614 * @type HTMLElement
|
|
2615 */
|
|
2616 dompath: null,
|
|
2617 /**
|
|
2618 * @property beforeElement
|
|
2619 * @description A reference to the H2 placed before the editor for Accessibilty.
|
|
2620 * @type HTMLElement
|
|
2621 */
|
|
2622 beforeElement: null,
|
|
2623 /**
|
|
2624 * @property afterElement
|
|
2625 * @description A reference to the H2 placed after the editor for Accessibilty.
|
|
2626 * @type HTMLElement
|
|
2627 */
|
|
2628 afterElement: null,
|
|
2629 /**
|
|
2630 * @property invalidHTML
|
|
2631 * @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.
|
|
2632 * @type Object
|
|
2633 */
|
|
2634 invalidHTML: {
|
|
2635 form: true,
|
|
2636 input: true,
|
|
2637 button: true,
|
|
2638 select: true,
|
|
2639 link: true,
|
|
2640 html: true,
|
|
2641 body: true,
|
|
2642 iframe: true,
|
|
2643 script: true,
|
|
2644 style: true,
|
|
2645 textarea: true
|
|
2646 },
|
|
2647 /**
|
|
2648 * @property toolbar
|
|
2649 * @description Local property containing the <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a> instance
|
|
2650 * @type <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>
|
|
2651 */
|
|
2652 toolbar: null,
|
|
2653 /**
|
|
2654 * @private
|
|
2655 * @property _contentTimer
|
|
2656 * @description setTimeout holder for documentReady check
|
|
2657 */
|
|
2658 _contentTimer: null,
|
|
2659 /**
|
|
2660 * @private
|
|
2661 * @property _contentTimerMax
|
|
2662 * @description The number of times the loaded content should be checked before giving up. Default: 500
|
|
2663 */
|
|
2664 _contentTimerMax: 500,
|
|
2665 /**
|
|
2666 * @private
|
|
2667 * @property _contentTimerCounter
|
|
2668 * @description Counter to check the number of times the body is polled for before giving up
|
|
2669 * @type Number
|
|
2670 */
|
|
2671 _contentTimerCounter: 0,
|
|
2672 /**
|
|
2673 * @private
|
|
2674 * @property _disabled
|
|
2675 * @description The Toolbar items that should be disabled if there is no selection present in the editor.
|
|
2676 * @type Array
|
|
2677 */
|
|
2678 _disabled: [ 'createlink', 'fontname', 'fontsize', 'forecolor', 'backcolor' ],
|
|
2679 /**
|
|
2680 * @private
|
|
2681 * @property _alwaysDisabled
|
|
2682 * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
|
|
2683 * @type Object
|
|
2684 */
|
|
2685 _alwaysDisabled: { undo: true, redo: true },
|
|
2686 /**
|
|
2687 * @private
|
|
2688 * @property _alwaysEnabled
|
|
2689 * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
|
|
2690 * @type Object
|
|
2691 */
|
|
2692 _alwaysEnabled: { },
|
|
2693 /**
|
|
2694 * @private
|
|
2695 * @property _semantic
|
|
2696 * @description The Toolbar commands that we should attempt to make tags out of instead of using styles.
|
|
2697 * @type Object
|
|
2698 */
|
|
2699 _semantic: { 'bold': true, 'italic' : true, 'underline' : true },
|
|
2700 /**
|
|
2701 * @private
|
|
2702 * @property _tag2cmd
|
|
2703 * @description A tag map of HTML tags to convert to the different types of commands so we can select the proper toolbar button.
|
|
2704 * @type Object
|
|
2705 */
|
|
2706 _tag2cmd: {
|
|
2707 'b': 'bold',
|
|
2708 'strong': 'bold',
|
|
2709 'i': 'italic',
|
|
2710 'em': 'italic',
|
|
2711 'u': 'underline',
|
|
2712 'sup': 'superscript',
|
|
2713 'sub': 'subscript',
|
|
2714 'img': 'insertimage',
|
|
2715 'a' : 'createlink',
|
|
2716 'ul' : 'insertunorderedlist',
|
|
2717 'ol' : 'insertorderedlist'
|
|
2718 },
|
|
2719
|
|
2720 /**
|
|
2721 * @private _createIframe
|
|
2722 * @description Creates the DOM and YUI Element for the iFrame editor area.
|
|
2723 * @param {String} id The string ID to prefix the iframe with
|
|
2724 * @return {Object} iFrame object
|
|
2725 */
|
|
2726 _createIframe: function() {
|
|
2727 var ifrmDom = document.createElement('iframe');
|
|
2728 ifrmDom.id = this.get('id') + '_editor';
|
|
2729 var config = {
|
|
2730 border: '0',
|
|
2731 frameBorder: '0',
|
|
2732 marginWidth: '0',
|
|
2733 marginHeight: '0',
|
|
2734 leftMargin: '0',
|
|
2735 topMargin: '0',
|
|
2736 allowTransparency: 'true',
|
|
2737 width: '100%'
|
|
2738 };
|
|
2739 if (this.get('autoHeight')) {
|
|
2740 config.scrolling = 'no';
|
|
2741 }
|
|
2742 for (var i in config) {
|
|
2743 if (Lang.hasOwnProperty(config, i)) {
|
|
2744 ifrmDom.setAttribute(i, config[i]);
|
|
2745 }
|
|
2746 }
|
|
2747 var isrc = 'javascript:;';
|
|
2748 if (this.browser.ie) {
|
|
2749 //isrc = 'about:blank';
|
|
2750 //TODO - Check this, I have changed it before..
|
|
2751 isrc = 'javascript:false;';
|
|
2752 }
|
|
2753 ifrmDom.setAttribute('src', isrc);
|
|
2754 var ifrm = new YAHOO.util.Element(ifrmDom);
|
|
2755 ifrm.setStyle('visibility', 'hidden');
|
|
2756 return ifrm;
|
|
2757 },
|
|
2758 /**
|
|
2759 * @private _isElement
|
|
2760 * @description Checks to see if an Element reference is a valid one and has a certain tag type
|
|
2761 * @param {HTMLElement} el The element to check
|
|
2762 * @param {String} tag The tag that the element needs to be
|
|
2763 * @return {Boolean}
|
|
2764 */
|
|
2765 _isElement: function(el, tag) {
|
|
2766 if (el && el.tagName && (el.tagName.toLowerCase() == tag)) {
|
|
2767 return true;
|
|
2768 }
|
|
2769 if (el && el.getAttribute && (el.getAttribute('tag') == tag)) {
|
|
2770 return true;
|
|
2771 }
|
|
2772 return false;
|
|
2773 },
|
|
2774 /**
|
|
2775 * @private _hasParent
|
|
2776 * @description Checks to see if an Element reference or one of it's parents is a valid one and has a certain tag type
|
|
2777 * @param {HTMLElement} el The element to check
|
|
2778 * @param {String} tag The tag that the element needs to be
|
|
2779 * @return HTMLElement
|
|
2780 */
|
|
2781 _hasParent: function(el, tag) {
|
|
2782 if (!el || !el.parentNode) {
|
|
2783 return false;
|
|
2784 }
|
|
2785
|
|
2786 while (el.parentNode) {
|
|
2787 if (this._isElement(el, tag)) {
|
|
2788 return el;
|
|
2789 }
|
|
2790 if (el.parentNode) {
|
|
2791 el = el.parentNode;
|
|
2792 } else {
|
|
2793 return false;
|
|
2794 }
|
|
2795 }
|
|
2796 return false;
|
|
2797 },
|
|
2798 /**
|
|
2799 * @private
|
|
2800 * @method _getDoc
|
|
2801 * @description Get the Document of the IFRAME
|
|
2802 * @return {Object}
|
|
2803 */
|
|
2804 _getDoc: function() {
|
|
2805 var value = false;
|
|
2806 try {
|
|
2807 if (this.get('iframe').get('element').contentWindow.document) {
|
|
2808 value = this.get('iframe').get('element').contentWindow.document;
|
|
2809 return value;
|
|
2810 }
|
|
2811 } catch (e) {
|
|
2812 return false;
|
|
2813 }
|
|
2814 },
|
|
2815 /**
|
|
2816 * @private
|
|
2817 * @method _getWindow
|
|
2818 * @description Get the Window of the IFRAME
|
|
2819 * @return {Object}
|
|
2820 */
|
|
2821 _getWindow: function() {
|
|
2822 return this.get('iframe').get('element').contentWindow;
|
|
2823 },
|
|
2824 /**
|
|
2825 * @method focus
|
|
2826 * @description Attempt to set the focus of the iframes window.
|
|
2827 */
|
|
2828 focus: function() {
|
|
2829 this._getWindow().focus();
|
|
2830 },
|
|
2831 /**
|
|
2832 * @private
|
|
2833 * @depreciated - This should not be used, moved to this.focus();
|
|
2834 * @method _focusWindow
|
|
2835 * @description Attempt to set the focus of the iframes window.
|
|
2836 */
|
|
2837 _focusWindow: function() {
|
|
2838 YAHOO.log('_focusWindow: depreciated in favor of this.focus()', 'warn', 'Editor');
|
|
2839 this.focus();
|
|
2840 },
|
|
2841 /**
|
|
2842 * @private
|
|
2843 * @method _hasSelection
|
|
2844 * @description Determines if there is a selection in the editor document.
|
|
2845 * @return {Boolean}
|
|
2846 */
|
|
2847 _hasSelection: function() {
|
|
2848 var sel = this._getSelection();
|
|
2849 var range = this._getRange();
|
|
2850 var hasSel = false;
|
|
2851
|
|
2852 if (!sel || !range) {
|
|
2853 return hasSel;
|
|
2854 }
|
|
2855
|
|
2856 //Internet Explorer
|
|
2857 if (this.browser.ie || this.browser.opera) {
|
|
2858 if (range.text) {
|
|
2859 hasSel = true;
|
|
2860 }
|
|
2861 if (range.html) {
|
|
2862 hasSel = true;
|
|
2863 }
|
|
2864 } else {
|
|
2865 if (this.browser.webkit) {
|
|
2866 if (sel+'' !== '') {
|
|
2867 hasSel = true;
|
|
2868 }
|
|
2869 } else {
|
|
2870 if (sel && (sel.toString() !== '') && (sel !== undefined)) {
|
|
2871 hasSel = true;
|
|
2872 }
|
|
2873 }
|
|
2874 }
|
|
2875 return hasSel;
|
|
2876 },
|
|
2877 /**
|
|
2878 * @private
|
|
2879 * @method _getSelection
|
|
2880 * @description Handles the different selection objects across the A-Grade list.
|
|
2881 * @return {Object} Selection Object
|
|
2882 */
|
|
2883 _getSelection: function() {
|
|
2884 var _sel = null;
|
|
2885 if (this._getDoc() && this._getWindow()) {
|
|
2886 if (this._getDoc().selection) {
|
|
2887 _sel = this._getDoc().selection;
|
|
2888 } else {
|
|
2889 _sel = this._getWindow().getSelection();
|
|
2890 }
|
|
2891 //Handle Safari's lack of Selection Object
|
|
2892 if (this.browser.webkit) {
|
|
2893 if (_sel.baseNode) {
|
|
2894 this._selection = {};
|
|
2895 this._selection.baseNode = _sel.baseNode;
|
|
2896 this._selection.baseOffset = _sel.baseOffset;
|
|
2897 this._selection.extentNode = _sel.extentNode;
|
|
2898 this._selection.extentOffset = _sel.extentOffset;
|
|
2899 } else if (this._selection !== null) {
|
|
2900 _sel = this._getWindow().getSelection();
|
|
2901 _sel.setBaseAndExtent(
|
|
2902 this._selection.baseNode,
|
|
2903 this._selection.baseOffset,
|
|
2904 this._selection.extentNode,
|
|
2905 this._selection.extentOffset);
|
|
2906 this._selection = null;
|
|
2907 }
|
|
2908 }
|
|
2909 }
|
|
2910 return _sel;
|
|
2911 },
|
|
2912 /**
|
|
2913 * @private
|
|
2914 * @method _selectNode
|
|
2915 * @description Places the highlight around a given node
|
|
2916 * @param {HTMLElement} node The node to select
|
|
2917 */
|
|
2918 _selectNode: function(node, collapse) {
|
|
2919 if (!node) {
|
|
2920 return false;
|
|
2921 }
|
|
2922 var sel = this._getSelection(),
|
|
2923 range = null;
|
|
2924
|
|
2925 if (this.browser.ie) {
|
|
2926 try { //IE freaks out here sometimes..
|
|
2927 range = this._getDoc().body.createTextRange();
|
|
2928 range.moveToElementText(node);
|
|
2929 range.select();
|
|
2930 } catch (e) {
|
|
2931 YAHOO.log('IE failed to select element: ' + node.tagName, 'warn', 'SimpleEditor');
|
|
2932 }
|
|
2933 } else if (this.browser.webkit) {
|
|
2934 if (collapse) {
|
|
2935 sel.setBaseAndExtent(node, 1, node, node.innerText.length);
|
|
2936 } else {
|
|
2937 sel.setBaseAndExtent(node, 0, node, node.innerText.length);
|
|
2938 }
|
|
2939 } else if (this.browser.opera) {
|
|
2940 sel = this._getWindow().getSelection();
|
|
2941 range = this._getDoc().createRange();
|
|
2942 range.selectNode(node);
|
|
2943 sel.removeAllRanges();
|
|
2944 sel.addRange(range);
|
|
2945 } else {
|
|
2946 range = this._getDoc().createRange();
|
|
2947 range.selectNodeContents(node);
|
|
2948 sel.removeAllRanges();
|
|
2949 sel.addRange(range);
|
|
2950 }
|
|
2951 //TODO - Check Performance
|
|
2952 this.nodeChange();
|
|
2953 },
|
|
2954 /**
|
|
2955 * @private
|
|
2956 * @method _getRange
|
|
2957 * @description Handles the different range objects across the A-Grade list.
|
|
2958 * @return {Object} Range Object
|
|
2959 */
|
|
2960 _getRange: function() {
|
|
2961 var sel = this._getSelection();
|
|
2962
|
|
2963 if (sel === null) {
|
|
2964 return null;
|
|
2965 }
|
|
2966
|
|
2967 if (this.browser.webkit && !sel.getRangeAt) {
|
|
2968 var _range = this._getDoc().createRange();
|
|
2969 try {
|
|
2970 _range.setStart(sel.anchorNode, sel.anchorOffset);
|
|
2971 _range.setEnd(sel.focusNode, sel.focusOffset);
|
|
2972 } catch (e) {
|
|
2973 _range = this._getWindow().getSelection()+'';
|
|
2974 }
|
|
2975 return _range;
|
|
2976 }
|
|
2977
|
|
2978 if (this.browser.ie || this.browser.opera) {
|
|
2979 try {
|
|
2980 return sel.createRange();
|
|
2981 } catch (e2) {
|
|
2982 return null;
|
|
2983 }
|
|
2984 }
|
|
2985
|
|
2986 if (sel.rangeCount > 0) {
|
|
2987 return sel.getRangeAt(0);
|
|
2988 }
|
|
2989 return null;
|
|
2990 },
|
|
2991 /**
|
|
2992 * @private
|
|
2993 * @method _setDesignMode
|
|
2994 * @description Sets the designMode property of the iFrame document's body.
|
|
2995 * @param {String} state This should be either on or off
|
|
2996 */
|
|
2997 _setDesignMode: function(state) {
|
|
2998 if (this.get('setDesignMode')) {
|
|
2999 try {
|
|
3000 this._getDoc().designMode = ((state.toLowerCase() == 'off') ? 'off' : 'on');
|
|
3001 } catch(e) { }
|
|
3002 }
|
|
3003 },
|
|
3004 /**
|
|
3005 * @private
|
|
3006 * @method _toggleDesignMode
|
|
3007 * @description Toggles the designMode property of the iFrame document on and off.
|
|
3008 * @return {String} The state that it was set to.
|
|
3009 */
|
|
3010 _toggleDesignMode: function() {
|
|
3011 YAHOO.log('It is not recommended to use this method and it will be depreciated.', 'warn', 'SimpleEditor');
|
|
3012 var _dMode = this._getDoc().designMode,
|
|
3013 _state = ((_dMode.toLowerCase() == 'on') ? 'off' : 'on');
|
|
3014 this._setDesignMode(_state);
|
|
3015 return _state;
|
|
3016 },
|
|
3017 /**
|
|
3018 * @private
|
|
3019 * @property _focused
|
|
3020 * @description Holder for trapping focus/blur state and prevent double events
|
|
3021 * @type Boolean
|
|
3022 */
|
|
3023 _focused: null,
|
|
3024 /**
|
|
3025 * @private
|
|
3026 * @method _handleFocus
|
|
3027 * @description Handles the focus of the iframe. Note, this is window focus event, not an Editor focus event.
|
|
3028 * @param {Event} e The DOM Event
|
|
3029 */
|
|
3030 _handleFocus: function(e) {
|
|
3031 if (!this._focused) {
|
|
3032 //YAHOO.log('Editor Window Focused', 'info', 'SimpleEditor');
|
|
3033 this._focused = true;
|
|
3034 this.fireEvent('editorWindowFocus', { type: 'editorWindowFocus', target: this });
|
|
3035 }
|
|
3036 },
|
|
3037 /**
|
|
3038 * @private
|
|
3039 * @method _handleBlur
|
|
3040 * @description Handles the blur of the iframe. Note, this is window blur event, not an Editor blur event.
|
|
3041 * @param {Event} e The DOM Event
|
|
3042 */
|
|
3043 _handleBlur: function(e) {
|
|
3044 if (this._focused) {
|
|
3045 //YAHOO.log('Editor Window Blurred', 'info', 'SimpleEditor');
|
|
3046 this._focused = false;
|
|
3047 this.fireEvent('editorWindowBlur', { type: 'editorWindowBlur', target: this });
|
|
3048 }
|
|
3049 },
|
|
3050 /**
|
|
3051 * @private
|
|
3052 * @method _initEditorEvents
|
|
3053 * @description This method sets up the listeners on the Editors document.
|
|
3054 */
|
|
3055 _initEditorEvents: function() {
|
|
3056 //Setup Listeners on iFrame
|
|
3057 var doc = this._getDoc(),
|
|
3058 win = this._getWindow();
|
|
3059
|
|
3060 Event.on(doc, 'mouseup', this._handleMouseUp, this, true);
|
|
3061 Event.on(doc, 'mousedown', this._handleMouseDown, this, true);
|
|
3062 Event.on(doc, 'click', this._handleClick, this, true);
|
|
3063 Event.on(doc, 'dblclick', this._handleDoubleClick, this, true);
|
|
3064 Event.on(doc, 'keypress', this._handleKeyPress, this, true);
|
|
3065 Event.on(doc, 'keyup', this._handleKeyUp, this, true);
|
|
3066 Event.on(doc, 'keydown', this._handleKeyDown, this, true);
|
|
3067 /* TODO -- Everyone but Opera works here..
|
|
3068 Event.on(doc, 'paste', function() {
|
|
3069 YAHOO.log('PASTE', 'info', 'SimpleEditor');
|
|
3070 }, this, true);
|
|
3071 */
|
|
3072
|
|
3073 //Focus and blur..
|
|
3074 Event.on(win, 'focus', this._handleFocus, this, true);
|
|
3075 Event.on(win, 'blur', this._handleBlur, this, true);
|
|
3076 },
|
|
3077 /**
|
|
3078 * @private
|
|
3079 * @method _removeEditorEvents
|
|
3080 * @description This method removes the listeners on the Editors document (for disabling).
|
|
3081 */
|
|
3082 _removeEditorEvents: function() {
|
|
3083 //Remove Listeners on iFrame
|
|
3084 var doc = this._getDoc(),
|
|
3085 win = this._getWindow();
|
|
3086
|
|
3087 Event.removeListener(doc, 'mouseup', this._handleMouseUp, this, true);
|
|
3088 Event.removeListener(doc, 'mousedown', this._handleMouseDown, this, true);
|
|
3089 Event.removeListener(doc, 'click', this._handleClick, this, true);
|
|
3090 Event.removeListener(doc, 'dblclick', this._handleDoubleClick, this, true);
|
|
3091 Event.removeListener(doc, 'keypress', this._handleKeyPress, this, true);
|
|
3092 Event.removeListener(doc, 'keyup', this._handleKeyUp, this, true);
|
|
3093 Event.removeListener(doc, 'keydown', this._handleKeyDown, this, true);
|
|
3094
|
|
3095 //Focus and blur..
|
|
3096 Event.removeListener(win, 'focus', this._handleFocus, this, true);
|
|
3097 Event.removeListener(win, 'blur', this._handleBlur, this, true);
|
|
3098 },
|
|
3099 _fixWebkitDivs: function() {
|
|
3100 if (this.browser.webkit) {
|
|
3101 var divs = this._getDoc().body.getElementsByTagName('div');
|
|
3102 Dom.addClass(divs, 'yui-wk-div');
|
|
3103 }
|
|
3104 },
|
|
3105 /**
|
|
3106 * @private
|
|
3107 * @method _initEditor
|
|
3108 * @param {Boolean} raw Don't add events.
|
|
3109 * @description This method is fired from _checkLoaded when the document is ready. It turns on designMode and set's up the listeners.
|
|
3110 */
|
|
3111 _initEditor: function(raw) {
|
|
3112 if (this._editorInit) {
|
|
3113 return;
|
|
3114 }
|
|
3115 this._editorInit = true;
|
|
3116 if (this.browser.ie) {
|
|
3117 this._getDoc().body.style.margin = '0';
|
|
3118 }
|
|
3119 if (!this.get('disabled')) {
|
|
3120 this._setDesignMode('on');
|
|
3121 this._contentTimerCounter = 0;
|
|
3122 }
|
|
3123 if (!this._getDoc().body) {
|
|
3124 YAHOO.log('Body is null, check again', 'error', 'SimpleEditor');
|
|
3125 this._contentTimerCounter = 0;
|
|
3126 this._editorInit = false;
|
|
3127 this._checkLoaded();
|
|
3128 return false;
|
|
3129 }
|
|
3130
|
|
3131 YAHOO.log('editorLoaded', 'info', 'SimpleEditor');
|
|
3132 if (!raw) {
|
|
3133 this.toolbar.on('buttonClick', this._handleToolbarClick, this, true);
|
|
3134 }
|
|
3135 if (!this.get('disabled')) {
|
|
3136 this._initEditorEvents();
|
|
3137 this.toolbar.set('disabled', false);
|
|
3138 }
|
|
3139
|
|
3140 if (raw) {
|
|
3141 this.fireEvent('editorContentReloaded', { type: 'editorreloaded', target: this });
|
|
3142 } else {
|
|
3143 this.fireEvent('editorContentLoaded', { type: 'editorLoaded', target: this });
|
|
3144 }
|
|
3145 this._fixWebkitDivs();
|
|
3146 if (this.get('dompath')) {
|
|
3147 YAHOO.log('Delayed DomPath write', 'info', 'SimpleEditor');
|
|
3148 var self = this;
|
|
3149 setTimeout(function() {
|
|
3150 self._writeDomPath.call(self);
|
|
3151 self._setupResize.call(self);
|
|
3152 }, 150);
|
|
3153 }
|
|
3154 var br = [];
|
|
3155 for (var i in this.browser) {
|
|
3156 if (this.browser[i]) {
|
|
3157 br.push(i);
|
|
3158 }
|
|
3159 }
|
|
3160 if (this.get('ptags')) {
|
|
3161 br.push('ptags');
|
|
3162 }
|
|
3163 Dom.addClass(this._getDoc().body, br.join(' '));
|
|
3164 this.nodeChange(true);
|
|
3165 },
|
|
3166 /**
|
|
3167 * @private
|
|
3168 * @method _checkLoaded
|
|
3169 * @param {Boolean} raw Don't add events.
|
|
3170 * @description Called from a setTimeout loop to check if the iframes body.onload event has fired, then it will init the editor.
|
|
3171 */
|
|
3172 _checkLoaded: function(raw) {
|
|
3173 this._editorInit = false;
|
|
3174 this._contentTimerCounter++;
|
|
3175 if (this._contentTimer) {
|
|
3176 clearTimeout(this._contentTimer);
|
|
3177 }
|
|
3178 if (this._contentTimerCounter > this._contentTimerMax) {
|
|
3179 YAHOO.log('ERROR: Body Did Not load', 'error', 'SimpleEditor');
|
|
3180 return false;
|
|
3181 }
|
|
3182 var init = false;
|
|
3183 try {
|
|
3184 if (this._getDoc() && this._getDoc().body) {
|
|
3185 if (this.browser.ie) {
|
|
3186 if (this._getDoc().body.readyState == 'complete') {
|
|
3187 init = true;
|
|
3188 }
|
|
3189 } else {
|
|
3190 if (this._getDoc().body._rteLoaded === true) {
|
|
3191 init = true;
|
|
3192 }
|
|
3193 }
|
|
3194 }
|
|
3195 } catch (e) {
|
|
3196 init = false;
|
|
3197 YAHOO.log('checking body (e)' + e, 'error', 'SimpleEditor');
|
|
3198 }
|
|
3199
|
|
3200 if (init === true) {
|
|
3201 //The onload event has fired, clean up after ourselves and fire the _initEditor method
|
|
3202 YAHOO.log('Firing _initEditor', 'info', 'SimpleEditor');
|
|
3203 this._initEditor(raw);
|
|
3204 } else {
|
|
3205 var self = this;
|
|
3206 this._contentTimer = setTimeout(function() {
|
|
3207 self._checkLoaded.call(self, raw);
|
|
3208 }, 20);
|
|
3209 }
|
|
3210 },
|
|
3211 /**
|
|
3212 * @private
|
|
3213 * @method _setInitialContent
|
|
3214 * @param {Boolean} raw Don't add events.
|
|
3215 * @description This method will open the iframes content document and write the textareas value into it, then start the body.onload checking.
|
|
3216 */
|
|
3217 _setInitialContent: function(raw) {
|
|
3218 YAHOO.log('Populating editor body with contents of the text area', 'info', 'SimpleEditor');
|
|
3219
|
|
3220 var value = ((this._textarea) ? this.get('element').value : this.get('element').innerHTML),
|
|
3221 doc = null;
|
|
3222
|
|
3223 if (value === '') {
|
|
3224 value = '<br>';
|
|
3225 }
|
|
3226
|
|
3227 var html = Lang.substitute(this.get('html'), {
|
|
3228 TITLE: this.STR_TITLE,
|
|
3229 CONTENT: this._cleanIncomingHTML(value),
|
|
3230 CSS: this.get('css'),
|
|
3231 HIDDEN_CSS: ((this.get('hiddencss')) ? this.get('hiddencss') : '/* No Hidden CSS */'),
|
|
3232 EXTRA_CSS: ((this.get('extracss')) ? this.get('extracss') : '/* No Extra CSS */')
|
|
3233 }),
|
|
3234 check = true;
|
|
3235
|
|
3236 html = html.replace(/RIGHT_BRACKET/gi, '{');
|
|
3237 html = html.replace(/LEFT_BRACKET/gi, '}');
|
|
3238
|
|
3239 if (document.compatMode != 'BackCompat') {
|
|
3240 YAHOO.log('Adding Doctype to editable area', 'info', 'SimpleEditor');
|
|
3241 html = this._docType + "\n" + html;
|
|
3242 } else {
|
|
3243 YAHOO.log('DocType skipped because we are in BackCompat Mode.', 'warn', 'SimpleEditor');
|
|
3244 }
|
|
3245
|
|
3246 if (this.browser.ie || this.browser.webkit || this.browser.opera || (navigator.userAgent.indexOf('Firefox/1.5') != -1)) {
|
|
3247 //Firefox 1.5 doesn't like setting designMode on an document created with a data url
|
|
3248 try {
|
|
3249 //Adobe AIR Code
|
|
3250 if (this.browser.air) {
|
|
3251 doc = this._getDoc().implementation.createHTMLDocument();
|
|
3252 var origDoc = this._getDoc();
|
|
3253 origDoc.open();
|
|
3254 origDoc.close();
|
|
3255 doc.open();
|
|
3256 doc.write(html);
|
|
3257 doc.close();
|
|
3258 var node = origDoc.importNode(doc.getElementsByTagName("html")[0], true);
|
|
3259 origDoc.replaceChild(node, origDoc.getElementsByTagName("html")[0]);
|
|
3260 origDoc.body._rteLoaded = true;
|
|
3261 } else {
|
|
3262 doc = this._getDoc();
|
|
3263 doc.open();
|
|
3264 doc.write(html);
|
|
3265 doc.close();
|
|
3266 }
|
|
3267 } catch (e) {
|
|
3268 YAHOO.log('Setting doc failed.. (_setInitialContent)', 'error', 'SimpleEditor');
|
|
3269 //Safari will only be here if we are hidden
|
|
3270 check = false;
|
|
3271 }
|
|
3272 } else {
|
|
3273 //This keeps Firefox 2 from writing the iframe to history preserving the back buttons functionality
|
|
3274 this.get('iframe').get('element').src = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
|
|
3275 }
|
|
3276 this.get('iframe').setStyle('visibility', '');
|
|
3277 if (check) {
|
|
3278 this._checkLoaded(raw);
|
|
3279 }
|
|
3280 },
|
|
3281 /**
|
|
3282 * @private
|
|
3283 * @method _setMarkupType
|
|
3284 * @param {String} action The action to take. Possible values are: css, default or semantic
|
|
3285 * @description This method will turn on/off the useCSS execCommand.
|
|
3286 */
|
|
3287 _setMarkupType: function(action) {
|
|
3288 switch (this.get('markup')) {
|
|
3289 case 'css':
|
|
3290 this._setEditorStyle(true);
|
|
3291 break;
|
|
3292 case 'default':
|
|
3293 this._setEditorStyle(false);
|
|
3294 break;
|
|
3295 case 'semantic':
|
|
3296 case 'xhtml':
|
|
3297 if (this._semantic[action]) {
|
|
3298 this._setEditorStyle(false);
|
|
3299 } else {
|
|
3300 this._setEditorStyle(true);
|
|
3301 }
|
|
3302 break;
|
|
3303 }
|
|
3304 },
|
|
3305 /**
|
|
3306 * Set the editor to use CSS instead of HTML
|
|
3307 * @param {Booleen} stat True/False
|
|
3308 */
|
|
3309 _setEditorStyle: function(stat) {
|
|
3310 try {
|
|
3311 this._getDoc().execCommand('useCSS', false, !stat);
|
|
3312 } catch (ex) {
|
|
3313 }
|
|
3314 },
|
|
3315 /**
|
|
3316 * @private
|
|
3317 * @method _getSelectedElement
|
|
3318 * @description This method will attempt to locate the element that was last interacted with, either via selection, location or event.
|
|
3319 * @return {HTMLElement} The currently selected element.
|
|
3320 */
|
|
3321 _getSelectedElement: function() {
|
|
3322 var doc = this._getDoc(),
|
|
3323 range = null,
|
|
3324 sel = null,
|
|
3325 elm = null,
|
|
3326 check = true;
|
|
3327
|
|
3328 if (this.browser.ie) {
|
|
3329 this.currentEvent = this._getWindow().event; //Event utility assumes window.event, so we need to reset it to this._getWindow().event;
|
|
3330 range = this._getRange();
|
|
3331 if (range) {
|
|
3332 elm = range.item ? range.item(0) : range.parentElement();
|
|
3333 if (this._hasSelection()) {
|
|
3334 //TODO
|
|
3335 //WTF.. Why can't I get an element reference here?!??!
|
|
3336 }
|
|
3337 if (elm === doc.body) {
|
|
3338 elm = null;
|
|
3339 }
|
|
3340 }
|
|
3341 if ((this.currentEvent !== null) && (this.currentEvent.keyCode === 0)) {
|
|
3342 elm = Event.getTarget(this.currentEvent);
|
|
3343 }
|
|
3344 } else {
|
|
3345 sel = this._getSelection();
|
|
3346 range = this._getRange();
|
|
3347
|
|
3348 if (!sel || !range) {
|
|
3349 return null;
|
|
3350 }
|
|
3351 //TODO
|
|
3352 if (!this._hasSelection() && this.browser.webkit3) {
|
|
3353 //check = false;
|
|
3354 }
|
|
3355 if (this.browser.gecko) {
|
|
3356 //Added in 2.6.0
|
|
3357 if (range.startContainer) {
|
|
3358 if (range.startContainer.nodeType === 3) {
|
|
3359 elm = range.startContainer.parentNode;
|
|
3360 } else if (range.startContainer.nodeType === 1) {
|
|
3361 elm = range.startContainer;
|
|
3362 }
|
|
3363 //Added in 2.7.0
|
|
3364 if (this.currentEvent) {
|
|
3365 var tar = Event.getTarget(this.currentEvent);
|
|
3366 if (!this._isElement(tar, 'html')) {
|
|
3367 if (elm !== tar) {
|
|
3368 elm = tar;
|
|
3369 }
|
|
3370 }
|
|
3371 }
|
|
3372 }
|
|
3373 }
|
|
3374
|
|
3375 if (check) {
|
|
3376 if (sel.anchorNode && (sel.anchorNode.nodeType == 3)) {
|
|
3377 if (sel.anchorNode.parentNode) { //next check parentNode
|
|
3378 elm = sel.anchorNode.parentNode;
|
|
3379 }
|
|
3380 if (sel.anchorNode.nextSibling != sel.focusNode.nextSibling) {
|
|
3381 elm = sel.anchorNode.nextSibling;
|
|
3382 }
|
|
3383 }
|
|
3384 if (this._isElement(elm, 'br')) {
|
|
3385 elm = null;
|
|
3386 }
|
|
3387 if (!elm) {
|
|
3388 elm = range.commonAncestorContainer;
|
|
3389 if (!range.collapsed) {
|
|
3390 if (range.startContainer == range.endContainer) {
|
|
3391 if (range.startOffset - range.endOffset < 2) {
|
|
3392 if (range.startContainer.hasChildNodes()) {
|
|
3393 elm = range.startContainer.childNodes[range.startOffset];
|
|
3394 }
|
|
3395 }
|
|
3396 }
|
|
3397 }
|
|
3398 }
|
|
3399 }
|
|
3400 }
|
|
3401
|
|
3402 if (this.currentEvent !== null) {
|
|
3403 try {
|
|
3404 switch (this.currentEvent.type) {
|
|
3405 case 'click':
|
|
3406 case 'mousedown':
|
|
3407 case 'mouseup':
|
|
3408 if (this.browser.webkit) {
|
|
3409 elm = Event.getTarget(this.currentEvent);
|
|
3410 }
|
|
3411 break;
|
|
3412 default:
|
|
3413 //Do nothing
|
|
3414 break;
|
|
3415 }
|
|
3416 } catch (e) {
|
|
3417 YAHOO.log('Firefox 1.5 errors here: ' + e, 'error', 'SimpleEditor');
|
|
3418 }
|
|
3419 } else if ((this.currentElement && this.currentElement[0]) && (!this.browser.ie)) {
|
|
3420 //TODO is this still needed?
|
|
3421 //elm = this.currentElement[0];
|
|
3422 }
|
|
3423
|
|
3424
|
|
3425 if (this.browser.opera || this.browser.webkit) {
|
|
3426 if (this.currentEvent && !elm) {
|
|
3427 elm = YAHOO.util.Event.getTarget(this.currentEvent);
|
|
3428 }
|
|
3429 }
|
|
3430 if (!elm || !elm.tagName) {
|
|
3431 elm = doc.body;
|
|
3432 }
|
|
3433 if (this._isElement(elm, 'html')) {
|
|
3434 //Safari sometimes gives us the HTML node back..
|
|
3435 elm = doc.body;
|
|
3436 }
|
|
3437 if (this._isElement(elm, 'body')) {
|
|
3438 //make sure that body means this body not the parent..
|
|
3439 elm = doc.body;
|
|
3440 }
|
|
3441 if (elm && !elm.parentNode) { //Not in document
|
|
3442 elm = doc.body;
|
|
3443 }
|
|
3444 if (elm === undefined) {
|
|
3445 elm = null;
|
|
3446 }
|
|
3447 return elm;
|
|
3448 },
|
|
3449 /**
|
|
3450 * @private
|
|
3451 * @method _getDomPath
|
|
3452 * @description This method will attempt to build the DOM path from the currently selected element.
|
|
3453 * @param HTMLElement el The element to start with, if not provided _getSelectedElement is used
|
|
3454 * @return {Array} An array of node references that will create the DOM Path.
|
|
3455 */
|
|
3456 _getDomPath: function(el) {
|
|
3457 if (!el) {
|
|
3458 el = this._getSelectedElement();
|
|
3459 }
|
|
3460 var domPath = [];
|
|
3461 while (el !== null) {
|
|
3462 if (el.ownerDocument != this._getDoc()) {
|
|
3463 el = null;
|
|
3464 break;
|
|
3465 }
|
|
3466 //Check to see if we get el.nodeName and nodeType
|
|
3467 if (el.nodeName && el.nodeType && (el.nodeType == 1)) {
|
|
3468 domPath[domPath.length] = el;
|
|
3469 }
|
|
3470
|
|
3471 if (this._isElement(el, 'body')) {
|
|
3472 break;
|
|
3473 }
|
|
3474
|
|
3475 el = el.parentNode;
|
|
3476 }
|
|
3477 if (domPath.length === 0) {
|
|
3478 if (this._getDoc() && this._getDoc().body) {
|
|
3479 domPath[0] = this._getDoc().body;
|
|
3480 }
|
|
3481 }
|
|
3482 return domPath.reverse();
|
|
3483 },
|
|
3484 /**
|
|
3485 * @private
|
|
3486 * @method _writeDomPath
|
|
3487 * @description Write the current DOM path out to the dompath container below the editor.
|
|
3488 */
|
|
3489 _writeDomPath: function() {
|
|
3490 var path = this._getDomPath(),
|
|
3491 pathArr = [],
|
|
3492 classPath = '',
|
|
3493 pathStr = '';
|
|
3494
|
|
3495 for (var i = 0; i < path.length; i++) {
|
|
3496 var tag = path[i].tagName.toLowerCase();
|
|
3497 if ((tag == 'ol') && (path[i].type)) {
|
|
3498 tag += ':' + path[i].type;
|
|
3499 }
|
|
3500 if (Dom.hasClass(path[i], 'yui-tag')) {
|
|
3501 tag = path[i].getAttribute('tag');
|
|
3502 }
|
|
3503 if ((this.get('markup') == 'semantic') || (this.get('markup') == 'xhtml')) {
|
|
3504 switch (tag) {
|
|
3505 case 'b': tag = 'strong'; break;
|
|
3506 case 'i': tag = 'em'; break;
|
|
3507 }
|
|
3508 }
|
|
3509 if (!Dom.hasClass(path[i], 'yui-non')) {
|
|
3510 if (Dom.hasClass(path[i], 'yui-tag')) {
|
|
3511 pathStr = tag;
|
|
3512 } else {
|
|
3513 classPath = ((path[i].className !== '') ? '.' + path[i].className.replace(/ /g, '.') : '');
|
|
3514 if ((classPath.indexOf('yui') != -1) || (classPath.toLowerCase().indexOf('apple-style-span') != -1)) {
|
|
3515 classPath = '';
|
|
3516 }
|
|
3517 pathStr = tag + ((path[i].id) ? '#' + path[i].id : '') + classPath;
|
|
3518 }
|
|
3519 switch (tag) {
|
|
3520 case 'body':
|
|
3521 pathStr = 'body';
|
|
3522 break;
|
|
3523 case 'a':
|
|
3524 if (path[i].getAttribute('href', 2)) {
|
|
3525 pathStr += ':' + path[i].getAttribute('href', 2).replace('mailto:', '').replace('http:/'+'/', '').replace('https:/'+'/', ''); //May need to add others here ftp
|
|
3526 }
|
|
3527 break;
|
|
3528 case 'img':
|
|
3529 var h = path[i].height;
|
|
3530 var w = path[i].width;
|
|
3531 if (path[i].style.height) {
|
|
3532 h = parseInt(path[i].style.height, 10);
|
|
3533 }
|
|
3534 if (path[i].style.width) {
|
|
3535 w = parseInt(path[i].style.width, 10);
|
|
3536 }
|
|
3537 pathStr += '(' + w + 'x' + h + ')';
|
|
3538 break;
|
|
3539 }
|
|
3540
|
|
3541 if (pathStr.length > 10) {
|
|
3542 pathStr = '<span title="' + pathStr + '">' + pathStr.substring(0, 10) + '...' + '</span>';
|
|
3543 } else {
|
|
3544 pathStr = '<span title="' + pathStr + '">' + pathStr + '</span>';
|
|
3545 }
|
|
3546 pathArr[pathArr.length] = pathStr;
|
|
3547 }
|
|
3548 }
|
|
3549 var str = pathArr.join(' ' + this.SEP_DOMPATH + ' ');
|
|
3550 //Prevent flickering
|
|
3551 if (this.dompath.innerHTML != str) {
|
|
3552 this.dompath.innerHTML = str;
|
|
3553 }
|
|
3554 },
|
|
3555 /**
|
|
3556 * @private
|
|
3557 * @method _fixNodes
|
|
3558 * @description Fix href and imgs as well as remove invalid HTML.
|
|
3559 */
|
|
3560 _fixNodes: function() {
|
|
3561 try {
|
|
3562 var doc = this._getDoc(),
|
|
3563 els = [];
|
|
3564
|
|
3565 for (var v in this.invalidHTML) {
|
|
3566 if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
|
|
3567 if (v.toLowerCase() != 'span') {
|
|
3568 var tags = doc.body.getElementsByTagName(v);
|
|
3569 if (tags.length) {
|
|
3570 for (var i = 0; i < tags.length; i++) {
|
|
3571 els.push(tags[i]);
|
|
3572 }
|
|
3573 }
|
|
3574 }
|
|
3575 }
|
|
3576 }
|
|
3577 for (var h = 0; h < els.length; h++) {
|
|
3578 if (els[h].parentNode) {
|
|
3579 if (Lang.isObject(this.invalidHTML[els[h].tagName.toLowerCase()]) && this.invalidHTML[els[h].tagName.toLowerCase()].keepContents) {
|
|
3580 this._swapEl(els[h], 'span', function(el) {
|
|
3581 el.className = 'yui-non';
|
|
3582 });
|
|
3583 } else {
|
|
3584 els[h].parentNode.removeChild(els[h]);
|
|
3585 }
|
|
3586 }
|
|
3587 }
|
|
3588 var imgs = this._getDoc().getElementsByTagName('img');
|
|
3589 Dom.addClass(imgs, 'yui-img');
|
|
3590 } catch(e) {}
|
|
3591 },
|
|
3592 /**
|
|
3593 * @private
|
|
3594 * @method _isNonEditable
|
|
3595 * @param Event ev The Dom event being checked
|
|
3596 * @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.
|
|
3597 * 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
|
|
3598 * disable and enable the Editor's toolbar based on the noedit state.
|
|
3599 * @return Boolean
|
|
3600 */
|
|
3601 _isNonEditable: function(ev) {
|
|
3602 if (this.get('allowNoEdit')) {
|
|
3603 var el = Event.getTarget(ev);
|
|
3604 if (this._isElement(el, 'html')) {
|
|
3605 el = null;
|
|
3606 }
|
|
3607 var path = this._getDomPath(el);
|
|
3608 for (var i = (path.length - 1); i > -1; i--) {
|
|
3609 if (Dom.hasClass(path[i], this.CLASS_NOEDIT)) {
|
|
3610 //if (this.toolbar.get('disabled') === false) {
|
|
3611 // this.toolbar.set('disabled', true);
|
|
3612 //}
|
|
3613 try {
|
|
3614 this._getDoc().execCommand('enableObjectResizing', false, 'false');
|
|
3615 } catch (e) {}
|
|
3616 this.nodeChange();
|
|
3617 Event.stopEvent(ev);
|
|
3618 YAHOO.log('CLASS_NOEDIT found in DOM Path, stopping event', 'info', 'SimpleEditor');
|
|
3619 return true;
|
|
3620 }
|
|
3621 }
|
|
3622 //if (this.toolbar.get('disabled') === true) {
|
|
3623 //Should only happen once..
|
|
3624 //this.toolbar.set('disabled', false);
|
|
3625 try {
|
|
3626 this._getDoc().execCommand('enableObjectResizing', false, 'true');
|
|
3627 } catch (e2) {}
|
|
3628 //}
|
|
3629 }
|
|
3630 return false;
|
|
3631 },
|
|
3632 /**
|
|
3633 * @private
|
|
3634 * @method _setCurrentEvent
|
|
3635 * @param {Event} ev The event to cache
|
|
3636 * @description Sets the current event property
|
|
3637 */
|
|
3638 _setCurrentEvent: function(ev) {
|
|
3639 this.currentEvent = ev;
|
|
3640 },
|
|
3641 /**
|
|
3642 * @private
|
|
3643 * @method _handleClick
|
|
3644 * @param {Event} ev The event we are working on.
|
|
3645 * @description Handles all click events inside the iFrame document.
|
|
3646 */
|
|
3647 _handleClick: function(ev) {
|
|
3648 var ret = this.fireEvent('beforeEditorClick', { type: 'beforeEditorClick', target: this, ev: ev });
|
|
3649 if (ret === false) {
|
|
3650 return false;
|
|
3651 }
|
|
3652 if (this._isNonEditable(ev)) {
|
|
3653 return false;
|
|
3654 }
|
|
3655 this._setCurrentEvent(ev);
|
|
3656 if (this.currentWindow) {
|
|
3657 this.closeWindow();
|
|
3658 }
|
|
3659 if (this.currentWindow) {
|
|
3660 this.closeWindow();
|
|
3661 }
|
|
3662 if (this.browser.webkit) {
|
|
3663 var tar =Event.getTarget(ev);
|
|
3664 if (this._isElement(tar, 'a') || this._isElement(tar.parentNode, 'a')) {
|
|
3665 Event.stopEvent(ev);
|
|
3666 this.nodeChange();
|
|
3667 }
|
|
3668 } else {
|
|
3669 this.nodeChange();
|
|
3670 }
|
|
3671 this.fireEvent('editorClick', { type: 'editorClick', target: this, ev: ev });
|
|
3672 },
|
|
3673 /**
|
|
3674 * @private
|
|
3675 * @method _handleMouseUp
|
|
3676 * @param {Event} ev The event we are working on.
|
|
3677 * @description Handles all mouseup events inside the iFrame document.
|
|
3678 */
|
|
3679 _handleMouseUp: function(ev) {
|
|
3680 var ret = this.fireEvent('beforeEditorMouseUp', { type: 'beforeEditorMouseUp', target: this, ev: ev });
|
|
3681 if (ret === false) {
|
|
3682 return false;
|
|
3683 }
|
|
3684 if (this._isNonEditable(ev)) {
|
|
3685 return false;
|
|
3686 }
|
|
3687 //Don't set current event for mouseup.
|
|
3688 //It get's fired after a menu is closed and gives up a bogus event to work with
|
|
3689 //this._setCurrentEvent(ev);
|
|
3690 var self = this;
|
|
3691 if (this.browser.opera) {
|
|
3692 /*
|
|
3693 * @knownissue Opera appears to stop the MouseDown, Click and DoubleClick events on an image inside of a document with designMode on..
|
|
3694 * @browser Opera
|
|
3695 * @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.
|
|
3696 */
|
|
3697 var sel = Event.getTarget(ev);
|
|
3698 if (this._isElement(sel, 'img')) {
|
|
3699 this.nodeChange();
|
|
3700 if (this.operaEvent) {
|
|
3701 clearTimeout(this.operaEvent);
|
|
3702 this.operaEvent = null;
|
|
3703 this._handleDoubleClick(ev);
|
|
3704 } else {
|
|
3705 this.operaEvent = window.setTimeout(function() {
|
|
3706 self.operaEvent = false;
|
|
3707 }, 700);
|
|
3708 }
|
|
3709 }
|
|
3710 }
|
|
3711 //This will stop Safari from selecting the entire document if you select all the text in the editor
|
|
3712 if (this.browser.webkit || this.browser.opera) {
|
|
3713 if (this.browser.webkit) {
|
|
3714 Event.stopEvent(ev);
|
|
3715 }
|
|
3716 }
|
|
3717 this.nodeChange();
|
|
3718 this.fireEvent('editorMouseUp', { type: 'editorMouseUp', target: this, ev: ev });
|
|
3719 },
|
|
3720 /**
|
|
3721 * @private
|
|
3722 * @method _handleMouseDown
|
|
3723 * @param {Event} ev The event we are working on.
|
|
3724 * @description Handles all mousedown events inside the iFrame document.
|
|
3725 */
|
|
3726 _handleMouseDown: function(ev) {
|
|
3727 var ret = this.fireEvent('beforeEditorMouseDown', { type: 'beforeEditorMouseDown', 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.browser.webkit && this._hasSelection()) {
|
|
3737 var _sel = this._getSelection();
|
|
3738 if (!this.browser.webkit3) {
|
|
3739 _sel.collapse(true);
|
|
3740 } else {
|
|
3741 _sel.collapseToStart();
|
|
3742 }
|
|
3743 }
|
|
3744 if (this.browser.webkit && this._lastImage) {
|
|
3745 Dom.removeClass(this._lastImage, 'selected');
|
|
3746 this._lastImage = null;
|
|
3747 }
|
|
3748 if (this._isElement(sel, 'img') || this._isElement(sel, 'a')) {
|
|
3749 if (this.browser.webkit) {
|
|
3750 Event.stopEvent(ev);
|
|
3751 if (this._isElement(sel, 'img')) {
|
|
3752 Dom.addClass(sel, 'selected');
|
|
3753 this._lastImage = sel;
|
|
3754 }
|
|
3755 }
|
|
3756 if (this.currentWindow) {
|
|
3757 this.closeWindow();
|
|
3758 }
|
|
3759 this.nodeChange();
|
|
3760 }
|
|
3761 this.fireEvent('editorMouseDown', { type: 'editorMouseDown', target: this, ev: ev });
|
|
3762 },
|
|
3763 /**
|
|
3764 * @private
|
|
3765 * @method _handleDoubleClick
|
|
3766 * @param {Event} ev The event we are working on.
|
|
3767 * @description Handles all doubleclick events inside the iFrame document.
|
|
3768 */
|
|
3769 _handleDoubleClick: function(ev) {
|
|
3770 var ret = this.fireEvent('beforeEditorDoubleClick', { type: 'beforeEditorDoubleClick', target: this, ev: ev });
|
|
3771 if (ret === false) {
|
|
3772 return false;
|
|
3773 }
|
|
3774 if (this._isNonEditable(ev)) {
|
|
3775 return false;
|
|
3776 }
|
|
3777 this._setCurrentEvent(ev);
|
|
3778 var sel = Event.getTarget(ev);
|
|
3779 if (this._isElement(sel, 'img')) {
|
|
3780 this.currentElement[0] = sel;
|
|
3781 this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
|
|
3782 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
3783 } else if (this._hasParent(sel, 'a')) { //Handle elements inside an a
|
|
3784 this.currentElement[0] = this._hasParent(sel, 'a');
|
|
3785 this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
|
|
3786 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
3787 }
|
|
3788 this.nodeChange();
|
|
3789 this.fireEvent('editorDoubleClick', { type: 'editorDoubleClick', target: this, ev: ev });
|
|
3790 },
|
|
3791 /**
|
|
3792 * @private
|
|
3793 * @method _handleKeyUp
|
|
3794 * @param {Event} ev The event we are working on.
|
|
3795 * @description Handles all keyup events inside the iFrame document.
|
|
3796 */
|
|
3797 _handleKeyUp: function(ev) {
|
|
3798 var ret = this.fireEvent('beforeEditorKeyUp', { type: 'beforeEditorKeyUp', target: this, ev: ev });
|
|
3799 if (ret === false) {
|
|
3800 return false;
|
|
3801 }
|
|
3802 if (this._isNonEditable(ev)) {
|
|
3803 return false;
|
|
3804 }
|
|
3805 this._storeUndo();
|
|
3806 this._setCurrentEvent(ev);
|
|
3807 switch (ev.keyCode) {
|
|
3808 case this._keyMap.SELECT_ALL.key:
|
|
3809 if (this._checkKey(this._keyMap.SELECT_ALL, ev)) {
|
|
3810 this.nodeChange();
|
|
3811 }
|
|
3812 break;
|
|
3813 case 32: //Space Bar
|
|
3814 case 35: //End
|
|
3815 case 36: //Home
|
|
3816 case 37: //Left Arrow
|
|
3817 case 38: //Up Arrow
|
|
3818 case 39: //Right Arrow
|
|
3819 case 40: //Down Arrow
|
|
3820 case 46: //Forward Delete
|
|
3821 case 8: //Delete
|
|
3822 case this._keyMap.CLOSE_WINDOW.key: //W key if window is open
|
|
3823 if ((ev.keyCode == this._keyMap.CLOSE_WINDOW.key) && this.currentWindow) {
|
|
3824 if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) {
|
|
3825 this.closeWindow();
|
|
3826 }
|
|
3827 } else {
|
|
3828 if (!this.browser.ie) {
|
|
3829 if (this._nodeChangeTimer) {
|
|
3830 clearTimeout(this._nodeChangeTimer);
|
|
3831 }
|
|
3832 var self = this;
|
|
3833 this._nodeChangeTimer = setTimeout(function() {
|
|
3834 self._nodeChangeTimer = null;
|
|
3835 self.nodeChange.call(self);
|
|
3836 }, 100);
|
|
3837 } else {
|
|
3838 this.nodeChange();
|
|
3839 }
|
|
3840 this.editorDirty = true;
|
|
3841 }
|
|
3842 break;
|
|
3843 }
|
|
3844 this.fireEvent('editorKeyUp', { type: 'editorKeyUp', target: this, ev: ev });
|
|
3845 },
|
|
3846 /**
|
|
3847 * @private
|
|
3848 * @method _handleKeyPress
|
|
3849 * @param {Event} ev The event we are working on.
|
|
3850 * @description Handles all keypress events inside the iFrame document.
|
|
3851 */
|
|
3852 _handleKeyPress: function(ev) {
|
|
3853 var ret = this.fireEvent('beforeEditorKeyPress', { type: 'beforeEditorKeyPress', target: this, ev: ev });
|
|
3854 if (ret === false) {
|
|
3855 return false;
|
|
3856 }
|
|
3857
|
|
3858 if (this.get('allowNoEdit')) {
|
|
3859 //if (ev && ev.keyCode && ((ev.keyCode == 46) || ev.keyCode == 63272)) {
|
|
3860 if (ev && ev.keyCode && (ev.keyCode == 63272)) {
|
|
3861 //Forward delete key
|
|
3862 YAHOO.log('allowNoEdit is set, forward delete key has been disabled', 'warn', 'SimpleEditor');
|
|
3863 Event.stopEvent(ev);
|
|
3864 }
|
|
3865 }
|
|
3866 if (this._isNonEditable(ev)) {
|
|
3867 return false;
|
|
3868 }
|
|
3869 this._setCurrentEvent(ev);
|
|
3870 this._storeUndo();
|
|
3871 if (this.browser.opera) {
|
|
3872 if (ev.keyCode === 13) {
|
|
3873 var tar = this._getSelectedElement();
|
|
3874 if (!this._isElement(tar, 'li')) {
|
|
3875 this.execCommand('inserthtml', '<br>');
|
|
3876 Event.stopEvent(ev);
|
|
3877 }
|
|
3878 }
|
|
3879 }
|
|
3880 if (this.browser.webkit) {
|
|
3881 if (!this.browser.webkit3) {
|
|
3882 if (ev.keyCode && (ev.keyCode == 122) && (ev.metaKey)) {
|
|
3883 //This is CMD + z (for undo)
|
|
3884 if (this._hasParent(this._getSelectedElement(), 'li')) {
|
|
3885 YAHOO.log('We are in an LI and we found CMD + z, stopping the event', 'warn', 'SimpleEditor');
|
|
3886 Event.stopEvent(ev);
|
|
3887 }
|
|
3888 }
|
|
3889 }
|
|
3890 this._listFix(ev);
|
|
3891 }
|
|
3892 this._fixListDupIds();
|
|
3893 this.fireEvent('editorKeyPress', { type: 'editorKeyPress', target: this, ev: ev });
|
|
3894 },
|
|
3895 /**
|
|
3896 * @private
|
|
3897 * @method _handleKeyDown
|
|
3898 * @param {Event} ev The event we are working on.
|
|
3899 * @description Handles all keydown events inside the iFrame document.
|
|
3900 */
|
|
3901 _handleKeyDown: function(ev) {
|
|
3902 var ret = this.fireEvent('beforeEditorKeyDown', { type: 'beforeEditorKeyDown', target: this, ev: ev });
|
|
3903 if (ret === false) {
|
|
3904 return false;
|
|
3905 }
|
|
3906 var tar = null, _range = null;
|
|
3907 if (this._isNonEditable(ev)) {
|
|
3908 return false;
|
|
3909 }
|
|
3910 this._setCurrentEvent(ev);
|
|
3911 if (this.currentWindow) {
|
|
3912 this.closeWindow();
|
|
3913 }
|
|
3914 if (this.currentWindow) {
|
|
3915 this.closeWindow();
|
|
3916 }
|
|
3917 var doExec = false,
|
|
3918 action = null,
|
|
3919 value = null,
|
|
3920 exec = false;
|
|
3921
|
|
3922 //YAHOO.log('keyCode: ' + ev.keyCode, 'info', 'SimpleEditor');
|
|
3923
|
|
3924 switch (ev.keyCode) {
|
|
3925 case this._keyMap.FOCUS_TOOLBAR.key:
|
|
3926 if (this._checkKey(this._keyMap.FOCUS_TOOLBAR, ev)) {
|
|
3927 var h = this.toolbar.getElementsByTagName('h2')[0];
|
|
3928 if (h && h.firstChild) {
|
|
3929 h.firstChild.focus();
|
|
3930 }
|
|
3931 } else if (this._checkKey(this._keyMap.FOCUS_AFTER, ev)) {
|
|
3932 //Focus After Element - Esc
|
|
3933 this.afterElement.focus();
|
|
3934 }
|
|
3935 Event.stopEvent(ev);
|
|
3936 doExec = false;
|
|
3937 break;
|
|
3938 //case 76: //L
|
|
3939 case this._keyMap.CREATE_LINK.key: //L
|
|
3940 if (this._hasSelection()) {
|
|
3941 if (this._checkKey(this._keyMap.CREATE_LINK, ev)) {
|
|
3942 var makeLink = true;
|
|
3943 if (this.get('limitCommands')) {
|
|
3944 if (!this.toolbar.getButtonByValue('createlink')) {
|
|
3945 YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'SimpleEditor');
|
|
3946 makeLink = false;
|
|
3947 }
|
|
3948 }
|
|
3949 if (makeLink) {
|
|
3950 this.execCommand('createlink', '');
|
|
3951 this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
|
|
3952 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
3953 doExec = false;
|
|
3954 }
|
|
3955 }
|
|
3956 }
|
|
3957 break;
|
|
3958 //case 90: //Z
|
|
3959 case this._keyMap.UNDO.key:
|
|
3960 case this._keyMap.REDO.key:
|
|
3961 if (this._checkKey(this._keyMap.REDO, ev)) {
|
|
3962 action = 'redo';
|
|
3963 doExec = true;
|
|
3964 } else if (this._checkKey(this._keyMap.UNDO, ev)) {
|
|
3965 action = 'undo';
|
|
3966 doExec = true;
|
|
3967 }
|
|
3968 break;
|
|
3969 //case 66: //B
|
|
3970 case this._keyMap.BOLD.key:
|
|
3971 if (this._checkKey(this._keyMap.BOLD, ev)) {
|
|
3972 action = 'bold';
|
|
3973 doExec = true;
|
|
3974 }
|
|
3975 break;
|
|
3976 case this._keyMap.FONT_SIZE_UP.key:
|
|
3977 case this._keyMap.FONT_SIZE_DOWN.key:
|
|
3978 var uk = false, dk = false;
|
|
3979 if (this._checkKey(this._keyMap.FONT_SIZE_UP, ev)) {
|
|
3980 uk = true;
|
|
3981 }
|
|
3982 if (this._checkKey(this._keyMap.FONT_SIZE_DOWN, ev)) {
|
|
3983 dk = true;
|
|
3984 }
|
|
3985 if (uk || dk) {
|
|
3986 var fs_button = this.toolbar.getButtonByValue('fontsize'),
|
|
3987 label = parseInt(fs_button.get('label'), 10),
|
|
3988 newValue = (label + 1);
|
|
3989
|
|
3990 if (dk) {
|
|
3991 newValue = (label - 1);
|
|
3992 }
|
|
3993
|
|
3994 action = 'fontsize';
|
|
3995 value = newValue + 'px';
|
|
3996 doExec = true;
|
|
3997 }
|
|
3998 break;
|
|
3999 //case 73: //I
|
|
4000 case this._keyMap.ITALIC.key:
|
|
4001 if (this._checkKey(this._keyMap.ITALIC, ev)) {
|
|
4002 action = 'italic';
|
|
4003 doExec = true;
|
|
4004 }
|
|
4005 break;
|
|
4006 //case 85: //U
|
|
4007 case this._keyMap.UNDERLINE.key:
|
|
4008 if (this._checkKey(this._keyMap.UNDERLINE, ev)) {
|
|
4009 action = 'underline';
|
|
4010 doExec = true;
|
|
4011 }
|
|
4012 break;
|
|
4013 case 9:
|
|
4014 if (this.browser.ie) {
|
|
4015 //Insert a tab in Internet Explorer
|
|
4016 _range = this._getRange();
|
|
4017 tar = this._getSelectedElement();
|
|
4018 if (!this._isElement(tar, 'li')) {
|
|
4019 if (_range) {
|
|
4020 _range.pasteHTML(' ');
|
|
4021 _range.collapse(false);
|
|
4022 _range.select();
|
|
4023 }
|
|
4024 Event.stopEvent(ev);
|
|
4025 }
|
|
4026 }
|
|
4027 //Firefox 3 code
|
|
4028 if (this.browser.gecko > 1.8) {
|
|
4029 tar = this._getSelectedElement();
|
|
4030 if (this._isElement(tar, 'li')) {
|
|
4031 if (ev.shiftKey) {
|
|
4032 this._getDoc().execCommand('outdent', null, '');
|
|
4033 } else {
|
|
4034 this._getDoc().execCommand('indent', null, '');
|
|
4035 }
|
|
4036
|
|
4037 } else if (!this._hasSelection()) {
|
|
4038 this.execCommand('inserthtml', ' ');
|
|
4039 }
|
|
4040 Event.stopEvent(ev);
|
|
4041 }
|
|
4042 break;
|
|
4043 case 13:
|
|
4044 var p = null, i = 0;
|
|
4045 if (this.get('ptags') && !ev.shiftKey) {
|
|
4046 if (this.browser.gecko) {
|
|
4047 tar = this._getSelectedElement();
|
|
4048 if (!this._hasParent(tar, 'li')) {
|
|
4049 if (this._hasParent(tar, 'p')) {
|
|
4050 p = this._getDoc().createElement('p');
|
|
4051 p.innerHTML = ' ';
|
|
4052 Dom.insertAfter(p, tar);
|
|
4053 this._selectNode(p.firstChild);
|
|
4054 } else if (this._isElement(tar, 'body')) {
|
|
4055 this.execCommand('insertparagraph', null);
|
|
4056 var ps = this._getDoc().body.getElementsByTagName('p');
|
|
4057 for (i = 0; i < ps.length; i++) {
|
|
4058 if (ps[i].getAttribute('_moz_dirty') !== null) {
|
|
4059 p = this._getDoc().createElement('p');
|
|
4060 p.innerHTML = ' ';
|
|
4061 Dom.insertAfter(p, ps[i]);
|
|
4062 this._selectNode(p.firstChild);
|
|
4063 ps[i].removeAttribute('_moz_dirty');
|
|
4064 }
|
|
4065 }
|
|
4066 } else {
|
|
4067 YAHOO.log('Something went wrong with paragraphs, please file a bug!!', 'error', 'SimpleEditor');
|
|
4068 doExec = true;
|
|
4069 action = 'insertparagraph';
|
|
4070 }
|
|
4071 Event.stopEvent(ev);
|
|
4072 }
|
|
4073 }
|
|
4074 if (this.browser.webkit) {
|
|
4075 tar = this._getSelectedElement();
|
|
4076 if (!this._hasParent(tar, 'li')) {
|
|
4077 this.execCommand('insertparagraph', null);
|
|
4078 var divs = this._getDoc().body.getElementsByTagName('div');
|
|
4079 for (i = 0; i < divs.length; i++) {
|
|
4080 if (!Dom.hasClass(divs[i], 'yui-wk-div')) {
|
|
4081 Dom.addClass(divs[i], 'yui-wk-p');
|
|
4082 }
|
|
4083 }
|
|
4084 Event.stopEvent(ev);
|
|
4085 }
|
|
4086 }
|
|
4087 } else {
|
|
4088 if (this.browser.webkit) {
|
|
4089 tar = this._getSelectedElement();
|
|
4090 if (!this._hasParent(tar, 'li')) {
|
|
4091 if (this.browser.webkit4) {
|
|
4092 this.execCommand('insertlinebreak');
|
|
4093 } else {
|
|
4094 this.execCommand('inserthtml', '<var id="yui-br"></var>');
|
|
4095 var holder = this._getDoc().getElementById('yui-br'),
|
|
4096 br = this._getDoc().createElement('br'),
|
|
4097 caret = this._getDoc().createElement('span');
|
|
4098
|
|
4099 holder.parentNode.replaceChild(br, holder);
|
|
4100 caret.className = 'yui-non';
|
|
4101 caret.innerHTML = ' ';
|
|
4102 Dom.insertAfter(caret, br);
|
|
4103 this._selectNode(caret);
|
|
4104 }
|
|
4105 Event.stopEvent(ev);
|
|
4106 }
|
|
4107 }
|
|
4108 if (this.browser.ie) {
|
|
4109 YAHOO.log('Stopping P tags', 'info', 'SimpleEditor');
|
|
4110 //Insert a <br> instead of a <p></p> in Internet Explorer
|
|
4111 _range = this._getRange();
|
|
4112 tar = this._getSelectedElement();
|
|
4113 if (!this._isElement(tar, 'li')) {
|
|
4114 if (_range) {
|
|
4115 _range.pasteHTML('<br>');
|
|
4116 _range.collapse(false);
|
|
4117 _range.select();
|
|
4118 }
|
|
4119 Event.stopEvent(ev);
|
|
4120 }
|
|
4121 }
|
|
4122 }
|
|
4123 break;
|
|
4124 }
|
|
4125 if (this.browser.ie) {
|
|
4126 this._listFix(ev);
|
|
4127 }
|
|
4128 if (doExec && action) {
|
|
4129 this.execCommand(action, value);
|
|
4130 Event.stopEvent(ev);
|
|
4131 this.nodeChange();
|
|
4132 }
|
|
4133 this._storeUndo();
|
|
4134 this.fireEvent('editorKeyDown', { type: 'editorKeyDown', target: this, ev: ev });
|
|
4135 },
|
|
4136 /**
|
|
4137 * @private
|
|
4138 * @property _fixListRunning
|
|
4139 * @type Boolean
|
|
4140 * @description Keeps more than one _fixListDupIds from running at the same time.
|
|
4141 */
|
|
4142 _fixListRunning: null,
|
|
4143 /**
|
|
4144 * @private
|
|
4145 * @method _fixListDupIds
|
|
4146 * @description Some browsers will duplicate the id of an LI when created in designMode.
|
|
4147 * This method will fix the duplicate id issue. However it will only preserve the first element
|
|
4148 * in the document list with the unique id.
|
|
4149 */
|
|
4150 _fixListDupIds: function() {
|
|
4151 if (this._fixListRunning) {
|
|
4152 return false;
|
|
4153 }
|
|
4154 if (this._getDoc()) {
|
|
4155 this._fixListRunning = true;
|
|
4156 var lis = this._getDoc().body.getElementsByTagName('li'),
|
|
4157 i = 0, ids = {};
|
|
4158 for (i = 0; i < lis.length; i++) {
|
|
4159 if (lis[i].id) {
|
|
4160 if (ids[lis[i].id]) {
|
|
4161 lis[i].id = '';
|
|
4162 }
|
|
4163 ids[lis[i].id] = true;
|
|
4164 }
|
|
4165 }
|
|
4166 this._fixListRunning = false;
|
|
4167 }
|
|
4168 },
|
|
4169 /**
|
|
4170 * @private
|
|
4171 * @method _listFix
|
|
4172 * @param {Event} ev The event we are working on.
|
|
4173 * @description Handles the Enter key, Tab Key and Shift + Tab keys for List Items.
|
|
4174 */
|
|
4175 _listFix: function(ev) {
|
|
4176 //YAHOO.log('Lists Fix (' + ev.keyCode + ')', 'info', 'SimpleEditor');
|
|
4177 var testLi = null, par = null, preContent = false, range = null;
|
|
4178 //Enter Key
|
|
4179 if (this.browser.webkit) {
|
|
4180 if (ev.keyCode && (ev.keyCode == 13)) {
|
|
4181 if (this._hasParent(this._getSelectedElement(), 'li')) {
|
|
4182 var tar = this._hasParent(this._getSelectedElement(), 'li');
|
|
4183 if (tar.previousSibling) {
|
|
4184 if (tar.firstChild && (tar.firstChild.length == 1)) {
|
|
4185 this._selectNode(tar);
|
|
4186 }
|
|
4187 }
|
|
4188 }
|
|
4189 }
|
|
4190 }
|
|
4191 //Shift + Tab Key
|
|
4192 if (ev.keyCode && ((!this.browser.webkit3 && (ev.keyCode == 25)) || ((this.browser.webkit3 || !this.browser.webkit) && ((ev.keyCode == 9) && ev.shiftKey)))) {
|
|
4193 testLi = this._getSelectedElement();
|
|
4194 if (this._hasParent(testLi, 'li')) {
|
|
4195 testLi = this._hasParent(testLi, 'li');
|
|
4196 YAHOO.log('We have a SHIFT tab in an LI, reverse it..', 'info', 'SimpleEditor');
|
|
4197 if (this._hasParent(testLi, 'ul') || this._hasParent(testLi, 'ol')) {
|
|
4198 YAHOO.log('We have a double parent, move up a level', 'info', 'SimpleEditor');
|
|
4199 par = this._hasParent(testLi, 'ul');
|
|
4200 if (!par) {
|
|
4201 par = this._hasParent(testLi, 'ol');
|
|
4202 }
|
|
4203 //YAHOO.log(par.previousSibling + ' :: ' + par.previousSibling.innerHTML);
|
|
4204 if (this._isElement(par.previousSibling, 'li')) {
|
|
4205 par.removeChild(testLi);
|
|
4206 par.parentNode.insertBefore(testLi, par.nextSibling);
|
|
4207 if (this.browser.ie) {
|
|
4208 range = this._getDoc().body.createTextRange();
|
|
4209 range.moveToElementText(testLi);
|
|
4210 range.collapse(false);
|
|
4211 range.select();
|
|
4212 }
|
|
4213 if (this.browser.webkit) {
|
|
4214 this._selectNode(testLi.firstChild);
|
|
4215 }
|
|
4216 Event.stopEvent(ev);
|
|
4217 }
|
|
4218 }
|
|
4219 }
|
|
4220 }
|
|
4221 //Tab Key
|
|
4222 if (ev.keyCode && ((ev.keyCode == 9) && (!ev.shiftKey))) {
|
|
4223 YAHOO.log('List Fix - Tab', 'info', 'SimpleEditor');
|
|
4224 var preLi = this._getSelectedElement();
|
|
4225 if (this._hasParent(preLi, 'li')) {
|
|
4226 preContent = this._hasParent(preLi, 'li').innerHTML;
|
|
4227 }
|
|
4228 //YAHOO.log('preLI: ' + preLi.tagName + ' :: ' + preLi.innerHTML);
|
|
4229 if (this.browser.webkit) {
|
|
4230 this._getDoc().execCommand('inserttext', false, '\t');
|
|
4231 }
|
|
4232 testLi = this._getSelectedElement();
|
|
4233 if (this._hasParent(testLi, 'li')) {
|
|
4234 YAHOO.log('We have a tab in an LI', 'info', 'SimpleEditor');
|
|
4235 par = this._hasParent(testLi, 'li');
|
|
4236 YAHOO.log('parLI: ' + par.tagName + ' :: ' + par.innerHTML);
|
|
4237 var newUl = this._getDoc().createElement(par.parentNode.tagName.toLowerCase());
|
|
4238 if (this.browser.webkit) {
|
|
4239 var span = Dom.getElementsByClassName('Apple-tab-span', 'span', par);
|
|
4240 //Remove the span element that Safari puts in
|
|
4241 if (span[0]) {
|
|
4242 par.removeChild(span[0]);
|
|
4243 par.innerHTML = Lang.trim(par.innerHTML);
|
|
4244 //Put the HTML from the LI into this new LI
|
|
4245 if (preContent) {
|
|
4246 par.innerHTML = '<span class="yui-non">' + preContent + '</span> ';
|
|
4247 } else {
|
|
4248 par.innerHTML = '<span class="yui-non"> </span> ';
|
|
4249 }
|
|
4250 }
|
|
4251 } else {
|
|
4252 if (preContent) {
|
|
4253 par.innerHTML = preContent + ' ';
|
|
4254 } else {
|
|
4255 par.innerHTML = ' ';
|
|
4256 }
|
|
4257 }
|
|
4258
|
|
4259 par.parentNode.replaceChild(newUl, par);
|
|
4260 newUl.appendChild(par);
|
|
4261 if (this.browser.webkit) {
|
|
4262 this._getSelection().setBaseAndExtent(par.firstChild, 1, par.firstChild, par.firstChild.innerText.length);
|
|
4263 if (!this.browser.webkit3) {
|
|
4264 par.parentNode.parentNode.style.display = 'list-item';
|
|
4265 setTimeout(function() {
|
|
4266 par.parentNode.parentNode.style.display = 'block';
|
|
4267 }, 1);
|
|
4268 }
|
|
4269 } else if (this.browser.ie) {
|
|
4270 range = this._getDoc().body.createTextRange();
|
|
4271 range.moveToElementText(par);
|
|
4272 range.collapse(false);
|
|
4273 range.select();
|
|
4274 } else {
|
|
4275 this._selectNode(par);
|
|
4276 }
|
|
4277 Event.stopEvent(ev);
|
|
4278 }
|
|
4279 if (this.browser.webkit) {
|
|
4280 Event.stopEvent(ev);
|
|
4281 }
|
|
4282 this.nodeChange();
|
|
4283 }
|
|
4284 },
|
|
4285 /**
|
|
4286 * @method nodeChange
|
|
4287 * @param {Boolean} force Optional paramenter to skip the threshold counter
|
|
4288 * @description Handles setting up the toolbar buttons, getting the Dom path, fixing nodes.
|
|
4289 */
|
|
4290 nodeChange: function(force) {
|
|
4291 var NCself = this;
|
|
4292 this._storeUndo();
|
|
4293 if (this.get('nodeChangeDelay')) {
|
|
4294 this._nodeChangeDelayTimer = window.setTimeout(function() {
|
|
4295 NCself._nodeChangeDelayTimer = null;
|
|
4296 NCself._nodeChange.apply(NCself, arguments);
|
|
4297 }, 0);
|
|
4298 } else {
|
|
4299 this._nodeChange();
|
|
4300 }
|
|
4301 },
|
|
4302 /**
|
|
4303 * @private
|
|
4304 * @method _nodeChange
|
|
4305 * @param {Boolean} force Optional paramenter to skip the threshold counter
|
|
4306 * @description Fired from nodeChange in a setTimeout.
|
|
4307 */
|
|
4308 _nodeChange: function(force) {
|
|
4309 var threshold = parseInt(this.get('nodeChangeThreshold'), 10),
|
|
4310 thisNodeChange = Math.round(new Date().getTime() / 1000),
|
|
4311 self = this;
|
|
4312
|
|
4313 if (force === true) {
|
|
4314 this._lastNodeChange = 0;
|
|
4315 }
|
|
4316
|
|
4317 if ((this._lastNodeChange + threshold) < thisNodeChange) {
|
|
4318 if (this._fixNodesTimer === null) {
|
|
4319 this._fixNodesTimer = window.setTimeout(function() {
|
|
4320 self._fixNodes.call(self);
|
|
4321 self._fixNodesTimer = null;
|
|
4322 }, 0);
|
|
4323 }
|
|
4324 }
|
|
4325 this._lastNodeChange = thisNodeChange;
|
|
4326 if (this.currentEvent) {
|
|
4327 try {
|
|
4328 this._lastNodeChangeEvent = this.currentEvent.type;
|
|
4329 } catch (e) {}
|
|
4330 }
|
|
4331
|
|
4332 var beforeNodeChange = this.fireEvent('beforeNodeChange', { type: 'beforeNodeChange', target: this });
|
|
4333 if (beforeNodeChange === false) {
|
|
4334 return false;
|
|
4335 }
|
|
4336 if (this.get('dompath')) {
|
|
4337 window.setTimeout(function() {
|
|
4338 self._writeDomPath.call(self);
|
|
4339 }, 0);
|
|
4340 }
|
|
4341 //Check to see if we are disabled before continuing
|
|
4342 if (!this.get('disabled')) {
|
|
4343 if (this.STOP_NODE_CHANGE) {
|
|
4344 //Reset this var for next action
|
|
4345 this.STOP_NODE_CHANGE = false;
|
|
4346 return false;
|
|
4347 } else {
|
|
4348 var sel = this._getSelection(),
|
|
4349 range = this._getRange(),
|
|
4350 el = this._getSelectedElement(),
|
|
4351 fn_button = this.toolbar.getButtonByValue('fontname'),
|
|
4352 fs_button = this.toolbar.getButtonByValue('fontsize'),
|
|
4353 undo_button = this.toolbar.getButtonByValue('undo'),
|
|
4354 redo_button = this.toolbar.getButtonByValue('redo');
|
|
4355
|
|
4356 //Handle updating the toolbar with active buttons
|
|
4357 var _ex = {};
|
|
4358 if (this._lastButton) {
|
|
4359 _ex[this._lastButton.id] = true;
|
|
4360 //this._lastButton = null;
|
|
4361 }
|
|
4362 if (!this._isElement(el, 'body')) {
|
|
4363 if (fn_button) {
|
|
4364 _ex[fn_button.get('id')] = true;
|
|
4365 }
|
|
4366 if (fs_button) {
|
|
4367 _ex[fs_button.get('id')] = true;
|
|
4368 }
|
|
4369 }
|
|
4370 if (redo_button) {
|
|
4371 delete _ex[redo_button.get('id')];
|
|
4372 }
|
|
4373 this.toolbar.resetAllButtons(_ex);
|
|
4374
|
|
4375 //Handle disabled buttons
|
|
4376 for (var d = 0; d < this._disabled.length; d++) {
|
|
4377 var _button = this.toolbar.getButtonByValue(this._disabled[d]);
|
|
4378 if (_button && _button.get) {
|
|
4379 if (this._lastButton && (_button.get('id') === this._lastButton.id)) {
|
|
4380 //Skip
|
|
4381 } else {
|
|
4382 if (!this._hasSelection() && !this.get('insert')) {
|
|
4383 switch (this._disabled[d]) {
|
|
4384 case 'fontname':
|
|
4385 case 'fontsize':
|
|
4386 break;
|
|
4387 default:
|
|
4388 //No Selection - disable
|
|
4389 this.toolbar.disableButton(_button);
|
|
4390 }
|
|
4391 } else {
|
|
4392 if (!this._alwaysDisabled[this._disabled[d]]) {
|
|
4393 this.toolbar.enableButton(_button);
|
|
4394 }
|
|
4395 }
|
|
4396 if (!this._alwaysEnabled[this._disabled[d]]) {
|
|
4397 this.toolbar.deselectButton(_button);
|
|
4398 }
|
|
4399 }
|
|
4400 }
|
|
4401 }
|
|
4402 var path = this._getDomPath();
|
|
4403 var tag = null, cmd = null;
|
|
4404 for (var i = 0; i < path.length; i++) {
|
|
4405 tag = path[i].tagName.toLowerCase();
|
|
4406 if (path[i].getAttribute('tag')) {
|
|
4407 tag = path[i].getAttribute('tag').toLowerCase();
|
|
4408 }
|
|
4409 cmd = this._tag2cmd[tag];
|
|
4410 if (cmd === undefined) {
|
|
4411 cmd = [];
|
|
4412 }
|
|
4413 if (!Lang.isArray(cmd)) {
|
|
4414 cmd = [cmd];
|
|
4415 }
|
|
4416
|
|
4417 //Bold and Italic styles
|
|
4418 if (path[i].style.fontWeight.toLowerCase() == 'bold') {
|
|
4419 cmd[cmd.length] = 'bold';
|
|
4420 }
|
|
4421 if (path[i].style.fontStyle.toLowerCase() == 'italic') {
|
|
4422 cmd[cmd.length] = 'italic';
|
|
4423 }
|
|
4424 if (path[i].style.textDecoration.toLowerCase() == 'underline') {
|
|
4425 cmd[cmd.length] = 'underline';
|
|
4426 }
|
|
4427 if (path[i].style.textDecoration.toLowerCase() == 'line-through') {
|
|
4428 cmd[cmd.length] = 'strikethrough';
|
|
4429 }
|
|
4430 if (cmd.length > 0) {
|
|
4431 for (var j = 0; j < cmd.length; j++) {
|
|
4432 this.toolbar.selectButton(cmd[j]);
|
|
4433 this.toolbar.enableButton(cmd[j]);
|
|
4434 }
|
|
4435 }
|
|
4436 //Handle Alignment
|
|
4437 switch (path[i].style.textAlign.toLowerCase()) {
|
|
4438 case 'left':
|
|
4439 case 'right':
|
|
4440 case 'center':
|
|
4441 case 'justify':
|
|
4442 var alignType = path[i].style.textAlign.toLowerCase();
|
|
4443 if (path[i].style.textAlign.toLowerCase() == 'justify') {
|
|
4444 alignType = 'full';
|
|
4445 }
|
|
4446 this.toolbar.selectButton('justify' + alignType);
|
|
4447 this.toolbar.enableButton('justify' + alignType);
|
|
4448 break;
|
|
4449 }
|
|
4450 }
|
|
4451 //After for loop
|
|
4452
|
|
4453 //Reset Font Family and Size to the inital configs
|
|
4454 if (fn_button) {
|
|
4455 var family = fn_button._configs.label._initialConfig.value;
|
|
4456 fn_button.set('label', '<span class="yui-toolbar-fontname-' + this._cleanClassName(family) + '">' + family + '</span>');
|
|
4457 this._updateMenuChecked('fontname', family);
|
|
4458 }
|
|
4459
|
|
4460 if (fs_button) {
|
|
4461 fs_button.set('label', fs_button._configs.label._initialConfig.value);
|
|
4462 }
|
|
4463
|
|
4464 var hd_button = this.toolbar.getButtonByValue('heading');
|
|
4465 if (hd_button) {
|
|
4466 hd_button.set('label', hd_button._configs.label._initialConfig.value);
|
|
4467 this._updateMenuChecked('heading', 'none');
|
|
4468 }
|
|
4469 var img_button = this.toolbar.getButtonByValue('insertimage');
|
|
4470 if (img_button && this.currentWindow && (this.currentWindow.name == 'insertimage')) {
|
|
4471 this.toolbar.disableButton(img_button);
|
|
4472 }
|
|
4473 if (this._lastButton && this._lastButton.isSelected) {
|
|
4474 this.toolbar.deselectButton(this._lastButton.id);
|
|
4475 }
|
|
4476 this._undoNodeChange();
|
|
4477 }
|
|
4478 }
|
|
4479
|
|
4480 this.fireEvent('afterNodeChange', { type: 'afterNodeChange', target: this });
|
|
4481 },
|
|
4482 /**
|
|
4483 * @private
|
|
4484 * @method _updateMenuChecked
|
|
4485 * @param {Object} button The command identifier of the button you want to check
|
|
4486 * @param {String} value The value of the menu item you want to check
|
|
4487 * @param {<a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>} The Toolbar instance the button belongs to (defaults to this.toolbar)
|
|
4488 * @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.
|
|
4489 */
|
|
4490 _updateMenuChecked: function(button, value, tbar) {
|
|
4491 if (!tbar) {
|
|
4492 tbar = this.toolbar;
|
|
4493 }
|
|
4494 var _button = tbar.getButtonByValue(button);
|
|
4495 _button.checkValue(value);
|
|
4496 },
|
|
4497 /**
|
|
4498 * @private
|
|
4499 * @method _handleToolbarClick
|
|
4500 * @param {Event} ev The event that triggered the button click
|
|
4501 * @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.
|
|
4502 */
|
|
4503 _handleToolbarClick: function(ev) {
|
|
4504 var value = '';
|
|
4505 var str = '';
|
|
4506 var cmd = ev.button.value;
|
|
4507 if (ev.button.menucmd) {
|
|
4508 value = cmd;
|
|
4509 cmd = ev.button.menucmd;
|
|
4510 }
|
|
4511 this._lastButton = ev.button;
|
|
4512 if (this.STOP_EXEC_COMMAND) {
|
|
4513 YAHOO.log('execCommand skipped because we found the STOP_EXEC_COMMAND flag set to true', 'warn', 'SimpleEditor');
|
|
4514 YAHOO.log('NOEXEC::execCommand::(' + cmd + '), (' + value + ')', 'warn', 'SimpleEditor');
|
|
4515 this.STOP_EXEC_COMMAND = false;
|
|
4516 return false;
|
|
4517 } else {
|
|
4518 this.execCommand(cmd, value);
|
|
4519 if (!this.browser.webkit) {
|
|
4520 var Fself = this;
|
|
4521 setTimeout(function() {
|
|
4522 Fself.focus.call(Fself);
|
|
4523 }, 5);
|
|
4524 }
|
|
4525 }
|
|
4526 Event.stopEvent(ev);
|
|
4527 },
|
|
4528 /**
|
|
4529 * @private
|
|
4530 * @method _setupAfterElement
|
|
4531 * @description Creates the accessibility h2 header and places it after the iframe in the Dom for navigation.
|
|
4532 */
|
|
4533 _setupAfterElement: function() {
|
|
4534 if (!this.beforeElement) {
|
|
4535 this.beforeElement = document.createElement('h2');
|
|
4536 this.beforeElement.className = 'yui-editor-skipheader';
|
|
4537 this.beforeElement.tabIndex = '-1';
|
|
4538 this.beforeElement.innerHTML = this.STR_BEFORE_EDITOR;
|
|
4539 this.get('element_cont').get('firstChild').insertBefore(this.beforeElement, this.toolbar.get('nextSibling'));
|
|
4540 }
|
|
4541 if (!this.afterElement) {
|
|
4542 this.afterElement = document.createElement('h2');
|
|
4543 this.afterElement.className = 'yui-editor-skipheader';
|
|
4544 this.afterElement.tabIndex = '-1';
|
|
4545 this.afterElement.innerHTML = this.STR_LEAVE_EDITOR;
|
|
4546 this.get('element_cont').get('firstChild').appendChild(this.afterElement);
|
|
4547 }
|
|
4548 },
|
|
4549 /**
|
|
4550 * @private
|
|
4551 * @method _disableEditor
|
|
4552 * @param {Boolean} disabled Pass true to disable, false to enable
|
|
4553 * @description Creates a mask to place over the Editor.
|
|
4554 */
|
|
4555 _disableEditor: function(disabled) {
|
|
4556 var iframe, par, html, height;
|
|
4557 if (!this.get('disabled_iframe')) {
|
|
4558 iframe = this._createIframe();
|
|
4559 iframe.set('id', 'disabled_' + this.get('iframe').get('id'));
|
|
4560 iframe.setStyle('height', '100%');
|
|
4561 iframe.setStyle('display', 'none');
|
|
4562 iframe.setStyle('visibility', 'visible');
|
|
4563 this.set('disabled_iframe', iframe);
|
|
4564 par = this.get('iframe').get('parentNode');
|
|
4565 par.appendChild(iframe.get('element'));
|
|
4566 }
|
|
4567 if (!iframe) {
|
|
4568 iframe = this.get('disabled_iframe');
|
|
4569 }
|
|
4570 if (disabled) {
|
|
4571 this._orgIframe = this.get('iframe');
|
|
4572
|
|
4573 if (this.toolbar) {
|
|
4574 this.toolbar.set('disabled', true);
|
|
4575 }
|
|
4576
|
|
4577 html = this.getEditorHTML();
|
|
4578 height = this.get('iframe').get('offsetHeight');
|
|
4579 iframe.setStyle('visibility', '');
|
|
4580 iframe.setStyle('position', '');
|
|
4581 iframe.setStyle('top', '');
|
|
4582 iframe.setStyle('left', '');
|
|
4583 this._orgIframe.setStyle('visibility', 'hidden');
|
|
4584 this._orgIframe.setStyle('position', 'absolute');
|
|
4585 this._orgIframe.setStyle('top', '-99999px');
|
|
4586 this._orgIframe.setStyle('left', '-99999px');
|
|
4587 this.set('iframe', iframe);
|
|
4588 this._setInitialContent(true);
|
|
4589
|
|
4590 if (!this._mask) {
|
|
4591 this._mask = document.createElement('DIV');
|
|
4592 Dom.addClass(this._mask, 'yui-editor-masked');
|
|
4593 if (this.browser.ie) {
|
|
4594 this._mask.style.height = height + 'px';
|
|
4595 }
|
|
4596 this.get('iframe').get('parentNode').appendChild(this._mask);
|
|
4597 }
|
|
4598 this.on('editorContentReloaded', function() {
|
|
4599 this._getDoc().body._rteLoaded = false;
|
|
4600 this.setEditorHTML(html);
|
|
4601 iframe.setStyle('display', 'block');
|
|
4602 this.unsubscribeAll('editorContentReloaded');
|
|
4603 });
|
|
4604 } else {
|
|
4605 if (this._mask) {
|
|
4606 this._mask.parentNode.removeChild(this._mask);
|
|
4607 this._mask = null;
|
|
4608 if (this.toolbar) {
|
|
4609 this.toolbar.set('disabled', false);
|
|
4610 }
|
|
4611 iframe.setStyle('visibility', 'hidden');
|
|
4612 iframe.setStyle('position', 'absolute');
|
|
4613 iframe.setStyle('top', '-99999px');
|
|
4614 iframe.setStyle('left', '-99999px');
|
|
4615 this._orgIframe.setStyle('visibility', '');
|
|
4616 this._orgIframe.setStyle('position', '');
|
|
4617 this._orgIframe.setStyle('top', '');
|
|
4618 this._orgIframe.setStyle('left', '');
|
|
4619 this.set('iframe', this._orgIframe);
|
|
4620
|
|
4621 this.focus();
|
|
4622 var self = this;
|
|
4623 window.setTimeout(function() {
|
|
4624 self.nodeChange.call(self);
|
|
4625 }, 100);
|
|
4626 }
|
|
4627 }
|
|
4628 },
|
|
4629 /**
|
|
4630 * @property SEP_DOMPATH
|
|
4631 * @description The value to place in between the Dom path items
|
|
4632 * @type String
|
|
4633 */
|
|
4634 SEP_DOMPATH: '<',
|
|
4635 /**
|
|
4636 * @property STR_LEAVE_EDITOR
|
|
4637 * @description The accessibility string for the element after the iFrame
|
|
4638 * @type String
|
|
4639 */
|
|
4640 STR_LEAVE_EDITOR: 'You have left the Rich Text Editor.',
|
|
4641 /**
|
|
4642 * @property STR_BEFORE_EDITOR
|
|
4643 * @description The accessibility string for the element before the iFrame
|
|
4644 * @type String
|
|
4645 */
|
|
4646 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>',
|
|
4647 /**
|
|
4648 * @property STR_TITLE
|
|
4649 * @description The Title of the HTML document that is created in the iFrame
|
|
4650 * @type String
|
|
4651 */
|
|
4652 STR_TITLE: 'Rich Text Area.',
|
|
4653 /**
|
|
4654 * @property STR_IMAGE_HERE
|
|
4655 * @description The text to place in the URL textbox when using the blankimage.
|
|
4656 * @type String
|
|
4657 */
|
|
4658 STR_IMAGE_HERE: 'Image URL Here',
|
|
4659 /**
|
|
4660 * @property STR_IMAGE_URL
|
|
4661 * @description The label string for Image URL
|
|
4662 * @type String
|
|
4663 */
|
|
4664 STR_IMAGE_URL: 'Image URL',
|
|
4665 /**
|
|
4666 * @property STR_LINK_URL
|
|
4667 * @description The label string for the Link URL.
|
|
4668 * @type String
|
|
4669 */
|
|
4670 STR_LINK_URL: 'Link URL',
|
|
4671 /**
|
|
4672 * @protected
|
|
4673 * @property STOP_EXEC_COMMAND
|
|
4674 * @description Set to true when you want the default execCommand function to not process anything
|
|
4675 * @type Boolean
|
|
4676 */
|
|
4677 STOP_EXEC_COMMAND: false,
|
|
4678 /**
|
|
4679 * @protected
|
|
4680 * @property STOP_NODE_CHANGE
|
|
4681 * @description Set to true when you want the default nodeChange function to not process anything
|
|
4682 * @type Boolean
|
|
4683 */
|
|
4684 STOP_NODE_CHANGE: false,
|
|
4685 /**
|
|
4686 * @protected
|
|
4687 * @property CLASS_NOEDIT
|
|
4688 * @description CSS class applied to elements that are not editable.
|
|
4689 * @type String
|
|
4690 */
|
|
4691 CLASS_NOEDIT: 'yui-noedit',
|
|
4692 /**
|
|
4693 * @protected
|
|
4694 * @property CLASS_CONTAINER
|
|
4695 * @description Default CSS class to apply to the editors container element
|
|
4696 * @type String
|
|
4697 */
|
|
4698 CLASS_CONTAINER: 'yui-editor-container',
|
|
4699 /**
|
|
4700 * @protected
|
|
4701 * @property CLASS_EDITABLE
|
|
4702 * @description Default CSS class to apply to the editors iframe element
|
|
4703 * @type String
|
|
4704 */
|
|
4705 CLASS_EDITABLE: 'yui-editor-editable',
|
|
4706 /**
|
|
4707 * @protected
|
|
4708 * @property CLASS_EDITABLE_CONT
|
|
4709 * @description Default CSS class to apply to the editors iframe's parent element
|
|
4710 * @type String
|
|
4711 */
|
|
4712 CLASS_EDITABLE_CONT: 'yui-editor-editable-container',
|
|
4713 /**
|
|
4714 * @protected
|
|
4715 * @property CLASS_PREFIX
|
|
4716 * @description Default prefix for dynamically created class names
|
|
4717 * @type String
|
|
4718 */
|
|
4719 CLASS_PREFIX: 'yui-editor',
|
|
4720 /**
|
|
4721 * @property browser
|
|
4722 * @description Standard browser detection
|
|
4723 * @type Object
|
|
4724 */
|
|
4725 browser: function() {
|
|
4726 var br = YAHOO.env.ua;
|
|
4727 //Check for webkit3
|
|
4728 if (br.webkit >= 420) {
|
|
4729 br.webkit3 = br.webkit;
|
|
4730 } else {
|
|
4731 br.webkit3 = 0;
|
|
4732 }
|
|
4733 if (br.webkit >= 530) {
|
|
4734 br.webkit4 = br.webkit;
|
|
4735 } else {
|
|
4736 br.webkit4 = 0;
|
|
4737 }
|
|
4738 br.mac = false;
|
|
4739 //Check for Mac
|
|
4740 if (navigator.userAgent.indexOf('Macintosh') !== -1) {
|
|
4741 br.mac = true;
|
|
4742 }
|
|
4743
|
|
4744 return br;
|
|
4745 }(),
|
|
4746 /**
|
|
4747 * @method init
|
|
4748 * @description The Editor class' initialization method
|
|
4749 */
|
|
4750 init: function(p_oElement, p_oAttributes) {
|
|
4751 YAHOO.log('init', 'info', 'SimpleEditor');
|
|
4752
|
|
4753 if (!this._defaultToolbar) {
|
|
4754 this._defaultToolbar = {
|
|
4755 collapse: true,
|
|
4756 titlebar: 'Text Editing Tools',
|
|
4757 draggable: false,
|
|
4758 buttons: [
|
|
4759 { group: 'fontstyle', label: 'Font Name and Size',
|
|
4760 buttons: [
|
|
4761 { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
|
|
4762 menu: [
|
|
4763 { text: 'Arial', checked: true },
|
|
4764 { text: 'Arial Black' },
|
|
4765 { text: 'Comic Sans MS' },
|
|
4766 { text: 'Courier New' },
|
|
4767 { text: 'Lucida Console' },
|
|
4768 { text: 'Tahoma' },
|
|
4769 { text: 'Times New Roman' },
|
|
4770 { text: 'Trebuchet MS' },
|
|
4771 { text: 'Verdana' }
|
|
4772 ]
|
|
4773 },
|
|
4774 { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
|
|
4775 ]
|
|
4776 },
|
|
4777 { type: 'separator' },
|
|
4778 { group: 'textstyle', label: 'Font Style',
|
|
4779 buttons: [
|
|
4780 { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
|
|
4781 { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
|
|
4782 { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
|
|
4783 { type: 'push', label: 'Strike Through', value: 'strikethrough' },
|
|
4784 { type: 'separator' },
|
|
4785 { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
|
|
4786 { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }
|
|
4787
|
|
4788 ]
|
|
4789 },
|
|
4790 { type: 'separator' },
|
|
4791 { group: 'indentlist', label: 'Lists',
|
|
4792 buttons: [
|
|
4793 { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
|
|
4794 { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
|
|
4795 ]
|
|
4796 },
|
|
4797 { type: 'separator' },
|
|
4798 { group: 'insertitem', label: 'Insert Item',
|
|
4799 buttons: [
|
|
4800 { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
|
|
4801 { type: 'push', label: 'Insert Image', value: 'insertimage' }
|
|
4802 ]
|
|
4803 }
|
|
4804 ]
|
|
4805 };
|
|
4806 }
|
|
4807
|
|
4808 YAHOO.widget.SimpleEditor.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
4809 YAHOO.widget.EditorInfo._instances[this.get('id')] = this;
|
|
4810
|
|
4811
|
|
4812 this.currentElement = [];
|
|
4813 this.on('contentReady', function() {
|
|
4814 this.DOMReady = true;
|
|
4815 this.fireQueue();
|
|
4816 }, this, true);
|
|
4817
|
|
4818 },
|
|
4819 /**
|
|
4820 * @method initAttributes
|
|
4821 * @description Initializes all of the configuration attributes used to create
|
|
4822 * the editor.
|
|
4823 * @param {Object} attr Object literal specifying a set of
|
|
4824 * configuration attributes used to create the editor.
|
|
4825 */
|
|
4826 initAttributes: function(attr) {
|
|
4827 YAHOO.widget.SimpleEditor.superclass.initAttributes.call(this, attr);
|
|
4828 var self = this;
|
|
4829
|
|
4830 /**
|
|
4831 * @config setDesignMode
|
|
4832 * @description Should the Editor set designMode on the document. Default: true.
|
|
4833 * @default true
|
|
4834 * @type Boolean
|
|
4835 */
|
|
4836 this.setAttributeConfig('setDesignMode', {
|
|
4837 value: ((attr.setDesignMode === false) ? false : true)
|
|
4838 });
|
|
4839 /**
|
|
4840 * @config nodeChangeDelay
|
|
4841 * @description Do we wrap the nodeChange method in a timeout for performance. Default: true.
|
|
4842 * @default true
|
|
4843 * @type Boolean
|
|
4844 */
|
|
4845 this.setAttributeConfig('nodeChangeDelay', {
|
|
4846 value: ((attr.nodeChangeDelay === false) ? false : true)
|
|
4847 });
|
|
4848 /**
|
|
4849 * @config maxUndo
|
|
4850 * @description The max number of undo levels to store.
|
|
4851 * @default 30
|
|
4852 * @type Number
|
|
4853 */
|
|
4854 this.setAttributeConfig('maxUndo', {
|
|
4855 writeOnce: true,
|
|
4856 value: attr.maxUndo || 30
|
|
4857 });
|
|
4858
|
|
4859 /**
|
|
4860 * @config ptags
|
|
4861 * @description If true, the editor uses <P> tags instead of <br> tags. (Use Shift + Enter to get a <br>)
|
|
4862 * @default false
|
|
4863 * @type Boolean
|
|
4864 */
|
|
4865 this.setAttributeConfig('ptags', {
|
|
4866 writeOnce: true,
|
|
4867 value: attr.ptags || false
|
|
4868 });
|
|
4869 /**
|
|
4870 * @config insert
|
|
4871 * @description If true, selection is not required for: fontname, fontsize, forecolor, backcolor.
|
|
4872 * @default false
|
|
4873 * @type Boolean
|
|
4874 */
|
|
4875 this.setAttributeConfig('insert', {
|
|
4876 writeOnce: true,
|
|
4877 value: attr.insert || false,
|
|
4878 method: function(insert) {
|
|
4879 if (insert) {
|
|
4880 var buttons = {
|
|
4881 fontname: true,
|
|
4882 fontsize: true,
|
|
4883 forecolor: true,
|
|
4884 backcolor: true
|
|
4885 };
|
|
4886 var tmp = this._defaultToolbar.buttons;
|
|
4887 for (var i = 0; i < tmp.length; i++) {
|
|
4888 if (tmp[i].buttons) {
|
|
4889 for (var a = 0; a < tmp[i].buttons.length; a++) {
|
|
4890 if (tmp[i].buttons[a].value) {
|
|
4891 if (buttons[tmp[i].buttons[a].value]) {
|
|
4892 delete tmp[i].buttons[a].disabled;
|
|
4893 }
|
|
4894 }
|
|
4895 }
|
|
4896 }
|
|
4897 }
|
|
4898 }
|
|
4899 }
|
|
4900 });
|
|
4901 /**
|
|
4902 * @config container
|
|
4903 * @description Used when dynamically creating the Editor from Javascript with no default textarea.
|
|
4904 * We will create one and place it in this container. If no container is passed we will append to document.body.
|
|
4905 * @default false
|
|
4906 * @type HTMLElement
|
|
4907 */
|
|
4908 this.setAttributeConfig('container', {
|
|
4909 writeOnce: true,
|
|
4910 value: attr.container || false
|
|
4911 });
|
|
4912 /**
|
|
4913 * @config plainText
|
|
4914 * @description Process the inital textarea data as if it was plain text. Accounting for spaces, tabs and line feeds.
|
|
4915 * @default false
|
|
4916 * @type Boolean
|
|
4917 */
|
|
4918 this.setAttributeConfig('plainText', {
|
|
4919 writeOnce: true,
|
|
4920 value: attr.plainText || false
|
|
4921 });
|
|
4922 /**
|
|
4923 * @private
|
|
4924 * @config iframe
|
|
4925 * @description Internal config for holding the iframe element.
|
|
4926 * @default null
|
|
4927 * @type HTMLElement
|
|
4928 */
|
|
4929 this.setAttributeConfig('iframe', {
|
|
4930 value: null
|
|
4931 });
|
|
4932 /**
|
|
4933 * @private
|
|
4934 * @config disabled_iframe
|
|
4935 * @description Internal config for holding the iframe element used when disabling the Editor.
|
|
4936 * @default null
|
|
4937 * @type HTMLElement
|
|
4938 */
|
|
4939 this.setAttributeConfig('disabled_iframe', {
|
|
4940 value: null
|
|
4941 });
|
|
4942 /**
|
|
4943 * @private
|
|
4944 * @depreciated - No longer used, should use this.get('element')
|
|
4945 * @config textarea
|
|
4946 * @description Internal config for holding the textarea element (replaced with element).
|
|
4947 * @default null
|
|
4948 * @type HTMLElement
|
|
4949 */
|
|
4950 this.setAttributeConfig('textarea', {
|
|
4951 value: null,
|
|
4952 writeOnce: true
|
|
4953 });
|
|
4954 /**
|
|
4955 * @config nodeChangeThreshold
|
|
4956 * @description The number of seconds that need to be in between nodeChange processing
|
|
4957 * @default 3
|
|
4958 * @type Number
|
|
4959 */
|
|
4960 this.setAttributeConfig('nodeChangeThreshold', {
|
|
4961 value: attr.nodeChangeThreshold || 3,
|
|
4962 validator: YAHOO.lang.isNumber
|
|
4963 });
|
|
4964 /**
|
|
4965 * @config allowNoEdit
|
|
4966 * @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.
|
|
4967 * Such as highlighting an element below and above the content and hitting a toolbar button or a shortcut key.
|
|
4968 * @default false
|
|
4969 * @type Boolean
|
|
4970 */
|
|
4971 this.setAttributeConfig('allowNoEdit', {
|
|
4972 value: attr.allowNoEdit || false,
|
|
4973 validator: YAHOO.lang.isBoolean
|
|
4974 });
|
|
4975 /**
|
|
4976 * @config limitCommands
|
|
4977 * @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.
|
|
4978 * @default false
|
|
4979 * @type Boolean
|
|
4980 */
|
|
4981 this.setAttributeConfig('limitCommands', {
|
|
4982 value: attr.limitCommands || false,
|
|
4983 validator: YAHOO.lang.isBoolean
|
|
4984 });
|
|
4985 /**
|
|
4986 * @config element_cont
|
|
4987 * @description Internal config for the editors container
|
|
4988 * @default false
|
|
4989 * @type HTMLElement
|
|
4990 */
|
|
4991 this.setAttributeConfig('element_cont', {
|
|
4992 value: attr.element_cont
|
|
4993 });
|
|
4994 /**
|
|
4995 * @private
|
|
4996 * @config editor_wrapper
|
|
4997 * @description The outter wrapper for the entire editor.
|
|
4998 * @default null
|
|
4999 * @type HTMLElement
|
|
5000 */
|
|
5001 this.setAttributeConfig('editor_wrapper', {
|
|
5002 value: attr.editor_wrapper || null,
|
|
5003 writeOnce: true
|
|
5004 });
|
|
5005 /**
|
|
5006 * @attribute height
|
|
5007 * @description The height of the editor iframe container, not including the toolbar..
|
|
5008 * @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
|
|
5009 * @type String
|
|
5010 */
|
|
5011 this.setAttributeConfig('height', {
|
|
5012 value: attr.height || Dom.getStyle(self.get('element'), 'height'),
|
|
5013 method: function(height) {
|
|
5014 if (this._rendered) {
|
|
5015 //We have been rendered, change the height
|
|
5016 if (this.get('animate')) {
|
|
5017 var anim = new YAHOO.util.Anim(this.get('iframe').get('parentNode'), {
|
|
5018 height: {
|
|
5019 to: parseInt(height, 10)
|
|
5020 }
|
|
5021 }, 0.5);
|
|
5022 anim.animate();
|
|
5023 } else {
|
|
5024 Dom.setStyle(this.get('iframe').get('parentNode'), 'height', height);
|
|
5025 }
|
|
5026 }
|
|
5027 }
|
|
5028 });
|
|
5029 /**
|
|
5030 * @config autoHeight
|
|
5031 * @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.
|
|
5032 * @default false
|
|
5033 * @type Boolean || Number
|
|
5034 */
|
|
5035 this.setAttributeConfig('autoHeight', {
|
|
5036 value: attr.autoHeight || false,
|
|
5037 method: function(a) {
|
|
5038 if (a) {
|
|
5039 if (this.get('iframe')) {
|
|
5040 this.get('iframe').get('element').setAttribute('scrolling', 'no');
|
|
5041 }
|
|
5042 this.on('afterNodeChange', this._handleAutoHeight, this, true);
|
|
5043 this.on('editorKeyDown', this._handleAutoHeight, this, true);
|
|
5044 this.on('editorKeyPress', this._handleAutoHeight, this, true);
|
|
5045 } else {
|
|
5046 if (this.get('iframe')) {
|
|
5047 this.get('iframe').get('element').setAttribute('scrolling', 'auto');
|
|
5048 }
|
|
5049 this.unsubscribe('afterNodeChange', this._handleAutoHeight);
|
|
5050 this.unsubscribe('editorKeyDown', this._handleAutoHeight);
|
|
5051 this.unsubscribe('editorKeyPress', this._handleAutoHeight);
|
|
5052 }
|
|
5053 }
|
|
5054 });
|
|
5055 /**
|
|
5056 * @attribute width
|
|
5057 * @description The width of the editor container.
|
|
5058 * @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
|
|
5059 * @type String
|
|
5060 */
|
|
5061 this.setAttributeConfig('width', {
|
|
5062 value: attr.width || Dom.getStyle(this.get('element'), 'width'),
|
|
5063 method: function(width) {
|
|
5064 if (this._rendered) {
|
|
5065 //We have been rendered, change the width
|
|
5066 if (this.get('animate')) {
|
|
5067 var anim = new YAHOO.util.Anim(this.get('element_cont').get('element'), {
|
|
5068 width: {
|
|
5069 to: parseInt(width, 10)
|
|
5070 }
|
|
5071 }, 0.5);
|
|
5072 anim.animate();
|
|
5073 } else {
|
|
5074 this.get('element_cont').setStyle('width', width);
|
|
5075 }
|
|
5076 }
|
|
5077 }
|
|
5078 });
|
|
5079
|
|
5080 /**
|
|
5081 * @attribute blankimage
|
|
5082 * @description The URL for the image placeholder to put in when inserting an image.
|
|
5083 * @default The yahooapis.com address for the current release + 'assets/blankimage.png'
|
|
5084 * @type String
|
|
5085 */
|
|
5086 this.setAttributeConfig('blankimage', {
|
|
5087 value: attr.blankimage || this._getBlankImage()
|
|
5088 });
|
|
5089 /**
|
|
5090 * @attribute css
|
|
5091 * @description The Base CSS used to format the content of the editor
|
|
5092 * @default <code><pre>html {
|
|
5093 height: 95%;
|
|
5094 }
|
|
5095 body {
|
|
5096 height: 100%;
|
|
5097 padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;
|
|
5098 }
|
|
5099 a {
|
|
5100 color: blue;
|
|
5101 text-decoration: underline;
|
|
5102 cursor: pointer;
|
|
5103 }
|
|
5104 .warning-localfile {
|
|
5105 border-bottom: 1px dashed red !important;
|
|
5106 }
|
|
5107 .yui-busy {
|
|
5108 cursor: wait !important;
|
|
5109 }
|
|
5110 img.selected { //Safari image selection
|
|
5111 border: 2px dotted #808080;
|
|
5112 }
|
|
5113 img {
|
|
5114 cursor: pointer !important;
|
|
5115 border: none;
|
|
5116 }
|
|
5117 </pre></code>
|
|
5118 * @type String
|
|
5119 */
|
|
5120 this.setAttributeConfig('css', {
|
|
5121 value: attr.css || this._defaultCSS,
|
|
5122 writeOnce: true
|
|
5123 });
|
|
5124 /**
|
|
5125 * @attribute html
|
|
5126 * @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)
|
|
5127 * @default This HTML requires a few things if you are to override:
|
|
5128 <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>
|
|
5129 <p><code>onload="document.body._rteLoaded = true;"</code> : the onload statement must be there or the editor will not finish loading.</p>
|
|
5130 <code>
|
|
5131 <pre>
|
|
5132 <html>
|
|
5133 <head>
|
|
5134 <title>{TITLE}</title>
|
|
5135 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
5136 <style>
|
|
5137 {CSS}
|
|
5138 </style>
|
|
5139 <style>
|
|
5140 {HIDDEN_CSS}
|
|
5141 </style>
|
|
5142 <style>
|
|
5143 {EXTRA_CSS}
|
|
5144 </style>
|
|
5145 </head>
|
|
5146 <body onload="document.body._rteLoaded = true;">
|
|
5147 {CONTENT}
|
|
5148 </body>
|
|
5149 </html>
|
|
5150 </pre>
|
|
5151 </code>
|
|
5152 * @type String
|
|
5153 */
|
|
5154 this.setAttributeConfig('html', {
|
|
5155 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>',
|
|
5156 writeOnce: true
|
|
5157 });
|
|
5158
|
|
5159 /**
|
|
5160 * @attribute extracss
|
|
5161 * @description Extra user defined css to load after the default SimpleEditor CSS
|
|
5162 * @default ''
|
|
5163 * @type String
|
|
5164 */
|
|
5165 this.setAttributeConfig('extracss', {
|
|
5166 value: attr.extracss || '',
|
|
5167 writeOnce: true
|
|
5168 });
|
|
5169
|
|
5170 /**
|
|
5171 * @attribute handleSubmit
|
|
5172 * @description Config handles if the editor will attach itself to the textareas parent form's submit handler.
|
|
5173 If it is set to true, the editor will attempt to attach a submit listener to the textareas parent form.
|
|
5174 Then it will trigger the editors save handler and place the new content back into the text area before the form is submitted.
|
|
5175 * @default false
|
|
5176 * @type Boolean
|
|
5177 */
|
|
5178 this.setAttributeConfig('handleSubmit', {
|
|
5179 value: attr.handleSubmit || false,
|
|
5180 method: function(exec) {
|
|
5181 if (this.get('element').form) {
|
|
5182 if (!this._formButtons) {
|
|
5183 this._formButtons = [];
|
|
5184 }
|
|
5185 if (exec) {
|
|
5186 Event.on(this.get('element').form, 'submit', this._handleFormSubmit, this, true);
|
|
5187 var i = this.get('element').form.getElementsByTagName('input');
|
|
5188 for (var s = 0; s < i.length; s++) {
|
|
5189 var type = i[s].getAttribute('type');
|
|
5190 if (type && (type.toLowerCase() == 'submit')) {
|
|
5191 Event.on(i[s], 'click', this._handleFormButtonClick, this, true);
|
|
5192 this._formButtons[this._formButtons.length] = i[s];
|
|
5193 }
|
|
5194 }
|
|
5195 } else {
|
|
5196 Event.removeListener(this.get('element').form, 'submit', this._handleFormSubmit);
|
|
5197 if (this._formButtons) {
|
|
5198 Event.removeListener(this._formButtons, 'click', this._handleFormButtonClick);
|
|
5199 }
|
|
5200 }
|
|
5201 }
|
|
5202 }
|
|
5203 });
|
|
5204 /**
|
|
5205 * @attribute disabled
|
|
5206 * @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.
|
|
5207 All Toolbar buttons are also disabled so they cannot be used.
|
|
5208 * @default false
|
|
5209 * @type Boolean
|
|
5210 */
|
|
5211
|
|
5212 this.setAttributeConfig('disabled', {
|
|
5213 value: false,
|
|
5214 method: function(disabled) {
|
|
5215 if (this._rendered) {
|
|
5216 this._disableEditor(disabled);
|
|
5217 }
|
|
5218 }
|
|
5219 });
|
|
5220 /**
|
|
5221 * @config saveEl
|
|
5222 * @description When save HTML is called, this element will be updated as well as the source of data.
|
|
5223 * @default element
|
|
5224 * @type HTMLElement
|
|
5225 */
|
|
5226 this.setAttributeConfig('saveEl', {
|
|
5227 value: this.get('element')
|
|
5228 });
|
|
5229 /**
|
|
5230 * @config toolbar_cont
|
|
5231 * @description Internal config for the toolbars container
|
|
5232 * @default false
|
|
5233 * @type Boolean
|
|
5234 */
|
|
5235 this.setAttributeConfig('toolbar_cont', {
|
|
5236 value: null,
|
|
5237 writeOnce: true
|
|
5238 });
|
|
5239 /**
|
|
5240 * @attribute toolbar
|
|
5241 * @description The default toolbar config.
|
|
5242 * @type Object
|
|
5243 */
|
|
5244 this.setAttributeConfig('toolbar', {
|
|
5245 value: attr.toolbar || this._defaultToolbar,
|
|
5246 writeOnce: true,
|
|
5247 method: function(toolbar) {
|
|
5248 if (!toolbar.buttonType) {
|
|
5249 toolbar.buttonType = this._defaultToolbar.buttonType;
|
|
5250 }
|
|
5251 this._defaultToolbar = toolbar;
|
|
5252 }
|
|
5253 });
|
|
5254 /**
|
|
5255 * @attribute animate
|
|
5256 * @description Should the editor animate window movements
|
|
5257 * @default false unless Animation is found, then true
|
|
5258 * @type Boolean
|
|
5259 */
|
|
5260 this.setAttributeConfig('animate', {
|
|
5261 value: ((attr.animate) ? ((YAHOO.util.Anim) ? true : false) : false),
|
|
5262 validator: function(value) {
|
|
5263 var ret = true;
|
|
5264 if (!YAHOO.util.Anim) {
|
|
5265 ret = false;
|
|
5266 }
|
|
5267 return ret;
|
|
5268 }
|
|
5269 });
|
|
5270 /**
|
|
5271 * @config panel
|
|
5272 * @description A reference to the panel we are using for windows.
|
|
5273 * @default false
|
|
5274 * @type Boolean
|
|
5275 */
|
|
5276 this.setAttributeConfig('panel', {
|
|
5277 value: null,
|
|
5278 writeOnce: true,
|
|
5279 validator: function(value) {
|
|
5280 var ret = true;
|
|
5281 if (!YAHOO.widget.Overlay) {
|
|
5282 ret = false;
|
|
5283 }
|
|
5284 return ret;
|
|
5285 }
|
|
5286 });
|
|
5287 /**
|
|
5288 * @attribute focusAtStart
|
|
5289 * @description Should we focus the window when the content is ready?
|
|
5290 * @default false
|
|
5291 * @type Boolean
|
|
5292 */
|
|
5293 this.setAttributeConfig('focusAtStart', {
|
|
5294 value: attr.focusAtStart || false,
|
|
5295 writeOnce: true,
|
|
5296 method: function(fs) {
|
|
5297 if (fs) {
|
|
5298 this.on('editorContentLoaded', function() {
|
|
5299 var self = this;
|
|
5300 setTimeout(function() {
|
|
5301 self.focus.call(self);
|
|
5302 self.editorDirty = false;
|
|
5303 }, 400);
|
|
5304 }, this, true);
|
|
5305 }
|
|
5306 }
|
|
5307 });
|
|
5308 /**
|
|
5309 * @attribute dompath
|
|
5310 * @description Toggle the display of the current Dom path below the editor
|
|
5311 * @default false
|
|
5312 * @type Boolean
|
|
5313 */
|
|
5314 this.setAttributeConfig('dompath', {
|
|
5315 value: attr.dompath || false,
|
|
5316 method: function(dompath) {
|
|
5317 if (dompath && !this.dompath) {
|
|
5318 this.dompath = document.createElement('DIV');
|
|
5319 this.dompath.id = this.get('id') + '_dompath';
|
|
5320 Dom.addClass(this.dompath, 'dompath');
|
|
5321 this.get('element_cont').get('firstChild').appendChild(this.dompath);
|
|
5322 if (this.get('iframe')) {
|
|
5323 this._writeDomPath();
|
|
5324 }
|
|
5325 } else if (!dompath && this.dompath) {
|
|
5326 this.dompath.parentNode.removeChild(this.dompath);
|
|
5327 this.dompath = null;
|
|
5328 }
|
|
5329 }
|
|
5330 });
|
|
5331 /**
|
|
5332 * @attribute markup
|
|
5333 * @description Should we try to adjust the markup for the following types: semantic, css, default or xhtml
|
|
5334 * @default "semantic"
|
|
5335 * @type String
|
|
5336 */
|
|
5337 this.setAttributeConfig('markup', {
|
|
5338 value: attr.markup || 'semantic',
|
|
5339 validator: function(markup) {
|
|
5340 switch (markup.toLowerCase()) {
|
|
5341 case 'semantic':
|
|
5342 case 'css':
|
|
5343 case 'default':
|
|
5344 case 'xhtml':
|
|
5345 return true;
|
|
5346 }
|
|
5347 return false;
|
|
5348 }
|
|
5349 });
|
|
5350 /**
|
|
5351 * @attribute removeLineBreaks
|
|
5352 * @description Should we remove linebreaks and extra spaces on cleanup
|
|
5353 * @default false
|
|
5354 * @type Boolean
|
|
5355 */
|
|
5356 this.setAttributeConfig('removeLineBreaks', {
|
|
5357 value: attr.removeLineBreaks || false,
|
|
5358 validator: YAHOO.lang.isBoolean
|
|
5359 });
|
|
5360
|
|
5361 /**
|
|
5362 * @config drag
|
|
5363 * @description Set this config to make the Editor draggable, pass 'proxy' to make use YAHOO.util.DDProxy.
|
|
5364 * @type {Boolean/String}
|
|
5365 */
|
|
5366 this.setAttributeConfig('drag', {
|
|
5367 writeOnce: true,
|
|
5368 value: attr.drag || false
|
|
5369 });
|
|
5370
|
|
5371 /**
|
|
5372 * @config resize
|
|
5373 * @description Set this to true to make the Editor Resizable with YAHOO.util.Resize. The default config is available: myEditor._resizeConfig
|
|
5374 * Animation will be ignored while performing this resize to allow for the dynamic change in size of the toolbar.
|
|
5375 * @type Boolean
|
|
5376 */
|
|
5377 this.setAttributeConfig('resize', {
|
|
5378 writeOnce: true,
|
|
5379 value: attr.resize || false
|
|
5380 });
|
|
5381
|
|
5382 /**
|
|
5383 * @config filterWord
|
|
5384 * @description Attempt to filter out MS Word HTML from the Editor's output.
|
|
5385 * @type Boolean
|
|
5386 */
|
|
5387 this.setAttributeConfig('filterWord', {
|
|
5388 value: attr.filterWord || false,
|
|
5389 validator: YAHOO.lang.isBoolean
|
|
5390 });
|
|
5391
|
|
5392 },
|
|
5393 /**
|
|
5394 * @private
|
|
5395 * @method _getBlankImage
|
|
5396 * @description Retrieves the full url of the image to use as the blank image.
|
|
5397 * @return {String} The URL to the blank image
|
|
5398 */
|
|
5399 _getBlankImage: function() {
|
|
5400 if (!this.DOMReady) {
|
|
5401 this._queue[this._queue.length] = ['_getBlankImage', arguments];
|
|
5402 return '';
|
|
5403 }
|
|
5404 var img = '';
|
|
5405 if (!this._blankImageLoaded) {
|
|
5406 if (YAHOO.widget.EditorInfo.blankImage) {
|
|
5407 this.set('blankimage', YAHOO.widget.EditorInfo.blankImage);
|
|
5408 this._blankImageLoaded = true;
|
|
5409 } else {
|
|
5410 var div = document.createElement('div');
|
|
5411 div.style.position = 'absolute';
|
|
5412 div.style.top = '-9999px';
|
|
5413 div.style.left = '-9999px';
|
|
5414 div.className = this.CLASS_PREFIX + '-blankimage';
|
|
5415 document.body.appendChild(div);
|
|
5416 img = YAHOO.util.Dom.getStyle(div, 'background-image');
|
|
5417 img = img.replace('url(', '').replace(')', '').replace(/"/g, '');
|
|
5418 //Adobe AIR Code
|
|
5419 img = img.replace('app:/', '');
|
|
5420 this.set('blankimage', img);
|
|
5421 this._blankImageLoaded = true;
|
|
5422 div.parentNode.removeChild(div);
|
|
5423 YAHOO.widget.EditorInfo.blankImage = img;
|
|
5424 }
|
|
5425 } else {
|
|
5426 img = this.get('blankimage');
|
|
5427 }
|
|
5428 return img;
|
|
5429 },
|
|
5430 /**
|
|
5431 * @private
|
|
5432 * @method _handleAutoHeight
|
|
5433 * @description Handles resizing the editor's height based on the content
|
|
5434 */
|
|
5435 _handleAutoHeight: function() {
|
|
5436 var doc = this._getDoc(),
|
|
5437 body = doc.body,
|
|
5438 docEl = doc.documentElement;
|
|
5439
|
|
5440 var height = parseInt(Dom.getStyle(this.get('editor_wrapper'), 'height'), 10);
|
|
5441 var newHeight = body.scrollHeight;
|
|
5442 if (this.browser.webkit) {
|
|
5443 newHeight = docEl.scrollHeight;
|
|
5444 }
|
|
5445 if (newHeight < parseInt(this.get('height'), 10)) {
|
|
5446 newHeight = parseInt(this.get('height'), 10);
|
|
5447 }
|
|
5448 if ((height != newHeight) && (newHeight >= parseInt(this.get('height'), 10))) {
|
|
5449 var anim = this.get('animate');
|
|
5450 this.set('animate', false);
|
|
5451 this.set('height', newHeight + 'px');
|
|
5452 this.set('animate', anim);
|
|
5453 if (this.browser.ie) {
|
|
5454 //Internet Explorer needs this
|
|
5455 this.get('iframe').setStyle('height', '99%');
|
|
5456 this.get('iframe').setStyle('zoom', '1');
|
|
5457 var self = this;
|
|
5458 window.setTimeout(function() {
|
|
5459 self.get('iframe').setStyle('height', '100%');
|
|
5460 }, 1);
|
|
5461 }
|
|
5462 }
|
|
5463 },
|
|
5464 /**
|
|
5465 * @private
|
|
5466 * @property _formButtons
|
|
5467 * @description Array of buttons that are in the Editor's parent form (for handleSubmit)
|
|
5468 * @type Array
|
|
5469 */
|
|
5470 _formButtons: null,
|
|
5471 /**
|
|
5472 * @private
|
|
5473 * @property _formButtonClicked
|
|
5474 * @description The form button that was clicked to submit the form.
|
|
5475 * @type HTMLElement
|
|
5476 */
|
|
5477 _formButtonClicked: null,
|
|
5478 /**
|
|
5479 * @private
|
|
5480 * @method _handleFormButtonClick
|
|
5481 * @description The click listener assigned to each submit button in the Editor's parent form.
|
|
5482 * @param {Event} ev The click event
|
|
5483 */
|
|
5484 _handleFormButtonClick: function(ev) {
|
|
5485 var tar = Event.getTarget(ev);
|
|
5486 this._formButtonClicked = tar;
|
|
5487 },
|
|
5488 /**
|
|
5489 * @private
|
|
5490 * @method _handleFormSubmit
|
|
5491 * @description Handles the form submission.
|
|
5492 * @param {Object} ev The Form Submit Event
|
|
5493 */
|
|
5494 _handleFormSubmit: function(ev) {
|
|
5495 this.saveHTML();
|
|
5496
|
|
5497 var form = this.get('element').form,
|
|
5498 tar = this._formButtonClicked || false;
|
|
5499
|
|
5500 Event.removeListener(form, 'submit', this._handleFormSubmit);
|
|
5501 if (YAHOO.env.ua.ie) {
|
|
5502 //form.fireEvent("onsubmit");
|
|
5503 if (tar && !tar.disabled) {
|
|
5504 tar.click();
|
|
5505 }
|
|
5506 } else { // Gecko, Opera, and Safari
|
|
5507 if (tar && !tar.disabled) {
|
|
5508 tar.click();
|
|
5509 }
|
|
5510 var oEvent = document.createEvent("HTMLEvents");
|
|
5511 oEvent.initEvent("submit", true, true);
|
|
5512 form.dispatchEvent(oEvent);
|
|
5513 if (YAHOO.env.ua.webkit) {
|
|
5514 if (YAHOO.lang.isFunction(form.submit)) {
|
|
5515 form.submit();
|
|
5516 }
|
|
5517 }
|
|
5518 }
|
|
5519 //2.6.0
|
|
5520 //Removed this, not need since removing Safari 2.x
|
|
5521 //Event.stopEvent(ev);
|
|
5522 },
|
|
5523 /**
|
|
5524 * @private
|
|
5525 * @method _handleFontSize
|
|
5526 * @description Handles the font size button in the toolbar.
|
|
5527 * @param {Object} o Object returned from Toolbar's buttonClick Event
|
|
5528 */
|
|
5529 _handleFontSize: function(o) {
|
|
5530 var button = this.toolbar.getButtonById(o.button.id);
|
|
5531 var value = button.get('label') + 'px';
|
|
5532 this.execCommand('fontsize', value);
|
|
5533 return false;
|
|
5534 },
|
|
5535 /**
|
|
5536 * @private
|
|
5537 * @description Handles the colorpicker buttons in the toolbar.
|
|
5538 * @param {Object} o Object returned from Toolbar's buttonClick Event
|
|
5539 */
|
|
5540 _handleColorPicker: function(o) {
|
|
5541 var cmd = o.button;
|
|
5542 var value = '#' + o.color;
|
|
5543 if ((cmd == 'forecolor') || (cmd == 'backcolor')) {
|
|
5544 this.execCommand(cmd, value);
|
|
5545 }
|
|
5546 },
|
|
5547 /**
|
|
5548 * @private
|
|
5549 * @method _handleAlign
|
|
5550 * @description Handles the alignment buttons in the toolbar.
|
|
5551 * @param {Object} o Object returned from Toolbar's buttonClick Event
|
|
5552 */
|
|
5553 _handleAlign: function(o) {
|
|
5554 var cmd = null;
|
|
5555 for (var i = 0; i < o.button.menu.length; i++) {
|
|
5556 if (o.button.menu[i].value == o.button.value) {
|
|
5557 cmd = o.button.menu[i].value;
|
|
5558 }
|
|
5559 }
|
|
5560 var value = this._getSelection();
|
|
5561
|
|
5562 this.execCommand(cmd, value);
|
|
5563 return false;
|
|
5564 },
|
|
5565 /**
|
|
5566 * @private
|
|
5567 * @method _handleAfterNodeChange
|
|
5568 * @description Fires after a nodeChange happens to setup the things that where reset on the node change (button state).
|
|
5569 */
|
|
5570 _handleAfterNodeChange: function() {
|
|
5571 var path = this._getDomPath(),
|
|
5572 elm = null,
|
|
5573 family = null,
|
|
5574 fontsize = null,
|
|
5575 validFont = false,
|
|
5576 fn_button = this.toolbar.getButtonByValue('fontname'),
|
|
5577 fs_button = this.toolbar.getButtonByValue('fontsize'),
|
|
5578 hd_button = this.toolbar.getButtonByValue('heading');
|
|
5579
|
|
5580 for (var i = 0; i < path.length; i++) {
|
|
5581 elm = path[i];
|
|
5582
|
|
5583 var tag = elm.tagName.toLowerCase();
|
|
5584
|
|
5585
|
|
5586 if (elm.getAttribute('tag')) {
|
|
5587 tag = elm.getAttribute('tag');
|
|
5588 }
|
|
5589
|
|
5590 family = elm.getAttribute('face');
|
|
5591 if (Dom.getStyle(elm, 'font-family')) {
|
|
5592 family = Dom.getStyle(elm, 'font-family');
|
|
5593 //Adobe AIR Code
|
|
5594 family = family.replace(/'/g, '');
|
|
5595 }
|
|
5596
|
|
5597 if (tag.substring(0, 1) == 'h') {
|
|
5598 if (hd_button) {
|
|
5599 for (var h = 0; h < hd_button._configs.menu.value.length; h++) {
|
|
5600 if (hd_button._configs.menu.value[h].value.toLowerCase() == tag) {
|
|
5601 hd_button.set('label', hd_button._configs.menu.value[h].text);
|
|
5602 }
|
|
5603 }
|
|
5604 this._updateMenuChecked('heading', tag);
|
|
5605 }
|
|
5606 }
|
|
5607 }
|
|
5608
|
|
5609 if (fn_button) {
|
|
5610 for (var b = 0; b < fn_button._configs.menu.value.length; b++) {
|
|
5611 if (family && fn_button._configs.menu.value[b].text.toLowerCase() == family.toLowerCase()) {
|
|
5612 validFont = true;
|
|
5613 family = fn_button._configs.menu.value[b].text; //Put the proper menu name in the button
|
|
5614 }
|
|
5615 }
|
|
5616 if (!validFont) {
|
|
5617 family = fn_button._configs.label._initialConfig.value;
|
|
5618 }
|
|
5619 var familyLabel = '<span class="yui-toolbar-fontname-' + this._cleanClassName(family) + '">' + family + '</span>';
|
|
5620 if (fn_button.get('label') != familyLabel) {
|
|
5621 fn_button.set('label', familyLabel);
|
|
5622 this._updateMenuChecked('fontname', family);
|
|
5623 }
|
|
5624 }
|
|
5625
|
|
5626 if (fs_button) {
|
|
5627 fontsize = parseInt(Dom.getStyle(elm, 'fontSize'), 10);
|
|
5628 if ((fontsize === null) || isNaN(fontsize)) {
|
|
5629 fontsize = fs_button._configs.label._initialConfig.value;
|
|
5630 }
|
|
5631 fs_button.set('label', ''+fontsize);
|
|
5632 }
|
|
5633
|
|
5634 if (!this._isElement(elm, 'body') && !this._isElement(elm, 'img')) {
|
|
5635 this.toolbar.enableButton(fn_button);
|
|
5636 this.toolbar.enableButton(fs_button);
|
|
5637 this.toolbar.enableButton('forecolor');
|
|
5638 this.toolbar.enableButton('backcolor');
|
|
5639 }
|
|
5640 if (this._isElement(elm, 'img')) {
|
|
5641 if (YAHOO.widget.Overlay) {
|
|
5642 this.toolbar.enableButton('createlink');
|
|
5643 }
|
|
5644 }
|
|
5645 if (this._hasParent(elm, 'blockquote')) {
|
|
5646 this.toolbar.selectButton('indent');
|
|
5647 this.toolbar.disableButton('indent');
|
|
5648 this.toolbar.enableButton('outdent');
|
|
5649 }
|
|
5650 if (this._hasParent(elm, 'ol') || this._hasParent(elm, 'ul')) {
|
|
5651 this.toolbar.disableButton('indent');
|
|
5652 }
|
|
5653 this._lastButton = null;
|
|
5654
|
|
5655 },
|
|
5656 /**
|
|
5657 * @private
|
|
5658 * @method _handleInsertImageClick
|
|
5659 * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
|
|
5660 */
|
|
5661 _handleInsertImageClick: function() {
|
|
5662 if (this.get('limitCommands')) {
|
|
5663 if (!this.toolbar.getButtonByValue('insertimage')) {
|
|
5664 YAHOO.log('Toolbar Button for (insertimage) was not found, skipping exec.', 'info', 'SimpleEditor');
|
|
5665 return false;
|
|
5666 }
|
|
5667 }
|
|
5668
|
|
5669 this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
|
|
5670 var _handleAEC = function() {
|
|
5671 var el = this.currentElement[0],
|
|
5672 src = 'http://';
|
|
5673 if (!el) {
|
|
5674 el = this._getSelectedElement();
|
|
5675 }
|
|
5676 if (el) {
|
|
5677 if (el.getAttribute('src')) {
|
|
5678 src = el.getAttribute('src', 2);
|
|
5679 if (src.indexOf(this.get('blankimage')) != -1) {
|
|
5680 src = this.STR_IMAGE_HERE;
|
|
5681 }
|
|
5682 }
|
|
5683 }
|
|
5684 var str = prompt(this.STR_IMAGE_URL + ': ', src);
|
|
5685 if ((str !== '') && (str !== null)) {
|
|
5686 el.setAttribute('src', str);
|
|
5687 } else if (str === '') {
|
|
5688 el.parentNode.removeChild(el);
|
|
5689 this.currentElement = [];
|
|
5690 this.nodeChange();
|
|
5691 } else if ((str === null)) {
|
|
5692 src = el.getAttribute('src', 2);
|
|
5693 if (src.indexOf(this.get('blankimage')) != -1) {
|
|
5694 el.parentNode.removeChild(el);
|
|
5695 this.currentElement = [];
|
|
5696 this.nodeChange();
|
|
5697 }
|
|
5698 }
|
|
5699 this.closeWindow();
|
|
5700 this.toolbar.set('disabled', false);
|
|
5701 this.unsubscribe('afterExecCommand', _handleAEC, this, true);
|
|
5702 };
|
|
5703 this.on('afterExecCommand', _handleAEC, this, true);
|
|
5704 },
|
|
5705 /**
|
|
5706 * @private
|
|
5707 * @method _handleInsertImageWindowClose
|
|
5708 * @description Handles the closing of the Image Properties Window.
|
|
5709 */
|
|
5710 _handleInsertImageWindowClose: function() {
|
|
5711 this.nodeChange();
|
|
5712 },
|
|
5713 /**
|
|
5714 * @private
|
|
5715 * @method _isLocalFile
|
|
5716 * @param {String} url THe url/string to check
|
|
5717 * @description Checks to see if a string (href or img src) is possibly a local file reference..
|
|
5718 */
|
|
5719 _isLocalFile: function(url) {
|
|
5720 if ((url) && (url !== '') && ((url.indexOf('file:/') != -1) || (url.indexOf(':\\') != -1))) {
|
|
5721 return true;
|
|
5722 }
|
|
5723 return false;
|
|
5724 },
|
|
5725 /**
|
|
5726 * @private
|
|
5727 * @method _handleCreateLinkClick
|
|
5728 * @description Handles the opening of the Link Properties Window when the Create Link button is clicked or an href is doubleclicked.
|
|
5729 */
|
|
5730 _handleCreateLinkClick: function() {
|
|
5731 if (this.get('limitCommands')) {
|
|
5732 if (!this.toolbar.getButtonByValue('createlink')) {
|
|
5733 YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'SimpleEditor');
|
|
5734 return false;
|
|
5735 }
|
|
5736 }
|
|
5737
|
|
5738 this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
|
|
5739
|
|
5740 var _handleAEC = function() {
|
|
5741 var el = this.currentElement[0],
|
|
5742 url = '';
|
|
5743
|
|
5744 if (el) {
|
|
5745 if (el.getAttribute('href', 2) !== null) {
|
|
5746 url = el.getAttribute('href', 2);
|
|
5747 }
|
|
5748 }
|
|
5749 var str = prompt(this.STR_LINK_URL + ': ', url);
|
|
5750 if ((str !== '') && (str !== null)) {
|
|
5751 var urlValue = str;
|
|
5752 if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
5753 if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
5754 //Found an @ sign, prefix with mailto:
|
|
5755 urlValue = 'mailto:' + urlValue;
|
|
5756 } else {
|
|
5757 /* :// not found adding */
|
|
5758 if (urlValue.substring(0, 1) != '#') {
|
|
5759 //urlValue = 'http:/'+'/' + urlValue;
|
|
5760 }
|
|
5761 }
|
|
5762 }
|
|
5763 el.setAttribute('href', urlValue);
|
|
5764 } else if (str !== null) {
|
|
5765 var _span = this._getDoc().createElement('span');
|
|
5766 _span.innerHTML = el.innerHTML;
|
|
5767 Dom.addClass(_span, 'yui-non');
|
|
5768 el.parentNode.replaceChild(_span, el);
|
|
5769 }
|
|
5770 this.closeWindow();
|
|
5771 this.toolbar.set('disabled', false);
|
|
5772 this.unsubscribe('afterExecCommand', _handleAEC, this, true);
|
|
5773 };
|
|
5774 this.on('afterExecCommand', _handleAEC, this);
|
|
5775
|
|
5776 },
|
|
5777 /**
|
|
5778 * @private
|
|
5779 * @method _handleCreateLinkWindowClose
|
|
5780 * @description Handles the closing of the Link Properties Window.
|
|
5781 */
|
|
5782 _handleCreateLinkWindowClose: function() {
|
|
5783 this.nodeChange();
|
|
5784 this.currentElement = [];
|
|
5785 },
|
|
5786 /**
|
|
5787 * @method render
|
|
5788 * @description Calls the private method _render in a setTimeout to allow for other things on the page to continue to load.
|
|
5789 */
|
|
5790 render: function() {
|
|
5791 if (this._rendered) {
|
|
5792 return false;
|
|
5793 }
|
|
5794 YAHOO.log('Render', 'info', 'SimpleEditor');
|
|
5795 if (!this.DOMReady) {
|
|
5796 YAHOO.log('!DOMReady', 'info', 'SimpleEditor');
|
|
5797 this._queue[this._queue.length] = ['render', arguments];
|
|
5798 return false;
|
|
5799 }
|
|
5800 if (this.get('element')) {
|
|
5801 if (this.get('element').tagName) {
|
|
5802 this._textarea = true;
|
|
5803 if (this.get('element').tagName.toLowerCase() !== 'textarea') {
|
|
5804 this._textarea = false;
|
|
5805 }
|
|
5806 } else {
|
|
5807 YAHOO.log('No Valid Element', 'error', 'SimpleEditor');
|
|
5808 return false;
|
|
5809 }
|
|
5810 } else {
|
|
5811 YAHOO.log('No Element', 'error', 'SimpleEditor');
|
|
5812 return false;
|
|
5813 }
|
|
5814 this._rendered = true;
|
|
5815 var self = this;
|
|
5816 window.setTimeout(function() {
|
|
5817 self._render.call(self);
|
|
5818 }, 4);
|
|
5819 },
|
|
5820 /**
|
|
5821 * @private
|
|
5822 * @method _render
|
|
5823 * @description Causes the toolbar and the editor to render and replace the textarea.
|
|
5824 */
|
|
5825 _render: function() {
|
|
5826 var self = this;
|
|
5827 this.set('textarea', this.get('element'));
|
|
5828
|
|
5829 this.get('element_cont').setStyle('display', 'none');
|
|
5830 this.get('element_cont').addClass(this.CLASS_CONTAINER);
|
|
5831
|
|
5832 this.set('iframe', this._createIframe());
|
|
5833
|
|
5834 window.setTimeout(function() {
|
|
5835 self._setInitialContent.call(self);
|
|
5836 }, 10);
|
|
5837
|
|
5838 this.get('editor_wrapper').appendChild(this.get('iframe').get('element'));
|
|
5839
|
|
5840 if (this.get('disabled')) {
|
|
5841 this._disableEditor(true);
|
|
5842 }
|
|
5843
|
|
5844 var tbarConf = this.get('toolbar');
|
|
5845 //Create Toolbar instance
|
|
5846 if (tbarConf instanceof Toolbar) {
|
|
5847 this.toolbar = tbarConf;
|
|
5848 //Set the toolbar to disabled until content is loaded
|
|
5849 this.toolbar.set('disabled', true);
|
|
5850 } else {
|
|
5851 //Set the toolbar to disabled until content is loaded
|
|
5852 tbarConf.disabled = true;
|
|
5853 this.toolbar = new Toolbar(this.get('toolbar_cont'), tbarConf);
|
|
5854 }
|
|
5855
|
|
5856 YAHOO.log('fireEvent::toolbarLoaded', 'info', 'SimpleEditor');
|
|
5857 this.fireEvent('toolbarLoaded', { type: 'toolbarLoaded', target: this.toolbar });
|
|
5858
|
|
5859
|
|
5860 this.toolbar.on('toolbarCollapsed', function() {
|
|
5861 if (this.currentWindow) {
|
|
5862 this.moveWindow();
|
|
5863 }
|
|
5864 }, this, true);
|
|
5865 this.toolbar.on('toolbarExpanded', function() {
|
|
5866 if (this.currentWindow) {
|
|
5867 this.moveWindow();
|
|
5868 }
|
|
5869 }, this, true);
|
|
5870 this.toolbar.on('fontsizeClick', this._handleFontSize, this, true);
|
|
5871
|
|
5872 this.toolbar.on('colorPickerClicked', function(o) {
|
|
5873 this._handleColorPicker(o);
|
|
5874 return false; //Stop the buttonClick event
|
|
5875 }, this, true);
|
|
5876
|
|
5877 this.toolbar.on('alignClick', this._handleAlign, this, true);
|
|
5878 this.on('afterNodeChange', this._handleAfterNodeChange, this, true);
|
|
5879 this.toolbar.on('insertimageClick', this._handleInsertImageClick, this, true);
|
|
5880 this.on('windowinsertimageClose', this._handleInsertImageWindowClose, this, true);
|
|
5881 this.toolbar.on('createlinkClick', this._handleCreateLinkClick, this, true);
|
|
5882 this.on('windowcreatelinkClose', this._handleCreateLinkWindowClose, this, true);
|
|
5883
|
|
5884
|
|
5885 //Replace Textarea with editable area
|
|
5886 this.get('parentNode').replaceChild(this.get('element_cont').get('element'), this.get('element'));
|
|
5887
|
|
5888
|
|
5889 this.setStyle('visibility', 'hidden');
|
|
5890 this.setStyle('position', 'absolute');
|
|
5891 this.setStyle('top', '-9999px');
|
|
5892 this.setStyle('left', '-9999px');
|
|
5893 this.get('element_cont').appendChild(this.get('element'));
|
|
5894 this.get('element_cont').setStyle('display', 'block');
|
|
5895
|
|
5896
|
|
5897 Dom.addClass(this.get('iframe').get('parentNode'), this.CLASS_EDITABLE_CONT);
|
|
5898 this.get('iframe').addClass(this.CLASS_EDITABLE);
|
|
5899
|
|
5900 //Set height and width of editor container
|
|
5901 this.get('element_cont').setStyle('width', this.get('width'));
|
|
5902 Dom.setStyle(this.get('iframe').get('parentNode'), 'height', this.get('height'));
|
|
5903
|
|
5904 this.get('iframe').setStyle('width', '100%'); //WIDTH
|
|
5905 this.get('iframe').setStyle('height', '100%');
|
|
5906
|
|
5907 this._setupDD();
|
|
5908
|
|
5909 window.setTimeout(function() {
|
|
5910 self._setupAfterElement.call(self);
|
|
5911 }, 0);
|
|
5912 this.fireEvent('afterRender', { type: 'afterRender', target: this });
|
|
5913 },
|
|
5914 /**
|
|
5915 * @method execCommand
|
|
5916 * @param {String} action The "execCommand" action to try to execute (Example: bold, insertimage, inserthtml)
|
|
5917 * @param {String} value (optional) The value for a given action such as action: fontname value: 'Verdana'
|
|
5918 * @description This method attempts to try and level the differences in the various browsers and their support for execCommand actions
|
|
5919 */
|
|
5920 execCommand: function(action, value) {
|
|
5921 var beforeExec = this.fireEvent('beforeExecCommand', { type: 'beforeExecCommand', target: this, args: arguments });
|
|
5922 if ((beforeExec === false) || (this.STOP_EXEC_COMMAND)) {
|
|
5923 this.STOP_EXEC_COMMAND = false;
|
|
5924 return false;
|
|
5925 }
|
|
5926 this._lastCommand = action;
|
|
5927 this._setMarkupType(action);
|
|
5928 if (this.browser.ie) {
|
|
5929 this._getWindow().focus();
|
|
5930 }
|
|
5931 var exec = true;
|
|
5932
|
|
5933 if (this.get('limitCommands')) {
|
|
5934 if (!this.toolbar.getButtonByValue(action)) {
|
|
5935 YAHOO.log('Toolbar Button for (' + action + ') was not found, skipping exec.', 'info', 'SimpleEditor');
|
|
5936 exec = false;
|
|
5937 }
|
|
5938 }
|
|
5939
|
|
5940 this.editorDirty = true;
|
|
5941
|
|
5942 if ((typeof this['cmd_' + action.toLowerCase()] == 'function') && exec) {
|
|
5943 YAHOO.log('Found execCommand override method: (cmd_' + action.toLowerCase() + ')', 'info', 'SimpleEditor');
|
|
5944 var retValue = this['cmd_' + action.toLowerCase()](value);
|
|
5945 exec = retValue[0];
|
|
5946 if (retValue[1]) {
|
|
5947 action = retValue[1];
|
|
5948 }
|
|
5949 if (retValue[2]) {
|
|
5950 value = retValue[2];
|
|
5951 }
|
|
5952 }
|
|
5953 if (exec) {
|
|
5954 YAHOO.log('execCommand::(' + action + '), (' + value + ')', 'info', 'SimpleEditor');
|
|
5955 try {
|
|
5956 this._getDoc().execCommand(action, false, value);
|
|
5957 } catch(e) {
|
|
5958 YAHOO.log('execCommand Failed', 'error', 'SimpleEditor');
|
|
5959 }
|
|
5960 } else {
|
|
5961 YAHOO.log('OVERRIDE::execCommand::(' + action + '),(' + value + ') skipped', 'warn', 'SimpleEditor');
|
|
5962 }
|
|
5963 this.on('afterExecCommand', function() {
|
|
5964 this.unsubscribeAll('afterExecCommand');
|
|
5965 this.nodeChange();
|
|
5966 }, this, true);
|
|
5967 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
5968
|
|
5969 },
|
|
5970 /* {{{ Command Overrides */
|
|
5971
|
|
5972 /**
|
|
5973 * @method cmd_bold
|
|
5974 * @param value Value passed from the execCommand method
|
|
5975 * @description This is an execCommand override method. It is called from execCommand when the execCommand('bold') is used.
|
|
5976 */
|
|
5977 cmd_bold: function(value) {
|
|
5978 if (!this.browser.webkit) {
|
|
5979 var el = this._getSelectedElement();
|
|
5980 if (el && this._isElement(el, 'span') && this._hasSelection()) {
|
|
5981 if (el.style.fontWeight == 'bold') {
|
|
5982 el.style.fontWeight = '';
|
|
5983 var b = this._getDoc().createElement('b'),
|
|
5984 par = el.parentNode;
|
|
5985 par.replaceChild(b, el);
|
|
5986 b.appendChild(el);
|
|
5987 }
|
|
5988 }
|
|
5989 }
|
|
5990 return [true];
|
|
5991 },
|
|
5992 /**
|
|
5993 * @method cmd_italic
|
|
5994 * @param value Value passed from the execCommand method
|
|
5995 * @description This is an execCommand override method. It is called from execCommand when the execCommand('italic') is used.
|
|
5996 */
|
|
5997
|
|
5998 cmd_italic: function(value) {
|
|
5999 if (!this.browser.webkit) {
|
|
6000 var el = this._getSelectedElement();
|
|
6001 if (el && this._isElement(el, 'span') && this._hasSelection()) {
|
|
6002 if (el.style.fontStyle == 'italic') {
|
|
6003 el.style.fontStyle = '';
|
|
6004 var i = this._getDoc().createElement('i'),
|
|
6005 par = el.parentNode;
|
|
6006 par.replaceChild(i, el);
|
|
6007 i.appendChild(el);
|
|
6008 }
|
|
6009 }
|
|
6010 }
|
|
6011 return [true];
|
|
6012 },
|
|
6013
|
|
6014
|
|
6015 /**
|
|
6016 * @method cmd_underline
|
|
6017 * @param value Value passed from the execCommand method
|
|
6018 * @description This is an execCommand override method. It is called from execCommand when the execCommand('underline') is used.
|
|
6019 */
|
|
6020 cmd_underline: function(value) {
|
|
6021 if (!this.browser.webkit) {
|
|
6022 var el = this._getSelectedElement();
|
|
6023 if (el && this._isElement(el, 'span')) {
|
|
6024 if (el.style.textDecoration == 'underline') {
|
|
6025 el.style.textDecoration = 'none';
|
|
6026 } else {
|
|
6027 el.style.textDecoration = 'underline';
|
|
6028 }
|
|
6029 return [false];
|
|
6030 }
|
|
6031 }
|
|
6032 return [true];
|
|
6033 },
|
|
6034 /**
|
|
6035 * @method cmd_backcolor
|
|
6036 * @param value Value passed from the execCommand method
|
|
6037 * @description This is an execCommand override method. It is called from execCommand when the execCommand('backcolor') is used.
|
|
6038 */
|
|
6039 cmd_backcolor: function(value) {
|
|
6040 var exec = true,
|
|
6041 el = this._getSelectedElement(),
|
|
6042 action = 'backcolor';
|
|
6043
|
|
6044 if (this.browser.gecko || this.browser.opera) {
|
|
6045 this._setEditorStyle(true);
|
|
6046 action = 'hilitecolor';
|
|
6047 }
|
|
6048
|
|
6049 if (!this._isElement(el, 'body') && !this._hasSelection()) {
|
|
6050 el.style.backgroundColor = value;
|
|
6051 this._selectNode(el);
|
|
6052 exec = false;
|
|
6053 } else {
|
|
6054 if (this.get('insert')) {
|
|
6055 el = this._createInsertElement({ backgroundColor: value });
|
|
6056 } else {
|
|
6057 this._createCurrentElement('span', { backgroundColor: value, color: el.style.color, fontSize: el.style.fontSize, fontFamily: el.style.fontFamily });
|
|
6058 this._selectNode(this.currentElement[0]);
|
|
6059 }
|
|
6060 exec = false;
|
|
6061 }
|
|
6062
|
|
6063 return [exec, action];
|
|
6064 },
|
|
6065 /**
|
|
6066 * @method cmd_forecolor
|
|
6067 * @param value Value passed from the execCommand method
|
|
6068 * @description This is an execCommand override method. It is called from execCommand when the execCommand('forecolor') is used.
|
|
6069 */
|
|
6070 cmd_forecolor: function(value) {
|
|
6071 var exec = true,
|
|
6072 el = this._getSelectedElement();
|
|
6073
|
|
6074 if (!this._isElement(el, 'body') && !this._hasSelection()) {
|
|
6075 Dom.setStyle(el, 'color', value);
|
|
6076 this._selectNode(el);
|
|
6077 exec = false;
|
|
6078 } else {
|
|
6079 if (this.get('insert')) {
|
|
6080 el = this._createInsertElement({ color: value });
|
|
6081 } else {
|
|
6082 this._createCurrentElement('span', { color: value, fontSize: el.style.fontSize, fontFamily: el.style.fontFamily, backgroundColor: el.style.backgroundColor });
|
|
6083 this._selectNode(this.currentElement[0]);
|
|
6084 }
|
|
6085 exec = false;
|
|
6086 }
|
|
6087 return [exec];
|
|
6088 },
|
|
6089 /**
|
|
6090 * @method cmd_unlink
|
|
6091 * @param value Value passed from the execCommand method
|
|
6092 * @description This is an execCommand override method. It is called from execCommand when the execCommand('unlink') is used.
|
|
6093 */
|
|
6094 cmd_unlink: function(value) {
|
|
6095 this._swapEl(this.currentElement[0], 'span', function(el) {
|
|
6096 el.className = 'yui-non';
|
|
6097 });
|
|
6098 return [false];
|
|
6099 },
|
|
6100 /**
|
|
6101 * @method cmd_createlink
|
|
6102 * @param value Value passed from the execCommand method
|
|
6103 * @description This is an execCommand override method. It is called from execCommand when the execCommand('createlink') is used.
|
|
6104 */
|
|
6105 cmd_createlink: function(value) {
|
|
6106 var el = this._getSelectedElement(), _a = null;
|
|
6107 if (this._hasParent(el, 'a')) {
|
|
6108 this.currentElement[0] = this._hasParent(el, 'a');
|
|
6109 } else if (this._isElement(el, 'li')) {
|
|
6110 _a = this._getDoc().createElement('a');
|
|
6111 _a.innerHTML = el.innerHTML;
|
|
6112 el.innerHTML = '';
|
|
6113 el.appendChild(_a);
|
|
6114 this.currentElement[0] = _a;
|
|
6115 } else if (!this._isElement(el, 'a')) {
|
|
6116 this._createCurrentElement('a');
|
|
6117 _a = this._swapEl(this.currentElement[0], 'a');
|
|
6118 this.currentElement[0] = _a;
|
|
6119 } else {
|
|
6120 this.currentElement[0] = el;
|
|
6121 }
|
|
6122 return [false];
|
|
6123 },
|
|
6124 /**
|
|
6125 * @method cmd_insertimage
|
|
6126 * @param value Value passed from the execCommand method
|
|
6127 * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertimage') is used.
|
|
6128 */
|
|
6129 cmd_insertimage: function(value) {
|
|
6130 var exec = true, _img = null, action = 'insertimage',
|
|
6131 el = this._getSelectedElement();
|
|
6132
|
|
6133 if (value === '') {
|
|
6134 value = this.get('blankimage');
|
|
6135 }
|
|
6136
|
|
6137 /*
|
|
6138 * @knownissue Safari Cursor Position
|
|
6139 * @browser Safari 2.x
|
|
6140 * @description The issue here is that we have no way of knowing where the cursor position is
|
|
6141 * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
|
|
6142 */
|
|
6143
|
|
6144 YAHOO.log('InsertImage: ' + el.tagName, 'info', 'SimpleEditor');
|
|
6145 if (this._isElement(el, 'img')) {
|
|
6146 this.currentElement[0] = el;
|
|
6147 exec = false;
|
|
6148 } else {
|
|
6149 if (this._getDoc().queryCommandEnabled(action)) {
|
|
6150 this._getDoc().execCommand(action, false, value);
|
|
6151 var imgs = this._getDoc().getElementsByTagName('img');
|
|
6152 for (var i = 0; i < imgs.length; i++) {
|
|
6153 if (!YAHOO.util.Dom.hasClass(imgs[i], 'yui-img')) {
|
|
6154 YAHOO.util.Dom.addClass(imgs[i], 'yui-img');
|
|
6155 this.currentElement[0] = imgs[i];
|
|
6156 }
|
|
6157 }
|
|
6158 exec = false;
|
|
6159 } else {
|
|
6160 if (el == this._getDoc().body) {
|
|
6161 _img = this._getDoc().createElement('img');
|
|
6162 _img.setAttribute('src', value);
|
|
6163 YAHOO.util.Dom.addClass(_img, 'yui-img');
|
|
6164 this._getDoc().body.appendChild(_img);
|
|
6165 } else {
|
|
6166 this._createCurrentElement('img');
|
|
6167 _img = this._getDoc().createElement('img');
|
|
6168 _img.setAttribute('src', value);
|
|
6169 YAHOO.util.Dom.addClass(_img, 'yui-img');
|
|
6170 this.currentElement[0].parentNode.replaceChild(_img, this.currentElement[0]);
|
|
6171 }
|
|
6172 this.currentElement[0] = _img;
|
|
6173 exec = false;
|
|
6174 }
|
|
6175 }
|
|
6176 return [exec];
|
|
6177 },
|
|
6178 /**
|
|
6179 * @method cmd_inserthtml
|
|
6180 * @param value Value passed from the execCommand method
|
|
6181 * @description This is an execCommand override method. It is called from execCommand when the execCommand('inserthtml') is used.
|
|
6182 */
|
|
6183 cmd_inserthtml: function(value) {
|
|
6184 var exec = true, action = 'inserthtml', _span = null, _range = null;
|
|
6185 /*
|
|
6186 * @knownissue Safari cursor position
|
|
6187 * @browser Safari 2.x
|
|
6188 * @description The issue here is that we have no way of knowing where the cursor position is
|
|
6189 * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
|
|
6190 */
|
|
6191 if (this.browser.webkit && !this._getDoc().queryCommandEnabled(action)) {
|
|
6192 YAHOO.log('More Safari DOM tricks (inserthtml)', 'info', 'EditorSafari');
|
|
6193 this._createCurrentElement('img');
|
|
6194 _span = this._getDoc().createElement('span');
|
|
6195 _span.innerHTML = value;
|
|
6196 this.currentElement[0].parentNode.replaceChild(_span, this.currentElement[0]);
|
|
6197 exec = false;
|
|
6198 } else if (this.browser.ie) {
|
|
6199 _range = this._getRange();
|
|
6200 if (_range.item) {
|
|
6201 _range.item(0).outerHTML = value;
|
|
6202 } else {
|
|
6203 _range.pasteHTML(value);
|
|
6204 }
|
|
6205 exec = false;
|
|
6206 }
|
|
6207 return [exec];
|
|
6208 },
|
|
6209 /**
|
|
6210 * @method cmd_list
|
|
6211 * @param tag The tag of the list you want to create (eg, ul or ol)
|
|
6212 * @description This is a combined execCommand override method. It is called from the cmd_insertorderedlist and cmd_insertunorderedlist methods.
|
|
6213 */
|
|
6214 cmd_list: function(tag) {
|
|
6215 var exec = true, list = null, li = 0, el = null, str = '',
|
|
6216 selEl = this._getSelectedElement(), action = 'insertorderedlist';
|
|
6217 if (tag == 'ul') {
|
|
6218 action = 'insertunorderedlist';
|
|
6219 }
|
|
6220 /*
|
|
6221 * @knownissue Safari 2.+ doesn't support ordered and unordered lists
|
|
6222 * @browser Safari 2.x
|
|
6223 * The issue with this workaround is that when applied to a set of text
|
|
6224 * that has BR's in it, Safari may or may not pick up the individual items as
|
|
6225 * list items. This is fixed in WebKit (Safari 3)
|
|
6226 * 2.6.0: Seems there are still some issues with List Creation and Safari 3, reverting to previously working Safari 2.x code
|
|
6227 */
|
|
6228 //if ((this.browser.webkit && !this._getDoc().queryCommandEnabled(action))) {
|
|
6229 if ((this.browser.webkit && !this.browser.webkit4) || (this.browser.opera)) {
|
|
6230 if (this._isElement(selEl, 'li') && this._isElement(selEl.parentNode, tag)) {
|
|
6231 YAHOO.log('We already have a list, undo it', 'info', 'SimpleEditor');
|
|
6232 el = selEl.parentNode;
|
|
6233 list = this._getDoc().createElement('span');
|
|
6234 YAHOO.util.Dom.addClass(list, 'yui-non');
|
|
6235 str = '';
|
|
6236 var lis = el.getElementsByTagName('li'), p_tag = ((this.browser.opera && this.get('ptags')) ? 'p' : 'div');
|
|
6237 for (li = 0; li < lis.length; li++) {
|
|
6238 str += '<' + p_tag + '>' + lis[li].innerHTML + '</' + p_tag + '>';
|
|
6239 }
|
|
6240 list.innerHTML = str;
|
|
6241 this.currentElement[0] = el;
|
|
6242 this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
|
|
6243 } else {
|
|
6244 YAHOO.log('Create list item', 'info', 'SimpleEditor');
|
|
6245 this._createCurrentElement(tag.toLowerCase());
|
|
6246 list = this._getDoc().createElement(tag);
|
|
6247 for (li = 0; li < this.currentElement.length; li++) {
|
|
6248 var newli = this._getDoc().createElement('li');
|
|
6249 newli.innerHTML = this.currentElement[li].innerHTML + '<span class="yui-non"> </span> ';
|
|
6250 list.appendChild(newli);
|
|
6251 if (li > 0) {
|
|
6252 this.currentElement[li].parentNode.removeChild(this.currentElement[li]);
|
|
6253 }
|
|
6254 }
|
|
6255 var b_tag = ((this.browser.opera) ? '<BR>' : '<br>'),
|
|
6256 items = list.firstChild.innerHTML.split(b_tag), i, item;
|
|
6257 if (items.length > 0) {
|
|
6258 list.innerHTML = '';
|
|
6259 for (i = 0; i < items.length; i++) {
|
|
6260 item = this._getDoc().createElement('li');
|
|
6261 item.innerHTML = items[i];
|
|
6262 list.appendChild(item);
|
|
6263 }
|
|
6264 }
|
|
6265
|
|
6266 this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
|
|
6267 this.currentElement[0] = list;
|
|
6268 var _h = this.currentElement[0].firstChild;
|
|
6269 _h = Dom.getElementsByClassName('yui-non', 'span', _h)[0];
|
|
6270 if (this.browser.webkit) {
|
|
6271 this._getSelection().setBaseAndExtent(_h, 1, _h, _h.innerText.length);
|
|
6272 }
|
|
6273 }
|
|
6274 exec = false;
|
|
6275 } else {
|
|
6276 el = this._getSelectedElement();
|
|
6277 YAHOO.log(el.tagName);
|
|
6278 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..
|
|
6279 YAHOO.log('We already have a list, undo it', 'info', 'SimpleEditor');
|
|
6280 if (this.browser.ie) {
|
|
6281 if ((this.browser.ie && this._isElement(el, 'ul')) || (this.browser.ie && this._isElement(el, 'ol'))) {
|
|
6282 el = el.getElementsByTagName('li')[0];
|
|
6283 }
|
|
6284 YAHOO.log('Undo IE', 'info', 'SimpleEditor');
|
|
6285 str = '';
|
|
6286 var lis2 = el.parentNode.getElementsByTagName('li');
|
|
6287 for (var j = 0; j < lis2.length; j++) {
|
|
6288 str += lis2[j].innerHTML + '<br>';
|
|
6289 }
|
|
6290 var newEl = this._getDoc().createElement('span');
|
|
6291 newEl.innerHTML = str;
|
|
6292 el.parentNode.parentNode.replaceChild(newEl, el.parentNode);
|
|
6293 } else {
|
|
6294 this.nodeChange();
|
|
6295 this._getDoc().execCommand(action, '', el.parentNode);
|
|
6296 this.nodeChange();
|
|
6297 }
|
|
6298 exec = false;
|
|
6299 }
|
|
6300 if (this.browser.opera) {
|
|
6301 var self = this;
|
|
6302 window.setTimeout(function() {
|
|
6303 var liso = self._getDoc().getElementsByTagName('li');
|
|
6304 for (var i = 0; i < liso.length; i++) {
|
|
6305 if (liso[i].innerHTML.toLowerCase() == '<br>') {
|
|
6306 liso[i].parentNode.parentNode.removeChild(liso[i].parentNode);
|
|
6307 }
|
|
6308 }
|
|
6309 },30);
|
|
6310 }
|
|
6311 if (this.browser.ie && exec) {
|
|
6312 var html = '';
|
|
6313 if (this._getRange().html) {
|
|
6314 html = '<li>' + this._getRange().html+ '</li>';
|
|
6315 } else {
|
|
6316 var t = this._getRange().text.split('\n');
|
|
6317 if (t.length > 1) {
|
|
6318 html = '';
|
|
6319 for (var ie = 0; ie < t.length; ie++) {
|
|
6320 html += '<li>' + t[ie] + '</li>';
|
|
6321 }
|
|
6322 } else {
|
|
6323 var txt = this._getRange().text;
|
|
6324 if (txt === '') {
|
|
6325 html = '<li id="new_list_item">' + txt + '</li>';
|
|
6326 } else {
|
|
6327 html = '<li>' + txt + '</li>';
|
|
6328 }
|
|
6329 }
|
|
6330 }
|
|
6331 this._getRange().pasteHTML('<' + tag + '>' + html + '</' + tag + '>');
|
|
6332 var new_item = this._getDoc().getElementById('new_list_item');
|
|
6333 if (new_item) {
|
|
6334 var range = this._getDoc().body.createTextRange();
|
|
6335 range.moveToElementText(new_item);
|
|
6336 range.collapse(false);
|
|
6337 range.select();
|
|
6338 new_item.id = '';
|
|
6339 }
|
|
6340 exec = false;
|
|
6341 }
|
|
6342 }
|
|
6343 return exec;
|
|
6344 },
|
|
6345 /**
|
|
6346 * @method cmd_insertorderedlist
|
|
6347 * @param value Value passed from the execCommand method
|
|
6348 * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertorderedlist ') is used.
|
|
6349 */
|
|
6350 cmd_insertorderedlist: function(value) {
|
|
6351 return [this.cmd_list('ol')];
|
|
6352 },
|
|
6353 /**
|
|
6354 * @method cmd_insertunorderedlist
|
|
6355 * @param value Value passed from the execCommand method
|
|
6356 * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertunorderedlist') is used.
|
|
6357 */
|
|
6358 cmd_insertunorderedlist: function(value) {
|
|
6359 return [this.cmd_list('ul')];
|
|
6360 },
|
|
6361 /**
|
|
6362 * @method cmd_fontname
|
|
6363 * @param value Value passed from the execCommand method
|
|
6364 * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontname') is used.
|
|
6365 */
|
|
6366 cmd_fontname: function(value) {
|
|
6367 var exec = true,
|
|
6368 selEl = this._getSelectedElement();
|
|
6369
|
|
6370 this.currentFont = value;
|
|
6371 if (selEl && selEl.tagName && !this._hasSelection() && !this._isElement(selEl, 'body') && !this.get('insert')) {
|
|
6372 YAHOO.util.Dom.setStyle(selEl, 'font-family', value);
|
|
6373 exec = false;
|
|
6374 } else if (this.get('insert') && !this._hasSelection()) {
|
|
6375 YAHOO.log('No selection and no selected element and we are in insert mode', 'info', 'SimpleEditor');
|
|
6376 var el = this._createInsertElement({ fontFamily: value });
|
|
6377 exec = false;
|
|
6378 }
|
|
6379 return [exec];
|
|
6380 },
|
|
6381 /**
|
|
6382 * @method cmd_fontsize
|
|
6383 * @param value Value passed from the execCommand method
|
|
6384 * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontsize') is used.
|
|
6385 */
|
|
6386 cmd_fontsize: function(value) {
|
|
6387 var el = null, go = true;
|
|
6388 el = this._getSelectedElement();
|
|
6389 if (this.browser.webkit) {
|
|
6390 if (this.currentElement[0]) {
|
|
6391 if (el == this.currentElement[0]) {
|
|
6392 go = false;
|
|
6393 YAHOO.util.Dom.setStyle(el, 'fontSize', value);
|
|
6394 this._selectNode(el);
|
|
6395 this.currentElement[0] = el;
|
|
6396 }
|
|
6397 }
|
|
6398 }
|
|
6399 if (go) {
|
|
6400 if (!this._isElement(this._getSelectedElement(), 'body') && (!this._hasSelection())) {
|
|
6401 el = this._getSelectedElement();
|
|
6402 YAHOO.util.Dom.setStyle(el, 'fontSize', value);
|
|
6403 if (this.get('insert') && this.browser.ie) {
|
|
6404 var r = this._getRange();
|
|
6405 r.collapse(false);
|
|
6406 r.select();
|
|
6407 } else {
|
|
6408 this._selectNode(el);
|
|
6409 }
|
|
6410 } else if (this.currentElement && (this.currentElement.length > 0) && (!this._hasSelection()) && (!this.get('insert'))) {
|
|
6411 YAHOO.util.Dom.setStyle(this.currentElement, 'fontSize', value);
|
|
6412 } else {
|
|
6413 if (this.get('insert') && !this._hasSelection()) {
|
|
6414 el = this._createInsertElement({ fontSize: value });
|
|
6415 this.currentElement[0] = el;
|
|
6416 this._selectNode(this.currentElement[0]);
|
|
6417 } else {
|
|
6418 this._createCurrentElement('span', {'fontSize': value, fontFamily: el.style.fontFamily, color: el.style.color, backgroundColor: el.style.backgroundColor });
|
|
6419 this._selectNode(this.currentElement[0]);
|
|
6420 }
|
|
6421 }
|
|
6422 }
|
|
6423 return [false];
|
|
6424 },
|
|
6425 /* }}} */
|
|
6426 /**
|
|
6427 * @private
|
|
6428 * @method _swapEl
|
|
6429 * @param {HTMLElement} el The element to swap with
|
|
6430 * @param {String} tagName The tagname of the element that you wish to create
|
|
6431 * @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.
|
|
6432 * @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.
|
|
6433 */
|
|
6434 _swapEl: function(el, tagName, callback) {
|
|
6435 var _el = this._getDoc().createElement(tagName);
|
|
6436 if (el) {
|
|
6437 _el.innerHTML = el.innerHTML;
|
|
6438 }
|
|
6439 if (typeof callback == 'function') {
|
|
6440 callback.call(this, _el);
|
|
6441 }
|
|
6442 if (el) {
|
|
6443 el.parentNode.replaceChild(_el, el);
|
|
6444 }
|
|
6445 return _el;
|
|
6446 },
|
|
6447 /**
|
|
6448 * @private
|
|
6449 * @method _createInsertElement
|
|
6450 * @description Creates a new "currentElement" then adds some text (and other things) to make it selectable and stylable. Then the user can continue typing.
|
|
6451 * @param {Object} css (optional) Object literal containing styles to apply to the new element.
|
|
6452 * @return {HTMLElement}
|
|
6453 */
|
|
6454 _createInsertElement: function(css) {
|
|
6455 this._createCurrentElement('span', css);
|
|
6456 var el = this.currentElement[0];
|
|
6457 if (this.browser.webkit) {
|
|
6458 //Little Safari Hackery here..
|
|
6459 el.innerHTML = '<span class="yui-non"> </span>';
|
|
6460 el = el.firstChild;
|
|
6461 this._getSelection().setBaseAndExtent(el, 1, el, el.innerText.length);
|
|
6462 } else if (this.browser.ie || this.browser.opera) {
|
|
6463 el.innerHTML = ' ';
|
|
6464 }
|
|
6465 this.focus();
|
|
6466 this._selectNode(el, true);
|
|
6467 return el;
|
|
6468 },
|
|
6469 /**
|
|
6470 * @private
|
|
6471 * @method _createCurrentElement
|
|
6472 * @param {String} tagName (optional defaults to a) The tagname of the element that you wish to create
|
|
6473 * @param {Object} tagStyle (optional) Object literal containing styles to apply to the new element.
|
|
6474 * @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.
|
|
6475 * 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
|
|
6476 * <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.
|
|
6477 */
|
|
6478 _createCurrentElement: function(tagName, tagStyle) {
|
|
6479 tagName = ((tagName) ? tagName : 'a');
|
|
6480 var tar = null,
|
|
6481 el = [],
|
|
6482 _doc = this._getDoc();
|
|
6483
|
|
6484 if (this.currentFont) {
|
|
6485 if (!tagStyle) {
|
|
6486 tagStyle = {};
|
|
6487 }
|
|
6488 tagStyle.fontFamily = this.currentFont;
|
|
6489 this.currentFont = null;
|
|
6490 }
|
|
6491 this.currentElement = [];
|
|
6492
|
|
6493 var _elCreate = function(tagName, tagStyle) {
|
|
6494 var el = null;
|
|
6495 tagName = ((tagName) ? tagName : 'span');
|
|
6496 tagName = tagName.toLowerCase();
|
|
6497 switch (tagName) {
|
|
6498 case 'h1':
|
|
6499 case 'h2':
|
|
6500 case 'h3':
|
|
6501 case 'h4':
|
|
6502 case 'h5':
|
|
6503 case 'h6':
|
|
6504 el = _doc.createElement(tagName);
|
|
6505 break;
|
|
6506 default:
|
|
6507 el = _doc.createElement(tagName);
|
|
6508 if (tagName === 'span') {
|
|
6509 YAHOO.util.Dom.addClass(el, 'yui-tag-' + tagName);
|
|
6510 YAHOO.util.Dom.addClass(el, 'yui-tag');
|
|
6511 el.setAttribute('tag', tagName);
|
|
6512 }
|
|
6513
|
|
6514 for (var k in tagStyle) {
|
|
6515 if (YAHOO.lang.hasOwnProperty(tagStyle, k)) {
|
|
6516 el.style[k] = tagStyle[k];
|
|
6517 }
|
|
6518 }
|
|
6519 break;
|
|
6520 }
|
|
6521 return el;
|
|
6522 };
|
|
6523
|
|
6524 if (!this._hasSelection()) {
|
|
6525 if (this._getDoc().queryCommandEnabled('insertimage')) {
|
|
6526 this._getDoc().execCommand('insertimage', false, 'yui-tmp-img');
|
|
6527 var imgs = this._getDoc().getElementsByTagName('img');
|
|
6528 for (var j = 0; j < imgs.length; j++) {
|
|
6529 if (imgs[j].getAttribute('src', 2) == 'yui-tmp-img') {
|
|
6530 el = _elCreate(tagName, tagStyle);
|
|
6531 imgs[j].parentNode.replaceChild(el, imgs[j]);
|
|
6532 this.currentElement[this.currentElement.length] = el;
|
|
6533 }
|
|
6534 }
|
|
6535 } else {
|
|
6536 if (this.currentEvent) {
|
|
6537 tar = YAHOO.util.Event.getTarget(this.currentEvent);
|
|
6538 } else {
|
|
6539 //For Safari..
|
|
6540 tar = this._getDoc().body;
|
|
6541 }
|
|
6542 }
|
|
6543 if (tar) {
|
|
6544 /*
|
|
6545 * @knownissue Safari Cursor Position
|
|
6546 * @browser Safari 2.x
|
|
6547 * @description The issue here is that we have no way of knowing where the cursor position is
|
|
6548 * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
|
|
6549 */
|
|
6550 el = _elCreate(tagName, tagStyle);
|
|
6551 if (this._isElement(tar, 'body') || this._isElement(tar, 'html')) {
|
|
6552 if (this._isElement(tar, 'html')) {
|
|
6553 tar = this._getDoc().body;
|
|
6554 }
|
|
6555 tar.appendChild(el);
|
|
6556 } else if (tar.nextSibling) {
|
|
6557 tar.parentNode.insertBefore(el, tar.nextSibling);
|
|
6558 } else {
|
|
6559 tar.parentNode.appendChild(el);
|
|
6560 }
|
|
6561 //this.currentElement = el;
|
|
6562 this.currentElement[this.currentElement.length] = el;
|
|
6563 this.currentEvent = null;
|
|
6564 if (this.browser.webkit) {
|
|
6565 //Force Safari to focus the new element
|
|
6566 this._getSelection().setBaseAndExtent(el, 0, el, 0);
|
|
6567 if (this.browser.webkit3) {
|
|
6568 this._getSelection().collapseToStart();
|
|
6569 } else {
|
|
6570 this._getSelection().collapse(true);
|
|
6571 }
|
|
6572 }
|
|
6573 }
|
|
6574 } else {
|
|
6575 //Force CSS Styling for this action...
|
|
6576 this._setEditorStyle(true);
|
|
6577 this._getDoc().execCommand('fontname', false, 'yui-tmp');
|
|
6578 var _tmp = [], __tmp, __els = ['font', 'span', 'i', 'b', 'u'];
|
|
6579
|
|
6580 if (!this._isElement(this._getSelectedElement(), 'body')) {
|
|
6581 __els[__els.length] = this._getDoc().getElementsByTagName(this._getSelectedElement().tagName);
|
|
6582 __els[__els.length] = this._getDoc().getElementsByTagName(this._getSelectedElement().parentNode.tagName);
|
|
6583 }
|
|
6584 for (var _els = 0; _els < __els.length; _els++) {
|
|
6585 var _tmp1 = this._getDoc().getElementsByTagName(__els[_els]);
|
|
6586 for (var e = 0; e < _tmp1.length; e++) {
|
|
6587 _tmp[_tmp.length] = _tmp1[e];
|
|
6588 }
|
|
6589 }
|
|
6590
|
|
6591
|
|
6592 for (var i = 0; i < _tmp.length; i++) {
|
|
6593 if ((YAHOO.util.Dom.getStyle(_tmp[i], 'font-family') == 'yui-tmp') || (_tmp[i].face && (_tmp[i].face == 'yui-tmp'))) {
|
|
6594 if (tagName !== 'span') {
|
|
6595 el = _elCreate(tagName, tagStyle);
|
|
6596 } else {
|
|
6597 el = _elCreate(_tmp[i].tagName, tagStyle);
|
|
6598 }
|
|
6599 el.innerHTML = _tmp[i].innerHTML;
|
|
6600 if (this._isElement(_tmp[i], 'ol') || (this._isElement(_tmp[i], 'ul'))) {
|
|
6601 var fc = _tmp[i].getElementsByTagName('li')[0];
|
|
6602 _tmp[i].style.fontFamily = 'inherit';
|
|
6603 fc.style.fontFamily = 'inherit';
|
|
6604 el.innerHTML = fc.innerHTML;
|
|
6605 fc.innerHTML = '';
|
|
6606 fc.appendChild(el);
|
|
6607 this.currentElement[this.currentElement.length] = el;
|
|
6608 } else if (this._isElement(_tmp[i], 'li')) {
|
|
6609 _tmp[i].innerHTML = '';
|
|
6610 _tmp[i].appendChild(el);
|
|
6611 _tmp[i].style.fontFamily = 'inherit';
|
|
6612 this.currentElement[this.currentElement.length] = el;
|
|
6613 } else {
|
|
6614 if (_tmp[i].parentNode) {
|
|
6615 _tmp[i].parentNode.replaceChild(el, _tmp[i]);
|
|
6616 this.currentElement[this.currentElement.length] = el;
|
|
6617 this.currentEvent = null;
|
|
6618 if (this.browser.webkit) {
|
|
6619 //Force Safari to focus the new element
|
|
6620 this._getSelection().setBaseAndExtent(el, 0, el, 0);
|
|
6621 if (this.browser.webkit3) {
|
|
6622 this._getSelection().collapseToStart();
|
|
6623 } else {
|
|
6624 this._getSelection().collapse(true);
|
|
6625 }
|
|
6626 }
|
|
6627 if (this.browser.ie && tagStyle && tagStyle.fontSize) {
|
|
6628 this._getSelection().empty();
|
|
6629 }
|
|
6630 if (this.browser.gecko) {
|
|
6631 this._getSelection().collapseToStart();
|
|
6632 }
|
|
6633 }
|
|
6634 }
|
|
6635 }
|
|
6636 }
|
|
6637 var len = this.currentElement.length;
|
|
6638 for (var o = 0; o < len; o++) {
|
|
6639 if ((o + 1) != len) { //Skip the last one in the list
|
|
6640 if (this.currentElement[o] && this.currentElement[o].nextSibling) {
|
|
6641 if (this._isElement(this.currentElement[o], 'br')) {
|
|
6642 this.currentElement[this.currentElement.length] = this.currentElement[o].nextSibling;
|
|
6643 }
|
|
6644 }
|
|
6645 }
|
|
6646 }
|
|
6647 }
|
|
6648 },
|
|
6649 /**
|
|
6650 * @method saveHTML
|
|
6651 * @description Cleans the HTML with the cleanHTML method then places that string back into the textarea.
|
|
6652 * @return String
|
|
6653 */
|
|
6654 saveHTML: function() {
|
|
6655 var html = this.cleanHTML();
|
|
6656 if (this._textarea) {
|
|
6657 this.get('element').value = html;
|
|
6658 } else {
|
|
6659 this.get('element').innerHTML = html;
|
|
6660 }
|
|
6661 if (this.get('saveEl') !== this.get('element')) {
|
|
6662 var out = this.get('saveEl');
|
|
6663 if (Lang.isString(out)) {
|
|
6664 out = Dom.get(out);
|
|
6665 }
|
|
6666 if (out) {
|
|
6667 if (out.tagName.toLowerCase() === 'textarea') {
|
|
6668 out.value = html;
|
|
6669 } else {
|
|
6670 out.innerHTML = html;
|
|
6671 }
|
|
6672 }
|
|
6673 }
|
|
6674 return html;
|
|
6675 },
|
|
6676 /**
|
|
6677 * @method setEditorHTML
|
|
6678 * @param {String} incomingHTML The html content to load into the editor
|
|
6679 * @description Loads HTML into the editors body
|
|
6680 */
|
|
6681 setEditorHTML: function(incomingHTML) {
|
|
6682 var html = this._cleanIncomingHTML(incomingHTML);
|
|
6683 html = html.replace(/RIGHT_BRACKET/gi, '{');
|
|
6684 html = html.replace(/LEFT_BRACKET/gi, '}');
|
|
6685 this._getDoc().body.innerHTML = html;
|
|
6686 this.nodeChange();
|
|
6687 },
|
|
6688 /**
|
|
6689 * @method getEditorHTML
|
|
6690 * @description Gets the unprocessed/unfiltered HTML from the editor
|
|
6691 */
|
|
6692 getEditorHTML: function() {
|
|
6693 try {
|
|
6694 var b = this._getDoc().body;
|
|
6695 if (b === null) {
|
|
6696 YAHOO.log('Body is null, returning null.', 'error', 'SimpleEditor');
|
|
6697 return null;
|
|
6698 }
|
|
6699 return this._getDoc().body.innerHTML;
|
|
6700 } catch (e) {
|
|
6701 return '';
|
|
6702 }
|
|
6703 },
|
|
6704 /**
|
|
6705 * @method show
|
|
6706 * @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.
|
|
6707 */
|
|
6708 show: function() {
|
|
6709 if (this.browser.gecko) {
|
|
6710 this._setDesignMode('on');
|
|
6711 this.focus();
|
|
6712 }
|
|
6713 if (this.browser.webkit) {
|
|
6714 var self = this;
|
|
6715 window.setTimeout(function() {
|
|
6716 self._setInitialContent.call(self);
|
|
6717 }, 10);
|
|
6718 }
|
|
6719 //Adding this will close all other Editor window's when showing this one.
|
|
6720 if (this.currentWindow) {
|
|
6721 this.closeWindow();
|
|
6722 }
|
|
6723 //Put the iframe back in place
|
|
6724 this.get('iframe').setStyle('position', 'static');
|
|
6725 this.get('iframe').setStyle('left', '');
|
|
6726 },
|
|
6727 /**
|
|
6728 * @method hide
|
|
6729 * @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.
|
|
6730 */
|
|
6731 hide: function() {
|
|
6732 //Adding this will close all other Editor window's.
|
|
6733 if (this.currentWindow) {
|
|
6734 this.closeWindow();
|
|
6735 }
|
|
6736 if (this._fixNodesTimer) {
|
|
6737 clearTimeout(this._fixNodesTimer);
|
|
6738 this._fixNodesTimer = null;
|
|
6739 }
|
|
6740 if (this._nodeChangeTimer) {
|
|
6741 clearTimeout(this._nodeChangeTimer);
|
|
6742 this._nodeChangeTimer = null;
|
|
6743 }
|
|
6744 this._lastNodeChange = 0;
|
|
6745 //Move the iframe off of the screen, so that in containers with visiblity hidden, IE will not cover other elements.
|
|
6746 this.get('iframe').setStyle('position', 'absolute');
|
|
6747 this.get('iframe').setStyle('left', '-9999px');
|
|
6748 },
|
|
6749 /**
|
|
6750 * @method _cleanIncomingHTML
|
|
6751 * @param {String} html The unfiltered HTML
|
|
6752 * @description Process the HTML with a few regexes to clean it up and stabilize the input
|
|
6753 * @return {String} The filtered HTML
|
|
6754 */
|
|
6755 _cleanIncomingHTML: function(html) {
|
|
6756 html = html.replace(/{/gi, 'RIGHT_BRACKET');
|
|
6757 html = html.replace(/}/gi, 'LEFT_BRACKET');
|
|
6758
|
|
6759 html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
|
|
6760 html = html.replace(/<\/strong>/gi, '</b>');
|
|
6761
|
|
6762 //replace embed before em check
|
|
6763 html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
|
|
6764 html = html.replace(/<\/embed>/gi, '</YUI_EMBED>');
|
|
6765
|
|
6766 html = html.replace(/<em([^>]*)>/gi, '<i$1>');
|
|
6767 html = html.replace(/<\/em>/gi, '</i>');
|
|
6768 html = html.replace(/_moz_dirty=""/gi, '');
|
|
6769
|
|
6770 //Put embed tags back in..
|
|
6771 html = html.replace(/<YUI_EMBED([^>]*)>/gi, '<embed$1>');
|
|
6772 html = html.replace(/<\/YUI_EMBED>/gi, '</embed>');
|
|
6773 if (this.get('plainText')) {
|
|
6774 YAHOO.log('Filtering as plain text', 'info', 'SimpleEditor');
|
|
6775 html = html.replace(/\n/g, '<br>').replace(/\r/g, '<br>');
|
|
6776 html = html.replace(/ /gi, ' '); //Replace all double spaces
|
|
6777 html = html.replace(/\t/gi, ' '); //Replace all tabs
|
|
6778 }
|
|
6779 //Removing Script Tags from the Editor
|
|
6780 html = html.replace(/<script([^>]*)>/gi, '<bad>');
|
|
6781 html = html.replace(/<\/script([^>]*)>/gi, '</bad>');
|
|
6782 html = html.replace(/<script([^>]*)>/gi, '<bad>');
|
|
6783 html = html.replace(/<\/script([^>]*)>/gi, '</bad>');
|
|
6784 //Replace the line feeds
|
|
6785 html = html.replace(/\r\n/g, '<YUI_LF>').replace(/\n/g, '<YUI_LF>').replace(/\r/g, '<YUI_LF>');
|
|
6786
|
|
6787 //Remove Bad HTML elements (used to be script nodes)
|
|
6788 html = html.replace(new RegExp('<bad([^>]*)>(.*?)<\/bad>', 'gi'), '');
|
|
6789 //Replace the lines feeds
|
|
6790 html = html.replace(/<YUI_LF>/g, '\n');
|
|
6791 return html;
|
|
6792 },
|
|
6793 /**
|
|
6794 * @method cleanHTML
|
|
6795 * @param {String} html The unfiltered HTML
|
|
6796 * @description Process the HTML with a few regexes to clean it up and stabilize the output
|
|
6797 * @return {String} The filtered HTML
|
|
6798 */
|
|
6799 cleanHTML: function(html) {
|
|
6800 //Start Filtering Output
|
|
6801 //Begin RegExs..
|
|
6802 if (!html) {
|
|
6803 html = this.getEditorHTML();
|
|
6804 }
|
|
6805 var markup = this.get('markup');
|
|
6806 //Make some backups...
|
|
6807 html = this.pre_filter_linebreaks(html, markup);
|
|
6808
|
|
6809 //Filter MS Word
|
|
6810 html = this.filter_msword(html);
|
|
6811
|
|
6812 html = html.replace(/<img([^>]*)\/>/gi, '<YUI_IMG$1>');
|
|
6813 html = html.replace(/<img([^>]*)>/gi, '<YUI_IMG$1>');
|
|
6814
|
|
6815 html = html.replace(/<input([^>]*)\/>/gi, '<YUI_INPUT$1>');
|
|
6816 html = html.replace(/<input([^>]*)>/gi, '<YUI_INPUT$1>');
|
|
6817
|
|
6818 html = html.replace(/<ul([^>]*)>/gi, '<YUI_UL$1>');
|
|
6819 html = html.replace(/<\/ul>/gi, '<\/YUI_UL>');
|
|
6820 html = html.replace(/<blockquote([^>]*)>/gi, '<YUI_BQ$1>');
|
|
6821 html = html.replace(/<\/blockquote>/gi, '<\/YUI_BQ>');
|
|
6822
|
|
6823 html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
|
|
6824 html = html.replace(/<\/embed>/gi, '<\/YUI_EMBED>');
|
|
6825
|
|
6826 //Convert b and i tags to strong and em tags
|
|
6827 if ((markup == 'semantic') || (markup == 'xhtml')) {
|
|
6828 html = html.replace(/<i(\s+[^>]*)?>/gi, '<em$1>');
|
|
6829 html = html.replace(/<\/i>/gi, '</em>');
|
|
6830 html = html.replace(/<b(\s+[^>]*)?>/gi, '<strong$1>');
|
|
6831 html = html.replace(/<\/b>/gi, '</strong>');
|
|
6832 }
|
|
6833
|
|
6834 html = html.replace(/_moz_dirty=""/gi, '');
|
|
6835
|
|
6836 //normalize strikethrough
|
|
6837 html = html.replace(/<strike/gi, '<span style="text-decoration: line-through;"');
|
|
6838 html = html.replace(/\/strike>/gi, '/span>');
|
|
6839
|
|
6840
|
|
6841 //Case Changing
|
|
6842 if (this.browser.ie) {
|
|
6843 html = html.replace(/text-decoration/gi, 'text-decoration');
|
|
6844 html = html.replace(/font-weight/gi, 'font-weight');
|
|
6845 html = html.replace(/_width="([^>]*)"/gi, '');
|
|
6846 html = html.replace(/_height="([^>]*)"/gi, '');
|
|
6847 //Cleanup Image URL's
|
|
6848 var url = this._baseHREF.replace(/\//gi, '\\/'),
|
|
6849 re = new RegExp('src="' + url, 'gi');
|
|
6850 html = html.replace(re, 'src="');
|
|
6851 }
|
|
6852 html = html.replace(/<font/gi, '<font');
|
|
6853 html = html.replace(/<\/font>/gi, '</font>');
|
|
6854 html = html.replace(/<span/gi, '<span');
|
|
6855 html = html.replace(/<\/span>/gi, '</span>');
|
|
6856 if ((markup == 'semantic') || (markup == 'xhtml') || (markup == 'css')) {
|
|
6857 html = html.replace(new RegExp('<font([^>]*)face="([^>]*)">(.*?)<\/font>', 'gi'), '<span $1 style="font-family: $2;">$3</span>');
|
|
6858 html = html.replace(/<u/gi, '<span style="text-decoration: underline;"');
|
|
6859 if (this.browser.webkit) {
|
|
6860 html = html.replace(new RegExp('<span class="Apple-style-span" style="font-weight: bold;">([^>]*)<\/span>', 'gi'), '<strong>$1</strong>');
|
|
6861 html = html.replace(new RegExp('<span class="Apple-style-span" style="font-style: italic;">([^>]*)<\/span>', 'gi'), '<em>$1</em>');
|
|
6862 }
|
|
6863 html = html.replace(/\/u>/gi, '/span>');
|
|
6864 if (markup == 'css') {
|
|
6865 html = html.replace(/<em([^>]*)>/gi, '<i$1>');
|
|
6866 html = html.replace(/<\/em>/gi, '</i>');
|
|
6867 html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
|
|
6868 html = html.replace(/<\/strong>/gi, '</b>');
|
|
6869 html = html.replace(/<b/gi, '<span style="font-weight: bold;"');
|
|
6870 html = html.replace(/\/b>/gi, '/span>');
|
|
6871 html = html.replace(/<i/gi, '<span style="font-style: italic;"');
|
|
6872 html = html.replace(/\/i>/gi, '/span>');
|
|
6873 }
|
|
6874 html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single
|
|
6875 } else {
|
|
6876 html = html.replace(/<u/gi, '<u');
|
|
6877 html = html.replace(/\/u>/gi, '/u>');
|
|
6878 }
|
|
6879 html = html.replace(/<ol([^>]*)>/gi, '<ol$1>');
|
|
6880 html = html.replace(/\/ol>/gi, '/ol>');
|
|
6881 html = html.replace(/<li/gi, '<li');
|
|
6882 html = html.replace(/\/li>/gi, '/li>');
|
|
6883 html = this.filter_safari(html);
|
|
6884
|
|
6885 html = this.filter_internals(html);
|
|
6886
|
|
6887 html = this.filter_all_rgb(html);
|
|
6888
|
|
6889 //Replace our backups with the real thing
|
|
6890 html = this.post_filter_linebreaks(html, markup);
|
|
6891
|
|
6892 if (markup == 'xhtml') {
|
|
6893 html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1 />');
|
|
6894 html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1 />');
|
|
6895 } else {
|
|
6896 html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1>');
|
|
6897 html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1>');
|
|
6898 }
|
|
6899 html = html.replace(/<YUI_UL([^>]*)>/g, '<ul$1>');
|
|
6900 html = html.replace(/<\/YUI_UL>/g, '<\/ul>');
|
|
6901
|
|
6902 html = this.filter_invalid_lists(html);
|
|
6903
|
|
6904 html = html.replace(/<YUI_BQ([^>]*)>/g, '<blockquote$1>');
|
|
6905 html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>');
|
|
6906
|
|
6907 html = html.replace(/<YUI_EMBED([^>]*)>/g, '<embed$1>');
|
|
6908 html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>');
|
|
6909
|
|
6910 //This should fix &'s in URL's
|
|
6911 html = html.replace(/ & /gi, ' YUI_AMP ');
|
|
6912 html = html.replace(/ &/gi, ' YUI_AMP_F ');
|
|
6913 html = html.replace(/& /gi, ' YUI_AMP_R ');
|
|
6914 html = html.replace(/&/gi, '&');
|
|
6915 html = html.replace(/ YUI_AMP /gi, ' & ');
|
|
6916 html = html.replace(/ YUI_AMP_F /gi, ' &');
|
|
6917 html = html.replace(/ YUI_AMP_R /gi, '& ');
|
|
6918
|
|
6919 //Trim the output, removing whitespace from the beginning and end
|
|
6920 html = YAHOO.lang.trim(html);
|
|
6921
|
|
6922 if (this.get('removeLineBreaks')) {
|
|
6923 html = html.replace(/\n/g, '').replace(/\r/g, '');
|
|
6924 html = html.replace(/ /gi, ' '); //Replace all double spaces and replace with a single
|
|
6925 }
|
|
6926
|
|
6927 for (var v in this.invalidHTML) {
|
|
6928 if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
|
|
6929 if (Lang.isObject(v) && v.keepContents) {
|
|
6930 html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1');
|
|
6931 } else {
|
|
6932 html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '');
|
|
6933 }
|
|
6934 }
|
|
6935 }
|
|
6936
|
|
6937 /* LATER -- Add DOM manipulation
|
|
6938 console.log(html);
|
|
6939 var frag = document.createDocumentFragment();
|
|
6940 frag.innerHTML = html;
|
|
6941
|
|
6942 var ps = frag.getElementsByTagName('p'),
|
|
6943 len = ps.length;
|
|
6944 for (var i = 0; i < len; i++) {
|
|
6945 var ps2 = ps[i].getElementsByTagName('p');
|
|
6946 if (ps2.length) {
|
|
6947
|
|
6948 }
|
|
6949
|
|
6950 }
|
|
6951 html = frag.innerHTML;
|
|
6952 console.log(html);
|
|
6953 */
|
|
6954
|
|
6955 this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html });
|
|
6956
|
|
6957 return html;
|
|
6958 },
|
|
6959 /**
|
|
6960 * @method filter_msword
|
|
6961 * @param String html The HTML string to filter
|
|
6962 * @description Filters out msword html attributes and other junk. Activate with filterWord: true in config
|
|
6963 */
|
|
6964 filter_msword: function(html) {
|
|
6965 if (!this.get('filterWord')) {
|
|
6966 return html;
|
|
6967 }
|
|
6968 //Remove the ms o: tags
|
|
6969 html = html.replace(/<o:p>\s*<\/o:p>/g, '');
|
|
6970 html = html.replace(/<o:p>[\s\S]*?<\/o:p>/g, ' ');
|
|
6971
|
|
6972 //Remove the ms w: tags
|
|
6973 html = html.replace( /<w:[^>]*>[\s\S]*?<\/w:[^>]*>/gi, '');
|
|
6974
|
|
6975 //Remove mso-? styles.
|
|
6976 html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '');
|
|
6977
|
|
6978 //Remove more bogus MS styles.
|
|
6979 html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*;/gi, '');
|
|
6980 html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*"/gi, "\"");
|
|
6981 html = html.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '');
|
|
6982 html = html.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"");
|
|
6983 html = html.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"");
|
|
6984 html = html.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" );
|
|
6985 html = html.replace( /\s*tab-stops:[^;"]*;?/gi, '');
|
|
6986 html = html.replace( /\s*tab-stops:[^"]*/gi, '');
|
|
6987
|
|
6988 //Remove XML declarations
|
|
6989 html = html.replace(/<\\?\?xml[^>]*>/gi, '');
|
|
6990
|
|
6991 //Remove lang
|
|
6992 html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
|
|
6993
|
|
6994 //Remove language tags
|
|
6995 html = html.replace( /<(\w[^>]*) language=([^ |>]*)([^>]*)/gi, "<$1$3");
|
|
6996
|
|
6997 //Remove onmouseover and onmouseout events (from MS Word comments effect)
|
|
6998 html = html.replace( /<(\w[^>]*) onmouseover="([^\"]*)"([^>]*)/gi, "<$1$3");
|
|
6999 html = html.replace( /<(\w[^>]*) onmouseout="([^\"]*)"([^>]*)/gi, "<$1$3");
|
|
7000
|
|
7001 return html;
|
|
7002 },
|
|
7003 /**
|
|
7004 * @method filter_invalid_lists
|
|
7005 * @param String html The HTML string to filter
|
|
7006 * @description Filters invalid ol and ul list markup, converts this: <li></li><ol>..</ol> to this: <li></li><li><ol>..</ol></li>
|
|
7007 */
|
|
7008 filter_invalid_lists: function(html) {
|
|
7009 html = html.replace(/<\/li>\n/gi, '</li>');
|
|
7010
|
|
7011 html = html.replace(/<\/li><ol>/gi, '</li><li><ol>');
|
|
7012 html = html.replace(/<\/ol>/gi, '</ol></li>');
|
|
7013 html = html.replace(/<\/ol><\/li>\n/gi, "</ol>");
|
|
7014
|
|
7015 html = html.replace(/<\/li><ul>/gi, '</li><li><ul>');
|
|
7016 html = html.replace(/<\/ul>/gi, '</ul></li>');
|
|
7017 html = html.replace(/<\/ul><\/li>\n?/gi, "</ul>");
|
|
7018
|
|
7019 html = html.replace(/<\/li>/gi, "</li>");
|
|
7020 html = html.replace(/<\/ol>/gi, "</ol>");
|
|
7021 html = html.replace(/<ol>/gi, "<ol>");
|
|
7022 html = html.replace(/<ul>/gi, "<ul>");
|
|
7023 return html;
|
|
7024 },
|
|
7025 /**
|
|
7026 * @method filter_safari
|
|
7027 * @param String html The HTML string to filter
|
|
7028 * @description Filters strings specific to Safari
|
|
7029 * @return String
|
|
7030 */
|
|
7031 filter_safari: function(html) {
|
|
7032 if (this.browser.webkit) {
|
|
7033 //<span class="Apple-tab-span" style="white-space:pre"> </span>
|
|
7034 html = html.replace(/<span class="Apple-tab-span" style="white-space:pre">([^>])<\/span>/gi, ' ');
|
|
7035 html = html.replace(/Apple-style-span/gi, '');
|
|
7036 html = html.replace(/style="line-height: normal;"/gi, '');
|
|
7037 html = html.replace(/yui-wk-div/gi, '');
|
|
7038 html = html.replace(/yui-wk-p/gi, '');
|
|
7039
|
|
7040
|
|
7041 //Remove bogus LI's
|
|
7042 html = html.replace(/<li><\/li>/gi, '');
|
|
7043 html = html.replace(/<li> <\/li>/gi, '');
|
|
7044 html = html.replace(/<li> <\/li>/gi, '');
|
|
7045 //Remove bogus DIV's - updated from just removing the div's to replacing /div with a break
|
|
7046 if (this.get('ptags')) {
|
|
7047 html = html.replace(/<div([^>]*)>/g, '<p$1>');
|
|
7048 html = html.replace(/<\/div>/gi, '</p>');
|
|
7049 } else {
|
|
7050 //html = html.replace(/<div>/gi, '<br>');
|
|
7051 html = html.replace(/<div([^>]*)>([ tnr]*)<\/div>/gi, '<br>');
|
|
7052 html = html.replace(/<\/div>/gi, '');
|
|
7053 }
|
|
7054 }
|
|
7055 return html;
|
|
7056 },
|
|
7057 /**
|
|
7058 * @method filter_internals
|
|
7059 * @param String html The HTML string to filter
|
|
7060 * @description Filters internal RTE strings and bogus attrs we don't want
|
|
7061 * @return String
|
|
7062 */
|
|
7063 filter_internals: function(html) {
|
|
7064 html = html.replace(/\r/g, '');
|
|
7065 //Fix stuff we don't want
|
|
7066 html = html.replace(/<\/?(body|head|html)[^>]*>/gi, '');
|
|
7067 //Fix last BR in LI
|
|
7068 html = html.replace(/<YUI_BR><\/li>/gi, '</li>');
|
|
7069
|
|
7070 html = html.replace(/yui-tag-span/gi, '');
|
|
7071 html = html.replace(/yui-tag/gi, '');
|
|
7072 html = html.replace(/yui-non/gi, '');
|
|
7073 html = html.replace(/yui-img/gi, '');
|
|
7074 html = html.replace(/ tag="span"/gi, '');
|
|
7075 html = html.replace(/ class=""/gi, '');
|
|
7076 html = html.replace(/ style=""/gi, '');
|
|
7077 html = html.replace(/ class=" "/gi, '');
|
|
7078 html = html.replace(/ class=" "/gi, '');
|
|
7079 html = html.replace(/ target=""/gi, '');
|
|
7080 html = html.replace(/ title=""/gi, '');
|
|
7081
|
|
7082 if (this.browser.ie) {
|
|
7083 html = html.replace(/ class= /gi, '');
|
|
7084 html = html.replace(/ class= >/gi, '');
|
|
7085 }
|
|
7086
|
|
7087 return html;
|
|
7088 },
|
|
7089 /**
|
|
7090 * @method filter_all_rgb
|
|
7091 * @param String str The HTML string to filter
|
|
7092 * @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"
|
|
7093 * @return String
|
|
7094 */
|
|
7095 filter_all_rgb: function(str) {
|
|
7096 var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi");
|
|
7097 var arr = str.match(exp);
|
|
7098 if (Lang.isArray(arr)) {
|
|
7099 for (var i = 0; i < arr.length; i++) {
|
|
7100 var color = this.filter_rgb(arr[i]);
|
|
7101 str = str.replace(arr[i].toString(), color);
|
|
7102 }
|
|
7103 }
|
|
7104
|
|
7105 return str;
|
|
7106 },
|
|
7107 /**
|
|
7108 * @method filter_rgb
|
|
7109 * @param String css The CSS string containing rgb(#,#,#);
|
|
7110 * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00
|
|
7111 * @return String
|
|
7112 */
|
|
7113 filter_rgb: function(css) {
|
|
7114 if (css.toLowerCase().indexOf('rgb') != -1) {
|
|
7115 var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
|
|
7116 var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(',');
|
|
7117
|
|
7118 if (rgb.length == 5) {
|
|
7119 var r = parseInt(rgb[1], 10).toString(16);
|
|
7120 var g = parseInt(rgb[2], 10).toString(16);
|
|
7121 var b = parseInt(rgb[3], 10).toString(16);
|
|
7122
|
|
7123 r = r.length == 1 ? '0' + r : r;
|
|
7124 g = g.length == 1 ? '0' + g : g;
|
|
7125 b = b.length == 1 ? '0' + b : b;
|
|
7126
|
|
7127 css = "#" + r + g + b;
|
|
7128 }
|
|
7129 }
|
|
7130 return css;
|
|
7131 },
|
|
7132 /**
|
|
7133 * @method pre_filter_linebreaks
|
|
7134 * @param String html The HTML to filter
|
|
7135 * @param String markup The markup type to filter to
|
|
7136 * @description HTML Pre Filter
|
|
7137 * @return String
|
|
7138 */
|
|
7139 pre_filter_linebreaks: function(html, markup) {
|
|
7140 if (this.browser.webkit) {
|
|
7141 html = html.replace(/<br class="khtml-block-placeholder">/gi, '<YUI_BR>');
|
|
7142 html = html.replace(/<br class="webkit-block-placeholder">/gi, '<YUI_BR>');
|
|
7143 }
|
|
7144 html = html.replace(/<br>/gi, '<YUI_BR>');
|
|
7145 html = html.replace(/<br (.*?)>/gi, '<YUI_BR>');
|
|
7146 html = html.replace(/<br\/>/gi, '<YUI_BR>');
|
|
7147 html = html.replace(/<br \/>/gi, '<YUI_BR>');
|
|
7148 html = html.replace(/<div><YUI_BR><\/div>/gi, '<YUI_BR>');
|
|
7149 html = html.replace(/<p>( | )<\/p>/g, '<YUI_BR>');
|
|
7150 html = html.replace(/<p><br> <\/p>/gi, '<YUI_BR>');
|
|
7151 html = html.replace(/<p> <\/p>/gi, '<YUI_BR>');
|
|
7152 //Fix last BR
|
|
7153 html = html.replace(/<YUI_BR>$/, '');
|
|
7154 //Fix last BR in P
|
|
7155 html = html.replace(/<YUI_BR><\/p>/g, '</p>');
|
|
7156 if (this.browser.ie) {
|
|
7157 html = html.replace(/ /g, '\t');
|
|
7158 }
|
|
7159 return html;
|
|
7160 },
|
|
7161 /**
|
|
7162 * @method post_filter_linebreaks
|
|
7163 * @param String html The HTML to filter
|
|
7164 * @param String markup The markup type to filter to
|
|
7165 * @description HTML Pre Filter
|
|
7166 * @return String
|
|
7167 */
|
|
7168 post_filter_linebreaks: function(html, markup) {
|
|
7169 if (markup == 'xhtml') {
|
|
7170 html = html.replace(/<YUI_BR>/g, '<br />');
|
|
7171 } else {
|
|
7172 html = html.replace(/<YUI_BR>/g, '<br>');
|
|
7173 }
|
|
7174 return html;
|
|
7175 },
|
|
7176 /**
|
|
7177 * @method clearEditorDoc
|
|
7178 * @description Clear the doc of the Editor
|
|
7179 */
|
|
7180 clearEditorDoc: function() {
|
|
7181 this._getDoc().body.innerHTML = ' ';
|
|
7182 },
|
|
7183 /**
|
|
7184 * @method openWindow
|
|
7185 * @description Override Method for Advanced Editor
|
|
7186 */
|
|
7187 openWindow: function(win) {
|
|
7188 },
|
|
7189 /**
|
|
7190 * @method moveWindow
|
|
7191 * @description Override Method for Advanced Editor
|
|
7192 */
|
|
7193 moveWindow: function() {
|
|
7194 },
|
|
7195 /**
|
|
7196 * @private
|
|
7197 * @method _closeWindow
|
|
7198 * @description Override Method for Advanced Editor
|
|
7199 */
|
|
7200 _closeWindow: function() {
|
|
7201 },
|
|
7202 /**
|
|
7203 * @method closeWindow
|
|
7204 * @description Override Method for Advanced Editor
|
|
7205 */
|
|
7206 closeWindow: function() {
|
|
7207 //this.unsubscribeAll('afterExecCommand');
|
|
7208 this.toolbar.resetAllButtons();
|
|
7209 this.focus();
|
|
7210 },
|
|
7211 /**
|
|
7212 * @method destroy
|
|
7213 * @description Destroys the editor, all of it's elements and objects.
|
|
7214 * @return {Boolean}
|
|
7215 */
|
|
7216 destroy: function() {
|
|
7217 if (this._nodeChangeDelayTimer) {
|
|
7218 clearTimeout(this._nodeChangeDelayTimer);
|
|
7219 }
|
|
7220 this.hide();
|
|
7221
|
|
7222 YAHOO.log('Destroying Editor', 'warn', 'SimpleEditor');
|
|
7223 if (this.resize) {
|
|
7224 YAHOO.log('Destroying Resize', 'warn', 'SimpleEditor');
|
|
7225 this.resize.destroy();
|
|
7226 }
|
|
7227 if (this.dd) {
|
|
7228 YAHOO.log('Unreg DragDrop Instance', 'warn', 'SimpleEditor');
|
|
7229 this.dd.unreg();
|
|
7230 }
|
|
7231 if (this.get('panel')) {
|
|
7232 YAHOO.log('Destroying Editor Panel', 'warn', 'SimpleEditor');
|
|
7233 this.get('panel').destroy();
|
|
7234 }
|
|
7235 this.saveHTML();
|
|
7236 this.toolbar.destroy();
|
|
7237 YAHOO.log('Restoring TextArea', 'info', 'SimpleEditor');
|
|
7238 this.setStyle('visibility', 'visible');
|
|
7239 this.setStyle('position', 'static');
|
|
7240 this.setStyle('top', '');
|
|
7241 this.setStyle('left', '');
|
|
7242 var textArea = this.get('element');
|
|
7243 this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element'));
|
|
7244 this.get('element_cont').get('element').innerHTML = '';
|
|
7245 this.set('handleSubmit', false); //Remove the submit handler
|
|
7246 return true;
|
|
7247 },
|
|
7248 /**
|
|
7249 * @method toString
|
|
7250 * @description Returns a string representing the editor.
|
|
7251 * @return {String}
|
|
7252 */
|
|
7253 toString: function() {
|
|
7254 var str = 'SimpleEditor';
|
|
7255 if (this.get && this.get('element_cont')) {
|
|
7256 str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
|
|
7257 }
|
|
7258 return str;
|
|
7259 }
|
|
7260 });
|
|
7261
|
|
7262 /**
|
|
7263 * @event toolbarLoaded
|
|
7264 * @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.
|
|
7265 * @type YAHOO.util.CustomEvent
|
|
7266 */
|
|
7267 /**
|
|
7268 * @event cleanHTML
|
|
7269 * @description Event is fired after the cleanHTML method is called.
|
|
7270 * @type YAHOO.util.CustomEvent
|
|
7271 */
|
|
7272 /**
|
|
7273 * @event afterRender
|
|
7274 * @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.
|
|
7275 * @type YAHOO.util.CustomEvent
|
|
7276 */
|
|
7277 /**
|
|
7278 * @event editorContentLoaded
|
|
7279 * @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.
|
|
7280 * @type YAHOO.util.CustomEvent
|
|
7281 */
|
|
7282 /**
|
|
7283 * @event beforeNodeChange
|
|
7284 * @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.
|
|
7285 * @type YAHOO.util.CustomEvent
|
|
7286 */
|
|
7287 /**
|
|
7288 * @event afterNodeChange
|
|
7289 * @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.
|
|
7290 * @type YAHOO.util.CustomEvent
|
|
7291 */
|
|
7292 /**
|
|
7293 * @event beforeExecCommand
|
|
7294 * @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.
|
|
7295 * @type YAHOO.util.CustomEvent
|
|
7296 */
|
|
7297 /**
|
|
7298 * @event afterExecCommand
|
|
7299 * @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.
|
|
7300 * @type YAHOO.util.CustomEvent
|
|
7301 */
|
|
7302 /**
|
|
7303 * @event editorMouseUp
|
|
7304 * @param {Event} ev The DOM Event that occured
|
|
7305 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7306 * @type YAHOO.util.CustomEvent
|
|
7307 */
|
|
7308 /**
|
|
7309 * @event editorMouseDown
|
|
7310 * @param {Event} ev The DOM Event that occured
|
|
7311 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7312 * @type YAHOO.util.CustomEvent
|
|
7313 */
|
|
7314 /**
|
|
7315 * @event editorDoubleClick
|
|
7316 * @param {Event} ev The DOM Event that occured
|
|
7317 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7318 * @type YAHOO.util.CustomEvent
|
|
7319 */
|
|
7320 /**
|
|
7321 * @event editorClick
|
|
7322 * @param {Event} ev The DOM Event that occured
|
|
7323 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7324 * @type YAHOO.util.CustomEvent
|
|
7325 */
|
|
7326 /**
|
|
7327 * @event editorKeyUp
|
|
7328 * @param {Event} ev The DOM Event that occured
|
|
7329 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7330 * @type YAHOO.util.CustomEvent
|
|
7331 */
|
|
7332 /**
|
|
7333 * @event editorKeyPress
|
|
7334 * @param {Event} ev The DOM Event that occured
|
|
7335 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7336 * @type YAHOO.util.CustomEvent
|
|
7337 */
|
|
7338 /**
|
|
7339 * @event editorKeyDown
|
|
7340 * @param {Event} ev The DOM Event that occured
|
|
7341 * @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
|
|
7342 * @type YAHOO.util.CustomEvent
|
|
7343 */
|
|
7344 /**
|
|
7345 * @event beforeEditorMouseUp
|
|
7346 * @param {Event} ev The DOM Event that occured
|
|
7347 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7348 * @type YAHOO.util.CustomEvent
|
|
7349 */
|
|
7350 /**
|
|
7351 * @event beforeEditorMouseDown
|
|
7352 * @param {Event} ev The DOM Event that occured
|
|
7353 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7354 * @type YAHOO.util.CustomEvent
|
|
7355 */
|
|
7356 /**
|
|
7357 * @event beforeEditorDoubleClick
|
|
7358 * @param {Event} ev The DOM Event that occured
|
|
7359 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7360 * @type YAHOO.util.CustomEvent
|
|
7361 */
|
|
7362 /**
|
|
7363 * @event beforeEditorClick
|
|
7364 * @param {Event} ev The DOM Event that occured
|
|
7365 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7366 * @type YAHOO.util.CustomEvent
|
|
7367 */
|
|
7368 /**
|
|
7369 * @event beforeEditorKeyUp
|
|
7370 * @param {Event} ev The DOM Event that occured
|
|
7371 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7372 * @type YAHOO.util.CustomEvent
|
|
7373 */
|
|
7374 /**
|
|
7375 * @event beforeEditorKeyPress
|
|
7376 * @param {Event} ev The DOM Event that occured
|
|
7377 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7378 * @type YAHOO.util.CustomEvent
|
|
7379 */
|
|
7380 /**
|
|
7381 * @event beforeEditorKeyDown
|
|
7382 * @param {Event} ev The DOM Event that occured
|
|
7383 * @description Fires before editor event, returning false will stop the internal processing.
|
|
7384 * @type YAHOO.util.CustomEvent
|
|
7385 */
|
|
7386
|
|
7387 /**
|
|
7388 * @event editorWindowFocus
|
|
7389 * @description Fires when the iframe is focused. Note, this is window focus event, not an Editor focus event.
|
|
7390 * @type YAHOO.util.CustomEvent
|
|
7391 */
|
|
7392 /**
|
|
7393 * @event editorWindowBlur
|
|
7394 * @description Fires when the iframe is blurred. Note, this is window blur event, not an Editor blur event.
|
|
7395 * @type YAHOO.util.CustomEvent
|
|
7396 */
|
|
7397
|
|
7398
|
|
7399 /**
|
|
7400 * @description Singleton object used to track the open window objects and panels across the various open editors
|
|
7401 * @class EditorInfo
|
|
7402 * @static
|
|
7403 */
|
|
7404 YAHOO.widget.EditorInfo = {
|
|
7405 /**
|
|
7406 * @private
|
|
7407 * @property _instances
|
|
7408 * @description A reference to all editors on the page.
|
|
7409 * @type Object
|
|
7410 */
|
|
7411 _instances: {},
|
|
7412 /**
|
|
7413 * @private
|
|
7414 * @property blankImage
|
|
7415 * @description A reference to the blankImage url
|
|
7416 * @type String
|
|
7417 */
|
|
7418 blankImage: '',
|
|
7419 /**
|
|
7420 * @private
|
|
7421 * @property window
|
|
7422 * @description A reference to the currently open window object in any editor on the page.
|
|
7423 * @type Object <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>
|
|
7424 */
|
|
7425 window: {},
|
|
7426 /**
|
|
7427 * @private
|
|
7428 * @property panel
|
|
7429 * @description A reference to the currently open panel in any editor on the page.
|
|
7430 * @type Object <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
|
|
7431 */
|
|
7432 panel: null,
|
|
7433 /**
|
|
7434 * @method getEditorById
|
|
7435 * @description Returns a reference to the Editor object associated with the given textarea
|
|
7436 * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of
|
|
7437 * @return Object <a href="YAHOO.widget.Editor.html">YAHOO.widget.Editor</a>
|
|
7438 */
|
|
7439 getEditorById: function(id) {
|
|
7440 if (!YAHOO.lang.isString(id)) {
|
|
7441 //Not a string, assume a node Reference
|
|
7442 id = id.id;
|
|
7443 }
|
|
7444 if (this._instances[id]) {
|
|
7445 return this._instances[id];
|
|
7446 }
|
|
7447 return false;
|
|
7448 },
|
|
7449 /**
|
|
7450 * @method saveAll
|
|
7451 * @description Saves all Editor instances on the page. If a form reference is passed, only Editor's bound to this form will be saved.
|
|
7452 * @param {HTMLElement} form The form to check if this Editor instance belongs to
|
|
7453 */
|
|
7454 saveAll: function(form) {
|
|
7455 var i, e, items = YAHOO.widget.EditorInfo._instances;
|
|
7456 if (form) {
|
|
7457 for (i in items) {
|
|
7458 if (Lang.hasOwnProperty(items, i)) {
|
|
7459 e = items[i];
|
|
7460 if (e.get('element').form && (e.get('element').form == form)) {
|
|
7461 e.saveHTML();
|
|
7462 }
|
|
7463 }
|
|
7464 }
|
|
7465 } else {
|
|
7466 for (i in items) {
|
|
7467 if (Lang.hasOwnProperty(items, i)) {
|
|
7468 items[i].saveHTML();
|
|
7469 }
|
|
7470 }
|
|
7471 }
|
|
7472 },
|
|
7473 /**
|
|
7474 * @method toString
|
|
7475 * @description Returns a string representing the EditorInfo.
|
|
7476 * @return {String}
|
|
7477 */
|
|
7478 toString: function() {
|
|
7479 var len = 0;
|
|
7480 for (var i in this._instances) {
|
|
7481 if (Lang.hasOwnProperty(this._instances, i)) {
|
|
7482 len++;
|
|
7483 }
|
|
7484 }
|
|
7485 return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')';
|
|
7486 }
|
|
7487 };
|
|
7488
|
|
7489
|
|
7490
|
|
7491
|
|
7492 })();
|
|
7493 /**
|
|
7494 * @module editor
|
|
7495 * @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>
|
|
7496 * @namespace YAHOO.widget
|
|
7497 * @requires yahoo, dom, element, event, container_core, simpleeditor
|
|
7498 * @optional dragdrop, animation, menu, button, resize
|
|
7499 */
|
|
7500
|
|
7501 (function() {
|
|
7502 var Dom = YAHOO.util.Dom,
|
|
7503 Event = YAHOO.util.Event,
|
|
7504 Lang = YAHOO.lang,
|
|
7505 Toolbar = YAHOO.widget.Toolbar;
|
|
7506
|
|
7507 /**
|
|
7508 * 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.
|
|
7509 * @constructor
|
|
7510 * @class Editor
|
|
7511 * @extends YAHOO.widget.SimpleEditor
|
|
7512 * @param {String/HTMLElement} el The textarea element to turn into an editor.
|
|
7513 * @param {Object} attrs Object liternal containing configuration parameters.
|
|
7514 */
|
|
7515
|
|
7516 YAHOO.widget.Editor = function(el, attrs) {
|
|
7517 YAHOO.log('Editor Initalizing', 'info', 'Editor');
|
|
7518 YAHOO.widget.Editor.superclass.constructor.call(this, el, attrs);
|
|
7519 };
|
|
7520
|
|
7521 YAHOO.extend(YAHOO.widget.Editor, YAHOO.widget.SimpleEditor, {
|
|
7522 /**
|
|
7523 * @private
|
|
7524 * @property _undoCache
|
|
7525 * @description An Array hash of the Undo Levels.
|
|
7526 * @type Array
|
|
7527 */
|
|
7528 _undoCache: null,
|
|
7529 /**
|
|
7530 * @private
|
|
7531 * @property _undoLevel
|
|
7532 * @description The index of the current undo state.
|
|
7533 * @type Number
|
|
7534 */
|
|
7535 _undoLevel: null,
|
|
7536 /**
|
|
7537 * @private
|
|
7538 * @method _hasUndoLevel
|
|
7539 * @description Checks to see if we have an undo level available
|
|
7540 * @return Boolean
|
|
7541 */
|
|
7542 _hasUndoLevel: function() {
|
|
7543 return ((this._undoCache.length > 1) && this._undoLevel);
|
|
7544 },
|
|
7545 /**
|
|
7546 * @private
|
|
7547 * @method _undoNodeChange
|
|
7548 * @description nodeChange listener for undo processing
|
|
7549 */
|
|
7550 _undoNodeChange: function() {
|
|
7551 var undo_button = this.toolbar.getButtonByValue('undo'),
|
|
7552 redo_button = this.toolbar.getButtonByValue('redo');
|
|
7553 if (undo_button && redo_button) {
|
|
7554 if (this._hasUndoLevel()) {
|
|
7555 this.toolbar.enableButton(undo_button);
|
|
7556 }
|
|
7557 if (this._undoLevel < this._undoCache.length) {
|
|
7558 this.toolbar.enableButton(redo_button);
|
|
7559 }
|
|
7560 }
|
|
7561 this._lastCommand = null;
|
|
7562 },
|
|
7563 /**
|
|
7564 * @private
|
|
7565 * @method _checkUndo
|
|
7566 * @description Prunes the undo cache when it reaches the maxUndo config
|
|
7567 */
|
|
7568 _checkUndo: function() {
|
|
7569 var len = this._undoCache.length,
|
|
7570 tmp = [];
|
|
7571 if (len >= this.get('maxUndo')) {
|
|
7572 //YAHOO.log('Undo cache too large (' + len + '), pruning..', 'info', 'SimpleEditor');
|
|
7573 for (var i = (len - this.get('maxUndo')); i < len; i++) {
|
|
7574 tmp.push(this._undoCache[i]);
|
|
7575 }
|
|
7576 this._undoCache = tmp;
|
|
7577 }
|
|
7578 },
|
|
7579 /**
|
|
7580 * @private
|
|
7581 * @method _putUndo
|
|
7582 * @description Puts the content of the Editor into the _undoCache.
|
|
7583 * //TODO Convert the hash to a series of TEXTAREAS to store state in.
|
|
7584 * @param {String} str The content of the Editor
|
|
7585 */
|
|
7586 _putUndo: function(str) {
|
|
7587 if (this._undoLevel === this._undoCache.length) {
|
|
7588 this._undoCache.push(str);
|
|
7589 this._undoLevel = this._undoCache.length;
|
|
7590 } else {
|
|
7591 var str = this.getEditorHTML();
|
|
7592 var last = this._undoCache[this._undoLevel];
|
|
7593 if (last) {
|
|
7594 if (str !== last) {
|
|
7595 this._undoCache = [];
|
|
7596 this._undoLevel = 0;
|
|
7597 }
|
|
7598 }
|
|
7599 }
|
|
7600 },
|
|
7601 /**
|
|
7602 * @private
|
|
7603 * @method _getUndo
|
|
7604 * @description Get's a level from the undo cache.
|
|
7605 * @param {Number} index The index of the undo level we want to get.
|
|
7606 * @return {String}
|
|
7607 */
|
|
7608 _getUndo: function(index) {
|
|
7609 this._undoLevel = index;
|
|
7610 return this._undoCache[index];
|
|
7611 },
|
|
7612 /**
|
|
7613 * @private
|
|
7614 * @method _storeUndo
|
|
7615 * @description Method to call when you want to store an undo state. Currently called from nodeChange and _handleKeyUp
|
|
7616 */
|
|
7617 _storeUndo: function() {
|
|
7618 if (this._lastCommand === 'undo' || this._lastCommand === 'redo') {
|
|
7619 return false;
|
|
7620 }
|
|
7621 if (!this._undoCache) {
|
|
7622 this._undoCache = [];
|
|
7623 this._undoLevel = 0;
|
|
7624 }
|
|
7625 this._checkUndo();
|
|
7626 var str = this.getEditorHTML();
|
|
7627 //var last = this._undoCache[this._undoCache.length - 1];
|
|
7628 var last = this._undoCache[this._undoLevel - 1];
|
|
7629 if (last) {
|
|
7630 if (str !== last) {
|
|
7631 //YAHOO.log('Storing Undo', 'info', 'SimpleEditor');
|
|
7632 this._putUndo(str);
|
|
7633 }
|
|
7634 } else {
|
|
7635 //YAHOO.log('Storing Undo', 'info', 'SimpleEditor');
|
|
7636 this._putUndo(str);
|
|
7637 }
|
|
7638 this._undoNodeChange();
|
|
7639 },
|
|
7640 /**
|
|
7641 * @property STR_BEFORE_EDITOR
|
|
7642 * @description The accessibility string for the element before the iFrame
|
|
7643 * @type String
|
|
7644 */
|
|
7645 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>',
|
|
7646 /**
|
|
7647 * @property STR_CLOSE_WINDOW
|
|
7648 * @description The Title of the close button in the Editor Window
|
|
7649 * @type String
|
|
7650 */
|
|
7651 STR_CLOSE_WINDOW: 'Close Window',
|
|
7652 /**
|
|
7653 * @property STR_CLOSE_WINDOW_NOTE
|
|
7654 * @description A note appearing in the Editor Window to tell the user that the Escape key will close the window
|
|
7655 * @type String
|
|
7656 */
|
|
7657 STR_CLOSE_WINDOW_NOTE: 'To close this window use the Control + Shift + W key',
|
|
7658 /**
|
|
7659 * @property STR_IMAGE_PROP_TITLE
|
|
7660 * @description The title for the Image Property Editor Window
|
|
7661 * @type String
|
|
7662 */
|
|
7663 STR_IMAGE_PROP_TITLE: 'Image Options',
|
|
7664 /**
|
|
7665 * @property STR_IMAGE_TITLE
|
|
7666 * @description The label string for Image Description
|
|
7667 * @type String
|
|
7668 */
|
|
7669 STR_IMAGE_TITLE: 'Description',
|
|
7670 /**
|
|
7671 * @property STR_IMAGE_SIZE
|
|
7672 * @description The label string for Image Size
|
|
7673 * @type String
|
|
7674 */
|
|
7675 STR_IMAGE_SIZE: 'Size',
|
|
7676 /**
|
|
7677 * @property STR_IMAGE_ORIG_SIZE
|
|
7678 * @description The label string for Original Image Size
|
|
7679 * @type String
|
|
7680 */
|
|
7681 STR_IMAGE_ORIG_SIZE: 'Original Size',
|
|
7682 /**
|
|
7683 * @property STR_IMAGE_COPY
|
|
7684 * @description The label string for the image copy and paste message for Opera and Safari
|
|
7685 * @type String
|
|
7686 */
|
|
7687 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>',
|
|
7688 /**
|
|
7689 * @property STR_IMAGE_PADDING
|
|
7690 * @description The label string for the image padding.
|
|
7691 * @type String
|
|
7692 */
|
|
7693 STR_IMAGE_PADDING: 'Padding',
|
|
7694 /**
|
|
7695 * @property STR_IMAGE_BORDER
|
|
7696 * @description The label string for the image border.
|
|
7697 * @type String
|
|
7698 */
|
|
7699 STR_IMAGE_BORDER: 'Border',
|
|
7700 /**
|
|
7701 * @property STR_IMAGE_BORDER_SIZE
|
|
7702 * @description The label string for the image border size.
|
|
7703 * @type String
|
|
7704 */
|
|
7705 STR_IMAGE_BORDER_SIZE: 'Border Size',
|
|
7706 /**
|
|
7707 * @property STR_IMAGE_BORDER_TYPE
|
|
7708 * @description The label string for the image border type.
|
|
7709 * @type String
|
|
7710 */
|
|
7711 STR_IMAGE_BORDER_TYPE: 'Border Type',
|
|
7712 /**
|
|
7713 * @property STR_IMAGE_TEXTFLOW
|
|
7714 * @description The label string for the image text flow.
|
|
7715 * @type String
|
|
7716 */
|
|
7717 STR_IMAGE_TEXTFLOW: 'Text Flow',
|
|
7718 /**
|
|
7719 * @property STR_LOCAL_FILE_WARNING
|
|
7720 * @description The label string for the local file warning.
|
|
7721 * @type String
|
|
7722 */
|
|
7723 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>',
|
|
7724 /**
|
|
7725 * @property STR_LINK_PROP_TITLE
|
|
7726 * @description The label string for the Link Property Editor Window.
|
|
7727 * @type String
|
|
7728 */
|
|
7729 STR_LINK_PROP_TITLE: 'Link Options',
|
|
7730 /**
|
|
7731 * @property STR_LINK_PROP_REMOVE
|
|
7732 * @description The label string for the Remove link from text link inside the property editor.
|
|
7733 * @type String
|
|
7734 */
|
|
7735 STR_LINK_PROP_REMOVE: 'Remove link from text',
|
|
7736 /**
|
|
7737 * @property STR_LINK_NEW_WINDOW
|
|
7738 * @description The string for the open in a new window label.
|
|
7739 * @type String
|
|
7740 */
|
|
7741 STR_LINK_NEW_WINDOW: 'Open in a new window.',
|
|
7742 /**
|
|
7743 * @property STR_LINK_TITLE
|
|
7744 * @description The string for the link description.
|
|
7745 * @type String
|
|
7746 */
|
|
7747 STR_LINK_TITLE: 'Description',
|
|
7748 /**
|
|
7749 * @property STR_NONE
|
|
7750 * @description The string for the word none.
|
|
7751 * @type String
|
|
7752 */
|
|
7753 STR_NONE: 'none',
|
|
7754 /**
|
|
7755 * @protected
|
|
7756 * @property CLASS_LOCAL_FILE
|
|
7757 * @description CSS class applied to an element when it's found to have a local url.
|
|
7758 * @type String
|
|
7759 */
|
|
7760 CLASS_LOCAL_FILE: 'warning-localfile',
|
|
7761 /**
|
|
7762 * @protected
|
|
7763 * @property CLASS_HIDDEN
|
|
7764 * @description CSS class applied to the body when the hiddenelements button is pressed.
|
|
7765 * @type String
|
|
7766 */
|
|
7767 CLASS_HIDDEN: 'yui-hidden',
|
|
7768 /**
|
|
7769 * @method init
|
|
7770 * @description The Editor class' initialization method
|
|
7771 */
|
|
7772 init: function(p_oElement, p_oAttributes) {
|
|
7773 YAHOO.log('init', 'info', 'Editor');
|
|
7774
|
|
7775 this._windows = {};
|
|
7776 if (!this._defaultToolbar) {
|
|
7777 this._defaultToolbar = {
|
|
7778 collapse: true,
|
|
7779 titlebar: 'Text Editing Tools',
|
|
7780 draggable: false,
|
|
7781 buttonType: 'advanced',
|
|
7782 buttons: [
|
|
7783 { group: 'fontstyle', label: 'Font Name and Size',
|
|
7784 buttons: [
|
|
7785 { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
|
|
7786 menu: [
|
|
7787 { text: 'Arial', checked: true },
|
|
7788 { text: 'Arial Black' },
|
|
7789 { text: 'Comic Sans MS' },
|
|
7790 { text: 'Courier New' },
|
|
7791 { text: 'Lucida Console' },
|
|
7792 { text: 'Tahoma' },
|
|
7793 { text: 'Times New Roman' },
|
|
7794 { text: 'Trebuchet MS' },
|
|
7795 { text: 'Verdana' }
|
|
7796 ]
|
|
7797 },
|
|
7798 { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
|
|
7799 ]
|
|
7800 },
|
|
7801 { type: 'separator' },
|
|
7802 { group: 'textstyle', label: 'Font Style',
|
|
7803 buttons: [
|
|
7804 { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
|
|
7805 { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
|
|
7806 { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
|
|
7807 { type: 'separator' },
|
|
7808 { type: 'push', label: 'Subscript', value: 'subscript', disabled: true },
|
|
7809 { type: 'push', label: 'Superscript', value: 'superscript', disabled: true }
|
|
7810 ]
|
|
7811 },
|
|
7812 { type: 'separator' },
|
|
7813 { group: 'textstyle2', label: ' ',
|
|
7814 buttons: [
|
|
7815 { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
|
|
7816 { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true },
|
|
7817 { type: 'separator' },
|
|
7818 { type: 'push', label: 'Remove Formatting', value: 'removeformat', disabled: true },
|
|
7819 { type: 'push', label: 'Show/Hide Hidden Elements', value: 'hiddenelements' }
|
|
7820 ]
|
|
7821 },
|
|
7822 { type: 'separator' },
|
|
7823 { group: 'undoredo', label: 'Undo/Redo',
|
|
7824 buttons: [
|
|
7825 { type: 'push', label: 'Undo', value: 'undo', disabled: true },
|
|
7826 { type: 'push', label: 'Redo', value: 'redo', disabled: true }
|
|
7827
|
|
7828 ]
|
|
7829 },
|
|
7830 { type: 'separator' },
|
|
7831 { group: 'alignment', label: 'Alignment',
|
|
7832 buttons: [
|
|
7833 { type: 'push', label: 'Align Left CTRL + SHIFT + [', value: 'justifyleft' },
|
|
7834 { type: 'push', label: 'Align Center CTRL + SHIFT + |', value: 'justifycenter' },
|
|
7835 { type: 'push', label: 'Align Right CTRL + SHIFT + ]', value: 'justifyright' },
|
|
7836 { type: 'push', label: 'Justify', value: 'justifyfull' }
|
|
7837 ]
|
|
7838 },
|
|
7839 { type: 'separator' },
|
|
7840 { group: 'parastyle', label: 'Paragraph Style',
|
|
7841 buttons: [
|
|
7842 { type: 'select', label: 'Normal', value: 'heading', disabled: true,
|
|
7843 menu: [
|
|
7844 { text: 'Normal', value: 'none', checked: true },
|
|
7845 { text: 'Header 1', value: 'h1' },
|
|
7846 { text: 'Header 2', value: 'h2' },
|
|
7847 { text: 'Header 3', value: 'h3' },
|
|
7848 { text: 'Header 4', value: 'h4' },
|
|
7849 { text: 'Header 5', value: 'h5' },
|
|
7850 { text: 'Header 6', value: 'h6' }
|
|
7851 ]
|
|
7852 }
|
|
7853 ]
|
|
7854 },
|
|
7855 { type: 'separator' },
|
|
7856
|
|
7857 { group: 'indentlist2', label: 'Indenting and Lists',
|
|
7858 buttons: [
|
|
7859 { type: 'push', label: 'Indent', value: 'indent', disabled: true },
|
|
7860 { type: 'push', label: 'Outdent', value: 'outdent', disabled: true },
|
|
7861 { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
|
|
7862 { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
|
|
7863 ]
|
|
7864 },
|
|
7865 { type: 'separator' },
|
|
7866 { group: 'insertitem', label: 'Insert Item',
|
|
7867 buttons: [
|
|
7868 { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
|
|
7869 { type: 'push', label: 'Insert Image', value: 'insertimage' }
|
|
7870 ]
|
|
7871 }
|
|
7872 ]
|
|
7873 };
|
|
7874 }
|
|
7875
|
|
7876 if (!this._defaultImageToolbarConfig) {
|
|
7877 this._defaultImageToolbarConfig = {
|
|
7878 buttonType: this._defaultToolbar.buttonType,
|
|
7879 buttons: [
|
|
7880 { group: 'textflow', label: this.STR_IMAGE_TEXTFLOW + ':',
|
|
7881 buttons: [
|
|
7882 { type: 'push', label: 'Left', value: 'left' },
|
|
7883 { type: 'push', label: 'Inline', value: 'inline' },
|
|
7884 { type: 'push', label: 'Block', value: 'block' },
|
|
7885 { type: 'push', label: 'Right', value: 'right' }
|
|
7886 ]
|
|
7887 },
|
|
7888 { type: 'separator' },
|
|
7889 { group: 'padding', label: this.STR_IMAGE_PADDING + ':',
|
|
7890 buttons: [
|
|
7891 { type: 'spin', label: '0', value: 'padding', range: [0, 50] }
|
|
7892 ]
|
|
7893 },
|
|
7894 { type: 'separator' },
|
|
7895 { group: 'border', label: this.STR_IMAGE_BORDER + ':',
|
|
7896 buttons: [
|
|
7897 { type: 'select', label: this.STR_IMAGE_BORDER_SIZE, value: 'bordersize',
|
|
7898 menu: [
|
|
7899 { text: 'none', value: '0', checked: true },
|
|
7900 { text: '1px', value: '1' },
|
|
7901 { text: '2px', value: '2' },
|
|
7902 { text: '3px', value: '3' },
|
|
7903 { text: '4px', value: '4' },
|
|
7904 { text: '5px', value: '5' }
|
|
7905 ]
|
|
7906 },
|
|
7907 { type: 'select', label: this.STR_IMAGE_BORDER_TYPE, value: 'bordertype', disabled: true,
|
|
7908 menu: [
|
|
7909 { text: 'Solid', value: 'solid', checked: true },
|
|
7910 { text: 'Dashed', value: 'dashed' },
|
|
7911 { text: 'Dotted', value: 'dotted' }
|
|
7912 ]
|
|
7913 },
|
|
7914 { type: 'color', label: 'Border Color', value: 'bordercolor', disabled: true }
|
|
7915 ]
|
|
7916 }
|
|
7917 ]
|
|
7918 };
|
|
7919 }
|
|
7920
|
|
7921 YAHOO.widget.Editor.superclass.init.call(this, p_oElement, p_oAttributes);
|
|
7922 },
|
|
7923 _render: function() {
|
|
7924 YAHOO.widget.Editor.superclass._render.apply(this, arguments);
|
|
7925 var self = this;
|
|
7926 //Render the panel in another thread and delay it a little..
|
|
7927 window.setTimeout(function() {
|
|
7928 self._renderPanel.call(self);
|
|
7929 }, 800);
|
|
7930 },
|
|
7931 /**
|
|
7932 * @method initAttributes
|
|
7933 * @description Initializes all of the configuration attributes used to create
|
|
7934 * the editor.
|
|
7935 * @param {Object} attr Object literal specifying a set of
|
|
7936 * configuration attributes used to create the editor.
|
|
7937 */
|
|
7938 initAttributes: function(attr) {
|
|
7939 YAHOO.widget.Editor.superclass.initAttributes.call(this, attr);
|
|
7940
|
|
7941 /**
|
|
7942 * @attribute localFileWarning
|
|
7943 * @description Should we throw the warning if we detect a file that is local to their machine?
|
|
7944 * @default true
|
|
7945 * @type Boolean
|
|
7946 */
|
|
7947 this.setAttributeConfig('localFileWarning', {
|
|
7948 value: attr.locaFileWarning || true
|
|
7949 });
|
|
7950
|
|
7951 /**
|
|
7952 * @attribute hiddencss
|
|
7953 * @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>
|
|
7954 * @default <code><pre>
|
|
7955 .yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u,
|
|
7956 .yui-hidden div, .yui-hidden p, .yui-hidden span, .yui-hidden img, .yui-hidden ul, .yui-hidden ol,
|
|
7957 .yui-hidden li, .yui-hidden table {
|
|
7958 border: 1px dotted #ccc;
|
|
7959 }
|
|
7960 .yui-hidden .yui-non {
|
|
7961 border: none;
|
|
7962 }
|
|
7963 .yui-hidden img {
|
|
7964 padding: 2px;
|
|
7965 }</pre></code>
|
|
7966 * @type String
|
|
7967 */
|
|
7968 this.setAttributeConfig('hiddencss', {
|
|
7969 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; }',
|
|
7970 writeOnce: true
|
|
7971 });
|
|
7972
|
|
7973 },
|
|
7974 /**
|
|
7975 * @private
|
|
7976 * @method _windows
|
|
7977 * @description A reference to the HTML elements used for the body of Editor Windows.
|
|
7978 */
|
|
7979 _windows: null,
|
|
7980 /**
|
|
7981 * @private
|
|
7982 * @method _defaultImageToolbar
|
|
7983 * @description A reference to the Toolbar Object inside Image Editor Window.
|
|
7984 */
|
|
7985 _defaultImageToolbar: null,
|
|
7986 /**
|
|
7987 * @private
|
|
7988 * @method _defaultImageToolbarConfig
|
|
7989 * @description Config to be used for the default Image Editor Window.
|
|
7990 */
|
|
7991 _defaultImageToolbarConfig: null,
|
|
7992 /**
|
|
7993 * @private
|
|
7994 * @method _fixNodes
|
|
7995 * @description Fix href and imgs as well as remove invalid HTML.
|
|
7996 */
|
|
7997 _fixNodes: function() {
|
|
7998 YAHOO.widget.Editor.superclass._fixNodes.call(this);
|
|
7999 try {
|
|
8000 var url = '';
|
|
8001
|
|
8002 var imgs = this._getDoc().getElementsByTagName('img');
|
|
8003 for (var im = 0; im < imgs.length; im++) {
|
|
8004 if (imgs[im].getAttribute('href', 2)) {
|
|
8005 url = imgs[im].getAttribute('src', 2);
|
|
8006 if (this._isLocalFile(url)) {
|
|
8007 Dom.addClass(imgs[im], this.CLASS_LOCAL_FILE);
|
|
8008 } else {
|
|
8009 Dom.removeClass(imgs[im], this.CLASS_LOCAL_FILE);
|
|
8010 }
|
|
8011 }
|
|
8012 }
|
|
8013 var fakeAs = this._getDoc().body.getElementsByTagName('a');
|
|
8014 for (var a = 0; a < fakeAs.length; a++) {
|
|
8015 if (fakeAs[a].getAttribute('href', 2)) {
|
|
8016 url = fakeAs[a].getAttribute('href', 2);
|
|
8017 if (this._isLocalFile(url)) {
|
|
8018 Dom.addClass(fakeAs[a], this.CLASS_LOCAL_FILE);
|
|
8019 } else {
|
|
8020 Dom.removeClass(fakeAs[a], this.CLASS_LOCAL_FILE);
|
|
8021 }
|
|
8022 }
|
|
8023 }
|
|
8024 } catch(e) {}
|
|
8025 },
|
|
8026 /**
|
|
8027 * @private
|
|
8028 * @property _disabled
|
|
8029 * @description The Toolbar items that should be disabled if there is no selection present in the editor.
|
|
8030 * @type Array
|
|
8031 */
|
|
8032 _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading', 'indent' ],
|
|
8033 /**
|
|
8034 * @private
|
|
8035 * @property _alwaysDisabled
|
|
8036 * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
|
|
8037 * @type Object
|
|
8038 */
|
|
8039 _alwaysDisabled: { 'outdent': true },
|
|
8040 /**
|
|
8041 * @private
|
|
8042 * @property _alwaysEnabled
|
|
8043 * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
|
|
8044 * @type Object
|
|
8045 */
|
|
8046 _alwaysEnabled: { hiddenelements: true },
|
|
8047 /**
|
|
8048 * @private
|
|
8049 * @method _handleKeyDown
|
|
8050 * @param {Event} ev The event we are working on.
|
|
8051 * @description Override method that handles some new keydown events inside the iFrame document.
|
|
8052 */
|
|
8053 _handleKeyDown: function(ev) {
|
|
8054 YAHOO.widget.Editor.superclass._handleKeyDown.call(this, ev);
|
|
8055 var doExec = false,
|
|
8056 action = null,
|
|
8057 exec = false;
|
|
8058
|
|
8059 switch (ev.keyCode) {
|
|
8060 //case 219: //Left
|
|
8061 case this._keyMap.JUSTIFY_LEFT.key: //Left
|
|
8062 if (this._checkKey(this._keyMap.JUSTIFY_LEFT, ev)) {
|
|
8063 action = 'justifyleft';
|
|
8064 doExec = true;
|
|
8065 }
|
|
8066 break;
|
|
8067 //case 220: //Center
|
|
8068 case this._keyMap.JUSTIFY_CENTER.key:
|
|
8069 if (this._checkKey(this._keyMap.JUSTIFY_CENTER, ev)) {
|
|
8070 action = 'justifycenter';
|
|
8071 doExec = true;
|
|
8072 }
|
|
8073 break;
|
|
8074 case 221: //Right
|
|
8075 case this._keyMap.JUSTIFY_RIGHT.key:
|
|
8076 if (this._checkKey(this._keyMap.JUSTIFY_RIGHT, ev)) {
|
|
8077 action = 'justifyright';
|
|
8078 doExec = true;
|
|
8079 }
|
|
8080 break;
|
|
8081 }
|
|
8082 if (doExec && action) {
|
|
8083 this.execCommand(action, null);
|
|
8084 Event.stopEvent(ev);
|
|
8085 this.nodeChange();
|
|
8086 }
|
|
8087 },
|
|
8088 /**
|
|
8089 * @private
|
|
8090 * @method _renderCreateLinkWindow
|
|
8091 * @description Pre renders the CreateLink window so we get faster window opening.
|
|
8092 */
|
|
8093 _renderCreateLinkWindow: function() {
|
|
8094 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>';
|
|
8095 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>';
|
|
8096 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>';
|
|
8097
|
|
8098 var body = document.createElement('div');
|
|
8099 body.innerHTML = str;
|
|
8100
|
|
8101 var unlinkCont = document.createElement('div');
|
|
8102 unlinkCont.className = 'removeLink';
|
|
8103 var unlink = document.createElement('a');
|
|
8104 unlink.href = '#';
|
|
8105 unlink.innerHTML = this.STR_LINK_PROP_REMOVE;
|
|
8106 unlink.title = this.STR_LINK_PROP_REMOVE;
|
|
8107 Event.on(unlink, 'click', function(ev) {
|
|
8108 Event.stopEvent(ev);
|
|
8109 this.unsubscribeAll('afterExecCommand');
|
|
8110 this.execCommand('unlink');
|
|
8111 this.closeWindow();
|
|
8112 }, this, true);
|
|
8113 unlinkCont.appendChild(unlink);
|
|
8114 body.appendChild(unlinkCont);
|
|
8115
|
|
8116 this._windows.createlink = {};
|
|
8117 this._windows.createlink.body = body;
|
|
8118 //body.style.display = 'none';
|
|
8119 Event.on(body, 'keyup', function(e) {
|
|
8120 Event.stopPropagation(e);
|
|
8121 });
|
|
8122 this.get('panel').editor_form.appendChild(body);
|
|
8123 this.fireEvent('windowCreateLinkRender', { type: 'windowCreateLinkRender', panel: this.get('panel'), body: body });
|
|
8124 return body;
|
|
8125 },
|
|
8126 _handleCreateLinkClick: function() {
|
|
8127 var el = this._getSelectedElement();
|
|
8128 if (this._isElement(el, 'img')) {
|
|
8129 this.STOP_EXEC_COMMAND = true;
|
|
8130 this.currentElement[0] = el;
|
|
8131 this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
|
|
8132 this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
|
|
8133 return false;
|
|
8134 }
|
|
8135 if (this.get('limitCommands')) {
|
|
8136 if (!this.toolbar.getButtonByValue('createlink')) {
|
|
8137 YAHOO.log('Toolbar Button for (createlink) was not found, skipping exec.', 'info', 'Editor');
|
|
8138 return false;
|
|
8139 }
|
|
8140 }
|
|
8141
|
|
8142 this.on('afterExecCommand', function() {
|
|
8143 var win = new YAHOO.widget.EditorWindow('createlink', {
|
|
8144 width: '350px'
|
|
8145 });
|
|
8146
|
|
8147 var el = this.currentElement[0],
|
|
8148 url = '',
|
|
8149 title = '',
|
|
8150 target = '',
|
|
8151 localFile = false;
|
|
8152 if (el) {
|
|
8153 win.el = el;
|
|
8154 if (el.getAttribute('href', 2) !== null) {
|
|
8155 url = el.getAttribute('href', 2);
|
|
8156 if (this._isLocalFile(url)) {
|
|
8157 //Local File throw Warning
|
|
8158 YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
|
|
8159 win.setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8160 localFile = true;
|
|
8161 } else {
|
|
8162 win.setFooter(' ');
|
|
8163 }
|
|
8164 }
|
|
8165 if (el.getAttribute('title') !== null) {
|
|
8166 title = el.getAttribute('title');
|
|
8167 }
|
|
8168 if (el.getAttribute('target') !== null) {
|
|
8169 target = el.getAttribute('target');
|
|
8170 }
|
|
8171 }
|
|
8172 var body = null;
|
|
8173 if (this._windows.createlink && this._windows.createlink.body) {
|
|
8174 body = this._windows.createlink.body;
|
|
8175 } else {
|
|
8176 body = this._renderCreateLinkWindow();
|
|
8177 }
|
|
8178
|
|
8179 win.setHeader(this.STR_LINK_PROP_TITLE);
|
|
8180 win.setBody(body);
|
|
8181
|
|
8182 Event.purgeElement(this.get('id') + '_createlink_url');
|
|
8183
|
|
8184 Dom.get(this.get('id') + '_createlink_url').value = url;
|
|
8185 Dom.get(this.get('id') + '_createlink_title').value = title;
|
|
8186 Dom.get(this.get('id') + '_createlink_target').checked = ((target) ? true : false);
|
|
8187
|
|
8188
|
|
8189 Event.onAvailable(this.get('id') + '_createlink_url', function() {
|
|
8190 var id = this.get('id');
|
|
8191 window.setTimeout(function() {
|
|
8192 try {
|
|
8193 YAHOO.util.Dom.get(id + '_createlink_url').focus();
|
|
8194 } catch (e) {}
|
|
8195 }, 50);
|
|
8196
|
|
8197 if (this._isLocalFile(url)) {
|
|
8198 //Local File throw Warning
|
|
8199 Dom.addClass(this.get('id') + '_createlink_url', 'warning');
|
|
8200 YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
|
|
8201 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8202 } else {
|
|
8203 Dom.removeClass(this.get('id') + '_createlink_url', 'warning');
|
|
8204 this.get('panel').setFooter(' ');
|
|
8205 }
|
|
8206 Event.on(this.get('id') + '_createlink_url', 'blur', function() {
|
|
8207 var url = Dom.get(this.get('id') + '_createlink_url');
|
|
8208 if (this._isLocalFile(url.value)) {
|
|
8209 //Local File throw Warning
|
|
8210 Dom.addClass(url, 'warning');
|
|
8211 YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
|
|
8212 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8213 } else {
|
|
8214 Dom.removeClass(url, 'warning');
|
|
8215 this.get('panel').setFooter(' ');
|
|
8216 }
|
|
8217 }, this, true);
|
|
8218 }, this, true);
|
|
8219
|
|
8220 this.openWindow(win);
|
|
8221
|
|
8222 });
|
|
8223 },
|
|
8224 /**
|
|
8225 * @private
|
|
8226 * @method _handleCreateLinkWindowClose
|
|
8227 * @description Handles the closing of the Link Properties Window.
|
|
8228 */
|
|
8229 _handleCreateLinkWindowClose: function() {
|
|
8230
|
|
8231 var url = Dom.get(this.get('id') + '_createlink_url'),
|
|
8232 target = Dom.get(this.get('id') + '_createlink_target'),
|
|
8233 title = Dom.get(this.get('id') + '_createlink_title'),
|
|
8234 el = arguments[0].win.el,
|
|
8235 a = el;
|
|
8236
|
|
8237 if (url && url.value) {
|
|
8238 var urlValue = url.value;
|
|
8239 if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8240 if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8241 //Found an @ sign, prefix with mailto:
|
|
8242 urlValue = 'mailto:' + urlValue;
|
|
8243 } else {
|
|
8244 // :// not found adding
|
|
8245 if (urlValue.substring(0, 1) != '#') {
|
|
8246 urlValue = 'http:/'+'/' + urlValue;
|
|
8247 }
|
|
8248
|
|
8249 }
|
|
8250 }
|
|
8251 el.setAttribute('href', urlValue);
|
|
8252 if (target.checked) {
|
|
8253 el.setAttribute('target', target.value);
|
|
8254 } else {
|
|
8255 el.setAttribute('target', '');
|
|
8256 }
|
|
8257 el.setAttribute('title', ((title.value) ? title.value : ''));
|
|
8258
|
|
8259 } else {
|
|
8260 var _span = this._getDoc().createElement('span');
|
|
8261 _span.innerHTML = el.innerHTML;
|
|
8262 Dom.addClass(_span, 'yui-non');
|
|
8263 el.parentNode.replaceChild(_span, el);
|
|
8264 }
|
|
8265 Dom.removeClass(url, 'warning');
|
|
8266 Dom.get(this.get('id') + '_createlink_url').value = '';
|
|
8267 Dom.get(this.get('id') + '_createlink_title').value = '';
|
|
8268 Dom.get(this.get('id') + '_createlink_target').checked = false;
|
|
8269 this.nodeChange();
|
|
8270 this.currentElement = [];
|
|
8271
|
|
8272 },
|
|
8273 /**
|
|
8274 * @private
|
|
8275 * @method _renderInsertImageWindow
|
|
8276 * @description Pre renders the InsertImage window so we get faster window opening.
|
|
8277 */
|
|
8278 _renderInsertImageWindow: function() {
|
|
8279 var el = this.currentElement[0];
|
|
8280 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>';
|
|
8281 var body = document.createElement('div');
|
|
8282 body.innerHTML = str;
|
|
8283
|
|
8284 var tbarCont = document.createElement('div');
|
|
8285 tbarCont.id = this.get('id') + '_img_toolbar';
|
|
8286 body.appendChild(tbarCont);
|
|
8287
|
|
8288 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>';
|
|
8289 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>';
|
|
8290 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>';
|
|
8291 var div = document.createElement('div');
|
|
8292 div.innerHTML = str2;
|
|
8293 body.appendChild(div);
|
|
8294
|
|
8295 var o = {};
|
|
8296 Lang.augmentObject(o, this._defaultImageToolbarConfig); //Break the config reference
|
|
8297
|
|
8298 var tbar = new YAHOO.widget.Toolbar(tbarCont, o);
|
|
8299 tbar.editor_el = el;
|
|
8300 this._defaultImageToolbar = tbar;
|
|
8301
|
|
8302 var cont = tbar.get('cont');
|
|
8303 var hw = document.createElement('div');
|
|
8304 hw.className = 'yui-toolbar-group yui-toolbar-group-height-width height-width';
|
|
8305 hw.innerHTML = '<h3>' + this.STR_IMAGE_SIZE + ':</h3>';
|
|
8306 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>';
|
|
8307 cont.insertBefore(hw, cont.firstChild);
|
|
8308
|
|
8309 Event.onAvailable(this.get('id') + '_insertimage_width', function() {
|
|
8310 Event.on(this.get('id') + '_insertimage_width', 'blur', function() {
|
|
8311 var value = parseInt(Dom.get(this.get('id') + '_insertimage_width').value, 10);
|
|
8312 if (value > 5) {
|
|
8313 this._defaultImageToolbar.editor_el.style.width = value + 'px';
|
|
8314 //Removed moveWindow call so the window doesn't jump
|
|
8315 //this.moveWindow();
|
|
8316 }
|
|
8317 }, this, true);
|
|
8318 }, this, true);
|
|
8319 Event.onAvailable(this.get('id') + '_insertimage_height', function() {
|
|
8320 Event.on(this.get('id') + '_insertimage_height', 'blur', function() {
|
|
8321 var value = parseInt(Dom.get(this.get('id') + '_insertimage_height').value, 10);
|
|
8322 if (value > 5) {
|
|
8323 this._defaultImageToolbar.editor_el.style.height = value + 'px';
|
|
8324 //Removed moveWindow call so the window doesn't jump
|
|
8325 //this.moveWindow();
|
|
8326 }
|
|
8327 }, this, true);
|
|
8328 }, this, true);
|
|
8329
|
|
8330
|
|
8331 tbar.on('colorPickerClicked', function(o) {
|
|
8332 var size = '1', type = 'solid', color = 'black', el = this._defaultImageToolbar.editor_el;
|
|
8333
|
|
8334 if (el.style.borderLeftWidth) {
|
|
8335 size = parseInt(el.style.borderLeftWidth, 10);
|
|
8336 }
|
|
8337 if (el.style.borderLeftStyle) {
|
|
8338 type = el.style.borderLeftStyle;
|
|
8339 }
|
|
8340 if (el.style.borderLeftColor) {
|
|
8341 color = el.style.borderLeftColor;
|
|
8342 }
|
|
8343 var borderString = size + 'px ' + type + ' #' + o.color;
|
|
8344 el.style.border = borderString;
|
|
8345 }, this, true);
|
|
8346
|
|
8347 tbar.on('buttonClick', function(o) {
|
|
8348 var value = o.button.value,
|
|
8349 el = this._defaultImageToolbar.editor_el,
|
|
8350 borderString = '';
|
|
8351 if (o.button.menucmd) {
|
|
8352 value = o.button.menucmd;
|
|
8353 }
|
|
8354 var size = '1', type = 'solid', color = 'black';
|
|
8355
|
|
8356 /* All border calcs are done on the left border
|
|
8357 since our default interface only supports
|
|
8358 one border size/type and color */
|
|
8359 if (el.style.borderLeftWidth) {
|
|
8360 size = parseInt(el.style.borderLeftWidth, 10);
|
|
8361 }
|
|
8362 if (el.style.borderLeftStyle) {
|
|
8363 type = el.style.borderLeftStyle;
|
|
8364 }
|
|
8365 if (el.style.borderLeftColor) {
|
|
8366 color = el.style.borderLeftColor;
|
|
8367 }
|
|
8368 switch(value) {
|
|
8369 case 'bordersize':
|
|
8370 if (this.browser.webkit && this._lastImage) {
|
|
8371 Dom.removeClass(this._lastImage, 'selected');
|
|
8372 this._lastImage = null;
|
|
8373 }
|
|
8374
|
|
8375 borderString = parseInt(o.button.value, 10) + 'px ' + type + ' ' + color;
|
|
8376 el.style.border = borderString;
|
|
8377 if (parseInt(o.button.value, 10) > 0) {
|
|
8378 tbar.enableButton('bordertype');
|
|
8379 tbar.enableButton('bordercolor');
|
|
8380 } else {
|
|
8381 tbar.disableButton('bordertype');
|
|
8382 tbar.disableButton('bordercolor');
|
|
8383 }
|
|
8384 break;
|
|
8385 case 'bordertype':
|
|
8386 if (this.browser.webkit && this._lastImage) {
|
|
8387 Dom.removeClass(this._lastImage, 'selected');
|
|
8388 this._lastImage = null;
|
|
8389 }
|
|
8390 borderString = size + 'px ' + o.button.value + ' ' + color;
|
|
8391 el.style.border = borderString;
|
|
8392 break;
|
|
8393 case 'right':
|
|
8394 case 'left':
|
|
8395 tbar.deselectAllButtons();
|
|
8396 el.style.display = '';
|
|
8397 el.align = o.button.value;
|
|
8398 break;
|
|
8399 case 'inline':
|
|
8400 tbar.deselectAllButtons();
|
|
8401 el.style.display = '';
|
|
8402 el.align = '';
|
|
8403 break;
|
|
8404 case 'block':
|
|
8405 tbar.deselectAllButtons();
|
|
8406 el.style.display = 'block';
|
|
8407 el.align = 'center';
|
|
8408 break;
|
|
8409 case 'padding':
|
|
8410 var _button = tbar.getButtonById(o.button.id);
|
|
8411 el.style.margin = _button.get('label') + 'px';
|
|
8412 break;
|
|
8413 }
|
|
8414 tbar.selectButton(o.button.value);
|
|
8415 if (value !== 'padding') {
|
|
8416 this.moveWindow();
|
|
8417 }
|
|
8418 }, this, true);
|
|
8419
|
|
8420
|
|
8421
|
|
8422 if (this.get('localFileWarning')) {
|
|
8423 Event.on(this.get('id') + '_insertimage_link', 'blur', function() {
|
|
8424 var url = Dom.get(this.get('id') + '_insertimage_link');
|
|
8425 if (this._isLocalFile(url.value)) {
|
|
8426 //Local File throw Warning
|
|
8427 Dom.addClass(url, 'warning');
|
|
8428 YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
|
|
8429 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8430 } else {
|
|
8431 Dom.removeClass(url, 'warning');
|
|
8432 this.get('panel').setFooter(' ');
|
|
8433 //Adobe AIR Code
|
|
8434 if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {
|
|
8435 this.get('panel').setFooter(this.STR_IMAGE_COPY);
|
|
8436 }
|
|
8437 }
|
|
8438 }, this, true);
|
|
8439 }
|
|
8440
|
|
8441 Event.on(this.get('id') + '_insertimage_url', 'blur', function() {
|
|
8442 var url = Dom.get(this.get('id') + '_insertimage_url'),
|
|
8443 el = this.currentElement[0];
|
|
8444
|
|
8445 if (url.value && el) {
|
|
8446 if (url.value == el.getAttribute('src', 2)) {
|
|
8447 YAHOO.log('Images are the same, bail on blur handler', 'info', 'Editor');
|
|
8448 return false;
|
|
8449 }
|
|
8450 }
|
|
8451 YAHOO.log('Images are different, process blur handler', 'info', 'Editor');
|
|
8452 if (this._isLocalFile(url.value)) {
|
|
8453 //Local File throw Warning
|
|
8454 Dom.addClass(url, 'warning');
|
|
8455 YAHOO.log('Local file reference found, show local warning', 'warn', 'Editor');
|
|
8456 this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
|
|
8457 } else if (this.currentElement[0]) {
|
|
8458 Dom.removeClass(url, 'warning');
|
|
8459 this.get('panel').setFooter(' ');
|
|
8460 //Adobe AIR Code
|
|
8461 if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {
|
|
8462 this.get('panel').setFooter(this.STR_IMAGE_COPY);
|
|
8463 }
|
|
8464
|
|
8465 if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
|
|
8466 this.currentElement[0].setAttribute('src', url.value);
|
|
8467 var self = this,
|
|
8468 img = new Image();
|
|
8469
|
|
8470 img.onerror = function() {
|
|
8471 url.value = self.STR_IMAGE_HERE;
|
|
8472 img.setAttribute('src', self.get('blankimage'));
|
|
8473 self.currentElement[0].setAttribute('src', self.get('blankimage'));
|
|
8474 YAHOO.util.Dom.get(self.get('id') + '_insertimage_height').value = img.height;
|
|
8475 YAHOO.util.Dom.get(self.get('id') + '_insertimage_width').value = img.width;
|
|
8476 };
|
|
8477 var id = this.get('id');
|
|
8478 window.setTimeout(function() {
|
|
8479 YAHOO.util.Dom.get(id + '_insertimage_height').value = img.height;
|
|
8480 YAHOO.util.Dom.get(id + '_insertimage_width').value = img.width;
|
|
8481 if (self.currentElement && self.currentElement[0]) {
|
|
8482 if (!self.currentElement[0]._height) {
|
|
8483 self.currentElement[0]._height = img.height;
|
|
8484 }
|
|
8485 if (!self.currentElement[0]._width) {
|
|
8486 self.currentElement[0]._width = img.width;
|
|
8487 }
|
|
8488 }
|
|
8489 //Removed moveWindow call so the window doesn't jump
|
|
8490 //self.moveWindow();
|
|
8491 }, 800); //Bumped the timeout up to account for larger images..
|
|
8492
|
|
8493 if (url.value != this.STR_IMAGE_HERE) {
|
|
8494 img.src = url.value;
|
|
8495 }
|
|
8496 }
|
|
8497 }
|
|
8498 }, this, true);
|
|
8499
|
|
8500
|
|
8501
|
|
8502 this._windows.insertimage = {};
|
|
8503 this._windows.insertimage.body = body;
|
|
8504 //body.style.display = 'none';
|
|
8505 this.get('panel').editor_form.appendChild(body);
|
|
8506 this.fireEvent('windowInsertImageRender', { type: 'windowInsertImageRender', panel: this.get('panel'), body: body, toolbar: tbar });
|
|
8507 return body;
|
|
8508 },
|
|
8509 /**
|
|
8510 * @private
|
|
8511 * @method _handleInsertImageClick
|
|
8512 * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
|
|
8513 */
|
|
8514 _handleInsertImageClick: function() {
|
|
8515 if (this.get('limitCommands')) {
|
|
8516 if (!this.toolbar.getButtonByValue('insertimage')) {
|
|
8517 YAHOO.log('Toolbar Button for (insertimage) was not found, skipping exec.', 'info', 'Editor');
|
|
8518 return false;
|
|
8519 }
|
|
8520 }
|
|
8521 this.on('afterExecCommand', function() {
|
|
8522 YAHOO.log('afterExecCommand :: _handleInsertImageClick', 'info', 'Editor');
|
|
8523 var el = this.currentElement[0],
|
|
8524 body = null,
|
|
8525 link = '',
|
|
8526 target = '',
|
|
8527 tbar = null,
|
|
8528 title = '',
|
|
8529 src = '',
|
|
8530 align = '',
|
|
8531 height = 75,
|
|
8532 width = 75,
|
|
8533 padding = 0,
|
|
8534 oheight = 0,
|
|
8535 owidth = 0,
|
|
8536 blankimage = false,
|
|
8537 win = new YAHOO.widget.EditorWindow('insertimage', {
|
|
8538 width: '415px'
|
|
8539 });
|
|
8540
|
|
8541 if (!el) {
|
|
8542 el = this._getSelectedElement();
|
|
8543 }
|
|
8544 if (el) {
|
|
8545 win.el = el;
|
|
8546 if (el.getAttribute('src')) {
|
|
8547 src = el.getAttribute('src', 2);
|
|
8548 if (src.indexOf(this.get('blankimage')) != -1) {
|
|
8549 src = this.STR_IMAGE_HERE;
|
|
8550 blankimage = true;
|
|
8551 }
|
|
8552 }
|
|
8553 if (el.getAttribute('alt', 2)) {
|
|
8554 title = el.getAttribute('alt', 2);
|
|
8555 }
|
|
8556 if (el.getAttribute('title', 2)) {
|
|
8557 title = el.getAttribute('title', 2);
|
|
8558 }
|
|
8559
|
|
8560 if (el.parentNode && this._isElement(el.parentNode, 'a')) {
|
|
8561 link = el.parentNode.getAttribute('href', 2);
|
|
8562 if (el.parentNode.getAttribute('target') !== null) {
|
|
8563 target = el.parentNode.getAttribute('target');
|
|
8564 }
|
|
8565 }
|
|
8566 height = parseInt(el.height, 10);
|
|
8567 width = parseInt(el.width, 10);
|
|
8568 if (el.style.height) {
|
|
8569 height = parseInt(el.style.height, 10);
|
|
8570 }
|
|
8571 if (el.style.width) {
|
|
8572 width = parseInt(el.style.width, 10);
|
|
8573 }
|
|
8574 if (el.style.margin) {
|
|
8575 padding = parseInt(el.style.margin, 10);
|
|
8576 }
|
|
8577 if (!blankimage) {
|
|
8578 if (!el._height) {
|
|
8579 el._height = height;
|
|
8580 }
|
|
8581 if (!el._width) {
|
|
8582 el._width = width;
|
|
8583 }
|
|
8584 oheight = el._height;
|
|
8585 owidth = el._width;
|
|
8586 }
|
|
8587 }
|
|
8588 if (this._windows.insertimage && this._windows.insertimage.body) {
|
|
8589 body = this._windows.insertimage.body;
|
|
8590 this._defaultImageToolbar.resetAllButtons();
|
|
8591 } else {
|
|
8592 body = this._renderInsertImageWindow();
|
|
8593 }
|
|
8594
|
|
8595 tbar = this._defaultImageToolbar;
|
|
8596 tbar.editor_el = el;
|
|
8597
|
|
8598
|
|
8599 var bsize = '0',
|
|
8600 btype = 'solid';
|
|
8601
|
|
8602 if (el.style.borderLeftWidth) {
|
|
8603 bsize = parseInt(el.style.borderLeftWidth, 10);
|
|
8604 }
|
|
8605 if (el.style.borderLeftStyle) {
|
|
8606 btype = el.style.borderLeftStyle;
|
|
8607 }
|
|
8608 var bs_button = tbar.getButtonByValue('bordersize'),
|
|
8609 bSizeStr = ((parseInt(bsize, 10) > 0) ? '' : this.STR_NONE);
|
|
8610 bs_button.set('label', '<span class="yui-toolbar-bordersize-' + bsize + '">' + bSizeStr + '</span>');
|
|
8611 this._updateMenuChecked('bordersize', bsize, tbar);
|
|
8612
|
|
8613 var bt_button = tbar.getButtonByValue('bordertype');
|
|
8614 bt_button.set('label', '<span class="yui-toolbar-bordertype-' + btype + '">asdfa</span>');
|
|
8615 this._updateMenuChecked('bordertype', btype, tbar);
|
|
8616 if (parseInt(bsize, 10) > 0) {
|
|
8617 tbar.enableButton(bt_button);
|
|
8618 tbar.enableButton(bs_button);
|
|
8619 tbar.enableButton('bordercolor');
|
|
8620 }
|
|
8621
|
|
8622 if ((el.align == 'right') || (el.align == 'left')) {
|
|
8623 tbar.selectButton(el.align);
|
|
8624 } else if (el.style.display == 'block') {
|
|
8625 tbar.selectButton('block');
|
|
8626 } else {
|
|
8627 tbar.selectButton('inline');
|
|
8628 }
|
|
8629 if (parseInt(el.style.marginLeft, 10) > 0) {
|
|
8630 tbar.getButtonByValue('padding').set('label', ''+parseInt(el.style.marginLeft, 10));
|
|
8631 }
|
|
8632 if (el.style.borderSize) {
|
|
8633 tbar.selectButton('bordersize');
|
|
8634 tbar.selectButton(parseInt(el.style.borderSize, 10));
|
|
8635 }
|
|
8636 tbar.getButtonByValue('padding').set('label', ''+padding);
|
|
8637
|
|
8638
|
|
8639
|
|
8640 win.setHeader(this.STR_IMAGE_PROP_TITLE);
|
|
8641 win.setBody(body);
|
|
8642 //Adobe AIR Code
|
|
8643 if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {
|
|
8644 win.setFooter(this.STR_IMAGE_COPY);
|
|
8645 }
|
|
8646 this.openWindow(win);
|
|
8647 Dom.get(this.get('id') + '_insertimage_url').value = src;
|
|
8648 Dom.get(this.get('id') + '_insertimage_title').value = title;
|
|
8649 Dom.get(this.get('id') + '_insertimage_link').value = link;
|
|
8650 Dom.get(this.get('id') + '_insertimage_target').checked = ((target) ? true : false);
|
|
8651 Dom.get(this.get('id') + '_insertimage_width').value = width;
|
|
8652 Dom.get(this.get('id') + '_insertimage_height').value = height;
|
|
8653
|
|
8654
|
|
8655 if (((height != oheight) || (width != owidth)) && (!blankimage)) {
|
|
8656 var s = document.createElement('span');
|
|
8657 s.className = 'info';
|
|
8658 s.innerHTML = this.STR_IMAGE_ORIG_SIZE + ': ('+ owidth +' x ' + oheight + ')';
|
|
8659 if (Dom.get(this.get('id') + '_insertimage_height').nextSibling) {
|
|
8660 var old = Dom.get(this.get('id') + '_insertimage_height').nextSibling;
|
|
8661 old.parentNode.removeChild(old);
|
|
8662 }
|
|
8663 Dom.get(this.get('id') + '_insertimage_height').parentNode.appendChild(s);
|
|
8664 }
|
|
8665
|
|
8666 this.toolbar.selectButton('insertimage');
|
|
8667 var id = this.get('id');
|
|
8668 window.setTimeout(function() {
|
|
8669 try {
|
|
8670 YAHOO.util.Dom.get(id + '_insertimage_url').focus();
|
|
8671 if (blankimage) {
|
|
8672 YAHOO.util.Dom.get(id + '_insertimage_url').select();
|
|
8673 }
|
|
8674 } catch (e) {}
|
|
8675 }, 50);
|
|
8676
|
|
8677 });
|
|
8678 },
|
|
8679 /**
|
|
8680 * @private
|
|
8681 * @method _handleInsertImageWindowClose
|
|
8682 * @description Handles the closing of the Image Properties Window.
|
|
8683 */
|
|
8684 _handleInsertImageWindowClose: function() {
|
|
8685 var url = Dom.get(this.get('id') + '_insertimage_url'),
|
|
8686 title = Dom.get(this.get('id') + '_insertimage_title'),
|
|
8687 link = Dom.get(this.get('id') + '_insertimage_link'),
|
|
8688 target = Dom.get(this.get('id') + '_insertimage_target'),
|
|
8689 el = arguments[0].win.el;
|
|
8690
|
|
8691 if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
|
|
8692 el.setAttribute('src', url.value);
|
|
8693 el.setAttribute('title', title.value);
|
|
8694 el.setAttribute('alt', title.value);
|
|
8695 var par = el.parentNode;
|
|
8696 if (link.value) {
|
|
8697 var urlValue = link.value;
|
|
8698 if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8699 if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
|
|
8700 //Found an @ sign, prefix with mailto:
|
|
8701 urlValue = 'mailto:' + urlValue;
|
|
8702 } else {
|
|
8703 // :// not found adding
|
|
8704 urlValue = 'http:/'+'/' + urlValue;
|
|
8705 }
|
|
8706 }
|
|
8707 if (par && this._isElement(par, 'a')) {
|
|
8708 par.setAttribute('href', urlValue);
|
|
8709 if (target.checked) {
|
|
8710 par.setAttribute('target', target.value);
|
|
8711 } else {
|
|
8712 par.setAttribute('target', '');
|
|
8713 }
|
|
8714 } else {
|
|
8715 var _a = this._getDoc().createElement('a');
|
|
8716 _a.setAttribute('href', urlValue);
|
|
8717 if (target.checked) {
|
|
8718 _a.setAttribute('target', target.value);
|
|
8719 } else {
|
|
8720 _a.setAttribute('target', '');
|
|
8721 }
|
|
8722 el.parentNode.replaceChild(_a, el);
|
|
8723 _a.appendChild(el);
|
|
8724 }
|
|
8725 } else {
|
|
8726 if (par && this._isElement(par, 'a')) {
|
|
8727 par.parentNode.replaceChild(el, par);
|
|
8728 }
|
|
8729 }
|
|
8730 } else {
|
|
8731 //No url/src given, remove the node from the document
|
|
8732 el.parentNode.removeChild(el);
|
|
8733 }
|
|
8734 Dom.get(this.get('id') + '_insertimage_url').value = '';
|
|
8735 Dom.get(this.get('id') + '_insertimage_title').value = '';
|
|
8736 Dom.get(this.get('id') + '_insertimage_link').value = '';
|
|
8737 Dom.get(this.get('id') + '_insertimage_target').checked = false;
|
|
8738 Dom.get(this.get('id') + '_insertimage_width').value = 0;
|
|
8739 Dom.get(this.get('id') + '_insertimage_height').value = 0;
|
|
8740 this._defaultImageToolbar.resetAllButtons();
|
|
8741 this.currentElement = [];
|
|
8742 this.nodeChange();
|
|
8743 },
|
|
8744 /**
|
|
8745 * @property EDITOR_PANEL_ID
|
|
8746 * @description HTML id to give the properties window in the DOM.
|
|
8747 * @type String
|
|
8748 */
|
|
8749 EDITOR_PANEL_ID: '-panel',
|
|
8750 /**
|
|
8751 * @private
|
|
8752 * @method _renderPanel
|
|
8753 * @description Renders the panel used for Editor Windows to the document so we can start using it..
|
|
8754 * @return {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>}
|
|
8755 */
|
|
8756 _renderPanel: function() {
|
|
8757 var panelEl = document.createElement('div');
|
|
8758 Dom.addClass(panelEl, 'yui-editor-panel');
|
|
8759 panelEl.id = this.get('id') + this.EDITOR_PANEL_ID;
|
|
8760 panelEl.style.position = 'absolute';
|
|
8761 panelEl.style.top = '-9999px';
|
|
8762 panelEl.style.left = '-9999px';
|
|
8763 document.body.appendChild(panelEl);
|
|
8764 this.get('element_cont').insertBefore(panelEl, this.get('element_cont').get('firstChild'));
|
|
8765
|
|
8766
|
|
8767
|
|
8768 var panel = new YAHOO.widget.Overlay(this.get('id') + this.EDITOR_PANEL_ID, {
|
|
8769 width: '300px',
|
|
8770 iframe: true,
|
|
8771 visible: false,
|
|
8772 underlay: 'none',
|
|
8773 draggable: false,
|
|
8774 close: false
|
|
8775 });
|
|
8776 this.set('panel', panel);
|
|
8777
|
|
8778 panel.setBody('---');
|
|
8779 panel.setHeader(' ');
|
|
8780 panel.setFooter(' ');
|
|
8781
|
|
8782
|
|
8783 var body = document.createElement('div');
|
|
8784 body.className = this.CLASS_PREFIX + '-body-cont';
|
|
8785 for (var b in this.browser) {
|
|
8786 if (this.browser[b]) {
|
|
8787 Dom.addClass(body, b);
|
|
8788 break;
|
|
8789 }
|
|
8790 }
|
|
8791 Dom.addClass(body, ((YAHOO.widget.Button && (this._defaultToolbar.buttonType == 'advanced')) ? 'good-button' : 'no-button'));
|
|
8792
|
|
8793 var _note = document.createElement('h3');
|
|
8794 _note.className = 'yui-editor-skipheader';
|
|
8795 _note.innerHTML = this.STR_CLOSE_WINDOW_NOTE;
|
|
8796 body.appendChild(_note);
|
|
8797 var form = document.createElement('fieldset');
|
|
8798 panel.editor_form = form;
|
|
8799
|
|
8800 body.appendChild(form);
|
|
8801 var _close = document.createElement('span');
|
|
8802 _close.innerHTML = 'X';
|
|
8803 _close.title = this.STR_CLOSE_WINDOW;
|
|
8804 _close.className = 'close';
|
|
8805
|
|
8806 Event.on(_close, 'click', this.closeWindow, this, true);
|
|
8807
|
|
8808 var _knob = document.createElement('span');
|
|
8809 _knob.innerHTML = '^';
|
|
8810 _knob.className = 'knob';
|
|
8811 panel.editor_knob = _knob;
|
|
8812
|
|
8813 var _header = document.createElement('h3');
|
|
8814 panel.editor_header = _header;
|
|
8815 _header.innerHTML = '<span></span>';
|
|
8816
|
|
8817 panel.setHeader(' '); //Clear the current header
|
|
8818 panel.appendToHeader(_header);
|
|
8819 _header.appendChild(_close);
|
|
8820 _header.appendChild(_knob);
|
|
8821 panel.setBody(' '); //Clear the current body
|
|
8822 panel.setFooter(' '); //Clear the current footer
|
|
8823 panel.appendToBody(body); //Append the new DOM node to it
|
|
8824
|
|
8825 Event.on(panel.element, 'click', function(ev) {
|
|
8826 Event.stopPropagation(ev);
|
|
8827 });
|
|
8828
|
|
8829 var fireShowEvent = function() {
|
|
8830 panel.bringToTop();
|
|
8831 YAHOO.util.Dom.setStyle(this.element, 'display', 'block');
|
|
8832 this._handleWindowInputs(false);
|
|
8833 };
|
|
8834 panel.showEvent.subscribe(fireShowEvent, this, true);
|
|
8835 panel.hideEvent.subscribe(function() {
|
|
8836 this._handleWindowInputs(true);
|
|
8837 }, this, true);
|
|
8838 panel.renderEvent.subscribe(function() {
|
|
8839 this._renderInsertImageWindow();
|
|
8840 this._renderCreateLinkWindow();
|
|
8841 this.fireEvent('windowRender', { type: 'windowRender', panel: panel });
|
|
8842 this._handleWindowInputs(true);
|
|
8843 }, this, true);
|
|
8844
|
|
8845 if (this.DOMReady) {
|
|
8846 this.get('panel').render();
|
|
8847 } else {
|
|
8848 Event.onDOMReady(function() {
|
|
8849 this.get('panel').render();
|
|
8850 }, this, true);
|
|
8851 }
|
|
8852 return this.get('panel');
|
|
8853 },
|
|
8854 /**
|
|
8855 * @method _handleWindowInputs
|
|
8856 * @param {Boolean} disable The state to set all inputs in all Editor windows to. Defaults to: false.
|
|
8857 * @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.
|
|
8858 */
|
|
8859 _handleWindowInputs: function(disable) {
|
|
8860 if (!Lang.isBoolean(disable)) {
|
|
8861 disable = false;
|
|
8862 }
|
|
8863 var inputs = this.get('panel').element.getElementsByTagName('input');
|
|
8864 for (var i = 0; i < inputs.length; i++) {
|
|
8865 try {
|
|
8866 inputs[i].disabled = disable;
|
|
8867 } catch (e) {}
|
|
8868 }
|
|
8869 },
|
|
8870 /**
|
|
8871 * @method openWindow
|
|
8872 * @param {<a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>} win A <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a> instance
|
|
8873 * @description Opens a new "window/panel"
|
|
8874 */
|
|
8875 openWindow: function(win) {
|
|
8876
|
|
8877 YAHOO.log('openWindow: ' + win.name, 'info', 'Editor');
|
|
8878 var self = this;
|
|
8879 window.setTimeout(function() {
|
|
8880 self.toolbar.set('disabled', true); //Disable the toolbar when an editor window is open..
|
|
8881 }, 10);
|
|
8882 Event.on(document, 'keydown', this._closeWindow, this, true);
|
|
8883
|
|
8884 if (this.currentWindow) {
|
|
8885 this.closeWindow();
|
|
8886 }
|
|
8887
|
|
8888 var xy = Dom.getXY(this.currentElement[0]),
|
|
8889 elXY = Dom.getXY(this.get('iframe').get('element')),
|
|
8890 panel = this.get('panel'),
|
|
8891 newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
|
|
8892 wWidth = (parseInt(win.attrs.width, 10) / 2),
|
|
8893 align = 'center',
|
|
8894 body = null;
|
|
8895
|
|
8896 this.fireEvent('beforeOpenWindow', { type: 'beforeOpenWindow', win: win, panel: panel });
|
|
8897
|
|
8898 var form = panel.editor_form;
|
|
8899
|
|
8900 var wins = this._windows;
|
|
8901 for (var b in wins) {
|
|
8902 if (Lang.hasOwnProperty(wins, b)) {
|
|
8903 if (wins[b] && wins[b].body) {
|
|
8904 if (b == win.name) {
|
|
8905 Dom.setStyle(wins[b].body, 'display', 'block');
|
|
8906 } else {
|
|
8907 Dom.setStyle(wins[b].body, 'display', 'none');
|
|
8908 }
|
|
8909 }
|
|
8910 }
|
|
8911 }
|
|
8912
|
|
8913 if (this._windows[win.name].body) {
|
|
8914 Dom.setStyle(this._windows[win.name].body, 'display', 'block');
|
|
8915 form.appendChild(this._windows[win.name].body);
|
|
8916 } else {
|
|
8917 if (Lang.isObject(win.body)) { //Assume it's a reference
|
|
8918 form.appendChild(win.body);
|
|
8919 } else { //Assume it's a string
|
|
8920 var _tmp = document.createElement('div');
|
|
8921 _tmp.innerHTML = win.body;
|
|
8922 form.appendChild(_tmp);
|
|
8923 }
|
|
8924 }
|
|
8925 panel.editor_header.firstChild.innerHTML = win.header;
|
|
8926 if (win.footer !== null) {
|
|
8927 panel.setFooter(win.footer);
|
|
8928 }
|
|
8929 panel.cfg.setProperty('width', win.attrs.width);
|
|
8930
|
|
8931 this.currentWindow = win;
|
|
8932 this.moveWindow(true);
|
|
8933 panel.show();
|
|
8934 this.fireEvent('afterOpenWindow', { type: 'afterOpenWindow', win: win, panel: panel });
|
|
8935 },
|
|
8936 /**
|
|
8937 * @method moveWindow
|
|
8938 * @param {Boolean} force Boolean to tell it to move but not use any animation (Usually done the first time the window is loaded.)
|
|
8939 * @description Realign the window with the currentElement and reposition the knob above the panel.
|
|
8940 */
|
|
8941 moveWindow: function(force) {
|
|
8942 if (!this.currentWindow) {
|
|
8943 return false;
|
|
8944 }
|
|
8945 var win = this.currentWindow,
|
|
8946 xy = Dom.getXY(this.currentElement[0]),
|
|
8947 elXY = Dom.getXY(this.get('iframe').get('element')),
|
|
8948 panel = this.get('panel'),
|
|
8949 //newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
|
|
8950 newXY = [(xy[0] + elXY[0]), (xy[1] + elXY[1])],
|
|
8951 wWidth = (parseInt(win.attrs.width, 10) / 2),
|
|
8952 align = 'center',
|
|
8953 orgXY = panel.cfg.getProperty('xy') || [0,0],
|
|
8954 _knob = panel.editor_knob,
|
|
8955 xDiff = 0,
|
|
8956 yDiff = 0,
|
|
8957 anim = false;
|
|
8958
|
|
8959
|
|
8960 newXY[0] = ((newXY[0] - wWidth) + 20);
|
|
8961 //Account for the Scroll bars in a scrolled editor window.
|
|
8962 newXY[0] = newXY[0] - Dom.getDocumentScrollLeft(this._getDoc());
|
|
8963 newXY[1] = newXY[1] - Dom.getDocumentScrollTop(this._getDoc());
|
|
8964
|
|
8965 if (this._isElement(this.currentElement[0], 'img')) {
|
|
8966 if (this.currentElement[0].src.indexOf(this.get('blankimage')) != -1) {
|
|
8967 newXY[0] = (newXY[0] + (75 / 2)); //Placeholder size
|
|
8968 newXY[1] = (newXY[1] + 75); //Placeholder sizea
|
|
8969 } else {
|
|
8970 var w = parseInt(this.currentElement[0].width, 10);
|
|
8971 var h = parseInt(this.currentElement[0].height, 10);
|
|
8972 newXY[0] = (newXY[0] + (w / 2));
|
|
8973 newXY[1] = (newXY[1] + h);
|
|
8974 }
|
|
8975 newXY[1] = newXY[1] + 15;
|
|
8976 } else {
|
|
8977 var fs = Dom.getStyle(this.currentElement[0], 'fontSize');
|
|
8978 if (fs && fs.indexOf && fs.indexOf('px') != -1) {
|
|
8979 newXY[1] = newXY[1] + parseInt(Dom.getStyle(this.currentElement[0], 'fontSize'), 10) + 5;
|
|
8980 } else {
|
|
8981 newXY[1] = newXY[1] + 20;
|
|
8982 }
|
|
8983 }
|
|
8984 if (newXY[0] < elXY[0]) {
|
|
8985 newXY[0] = elXY[0] + 5;
|
|
8986 align = 'left';
|
|
8987 }
|
|
8988
|
|
8989 if ((newXY[0] + (wWidth * 2)) > (elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10))) {
|
|
8990 newXY[0] = ((elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10)) - (wWidth * 2) - 5);
|
|
8991 align = 'right';
|
|
8992 }
|
|
8993
|
|
8994 try {
|
|
8995 xDiff = (newXY[0] - orgXY[0]);
|
|
8996 yDiff = (newXY[1] - orgXY[1]);
|
|
8997 } catch (e) {}
|
|
8998
|
|
8999
|
|
9000 var iTop = elXY[1] + parseInt(this.get('height'), 10);
|
|
9001 var iLeft = elXY[0] + parseInt(this.get('width'), 10);
|
|
9002 if (newXY[1] > iTop) {
|
|
9003 newXY[1] = iTop;
|
|
9004 }
|
|
9005 if (newXY[0] > iLeft) {
|
|
9006 newXY[0] = (iLeft / 2);
|
|
9007 }
|
|
9008
|
|
9009 //Convert negative numbers to positive so we can get the difference in distance
|
|
9010 xDiff = ((xDiff < 0) ? (xDiff * -1) : xDiff);
|
|
9011 yDiff = ((yDiff < 0) ? (yDiff * -1) : yDiff);
|
|
9012
|
|
9013 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)
|
|
9014 var _knobLeft = 0,
|
|
9015 elW = 0;
|
|
9016
|
|
9017 if (this.currentElement[0].width) {
|
|
9018 elW = (parseInt(this.currentElement[0].width, 10) / 2);
|
|
9019 }
|
|
9020
|
|
9021 var leftOffset = xy[0] + elXY[0] + elW;
|
|
9022 _knobLeft = leftOffset - newXY[0];
|
|
9023 //Check to see if the knob will go off either side & reposition it
|
|
9024 if (_knobLeft > (parseInt(win.attrs.width, 10) - 1)) {
|
|
9025 _knobLeft = ((parseInt(win.attrs.width, 10) - 30) - 1);
|
|
9026 } else if (_knobLeft < 40) {
|
|
9027 _knobLeft = 1;
|
|
9028 }
|
|
9029 if (isNaN(_knobLeft)) {
|
|
9030 _knobLeft = 1;
|
|
9031 }
|
|
9032 if (force) {
|
|
9033 if (_knob) {
|
|
9034 _knob.style.left = _knobLeft + 'px';
|
|
9035 }
|
|
9036 //Removed Animation from a forced move..
|
|
9037 panel.cfg.setProperty('xy', newXY);
|
|
9038 } else {
|
|
9039 if (this.get('animate')) {
|
|
9040 anim = new YAHOO.util.Anim(panel.element, {}, 0.5, YAHOO.util.Easing.easeOut);
|
|
9041 anim.attributes = {
|
|
9042 top: {
|
|
9043 to: newXY[1]
|
|
9044 },
|
|
9045 left: {
|
|
9046 to: newXY[0]
|
|
9047 }
|
|
9048 };
|
|
9049 anim.onComplete.subscribe(function() {
|
|
9050 panel.cfg.setProperty('xy', newXY);
|
|
9051 });
|
|
9052 //We have to animate the iframe shim at the same time as the panel or we get scrollbar bleed ..
|
|
9053 var iframeAnim = new YAHOO.util.Anim(panel.iframe, anim.attributes, 0.5, YAHOO.util.Easing.easeOut);
|
|
9054
|
|
9055 var _knobAnim = new YAHOO.util.Anim(_knob, {
|
|
9056 left: {
|
|
9057 to: _knobLeft
|
|
9058 }
|
|
9059 }, 0.6, YAHOO.util.Easing.easeOut);
|
|
9060 anim.animate();
|
|
9061 iframeAnim.animate();
|
|
9062 _knobAnim.animate();
|
|
9063 } else {
|
|
9064 _knob.style.left = _knobLeft + 'px';
|
|
9065 panel.cfg.setProperty('xy', newXY);
|
|
9066 }
|
|
9067 }
|
|
9068 }
|
|
9069 },
|
|
9070 /**
|
|
9071 * @private
|
|
9072 * @method _closeWindow
|
|
9073 * @description Close the currently open EditorWindow with the Escape key.
|
|
9074 * @param {Event} ev The keypress Event that we are trapping
|
|
9075 */
|
|
9076 _closeWindow: function(ev) {
|
|
9077 //if ((ev.charCode == 87) && ev.shiftKey && ev.ctrlKey) {
|
|
9078 if (this._checkKey(this._keyMap.CLOSE_WINDOW, ev)) {
|
|
9079 if (this.currentWindow) {
|
|
9080 this.closeWindow();
|
|
9081 }
|
|
9082 }
|
|
9083 },
|
|
9084 /**
|
|
9085 * @method closeWindow
|
|
9086 * @description Close the currently open EditorWindow.
|
|
9087 */
|
|
9088 closeWindow: function(keepOpen) {
|
|
9089 YAHOO.log('closeWindow: ' + this.currentWindow.name, 'info', 'Editor');
|
|
9090 this.fireEvent('window' + this.currentWindow.name + 'Close', { type: 'window' + this.currentWindow.name + 'Close', win: this.currentWindow, el: this.currentElement[0] });
|
|
9091 this.fireEvent('closeWindow', { type: 'closeWindow', win: this.currentWindow });
|
|
9092 this.currentWindow = null;
|
|
9093 this.get('panel').hide();
|
|
9094 this.get('panel').cfg.setProperty('xy', [-900,-900]);
|
|
9095 this.get('panel').syncIframe(); //Needed to move the iframe with the hidden panel
|
|
9096 this.unsubscribeAll('afterExecCommand');
|
|
9097 this.toolbar.set('disabled', false); //enable the toolbar now that the window is closed
|
|
9098 this.toolbar.resetAllButtons();
|
|
9099 this.focus();
|
|
9100 Event.removeListener(document, 'keydown', this._closeWindow);
|
|
9101 },
|
|
9102
|
|
9103 /* {{{ Command Overrides - These commands are only over written when we are using the advanced version */
|
|
9104
|
|
9105 /**
|
|
9106 * @method cmd_undo
|
|
9107 * @description Pulls an item from the Undo stack and updates the Editor
|
|
9108 * @param value Value passed from the execCommand method
|
|
9109 */
|
|
9110 cmd_undo: function(value) {
|
|
9111 if (this._hasUndoLevel()) {
|
|
9112 var c_html = this.getEditorHTML(), html;
|
|
9113 if (!this._undoLevel) {
|
|
9114 this._undoLevel = this._undoCache.length;
|
|
9115 }
|
|
9116 this._undoLevel = (this._undoLevel - 1);
|
|
9117 if (this._undoCache[this._undoLevel]) {
|
|
9118 html = this._getUndo(this._undoLevel);
|
|
9119 if (html != c_html) {
|
|
9120 this.setEditorHTML(html);
|
|
9121 } else {
|
|
9122 this._undoLevel = (this._undoLevel - 1);
|
|
9123 html = this._getUndo(this._undoLevel);
|
|
9124 if (html != c_html) {
|
|
9125 this.setEditorHTML(html);
|
|
9126 }
|
|
9127 }
|
|
9128 } else {
|
|
9129 this._undoLevel = 0;
|
|
9130 this.toolbar.disableButton('undo');
|
|
9131 }
|
|
9132 }
|
|
9133 return [false];
|
|
9134 },
|
|
9135
|
|
9136 /**
|
|
9137 * @method cmd_redo
|
|
9138 * @description Pulls an item from the Undo stack and updates the Editor
|
|
9139 * @param value Value passed from the execCommand method
|
|
9140 */
|
|
9141 cmd_redo: function(value) {
|
|
9142 this._undoLevel = this._undoLevel + 1;
|
|
9143 if (this._undoLevel >= this._undoCache.length) {
|
|
9144 this._undoLevel = this._undoCache.length;
|
|
9145 }
|
|
9146 YAHOO.log(this._undoLevel + ' :: ' + this._undoCache.length, 'warn', 'SimpleEditor');
|
|
9147 if (this._undoCache[this._undoLevel]) {
|
|
9148 var html = this._getUndo(this._undoLevel);
|
|
9149 this.setEditorHTML(html);
|
|
9150 } else {
|
|
9151 this.toolbar.disableButton('redo');
|
|
9152 }
|
|
9153 return [false];
|
|
9154 },
|
|
9155
|
|
9156 /**
|
|
9157 * @method cmd_heading
|
|
9158 * @param value Value passed from the execCommand method
|
|
9159 * @description This is an execCommand override method. It is called from execCommand when the execCommand('heading') is used.
|
|
9160 */
|
|
9161 cmd_heading: function(value) {
|
|
9162 var exec = true,
|
|
9163 el = null,
|
|
9164 action = 'heading',
|
|
9165 _sel = this._getSelection(),
|
|
9166 _selEl = this._getSelectedElement();
|
|
9167
|
|
9168 if (_selEl) {
|
|
9169 _sel = _selEl;
|
|
9170 }
|
|
9171
|
|
9172 if (this.browser.ie) {
|
|
9173 action = 'formatblock';
|
|
9174 }
|
|
9175 if (value == this.STR_NONE) {
|
|
9176 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'))) {
|
|
9177 if (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h') {
|
|
9178 _sel = _sel.parentNode;
|
|
9179 }
|
|
9180 if (this._isElement(_sel, 'html')) {
|
|
9181 return [false];
|
|
9182 }
|
|
9183 el = this._swapEl(_selEl, 'span', function(el) {
|
|
9184 el.className = 'yui-non';
|
|
9185 });
|
|
9186 this._selectNode(el);
|
|
9187 this.currentElement[0] = el;
|
|
9188 }
|
|
9189 exec = false;
|
|
9190 } else {
|
|
9191 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')) {
|
|
9192 el = this._swapEl(_selEl, value);
|
|
9193 this._selectNode(el);
|
|
9194 this.currentElement[0] = el;
|
|
9195 } else {
|
|
9196 this._createCurrentElement(value);
|
|
9197 this._selectNode(this.currentElement[0]);
|
|
9198 }
|
|
9199 exec = false;
|
|
9200 }
|
|
9201 return [exec, action];
|
|
9202 },
|
|
9203 /**
|
|
9204 * @method cmd_hiddenelements
|
|
9205 * @param value Value passed from the execCommand method
|
|
9206 * @description This is an execCommand override method. It is called from execCommand when the execCommand('hiddenelements') is used.
|
|
9207 */
|
|
9208 cmd_hiddenelements: function(value) {
|
|
9209 if (this._showingHiddenElements) {
|
|
9210 //Don't auto highlight the hidden button
|
|
9211 this._lastButton = null;
|
|
9212 YAHOO.log('Enabling hidden CSS File', 'info', 'SimpleEditor');
|
|
9213 this._showingHiddenElements = false;
|
|
9214 this.toolbar.deselectButton('hiddenelements');
|
|
9215 Dom.removeClass(this._getDoc().body, this.CLASS_HIDDEN);
|
|
9216 } else {
|
|
9217 YAHOO.log('Disabling hidden CSS File', 'info', 'SimpleEditor');
|
|
9218 this._showingHiddenElements = true;
|
|
9219 Dom.addClass(this._getDoc().body, this.CLASS_HIDDEN);
|
|
9220 this.toolbar.selectButton('hiddenelements');
|
|
9221 }
|
|
9222 return [false];
|
|
9223 },
|
|
9224 /**
|
|
9225 * @method cmd_removeformat
|
|
9226 * @param value Value passed from the execCommand method
|
|
9227 * @description This is an execCommand override method. It is called from execCommand when the execCommand('removeformat') is used.
|
|
9228 */
|
|
9229 cmd_removeformat: function(value) {
|
|
9230 var exec = true;
|
|
9231 /*
|
|
9232 * @knownissue Remove Format issue
|
|
9233 * @browser Safari 2.x
|
|
9234 * @description There is an issue here with Safari, that it may not always remove the format of the item that is selected.
|
|
9235 * Due to the way that Safari 2.x handles ranges, it is very difficult to determine what the selection holds.
|
|
9236 * So here we are making the best possible guess and acting on it.
|
|
9237 */
|
|
9238 if (this.browser.webkit && !this._getDoc().queryCommandEnabled('removeformat')) {
|
|
9239 var _txt = this._getSelection()+'';
|
|
9240 this._createCurrentElement('span');
|
|
9241 this.currentElement[0].className = 'yui-non';
|
|
9242 this.currentElement[0].innerHTML = _txt;
|
|
9243 for (var i = 1; i < this.currentElement.length; i++) {
|
|
9244 this.currentElement[i].parentNode.removeChild(this.currentElement[i]);
|
|
9245 }
|
|
9246
|
|
9247 exec = false;
|
|
9248 }
|
|
9249 return [exec];
|
|
9250 },
|
|
9251 /**
|
|
9252 * @method cmd_script
|
|
9253 * @param action action passed from the execCommand method
|
|
9254 * @param value Value passed from the execCommand method
|
|
9255 * @description This is a combined execCommand override method. It is called from the cmd_superscript and cmd_subscript methods.
|
|
9256 */
|
|
9257 cmd_script: function(action, value) {
|
|
9258 var exec = true, tag = action.toLowerCase().substring(0, 3),
|
|
9259 _span = null, _selEl = this._getSelectedElement();
|
|
9260
|
|
9261 if (this.browser.webkit) {
|
|
9262 YAHOO.log('Safari dom fun again (' + action + ')..', 'info', 'EditorSafari');
|
|
9263 if (this._isElement(_selEl, tag)) {
|
|
9264 YAHOO.log('we are a child of tag (' + tag + '), reverse process', 'info', 'EditorSafari');
|
|
9265 _span = this._swapEl(this.currentElement[0], 'span', function(el) {
|
|
9266 el.className = 'yui-non';
|
|
9267 });
|
|
9268 this._selectNode(_span);
|
|
9269 } else {
|
|
9270 this._createCurrentElement(tag);
|
|
9271 var _sub = this._swapEl(this.currentElement[0], tag);
|
|
9272 this._selectNode(_sub);
|
|
9273 this.currentElement[0] = _sub;
|
|
9274 }
|
|
9275 exec = false;
|
|
9276 }
|
|
9277 return exec;
|
|
9278 },
|
|
9279 /**
|
|
9280 * @method cmd_superscript
|
|
9281 * @param value Value passed from the execCommand method
|
|
9282 * @description This is an execCommand override method. It is called from execCommand when the execCommand('superscript') is used.
|
|
9283 */
|
|
9284 cmd_superscript: function(value) {
|
|
9285 return [this.cmd_script('superscript', value)];
|
|
9286 },
|
|
9287 /**
|
|
9288 * @method cmd_subscript
|
|
9289 * @param value Value passed from the execCommand method
|
|
9290 * @description This is an execCommand override method. It is called from execCommand when the execCommand('subscript') is used.
|
|
9291 */
|
|
9292 cmd_subscript: function(value) {
|
|
9293 return [this.cmd_script('subscript', value)];
|
|
9294 },
|
|
9295 /**
|
|
9296 * @method cmd_indent
|
|
9297 * @param value Value passed from the execCommand method
|
|
9298 * @description This is an execCommand override method. It is called from execCommand when the execCommand('indent') is used.
|
|
9299 */
|
|
9300 cmd_indent: function(value) {
|
|
9301 var exec = true, selEl = this._getSelectedElement(), _bq = null;
|
|
9302
|
|
9303 //if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
|
|
9304 //if (this.browser.webkit || this.browser.ie) {
|
|
9305 if (this.browser.ie) {
|
|
9306 if (this._isElement(selEl, 'blockquote')) {
|
|
9307 _bq = this._getDoc().createElement('blockquote');
|
|
9308 _bq.innerHTML = selEl.innerHTML;
|
|
9309 selEl.innerHTML = '';
|
|
9310 selEl.appendChild(_bq);
|
|
9311 this._selectNode(_bq);
|
|
9312 } else {
|
|
9313 _bq = this._getDoc().createElement('blockquote');
|
|
9314 var html = this._getRange().htmlText;
|
|
9315 _bq.innerHTML = html;
|
|
9316 this._createCurrentElement('blockquote');
|
|
9317 /*
|
|
9318 for (var i = 0; i < this.currentElement.length; i++) {
|
|
9319 _bq = this._getDoc().createElement('blockquote');
|
|
9320 _bq.innerHTML = this.currentElement[i].innerHTML;
|
|
9321 this.currentElement[i].parentNode.replaceChild(_bq, this.currentElement[i]);
|
|
9322 this.currentElement[i] = _bq;
|
|
9323 }
|
|
9324 */
|
|
9325 this.currentElement[0].parentNode.replaceChild(_bq, this.currentElement[0]);
|
|
9326 this.currentElement[0] = _bq;
|
|
9327 this._selectNode(this.currentElement[0]);
|
|
9328 }
|
|
9329 exec = false;
|
|
9330 } else {
|
|
9331 value = 'blockquote';
|
|
9332 }
|
|
9333 return [exec, 'formatblock', value];
|
|
9334 },
|
|
9335 /**
|
|
9336 * @method cmd_outdent
|
|
9337 * @param value Value passed from the execCommand method
|
|
9338 * @description This is an execCommand override method. It is called from execCommand when the execCommand('outdent') is used.
|
|
9339 */
|
|
9340 cmd_outdent: function(value) {
|
|
9341 var exec = true, selEl = this._getSelectedElement(), _bq = null, _span = null;
|
|
9342 //if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
|
|
9343 if (this.browser.webkit || this.browser.ie) {
|
|
9344 //if (this.browser.ie) {
|
|
9345 selEl = this._getSelectedElement();
|
|
9346 if (this._isElement(selEl, 'blockquote')) {
|
|
9347 var par = selEl.parentNode;
|
|
9348 if (this._isElement(selEl.parentNode, 'blockquote')) {
|
|
9349 par.innerHTML = selEl.innerHTML;
|
|
9350 this._selectNode(par);
|
|
9351 } else {
|
|
9352 _span = this._getDoc().createElement('span');
|
|
9353 _span.innerHTML = selEl.innerHTML;
|
|
9354 YAHOO.util.Dom.addClass(_span, 'yui-non');
|
|
9355 par.replaceChild(_span, selEl);
|
|
9356 this._selectNode(_span);
|
|
9357 }
|
|
9358 } else {
|
|
9359 YAHOO.log('Can not outdent, we are not inside a blockquote', 'warn', 'Editor');
|
|
9360 }
|
|
9361 exec = false;
|
|
9362 } else {
|
|
9363 value = false;
|
|
9364 }
|
|
9365 return [exec, 'outdent', value];
|
|
9366 },
|
|
9367 /**
|
|
9368 * @method cmd_justify
|
|
9369 * @param dir The direction to justify
|
|
9370 * @description This is a factory method for the justify family of commands.
|
|
9371 */
|
|
9372 cmd_justify: function(dir) {
|
|
9373 if (this.browser.ie) {
|
|
9374 if (this._hasSelection()) {
|
|
9375 this._createCurrentElement('span');
|
|
9376 this._swapEl(this.currentElement[0], 'div', function(el) {
|
|
9377 el.style.textAlign = dir;
|
|
9378 });
|
|
9379
|
|
9380 return [false];
|
|
9381 }
|
|
9382 }
|
|
9383 return [true, 'justify' + dir, ''];
|
|
9384 },
|
|
9385 /**
|
|
9386 * @method cmd_justifycenter
|
|
9387 * @param value Value passed from the execCommand method
|
|
9388 * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifycenter') is used.
|
|
9389 */
|
|
9390 cmd_justifycenter: function() {
|
|
9391 return [this.cmd_justify('center')];
|
|
9392 },
|
|
9393 /**
|
|
9394 * @method cmd_justifyleft
|
|
9395 * @param value Value passed from the execCommand method
|
|
9396 * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyleft') is used.
|
|
9397 */
|
|
9398 cmd_justifyleft: function() {
|
|
9399 return [this.cmd_justify('left')];
|
|
9400 },
|
|
9401 /**
|
|
9402 * @method cmd_justifyright
|
|
9403 * @param value Value passed from the execCommand method
|
|
9404 * @description This is an execCommand override method. It is called from execCommand when the execCommand('justifyright') is used.
|
|
9405 */
|
|
9406 cmd_justifyright: function() {
|
|
9407 return [this.cmd_justify('right')];
|
|
9408 },
|
|
9409 /* }}}*/
|
|
9410 /**
|
|
9411 * @method toString
|
|
9412 * @description Returns a string representing the editor.
|
|
9413 * @return {String}
|
|
9414 */
|
|
9415 toString: function() {
|
|
9416 var str = 'Editor';
|
|
9417 if (this.get && this.get('element_cont')) {
|
|
9418 str = 'Editor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
|
|
9419 }
|
|
9420 return str;
|
|
9421 }
|
|
9422 });
|
|
9423 /**
|
|
9424 * @event beforeOpenWindow
|
|
9425 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9426 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9427 * @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.
|
|
9428 * @type YAHOO.util.CustomEvent
|
|
9429 */
|
|
9430 /**
|
|
9431 * @event afterOpenWindow
|
|
9432 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9433 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9434 * @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.
|
|
9435 * @type YAHOO.util.CustomEvent
|
|
9436 */
|
|
9437 /**
|
|
9438 * @event closeWindow
|
|
9439 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9440 * @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.
|
|
9441 * @type YAHOO.util.CustomEvent
|
|
9442 */
|
|
9443 /**
|
|
9444 * @event windowCMDOpen
|
|
9445 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9446 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9447 * @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.
|
|
9448 * @type YAHOO.util.CustomEvent
|
|
9449 */
|
|
9450 /**
|
|
9451 * @event windowCMDClose
|
|
9452 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9453 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9454 * @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.
|
|
9455 * @type YAHOO.util.CustomEvent
|
|
9456 */
|
|
9457 /**
|
|
9458 * @event windowRender
|
|
9459 * @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
|
|
9460 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9461 * @description Event fired when the initial Overlay is rendered. Can be used to manipulate the content of the panel.
|
|
9462 * @type YAHOO.util.CustomEvent
|
|
9463 */
|
|
9464 /**
|
|
9465 * @event windowInsertImageRender
|
|
9466 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9467 * @param {HTMLElement} body The HTML element used as the body of the window..
|
|
9468 * @param {Toolbar} toolbar A reference to the toolbar object used inside this window.
|
|
9469 * @description Event fired when the pre render of the Insert Image window has finished.
|
|
9470 * @type YAHOO.util.CustomEvent
|
|
9471 */
|
|
9472 /**
|
|
9473 * @event windowCreateLinkRender
|
|
9474 * @param {Overlay} panel The Overlay object that is used to create the window.
|
|
9475 * @param {HTMLElement} body The HTML element used as the body of the window..
|
|
9476 * @description Event fired when the pre render of the Create Link window has finished.
|
|
9477 * @type YAHOO.util.CustomEvent
|
|
9478 */
|
|
9479
|
|
9480
|
|
9481
|
|
9482 /**
|
|
9483 * @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.
|
|
9484 * This is what you pass to Editor.openWindow();. These parameters will not take effect until the openWindow() is called in the editor.
|
|
9485 * @class EditorWindow
|
|
9486 * @param {String} name The name of the window.
|
|
9487 * @param {Object} attrs Attributes for the window. Current attributes used are : height and width
|
|
9488 */
|
|
9489 YAHOO.widget.EditorWindow = function(name, attrs) {
|
|
9490 /**
|
|
9491 * @private
|
|
9492 * @property name
|
|
9493 * @description A unique name for the window
|
|
9494 */
|
|
9495 this.name = name.replace(' ', '_');
|
|
9496 /**
|
|
9497 * @private
|
|
9498 * @property attrs
|
|
9499 * @description The window attributes
|
|
9500 */
|
|
9501 this.attrs = attrs;
|
|
9502 };
|
|
9503
|
|
9504 YAHOO.widget.EditorWindow.prototype = {
|
|
9505 /**
|
|
9506 * @private
|
|
9507 * @property header
|
|
9508 * @description Holder for the header of the window, used in Editor.openWindow
|
|
9509 */
|
|
9510 header: null,
|
|
9511 /**
|
|
9512 * @private
|
|
9513 * @property body
|
|
9514 * @description Holder for the body of the window, used in Editor.openWindow
|
|
9515 */
|
|
9516 body: null,
|
|
9517 /**
|
|
9518 * @private
|
|
9519 * @property footer
|
|
9520 * @description Holder for the footer of the window, used in Editor.openWindow
|
|
9521 */
|
|
9522 footer: null,
|
|
9523 /**
|
|
9524 * @method setHeader
|
|
9525 * @description Sets the header for the window.
|
|
9526 * @param {String/HTMLElement} str The string or DOM reference to be used as the windows header.
|
|
9527 */
|
|
9528 setHeader: function(str) {
|
|
9529 this.header = str;
|
|
9530 },
|
|
9531 /**
|
|
9532 * @method setBody
|
|
9533 * @description Sets the body for the window.
|
|
9534 * @param {String/HTMLElement} str The string or DOM reference to be used as the windows body.
|
|
9535 */
|
|
9536 setBody: function(str) {
|
|
9537 this.body = str;
|
|
9538 },
|
|
9539 /**
|
|
9540 * @method setFooter
|
|
9541 * @description Sets the footer for the window.
|
|
9542 * @param {String/HTMLElement} str The string or DOM reference to be used as the windows footer.
|
|
9543 */
|
|
9544 setFooter: function(str) {
|
|
9545 this.footer = str;
|
|
9546 },
|
|
9547 /**
|
|
9548 * @method toString
|
|
9549 * @description Returns a string representing the EditorWindow.
|
|
9550 * @return {String}
|
|
9551 */
|
|
9552 toString: function() {
|
|
9553 return 'Editor Window (' + this.name + ')';
|
|
9554 }
|
|
9555 };
|
|
9556 })();
|
|
9557 YAHOO.register("editor", YAHOO.widget.Editor, {version: "2.8.0r4", build: "2449"});
|