Config
Table of Contents

Namespace

O.Element

The O.Element namespace contains a number of helper functions for dealing with DOM elements.

/*global Element, document */

"use strict";


( function ( NS, undefined ) {


// Vars used to store references to fns so they can call each other.
var create, setStyle, setStyles, setAttributes, appendChildren, getPosition;

Private Property

Element-directProperties

  • Object
  • private

Any names that match keys in this map will be set as direct properties rather than as attributes on the element.

var directProperties = {
 'class': 'className',
 className: 'className',
 defaultValue: 'defaultValue',
 'for': 'htmlFor',
 html: 'innerHTML',
 text: 'textContent',
 unselectable: 'unselectable',
 value: 'value'
};

Private Property

Element-booleanProperties

  • Object
  • private

Any names that match keys in this map will be set as direct properties and have their value converted to a boolean.

var booleanProperties = {
 autofocus: 1,
 checked: 1,
 defaultChecked: 1,
 disabled: 1,
 hidden: 1,
 multiple: 1,
 readOnly: 1,
 required: 1,
 selected: 1
};

Method

Element#get( key )

Get a property or attribute of the element.

Parameters

keyString The name of the property/attribute to get.

Returns

String|Boolean The attribute or property.

Element.prototype.get = function ( key ) {
 var prop = directProperties[ key ];
 return prop ?
   this[ prop ] :
 booleanProperties[ key ] ?
   !!this[ key ] :
   this.getAttribute( key );
};

Method

Element#set( key, value )

Sets a property or attribute on the element.

Parameters

keyString The name of the property/attribute to set.
valueString|Boolean The value to set for that property.

Returns

Element Returns self.

Element.prototype.set = function ( key, value ) {
 var prop = directProperties[ key ],
   child;
 if ( prop ) {
   this[ prop ] = ( value == null ? '' : '' + value );
 } else if ( booleanProperties[ key ] ) {
   this[ key ] = !!value;
 } else if ( key === 'styles' ) {
   setStyles( this, value );
 } else if ( key === 'children' ) {
   while ( child = this.lastChild ) {
     this.removeChild( child );
   }
   appendChildren( this, value );
 } else if ( value == null ) {
   this.removeAttribute( key );
 } else {
   this.setAttribute( key, '' + value );
 }
 return this;
};

Private Property

Element-cssNoPx

  • Object
  • private

Keys for CSS properties that take raw numbers as a value.

var cssNoPx = {
 opacity: 1,
 zIndex: 1
};

Private Property

Element-styleNames

  • Object
  • private

Map of normal CSS names to the name used on the style object.

var styleNames = ( function () {
 var styles = NS.UA.cssProps,
   styleNames = {
     'float': document.body.style.cssFloat !== undefined ?
       'cssFloat' : 'styleFloat'
   },
   property, style;
 for ( property in styles ) {
   style = styles[ property ];
   if ( style ) {
     style = style.camelCase();
     // Stupid MS, don't follow convention.
     if ( style.slice( 0, 2 ) === 'Ms' ) {
       style = 'm' + style.slice( 1 );
     }
     styleNames[ property.camelCase() ] = style;
   }
 }
 return styleNames;
}() );

Private Property

O.Element-doc

  • Document
  • private

A reference to the document object.

var doc = document;

Private Property

O.Element-ieEventModel

  • Boolean
  • private

Does the browser only support the IE event model?

var ieEventModel = !!doc.addEventListener.isFake;

var DOCUMENT_POSITION_CONTAINED_BY = 16; // Node.DOCUMENT_POSITION_CONTAINED_BY;

var view = null;

NS.Element = {

Function

O.Element.forView( view )

Sets the view to which newly created elements should be associated. This is used to associate bindings with a view and to add child views as subviews correctly. This is normally handled automatically by the render method in O.View, however should you need to use it manually it is important to store the previous view (returned by the method) and restore it when you are done creating elements for your view.

Parameters

view(O.View|null) The view to associate new/appended DOM elements with.

Returns

(O.View|null) The previous view DOM elements were associated with.

forView: function ( newView ) {
   var oldView = view;
   view = newView;
   return oldView;
 },

Function

O.Element.create( tag, props, children )

Creates and returns a new element, setting any supplied properties and appending any supplied children. If the browser event system doesn't support capturing (just IE<8), then this will also add an event listener for change and input events to any form elements.

Parameters

tagString The tag name for the new class. You may also specify class names and an id here using CSS syntax (.class, #id). For example to create you could call: O.Element.create('span#id.class1.class2');
propsObject Optional The attributes to add to the element, e.g. Element.create('input', { type: 'text' }); The special attributes 'text' and 'html' allow you to set the textual or html content of the element respectively.
children{(Element|String)[]} Optional An array of child nodes and/or strings of text to append to the element. Text nodes will be created for each string supplied. Null or undefined values will simply be skipped.

Returns

Element The new element.

create: create = function ( tag, props, children ) {
   var i, l, parts, name, el;

   if ( props instanceof Array ) {
     children = props;
     props = null;
   }

   // Parse id/class names out of tag.
   if ( /[#.]/.test( tag ) ) {
     parts = tag.split( /([#.])/ );
     tag = parts[0];
     if ( !props ) { props = {}; }
     for ( i = 1, l = parts.length; i + 1 < l; i += 2 ) {
       name = parts[ i + 1 ];
       if ( parts[i] === '#' ) {
         props.id = name;
       } else {
         props.className = props.className ?
           props.className + ' ' + name : name;
       }
     }
   }

   // Create element, set props and add children
   el = doc.createElement( tag );

   if ( ieEventModel && ( tag === 'input' ||
       tag === 'select' || tag === 'textarea' ) ) {
     el.addEventListener( tag === 'select' ?
       'change' : 'propertychange', NS.ViewEventsController, false );
   }
   if ( props ) {
     setAttributes( el, props );
   }
   if ( children ) {
     appendChildren( el, children );
   }
   return el;
 },

Function

O.Element.setAttributes( el, props )

Sets each attribute in the object on the given element.

Parameters

elElement The element to set the attributes on.
propsObject The attributes to add to the element. e.g. `Element.create('input', { type: 'text' });` The special attributes `'text'` and `'html'` allow you to set the textual or html content of the element respectively.

Returns

Element The element.

setAttributes: setAttributes = function ( el, props ) {
   var prop, value;
   for ( prop in props ) {
     value = props[ prop ];
     if ( value !== undefined ) {
       if ( value instanceof NS.Binding ) {
         value.to( prop, el ).connect();
         if ( view ) { view.registerBinding( value ); }
       } else {
         el.set( prop, value );
       }
     }
   }
   return el;
 },

Function

O.Element.appendChildren( el, children )

Appends an array of children or views to an element

Parameters

elElement The element to append to.
children{(Element|O.View)[]} The children to append.

Returns

Element The element.

appendChildren: appendChildren = function ( el, children ) {
   if ( !( children instanceof Array ) ) { children = [ children ]; }
   var i, l, node;
   for ( i = 0, l = children.length; i < l; i += 1 ) {
     node = children[i];
     if ( node ) {
       if ( node instanceof Array ) {
         appendChildren( el, node );
       }
       else if ( node instanceof NS.View ) {
         view.insertView( node, el );
       } else {
         if ( typeof node !== 'object' ) {
           node = doc.createTextNode( node );
         }
         el.appendChild( node );
       }
     }
   }
   return el;
 },

Function

O.Element.hasClass( el, className )

Determines if an element has a particular class name.

Parameters

elElement The element to test.
classNameString The class name to check.

Returns

Boolean Does the element have the class?

hasClass: function ( el, className ) {
   return el.className.contains( className, ' ' );
 },

Function

O.Element.addClass( el, className )

Adds a class to the element if not already there.

Parameters

elElement The element to add the class to.
classNameString The class name to add.

Returns

O.Element Returns self.

addClass: function ( el, className ){
   var current = el.className;
   if ( !current.contains( className, ' ' ) ) {
     el.className = ( current ? current + ' ' : '' ) + className;
   }
   return this;
 },

Function

O.Element.removeClass( el, className )

Removes a class from the element if present.

Parameters

elElement The element to remove the class from.
classNameString The class name to remove.

Returns

O.Element Returns self.

removeClass: function ( el, className ) {
   var current = el.className,
     index = (' ' + current + ' ' ).indexOf( ' ' + className + ' ' );
   if ( index > -1 ) {
     el.className = current.slice( 0, index && index - 1 ) +
               current.slice( index + className.length );
   }
   return this;
 },

Function

O.Element.setStyle( el, style, value )

Sets a CSS style on the element.

Parameters

elElement The element to set the style on.
styleString The name of the style to set.
value(String|Number) The value to set the style to.

Returns

O.Element Returns self.

setStyle: setStyle = function ( el, style, value ) {
   if ( value !== undefined ) {
     style = style.camelCase();
     style = styleNames[ style ] || style;
     if ( typeof value === 'number' && !cssNoPx[ style ] ) {
       value += 'px';
     }
     // IE will throw an error if you try to set an invalid value for a
     // style.
     try {
       el.style[ style ] = value;
     } catch ( error ) {
       NS.RunLoop.didError({
         name: 'Element#setStyle',
         message: 'Invalid value set',
         details:
           'Style: ' + style +
            '\nValue: ' + value +
            '\nEl id: ' + el.id +
            '\nEl class: ' + el.className
       });
     }
   }
   return this;
 },

Function

O.Element.setStyles( el, styles )

Set a collection of CSS styles on the element.

Parameters

elElement The element to set the style on.
stylesObject A map of styles->values to set.

Returns

O.Element Returns self.

setStyles: setStyles = function ( el, styles ) {
   for ( var prop in styles ) {
     setStyle( el, prop, styles[ prop ] );
   }
   return this;
 },

Function

O.Element.contains( el, potentialChild )

Tests whether one element is a descendent of or is the same node as another element.

Parameters

elElement The element that might be the parent element
potentialChildElement The element to test if it is the same as or a descendent of the parent element.

Returns

Boolean Is the second element equal to or a descendent of the first element?

contains: function ( el, potentialChild ) {
   var relation = el.compareDocumentPosition( potentialChild );
   return !relation || !!( relation & DOCUMENT_POSITION_CONTAINED_BY );
 },

Function

O.Element.nearest( el, test, limit )

Looks for the nearest element which is accepted by the test function or is of the element type given as the test string. The element given is tested first, then its parent, then its parent's parent etc.

Parameters

elElement The element to start searching from.
test(String|Function) If a function, this is called on each successive element until one causes it to return a truthy value. That element is then returned. If it is a string, each element is instead checked to see if its nodeName is the same as this string.
limitElement Optional An element known to be higher in the hierarchy than the desired element. If this is found in the search path, a null result will be immediately be returned.

Returns

(Element|null) The nearest matching element, or null if none matched.

nearest: function ( el, test, limit ) {
   if ( !limit ) { limit = el.ownerDocument.documentElement; }
   if ( typeof test === 'string' ) {
     var nodeName = test.toUpperCase();
     test = function ( el ) {
       return ( el.nodeName === nodeName );
     };
   }
   while ( el && !test( el ) ) {
     if ( !el || el === limit ) {
       return null;
     }
     el = el.parentNode;
   }
   return el;
 },

Function

O.Element.getPosition( el, ancestor )

Find the position of the top left corner of the element in pixels, relative either to the page as a whole or a supplied ancestor of the element.

Parameters

elElement The element to determine the position of.
ancestorElement The top left corner of this element will be treated as co-ordinates (0,0). This must be an ancestor of the given element in the DOM tree.

Returns

Object The offset in pixels of the element relative to the given ancestor or the whole page. Has two properties: { top: Number, left: Number }.

getPosition: getPosition = function ( el, ancestor ) {
   var rect = el.getBoundingClientRect(),
     position = {
       top: rect.top,
       left: rect.left
     };
   if ( ancestor ) {
     rect = getPosition( ancestor );
     if ( ancestor.nodeName === 'BODY' ) {
       // document.documentElement - use of
       // body.scroll(Top|Left) is deprecated.
       ancestor = ancestor.parentNode;
     }
     position.top -= rect.top - ancestor.scrollTop;
     position.left -= rect.left - ancestor.scrollLeft;
   }
   return position;
 }
};

Function

Object.toCSSString( object )

Converts an object into a String of 'key:value' pairs, delimited by ';'. Keys are converted from camel case to hyphenated format and numerical values are converted to strings with a 'px' suffix.

Parameters

objectObject The object of CSS properties.

Returns

String The CSS string.

Object.toCSSString = function ( object ) {
 var result = '',
   key, value;
 for ( key in object ) {
   value = object[ key ];
   if ( value !== undefined ) {
     if ( typeof value === 'number' && !cssNoPx[ key ] ) {
       value += 'px';
     }
     key = key.hyphenate();
     key = NS.UA.cssProps[ key ] || key;
     result += key;
     result += ':';
     result += value;
     result += ';';
   }
 }
 return result;
};

}( O ) );
Animation
Application
Core
DataStore
DOM
DragDrop
Foundation
IO
Localisation
Selection
Parser
TimeZones
Storage
Touch
CollectionViews
UA
ContainerViews
ControlViews
PanelViews
View