1 /*
  2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
  3 For licensing, see LICENSE.html or http://ckeditor.com/license
  4 */
  5
  6 /**
  7  * @fileOverview Defines the {@link CKEDITOR.dom.element} class, which
  8  *		represents a DOM element.
  9  */
 10
 11 /**
 12  * Represents a DOM element.
 13  * @constructor
 14  * @augments CKEDITOR.dom.node
 15  * @param {Object|String} element A native DOM element or the element name for
 16  *		new elements.
 17  * @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
 18  *		the element in case of element creation.
 19  * @example
 20  * // Create a new <span> element.
 21  * var element = new CKEDITOR.dom.element( 'span' );
 22  * @example
 23  * // Create an element based on a native DOM element.
 24  * var element = new CKEDITOR.dom.element( document.getElementById( 'myId' ) );
 25  */
 26 CKEDITOR.dom.element = function( element, ownerDocument )
 27 {
 28 	if ( typeof element == 'string' )
 29 		element = ( ownerDocument ? ownerDocument.$ : document ).createElement( element );
 30
 31 	// Call the base constructor (we must not call CKEDITOR.dom.node).
 32 	CKEDITOR.dom.domObject.call( this, element );
 33 };
 34
 35 // PACKAGER_RENAME( CKEDITOR.dom.element )
 36
 37 /**
 38  * The the {@link CKEDITOR.dom.element} representing and element. If the
 39  * element is a native DOM element, it will be transformed into a valid
 40  * CKEDITOR.dom.element object.
 41  * @returns {CKEDITOR.dom.element} The transformed element.
 42  * @example
 43  * var element = new CKEDITOR.dom.element( 'span' );
 44  * alert( element == <b>CKEDITOR.dom.element.get( element )</b> );  "true"
 45  * @example
 46  * var element = document.getElementById( 'myElement' );
 47  * alert( <b>CKEDITOR.dom.element.get( element )</b>.getName() );  e.g. "p"
 48  */
 49 CKEDITOR.dom.element.get = function( element )
 50 {
 51 	return element && ( element.$ ? element : new CKEDITOR.dom.element( element ) );
 52 };
 53
 54 CKEDITOR.dom.element.prototype = new CKEDITOR.dom.node();
 55
 56 /**
 57  * Creates an instance of the {@link CKEDITOR.dom.element} class based on the
 58  * HTML representation of an element.
 59  * @param {String} html The element HTML. It should define only one element in
 60  *		the "root" level. The "root" element can have child nodes, but not
 61  *		siblings.
 62  * @returns {CKEDITOR.dom.element} The element instance.
 63  * @example
 64  * var element = <b>CKEDITOR.dom.element.createFromHtml( '<strong class="anyclass">My element</strong>' )</b>;
 65  * alert( element.getName() );  // "strong"
 66  */
 67 CKEDITOR.dom.element.createFromHtml = function( html, ownerDocument )
 68 {
 69 	var temp = new CKEDITOR.dom.element( 'div', ownerDocument );
 70 	temp.setHtml( html );
 71
 72 	// When returning the node, remove it from its parent to detach it.
 73 	return temp.getFirst().remove();
 74 };
 75
 76 CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype,
 77 	/** @lends CKEDITOR.dom.element.prototype */
 78 	{
 79 		/**
 80 		 * The node type. This is a constant value set to
 81 		 * {@link CKEDITOR.NODE_ELEMENT}.
 82 		 * @type Number
 83 		 * @example
 84 		 */
 85 		type : CKEDITOR.NODE_ELEMENT,
 86
 87 		/**
 88 		 * Adds a CSS class to the element. It appends the class to the
 89 		 * already existing names.
 90 		 * @param {String} className The name of the class to be added.
 91 		 * @example
 92 		 * var element = new CKEDITOR.dom.element( 'div' );
 93 		 * element.addClass( 'classA' );  // <div class="classA">
 94 		 * element.addClass( 'classB' );  // <div class="classA classB">
 95 		 * element.addClass( 'classA' );  // <div class="classA classB">
 96 		 */
 97 		addClass : function( className )
 98 		{
 99 			var c = this.$.className;
100 			if ( c )
101 			{
102 				var regex = new RegExp( '(?:^|\\s)' + className + '(?:\\s|$)', '' );
103 				if ( !regex.test( c ) )
104 					c += ' ' + className;
105 			}
106 			this.$.className = c || className;
107 		},
108
109 		/**
110 		 * Removes a CSS class name from the elements classes. Other classes
111 		 * remain untouched.
112 		 * @param {String} className The name of the class to remove.
113 		 * @example
114 		 * var element = new CKEDITOR.dom.element( 'div' );
115 		 * element.addClass( 'classA' );  // <div class="classA">
116 		 * element.addClass( 'classB' );  // <div class="classA classB">
117 		 * element.removeClass( 'classA' );  // <div class="classB">
118 		 * element.removeClass( 'classB' );  // <div>
119 		 */
120 		removeClass : function( className )
121 		{
122 			var c = this.$.className;
123 			if ( c )
124 			{
125 				var regex = new RegExp( '(?:^|\\s+)' + className + '(?=\\s|$)', '' );
126 				if ( regex.test( c ) )
127 				{
128 					c = c.replace( regex, '' ).replace( /^\s+/, '' );
129
130 					if ( c )
131 						this.$.className = c;
132 					else
133 						this.removeAttribute( 'class' );
134 				}
135 			}
136 		},
137
138 		/**
139 		 * Append a node as a child of this element.
140 		 * @param {CKEDITOR.dom.node|String} node The node or element name to be
141 		 *		appended.
142 		 * @param {Boolean} [toStart] Indicates that the element is to be
143 		 *		appended at the start.
144 		 * @returns {CKEDITOR.dom.node} The appended node.
145 		 * @example
146 		 * var p = new CKEDITOR.dom.element( 'p' );
147 		 *
148 		 * var strong = new CKEDITOR.dom.element( 'strong' );
149 		 * <b>p.append( strong );</b>
150 		 *
151 		 * var em = <b>p.append( 'em' );</b>
152 		 *
153 		 * // result: "<p><strong></strong><em></em></p>"
154 		 */
155 		append : function( node, toStart )
156 		{
157 			if ( typeof node == 'string' )
158 				node = new CKEDITOR.dom.element( node );
159
160 			if ( toStart )
161 				this.$.insertBefore( node.$, this.$.firstChild );
162 			else
163 				this.$.appendChild( node.$ );
164
165 			return node;
166 		},
167
168 		/**
169 		 * Append text to this element.
170 		 * @param {String} text The text to be appended.
171 		 * @returns {CKEDITOR.dom.node} The appended node.
172 		 * @example
173 		 * var p = new CKEDITOR.dom.element( 'p' );
174 		 * p.appendText( 'This is' );
175 		 * p.appendText( ' some text' );
176 		 *
177 		 * // result: "<p>This is some text</p>"
178 		 */
179 		appendText : function( text )
180 		{
181 			if ( this.$.text != undefined )
182 				this.$.text += text;
183 			else
184 				this.append( new CKEDITOR.dom.text( text ) );
185 		},
186
187 		/**
188 		 * Breaks one of the ancestor element in the element position, moving
189 		 * this element between the broken parts.
190 		 * @param {CKEDITOR.dom.element} parent The anscestor element to get broken.
191 		 * @example
192 		 * // Before breaking:
193 		 * //     <b>This <i>is some<span /> sample</i> test text</b>
194 		 * // If "element" is <span /> and "parent" is <i>:
195 		 * //     <b>This <i>is some</i><span /><i> sample</i> test text</b>
196 		 * element.breakParent( parent );
197 		 * @example
198 		 * // Before breaking:
199 		 * //     <b>This <i>is some<span /> sample</i> test text</b>
200 		 * // If "element" is <span /> and "parent" is <b>:
201 		 * //     <b>This <i>is some</i></b><span /><b><i> sample</i> test text</b>
202 		 * element.breakParent( parent );
203 		 */
204 		breakParent : function( parent )
205 		{
206 			var range = new CKEDITOR.dom.range( this.getDocument() );
207
208 			// We'll be extracting part of this element, so let's use our
209 			// range to get the correct piece.
210 			range.setStartAfter( this );
211 			range.setEndAfter( parent );
212
213 			// Extract it.
214 			var docFrag = range.extractContents();
215
216 			// Move the element outside the broken element.
217 			range.insertNode( this.remove() );
218
219 			// Re-insert the extracted piece after the element.
220 			docFrag.insertAfterNode( this );
221 		},
222
223 		contains :
224 			CKEDITOR.env.ie || CKEDITOR.env.webkit ?
225 				function( node )
226 				{
227 					var $ = this.$;
228
229 					return node.type != CKEDITOR.NODE_ELEMENT ?
230 						$.contains( node.getParent().$ ) :
231 						$ != node.$ && $.contains( node.$ );
232 				}
233 			:
234 				function( node )
235 				{
236 					return !!( this.$.compareDocumentPosition( node.$ ) & 16 );
237 				},
238
239 		/**
240 		 * Moves the selection focus to this element.
241 		 * @example
242 		 * var element = CKEDITOR.document.getById( 'myTextarea' );
243 		 * <b>element.focus()</b>;
244 		 */
245 		focus : function()
246 		{
247 			this.$.focus();
248 		},
249
250 		/**
251 		 * Gets the inner HTML of this element.
252 		 * @returns {String} The inner HTML of this element.
253 		 * @example
254 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b></div>' );
255 		 * alert( <b>p.getHtml()</b> );  // "<b>Example</b>"
256 		 */
257 		getHtml : function()
258 		{
259 			return this.$.innerHTML;
260 		},
261
262 		/**
263 		 * Sets the inner HTML of this element.
264 		 * @param {String} html The HTML to be set for this element.
265 		 * @returns {String} The inserted HTML.
266 		 * @example
267 		 * var p = new CKEDITOR.dom.element( 'p' );
268 		 * <b>p.setHtml( '<b>Inner</b> HTML' );</b>
269 		 *
270 		 * // result: "<p><b>Inner</b> HTML</p>"
271 		 */
272 		setHtml : function( html )
273 		{
274 			return ( this.$.innerHTML = html );
275 		},
276
277 		/**
278 		 * Sets the element contents as plain text.
279 		 * @param {String} text The text to be set.
280 		 * @returns {String} The inserted text.
281 		 * @example
282 		 * var element = new CKEDITOR.dom.element( 'div' );
283 		 * element.setText( 'A > B & C < D' );
284 		 * alert( element.innerHTML );  // "A &gt; B &amp; C &lt; D"
285 		 */
286 		setText : function( text )
287 		{
288 			CKEDITOR.dom.element.prototype.setText = ( this.$.innerText != undefined ) ?
289 				function ( text )
290 				{
291 					return this.$.innerText = text;
292 				} :
293 				function ( text )
294 				{
295 					return this.$.textContent = text;
296 				};
297
298 			return this.setText( text );
299 		},
300
301 		/**
302 		 * Gets the value of an element attribute.
303 		 * @function
304 		 * @param {String} name The attribute name.
305 		 * @returns {String} The attribute value or null if not defined.
306 		 * @example
307 		 * var element = CKEDITOR.dom.element.createFromHtml( '<input type="text" />' );
308 		 * alert( <b>element.getAttribute( 'type' )</b> );  // "text"
309 		 */
310 		getAttribute : (function()
311 		{
312 			var standard = function( name )
313 			{
314 				return this.$.getAttribute( name, 2 );
315 			};
316
317 			if ( CKEDITOR.env.ie )
318 			{
319 				return function( name )
320 				{
321 					switch ( name )
322 					{
323 						case 'class':
324 							name = 'className';
325 							break;
326
327 						case 'tabindex':
328 							var tabIndex = standard.call( this, name );
329
330 							// IE returns tabIndex=0 by default for all
331 							// elements. For those elements,
332 							// getAtrribute( 'tabindex', 2 ) returns 32768
333 							// instead. So, we must make this check to give a
334 							// uniform result among all browsers.
335 							if ( tabIndex !== 0 && this.$.tabIndex === 0 )
336 								tabIndex = null;
337
338 							return tabIndex;
339 							break;
340 					}
341
342 					return standard.call( this, name );
343 				};
344 			}
345 			else
346 				return standard;
347 		})(),
348
349 		getChildren : function()
350 		{
351 			return new CKEDITOR.dom.nodeList( this.$.childNodes );
352 		},
353
354 		/**
355 		 * Gets the current computed value of one of the element CSS style
356 		 * properties.
357 		 * @function
358 		 * @param {String} propertyName The style property name.
359 		 * @returns {String} The property value.
360 		 * @example
361 		 * var element = new CKEDITOR.dom.element( 'span' );
362 		 * alert( <b>element.getComputedStyle( 'display' )</b> );  // "inline"
363 		 */
364 		getComputedStyle :
365 			CKEDITOR.env.ie ?
366 				function( propertyName )
367 				{
368 					return this.$.currentStyle[ CKEDITOR.tools.cssStyleToDomStyle( propertyName ) ];
369 				}
370 			:
371 				function( propertyName )
372 				{
373 					return this.getWindow().$.getComputedStyle( this.$, '' ).getPropertyValue( propertyName );
374 				},
375
376 		/**
377 		 * Gets the DTD entries for this element.
378 		 * @returns {Object} An object containing the list of elements accepted
379 		 *		by this element.
380 		 */
381 		getDtd : function()
382 		{
383 			var dtd = CKEDITOR.dtd[ this.getName() ];
384
385 			this.getDtd = function()
386 			{
387 				return dtd;
388 			};
389
390 			return dtd;
391 		},
392
393 		getElementsByTag : function( tagName )
394 		{
395 			return new CKEDITOR.dom.nodeList( this.$.getElementsByTagName( tagName ) );
396 		},
397
398 		/**
399 		 * Gets the computed tabindex for this element.
400 		 * @function
401 		 * @returns {Number} The tabindex value.
402 		 * @example
403 		 * var element = CKEDITOR.document.getById( 'myDiv' );
404 		 * alert( <b>element.getTabIndex()</b> );  // e.g. "-1"
405 		 */
406 		getTabIndex :
407 			CKEDITOR.env.ie ?
408 				function()
409 				{
410 					var tabIndex = this.$.tabIndex;
411
412 					// IE returns tabIndex=0 by default for all elements. In
413 					// those cases we must check that the element really has
414 					// the tabindex attribute set to zero, or it is one of
415 					// those element that should have zero by default.
416 					if ( tabIndex === 0 && !CKEDITOR.dtd.$tabIndex[ this.getName() ] && parseInt( this.getAttribute( 'tabindex' ), 10 ) !== 0 )
417 						tabIndex = -1;
418
419 						return tabIndex;
420 				}
421 			: CKEDITOR.env.webkit ?
422 				function()
423 				{
424 					var tabIndex = this.$.tabIndex;
425
426 					// Safari returns "undefined" for elements that should not
427 					// have tabindex (like a div). So, we must try to get it
428 					// from the attribute.
429 					// https://bugs.webkit.org/show_bug.cgi?id=20596
430 					if ( tabIndex == undefined )
431 					{
432 						tabIndex = parseInt( this.getAttribute( 'tabindex' ), 10 );
433
434 						// If the element don't have the tabindex attribute,
435 						// then we should return -1.
436 						if ( isNaN( tabIndex ) )
437 							tabIndex = -1;
438 					}
439
440 					return tabIndex;
441 				}
442 			:
443 				function()
444 				{
445 					return this.$.tabIndex;
446 				},
447
448 		/**
449 		 * Gets the text value of this element.
450 		 *
451 		 * Only in IE (which uses innerText), <br> will cause linebreaks,
452 		 * and sucessive whitespaces (including line breaks) will be reduced to
453 		 * a single space. This behavior is ok for us, for now. It may change
454 		 * in the future.
455 		 * @returns {String} The text value.
456 		 * @example
457 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div>Same <i>text</i>.</div>' );
458 		 * alert( <b>element.getText()</b> );  // "Sample text."
459 		 */
460 		getText : function()
461 		{
462 			return this.$.textContent || this.$.innerText;
463 		},
464
465 		/**
466 		 * Gets the window object that contains this element.
467 		 * @returns {CKEDITOR.dom.window} The window object.
468 		 * @example
469 		 */
470 		getWindow : function()
471 		{
472 			return this.getDocument().getWindow();
473 		},
474
475 		/**
476 		 * Gets the value of the "id" attribute of this element.
477 		 * @returns {String} The element id, or null if not available.
478 		 * @example
479 		 * var element = CKEDITOR.dom.element.createFromHtml( '<p id="myId"></p>' );
480 		 * alert( <b>element.getId()</b> );  // "myId"
481 		 */
482 		getId : function()
483 		{
484 			return this.$.id || null;
485 		},
486
487 		/**
488 		 * Gets the value of the "name" attribute of this element.
489 		 * @returns {String} The element name, or null if not available.
490 		 * @example
491 		 * var element = CKEDITOR.dom.element.createFromHtml( '<input name="myName"></input>' );
492 		 * alert( <b>element.getNameAtt()</b> );  // "myName"
493 		 */
494 		getNameAtt : function()
495 		{
496 			return this.$.name || null;
497 		},
498
499 		/**
500 		 * Gets the element name (tag name). The returned name is guaranteed to
501 		 * be always full lowercased.
502 		 * @returns {String} The element name.
503 		 * @example
504 		 * var element = new CKEDITOR.dom.element( 'span' );
505 		 * alert( <b>element.getName()</b> );  // "span"
506 		 */
507 		getName : function()
508 		{
509 			// Cache the lowercased name inside a closure.
510 			var nodeName = this.$.nodeName.toLowerCase();
511
512 			return (
513 			/** @ignore */
514 			this.getName = function()
515 				{
516 					return nodeName;
517 				})();
518 		},
519
520 		/**
521 		 * Gets the value set to this element. This value is usually available
522 		 * for form field elements.
523 		 * @returns {String} The element value.
524 		 */
525 		getValue : function()
526 		{
527 			return this.$.value;
528 		},
529
530 		/**
531 		 * Gets the first child node of this element.
532 		 * @returns {CKEDITOR.dom.node} The first child node or null if not
533 		 *		available.
534 		 * @example
535 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b></div>' );
536 		 * var first = <b>element.getFirst()</b>;
537 		 * alert( first.getName() );  // "b"
538 		 */
539 		getFirst : function()
540 		{
541 			var $ = this.$.firstChild;
542 			return $ ? new CKEDITOR.dom.node( $ ) : null;
543 		},
544
545 		getLast : function()
546 		{
547 			var $ = this.$.lastChild;
548 			return $ ? new CKEDITOR.dom.node( $ ) : null;
549 		},
550
551 		/**
552 		 * Gets the node that follows this element in its parent's child list.
553 		 * @returns {CKEDITOR.dom.node} The next node or null if not
554 		 *		available.
555 		 * @example
556 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b> <i>next</i></div>' );
557 		 * var first = <b>element.getFirst().getNext()</b>;
558 		 * alert( first.getName() );  // "i"
559 		 */
560 		getNext : function()
561 		{
562 			var $ = this.$.nextSibling;
563 			return $ ? new CKEDITOR.dom.node( $ ) : null;
564 		},
565
566 		/**
567 		 * Checks if the element name matches one or more names.
568 		 * @param {String} name[,name[,...]] One or more names to be checked.
569 		 * @returns {Boolean} true if the element name matches any of the names.
570 		 * @example
571 		 * var element = new CKEDITOR.element( 'span' );
572 		 * alert( <b>element.is( 'span' )</b> );  "true"
573 		 * alert( <b>element.is( 'p', 'span' )</b> );  "true"
574 		 * alert( <b>element.is( 'p' )</b> );  "false"
575 		 * alert( <b>element.is( 'p', 'div' )</b> );  "false"
576 		 */
577 		is : function()
578 		{
579 			var name = this.getName();
580 			for ( var i = 0 ; i < arguments.length ; i++ )
581 			{
582 				if ( arguments[ i ] == name )
583 					return true;
584 			}
585 			return false;
586 		},
587
588 		/**
589 		 * Indicates that the element has defined attributes.
590 		 * @returns {Boolean} True if the element has attributes.
591 		 * @example
592 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div title="Test">Example</div>' );
593 		 * alert( <b>element.hasAttributes()</b> );  "true"
594 		 * @example
595 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div>Example</div>' );
596 		 * alert( <b>element.hasAttributes()</b> );  "false"
597 		 */
598 		hasAttributes :
599 			CKEDITOR.env.ie ?
600 				function()
601 				{
602 					var attributes = this.$.attributes;
603
604 					for ( var i = 0 ; i < attributes.length ; i++ )
605 					{
606 						var attribute = attributes[i];
607
608 						switch ( attribute.nodeName )
609 						{
610 							case 'class' :
611 								// IE has a strange bug. If calling removeAttribute('className'),
612 								// the attributes collection will still contain the "class"
613 								// attribute, which will be marked as "specified", even if the
614 								// outerHTML of the element is not displaying the class attribute.
615 								// Note : I was not able to reproduce it outside the editor,
616 								// but I've faced it while working on the TC of #1391.
617 								if ( this.$.className.length > 0 )
618 									return true;
619
620 							// Attributes to be ignored.
621 							case '_cke_expando' :
622 								continue;
623
624 							/*jsl:fallthru*/
625
626 							default :
627 								if ( attribute.specified )
628 									return true;
629 						}
630 					}
631
632 					return false;
633 				}
634 			:
635 				function()
636 				{
637 					return this.$.attributes.length > 0;
638 				},
639
640 		/**
641 		 * Hides this element (display:none).
642 		 * @example
643 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
644 		 * <b>element.hide()</b>;
645 		 */
646 		hide : function()
647 		{
648 			this.setStyle( 'display', 'none' );
649 		},
650
651 		moveChildren : function( target, toStart )
652 		{
653 			var $ = this.$;
654 			target = target.$;
655
656 			if ( $ == target )
657 				return;
658
659 			var child;
660
661 			if ( toStart )
662 			{
663 				while ( (child = $.lastChild) )
664 					target.insertBefore( $.removeChild( child ), target.firstChild );
665 			}
666 			else
667 			{
668 				while ( (child = $.firstChild) )
669 					target.appendChild( $.removeChild( child ) );
670 			}
671 		},
672
673 		/**
674 		 * Shows this element (display it).
675 		 * @example
676 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
677 		 * <b>element.show()</b>;
678 		 */
679 		show : function()
680 		{
681 			this.setStyles(
682 				{
683 					display : '',
684 					visibility : ''
685 				});
686 		},
687
688 		/**
689 		 * Sets the value of an element attribute.
690 		 * @param {String} name The name of the attribute.
691 		 * @param {String} value The value to be set to the attribute.
692 		 * @function
693 		 * @returns {CKEDITOR.dom.element} This element instance.
694 		 * @example
695 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
696 		 * <b>element.setAttribute( 'class', 'myClass' )</b>;
697 		 * <b>element.setAttribute( 'title', 'This is an example' )</b>;
698 		 */
699 		setAttribute : (function()
700 		{
701 			var standard = function( name, value )
702 			{
703 				this.$.setAttribute( name, value );
704 				return this;
705 			};
706
707 			if ( CKEDITOR.env.ie )
708 			{
709 				return function( name, value )
710 				{
711 					if ( name == 'class' )
712 						this.$.className = value;
713 					if ( name == 'style' )
714 						this.$.style.cssText = value;
715 					else
716 						standard.apply( this, arguments );
717 					return this;
718 				};
719 			}
720 			else
721 				return standard;
722 		})(),
723
724 		/**
725 		 * Sets the value of several element attributes.
726 		 * @param {Object} attributesPairs An object containing the names and
727 		 *		values of the attributes.
728 		 * @returns {CKEDITOR.dom.element} This element instance.
729 		 * @example
730 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
731 		 * <b>element.setAttributes({
732 		 *     'class' : 'myClass',
733 		 *     'title' : 'This is an example' })</b>;
734 		 */
735 		setAttributes : function( attributesPairs )
736 		{
737 			for ( var name in attributesPairs )
738 				this.setAttribute( name, attributesPairs[ name ] );
739 			return this;
740 		},
741
742 		/**
743 		 * Sets the element value. This function is usually used with form
744 		 * field element.
745 		 * @param {String} value The element value.
746 		 * @returns {CKEDITOR.dom.element} This element instance.
747 		 */
748 		setValue : function( value )
749 		{
750 			this.$.value = value;
751 			return this;
752 		},
753
754 		/**
755 		 * Removes an attribute from the element.
756 		 * @param {String} name The attribute name.
757 		 * @function
758 		 * @example
759 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div class="classA"></div>' );
760 		 * element.removeAttribute( 'class' );
761 		 */
762 		removeAttribute : (function()
763 		{
764 			var standard = function( name )
765 			{
766 				this.$.removeAttribute( name );
767 			};
768
769 			if ( CKEDITOR.env.ie )
770 			{
771 				return function( name )
772 				{
773 					if ( name == 'class' )
774 						name = 'className';
775 					standard.call( this, name );
776 				};
777 			}
778 			else
779 				return standard;
780 		})(),
781
782 		removeAttributes : function ( attributes )
783 		{
784 			for ( var i = 0 ; i < attributes.length ; i++ )
785 				this.removeAttribute( attributes[ i ] );
786 		},
787
788 		/**
789 		 * Removes a style from the element.
790 		 * @param {String} name The style name.
791 		 * @function
792 		 * @example
793 		 * var element = CKEDITOR.dom.element.createFromHtml( '<div style="display:none"></div>' );
794 		 * element.removeStyle( 'display' );
795 		 */
796 		removeStyle : function( name )
797 		{
798 			this.setStyle( name, '' );
799
800 			if ( !this.$.style.cssText )
801 				this.removeAttribute( 'style' );
802 		},
803
804 		/**
805 		 * Sets the value of an element style.
806 		 * @param {String} name The name of the style. The CSS naming notation
807 		 *		must be used (e.g. "background-color").
808 		 * @param {String} value The value to be set to the style.
809 		 * @returns {CKEDITOR.dom.element} This element instance.
810 		 * @example
811 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
812 		 * <b>element.setStyle( 'background-color', '#ff0000' )</b>;
813 		 * <b>element.setStyle( 'margin-top', '10px' )</b>;
814 		 * <b>element.setStyle( 'float', 'right' )</b>;
815 		 */
816 		setStyle : function( name, value )
817 		{
818 			this.$.style[ CKEDITOR.tools.cssStyleToDomStyle( name ) ] = value;
819 			return this;
820 		},
821
822 		/**
823 		 * Sets the value of several element styles.
824 		 * @param {Object} stylesPairs An object containing the names and
825 		 *		values of the styles.
826 		 * @returns {CKEDITOR.dom.element} This element instance.
827 		 * @example
828 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
829 		 * <b>element.setStyles({
830 		 *     'position' : 'absolute',
831 		 *     'float' : 'right' })</b>;
832 		 */
833 		setStyles : function( stylesPairs )
834 		{
835 			for ( var name in stylesPairs )
836 				this.setStyle( name, stylesPairs[ name ] );
837 			return this;
838 		},
839
840 		/**
841 		 * Sets the opacity of an element.
842 		 * @param {Number} opacity A number within the range [0.0, 1.0].
843 		 * @example
844 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
845 		 * <b>element.setOpacity( 0.75 )</b>;
846 		 */
847 		setOpacity : function( opacity )
848 		{
849 			if ( CKEDITOR.env.ie )
850 			{
851 				opacity = Math.round( opacity * 100 );
852 				this.setStyle( 'filter', opacity >= 100 ? '' : 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + opacity + ')' );
853 			}
854 			else
855 				this.setStyle( 'opacity', opacity );
856 		},
857
858 		/**
859 		 * Makes the element and its children unselectable.
860 		 * @function
861 		 * @example
862 		 * var element = CKEDITOR.dom.element.getById( 'myElement' );
863 		 * element.unselectable();
864 		 */
865 		unselectable :
866 			CKEDITOR.env.gecko ?
867 				function()
868 				{
869 					this.$.style.MozUserSelect = 'none';
870 				}
871 			: CKEDITOR.env.webkit ?
872 				function()
873 				{
874 					this.$.style.KhtmlUserSelect = 'none';
875 				}
876 			:
877 				function()
878 				{
879 					if ( CKEDITOR.env.ie || CKEDITOR.env.opera )
880 					{
881 						var element = this.$,
882 							e,
883 							i = 0;
884
885 						element.unselectable = 'on';
886
887 						while ( ( e = element.all[ i++ ] ) )
888 						{
889 							switch ( e.tagName.toLowerCase() )
890 							{
891 								case 'iframe' :
892 								case 'textarea' :
893 								case 'input' :
894 								case 'select' :
895 									/* Ignore the above tags */
896 									break;
897 								default :
898 									e.unselectable = 'on';
899 							}
900 						}
901 					}
902 				}
903 	});
904