SOURCE CODE: Uize.Dom.Basics (view docs)

/*______________
|       ______  |   U I Z E    J A V A S C R I P T    F R A M E W O R K
|     /      /  |   ---------------------------------------------------
|    /    O /   |    MODULE : Uize.Dom.Basics Package
|   /    / /    |
|  /    / /  /| |    ONLINE : http://uize.com
| /____/ /__/_| | COPYRIGHT : (c)2004-2016 UIZE
|          /___ |   LICENSE : Available under MIT License or GNU General Public License
|_______________|             http://uize.com/license.html
*/

/* Module Meta Data
  type: Package
  importance: 9
  codeCompleteness: 100
  docCompleteness: 95
*/

/*?
  Introduction
    The =Uize.Dom.Basics= module provides a very minimal set of methods to ease working with DOM nodes - just the basics that are needed by the =Uize.Widget= class.

    *DEVELOPERS:* `Chris van Rensburg`

    Features
      Node Blob
        Many of the methods in this package can operate on multiple nodes at a time by specifying the nodes using the =nodeBLOB= parameter.

        This parameter may be...

        - a string, being the =id= of one node
        - an object reference to one node
        - a =null= or =undefined= value, which will be ignored
        - an array, whose elements are node blobs
        - an object, whose properties have values that are node blobs

        Effectively, this means that one can specify an arbitrary number of nodes in an arbitrarily complex data structure, combining nested arrays and objects as appropriate to the application.

        EXAMPLE
        .......................................................................
        Uize.Dom.Basics.show (['saveButton','cancelButton','skipButton'],true);
        .......................................................................

        In the above example, the =nodeBLOB= parameter is an array, where each element is a string representing the =id= of a button to show.

        EXAMPLE
        ....................................................................
        var
          topButtons = ['loginLogoutButton','checkoutButton','helpButton'],
          bottomButtons = ['saveButton','cancelButton','skipButton']
        ;
        Uize.Dom.Basics.show ([topButtons,bottomButtons],true);
        ....................................................................

        In a slightly more complex example, the =nodeBLOB= parameter is an array, where each element is itself an array of button node ids.

        If a particular method can accept an =nodeBLOB= parameter, it will be noted in the reference section for that method.
*/

Uize.module ({
  name:'Uize.Dom.Basics',
  required:'Uize.Event.Bus',
  builder:function () {
    'use strict';

    var
      /*** Variables for Scruncher Optimization ***/
        _undefined,
        _null = null,
        _true = true,
        _false = false,
        _typeString = 'string',
        _typeObject = 'object',
        _Uize = Uize,
        _copyInto = _Uize.copyInto,
        _returnFalse = _Uize.returnFalse,

      /*** references to static methods used internally ***/
        _getById,
        _doForAll,
        _isNode,
        _joinIdPrefixAndNodeId,
        _isOnNodeTree,
        _getStyle,
        _setStyle,
        _unwire,

      /*** General Variables ***/
        _isBrowser = typeof navigator != 'undefined',
        _navigator = _isBrowser ? navigator : {userAgent:'',appName:''},
        _userAgent = _navigator.userAgent.toLowerCase (),
        _isIe = _navigator.appName == 'Microsoft Internet Explorer',
        _ieMajorVersion = +(_isIe && (_userAgent.match (/MSIE\s*(\d+)/i) || [0,0]) [1]),
        _isMozilla = _userAgent.indexOf ('gecko') > -1,
        _isOpera = _userAgent.indexOf ('opera') > -1,
        _isMozillaOrOpera = _isMozilla || _isOpera,
        _mousePos = {clientX:0,clientY:0,pageX:0,pageY:0},
        _ActiveXObject = _isIe && ActiveXObject,

      /*** variables for event wiring methods ***/
        _wirings = {},
        _wiringIdsByOwnerId = {},
        _totalWirings = 0,
        _needsWindowEventVehicle = _isIe && _ieMajorVersion < 7,

      /*** variables for display method ***/
        _tableDisplayValuePrefix = 'table-',
        _tableRowDisplayValue = _tableDisplayValuePrefix + 'row',
        _tableCellDisplayValue = _tableDisplayValuePrefix + 'cell',
        _tagSpecificDisplayValues = _copyInto (
          {
            SPAN:'inline',
            THEAD:_tableDisplayValuePrefix + 'header-group',
            TFOOT:_tableDisplayValuePrefix + 'footer-group',
            LI:'list-item'
          },
          _isIe && typeof DOMImplementation == 'undefined'
            /* NOTE:
              IE8 supports all the display values, and also the DOMImplementation object (so we use it for testing for older IE)
            */
            ? _null
            : {
              TABLE:'table',
              TR:_tableRowDisplayValue,
              TH:_tableCellDisplayValue,
              TD:_tableCellDisplayValue,
              TBODY:_tableRowDisplayValue + '-group',
              COLGROUP:_tableDisplayValuePrefix + 'column-group',
              COL:_tableDisplayValuePrefix + 'column',
              CAPTION:_tableDisplayValuePrefix + 'caption'
            }
        ),

      /*** variables for getStyle method ***/
        _trblStylePropertiesMap = {
          borderColor:['border','Color'],
          borderWidth:['border','Width'],
          padding:1,
          margin:1
        },

      /*** variables for injectHtml method ***/
        _ieInnerHtmlReadOnly = {
          TABLE:_true, THEAD:_true, TFOOT:_true, TBODY:_true, TR:_true, COL:_true, COLGRPUP:_true,
          FRAMESET:_true, HEAD:_true, HTML:_true, STYLE:_true, TITLE:_true
        },

      /*** variables for setOpacity method ***/
        _opacityStyleProperty = {}
    ;

    /*** Utility Functions ***/
      function _getElementById (_nodeId) {
        var _result = document.getElementById (_nodeId);
        return (!_isIe || (_result && _result.id == _nodeId)) ? _result : _null;
        /* WORKAROUND:
          stupid issue in IE, where document.getElementById will return a reference to a node that has a name attribute with the specified ID value, if no node has an id with that value
        */
      }

      function _captureMousePos (_event) {
        _mousePos.clientX = _event.clientX;
        _mousePos.clientY = _event.clientY;
        _mousePos.pageX = _event.pageX;
        _mousePos.pageY = _event.pageY;
      }

      function _resolveStringEventName (_eventName) {
        var _VirtualEvent = _Uize.Dom.VirtualEvent;
        return (
          _VirtualEvent && _eventName.charCodeAt (_eventName.length - 1) == 41
            ? _VirtualEvent.resolve (_eventName)
            : _eventName.charCodeAt (0) == 111 && _eventName.charCodeAt (1) == 110
              ? _eventName.slice (2)
              : _eventName
        );
      }

    var _package = _Uize.package ({
      /*** Private Static Properties ***/
        _wirings:_wirings,
        _captureMousePos:_captureMousePos, // NOTE: this is needed for the quarantined mouseover handler

      /*** Public Static Methods ***/
        display:function (_nodeBlob,_mustDisplay) {
          _mustDisplay = _mustDisplay === _undefined || !!_mustDisplay;
          _doForAll (
            _nodeBlob,
            function (_node) {
              _node.style.display = _mustDisplay ? (_tagSpecificDisplayValues [_node.tagName] || 'block') : 'none';
            }
          );
          /*?
            Static Methods
              Uize.Dom.Basics.display
                Displays or hides the specified `node blob`, using the "display" CSS property.

                SYNTAX
                ......................................................
                Uize.Dom.Basics.display (nodeBLOB,mustDisplayANYTYPE);
                ......................................................

                While typically a Boolean, the =mustDisplayANYTYPE= parameter can be of any type and the node(s) will be displayed if it resolves to =true=, and hidden if it resolves to =false= - with the exception of =undefined=, when the node(s) will be displayed (see explanation below).

                VARIATION
                ...................................
                Uize.Dom.Basics.display (nodeBLOB);
                ...................................

                When no =mustDisplayANYTYPE= parameter is specified (or when its value is =undefined=), the node(s) will be displayed.

                NOTES
                - compare to the =Uize.Dom.Basics.show= static method
                - this method can operate on multiple nodes at a time. For more details, see the section on `node blob`
          */
        },

        find:function (_properties) {
          /*** return early if the parameter for find is already resolved to a node or array of nodes ***/
            if (
              typeof _properties != _typeObject || !_properties ||
              typeof _properties.length == 'number' || _isNode (_properties)
            )
              return _properties
            ;

          var
            _document = document,
            _isPrimitive = _Uize.isPrimitive,
            _nodePool = [],
            _unusedProperties = _copyInto ({},_properties),
            _root = 'root' in _unusedProperties ? _getById (_unusedProperties.root) : _document
          ;
          delete _unusedProperties.root;

          /*** narrow down node pool, consuming root, id, name, and tagName tests, where possible ***/
            if (_root) {
              var _tagName = _unusedProperties.tagName;
              if ('id' in _unusedProperties && _isPrimitive (_unusedProperties.id)) {
                /* NOTE: optimization for when id is specified and has a simple value */
                var _node = _getElementById (_unusedProperties.id);
                _node && _nodePool.push (_node);
                delete _unusedProperties.id;
              } else if ('name' in _unusedProperties && _isPrimitive (_unusedProperties.name)) {
                /* NOTE: optimization for when name is specified and has a simple value */
                _nodePool = _document.getElementsByName (_unusedProperties.name);
                delete _unusedProperties.name;
              } else {
                /* NOTE:
                  populate the node pool using getElementsByTagName, with optimization for when tagName is specified and has a simple value
                */
                var _tagNameIsSimplyType = _isPrimitive (_tagName);
                _tagNameIsSimplyType && delete _unusedProperties.tagName;
                _nodePool = _root.getElementsByTagName (_tagName && _tagNameIsSimplyType ? _tagName : '*');
                _root = _null;
              }
              if (_root == _document)
                /* NOTE:
                  By this point, if the root has not been consumed and *is* the document, then eliminate it as a test, since all nodes in the pool will fall under this root.
                */
                _root = _null
              ;
              if (!_tagName || _tagName == '*')
                /* NOTE:
                  By this point, if we weren't able to consume tagName (because we fell into the id case or the name case) and it is the wildcard character (or an empty string or null or undefined), then eliminate it as a test, since it will have no limiting effect (being the wildcard that it is).
                */
                delete _unusedProperties.tagName
              ;
            }

          /*** return early (which I generally hate doing) if node pool is empty, or no unused properties ***/
            var _nodePoolLength = _nodePool.length;
            for (var _firstUnusedPropertyName in _unusedProperties) break;
            if (!_nodePoolLength || (_firstUnusedPropertyName == _undefined && !_root)) return _nodePool;

          /*** test each node in node pool against remaining unused properties (and possible root test) ***/
            var
              _matchingNodes = [],
              _isMatch
            ;
            for (var _nodeNo = -1; ++_nodeNo < _nodePoolLength;) {
              var _node = _nodePool [_nodeNo];
              if (_isMatch = _root ? _isOnNodeTree (_node,_root) : _true) {
                for (var _propertyName in _unusedProperties) {
                  var
                    _nodePropertyValue = _node [_propertyName],
                    _test = _unusedProperties [_propertyName],
                    _isFunction = _Uize.isFunction
                  ;
                  if (
                    !(
                      _isPrimitive (_test)
                        ? _nodePropertyValue == _test
                        : (
                          _test instanceof RegExp
                            ? _test.test (_nodePropertyValue || '')
                            : (_isFunction (_test) ? _test.call (_node,_nodePropertyValue) : _true)
                        )
                    )
                  ) {
                    _isMatch = _false;
                    break;
                  }
                }
              }
              _isMatch && _matchingNodes.push (_node);
            }
            return _matchingNodes;
          /*?
            Static Methods
              Uize.Dom.Basics.find
                Returns an array, representing those nodes within the document that match the specified find expression.

                SYNTAX
                ......................................................
                nodesARRAY = Uize.Dom.Basics.find (findExpressionOBJ);
                ......................................................

                With the exception of a few =Special Qualifiers=, each property of the =findExpressionOBJ= parameter is a property test for potential node matches, where the property's name is the name of a node property to test, and the property's value is the test to perform. The test can be a simple equality test, or it can also be a regular expression or function test.

                In order for a node being tested to be a match for the find, all of the tests must succeed, so there is an implicit logical =and= operation between all the tests specified in the =findExpressionOBJ= parameter, although the individual tests could succeed for multiple values by utilizing the more powerful =Regular Expression Test= and =Function Test= types of tests (described in more detail below).

                Test Types
                  Simple Test
                    In the case of a simple test, the value of the property to be tested will simply be tested for equality against the test value.

                    EXAMPLE
                    .............................................................................
                    var buttonImages = Uize.Dom.Basics.find ({tagName:'IMG',className:'button'});
                    .............................................................................

                    The above example will return an array of all the nodes in the document that are =IMG= tags and that have their =class= attribute set to the value =button=.

                  Regular Expression Test
                    In the case of a regular expression test, the value of the property to be tested will be tested using the specified regular expression.

                    Expanding on the example from the =Simple Test= explanation above, let's say that we didn't want to find *only* those nodes whose =class= attribute was exactly =button=, but rather any image node that contained the class =button= somewhere in its =class= attribute. Then you could use a find expression as follows...

                    EXAMPLE
                    .................................................................................
                    var buttonImages = Uize.Dom.Basics.find ({tagName:'IMG',className:/\bbutton\b/});
                    .................................................................................

                    In the above example, a regular expression is being specified for the =className= test that will test to find the string =button= between word boundaries (sometimes referred to as a whole word match).

                  Function Test
                    In the case of a function test, the value of the property to be tested will be tested using the specified function.

                    The test function should expect to receive the value to be tested as its single parameter, and it should return a value to indicate if the test succeeded. Expanding on the example from the =Regular Expression Test= explanation above, let's say that we also wanted to ensure that the matching nodes had to have an =offsetWidth= value greater than 100 pixels and an =offsetHeight= value greater than 30 pixels. Then you could use a find expression as follows...

                    .....................................................
                    var bigButtonImages = Uize.Dom.Basics.find ({
                      tagName:'IMG',
                      className:/\bbutton\b/,
                      offsetWidth:function (value) {return value > 100},
                      offsetHeight:function (value) {return value > 30}
                    });
                    .....................................................

                Not a CSS Selector
                  The =Uize.Dom.Basics.find= method is a means of finding nodes within a document. The find expression specified is fundamentally not a CSS selector, is not as powerful in a number of ways, but is also somewhat more powerful in a number of ways, and can be used in many cases to accomplish very similar things. For example...

                  CSS SELECTOR
                  ...........................................................
                  div.myCssClassName, span.myCssClassName, img.myCssClassName
                  ...........................................................

                  The effect of the above CSS selector could be accomplished by the following find expression...

                  FIND EXPRESSION
                  ...........................................................
                  {tagName:/^(DIV|SPAN|IMG)$/,className:/\bmyCssClassName\b/}
                  ...........................................................

                  Regular expressions are more powerful in what they can accomplish. So, for example, if we wanted to find all the nodes in the document whose id's started with the prefix =page=, you could use a find expression like...

                  ................................................................
                  var nodesWithPageIdPrefix = Uize.Dom.Basics.find ({id:/^page/});
                  ................................................................

                  Significantly, the =Uize.Dom.Basics.find= method tests the reflected properties of nodes, so one can programmatically select nodes based upon properties that are interesting in the land of JavaScript but that are not accessible to the land of CSS. So, for example, you could find all =div= nodes in the document with the CSS class =scrollableDiv= and that have been scrolled vertically, using the following find expression...

                  ..............................................................
                  var verticallyScrolledScrollableDivs = Uize.Dom.Basics.find ({
                    tagName:'DIV',
                    className:/\bscrollableDiv\b/,
                    scrollTop:function (value) {return value > 0}
                  });
                  ..............................................................

                  So, in essence, the =Uize.Dom.Basics.find= method provides the ability to find nodes in a lightweight implementation and in a reasonably intuitive manner that very deliberately leverages the power of JavaScript for testing values. It is neither a CSS selector evaluator nor an XPath query evaluator, both of which are substantially more complex in the complete scope of their specifications.

                Special Qualifiers
                  The =Uize.Dom.Basics.find= method supports some special qualifiers that can help to narrow down a find, improve performance, and provide other capabilities.

                  root
                    In a number of cases, you might want to find nodes that match a find expression within the limited scope of a specific root node - you don't want to scan all the nodes in the entire document. In such cases, the =root= qualifier lets you specify the root node under which to perform the find. Only nodes that are descendants of the root node will be considered in the find. The root node can be specified by id or reference.

                    EXAMPLE
                    ................................................
                    var myWidgetButtonImageNodes = Uize.Dom.Basics.find ({
                      root:myWidget.getNode (),
                      tagName:'IMG',
                      className:/\bbutton\b/
                    });
                    ................................................

                    In the above example, the =Uize.Dom.Basics.find= method would find only those image nodes that are descendants of the =myWidget= widget's root node and that have the CSS class =button= specified in their =class= attribute. The =root= qualifier is set to a reference to the widget's root node, obtained using the =getNode= instance method of the =Uize.Widget= class (specifying no parameter gets you the root node).

                  self
                    The =self= qualifier lets you specify a test that can be performed on the node, itself, as a whole. This can be useful when you want to provide a test that involves an interaction between multiple properties of the nodes being tested.

                    EXAMPLE
                    .............................................................
                    var thumbnailImages = Uize.Dom.Basics.find ({
                      tagName:'IMG',
                      self:function () {return this.width * this.height < 40000}
                    });
                    .............................................................

                    In the above example, image nodes are being found whose area is less than =40000= square pixels (the area of a 200x200 image).

                    When using the =self= qualifier, it is not meaningful to specify a test type other than a =Function Test=. Also, the function that you specify does not need to declare a parameter in this case - it will not receive a defined value, anyway. Like all function tests, the function that you specify for the test will be called as an instance method on the node being tested, so the =this= keyword will hold a reference to the node inside the scope of your function's implementation. This gives your function full access to the properties and methods of the node for the purpose of performing the test.

                Optimizations
                  The =Uize.Dom.Basics.find= method performs optimizations wherever possible to utilize high performance built-in DOM methods, such as =getElementById=, =getElementsByName=, and =getElementsByTagName=. However, if test values specified for =id=, =name=, or =tagName= are not simple types, then this method will have to iterate in order to perform such tests.

                NOTES
                - in the event that no matches are found, an empty array will be returned
                - when the value of the =findExpressionOBJ= parameter is an array, node reference, or string, then that value will simply be returned as is and no find operation will be performed, making this method convenient to use in classes where either a find expression object or a node or array of nodes may be specified
                - see also the =Uize.Dom.Basics.getById= static method
          */
        },

        getById:_getById = function (_node,_idPrefix,_nodeCache) {
          if (typeof _node != _typeString) return _node;

          var _result = _nodeCache ? _nodeCache [_node] : _undefined;
          if (_result === _undefined) {
            var _nodeIdOrName = _joinIdPrefixAndNodeId (_idPrefix,_node);
            (_result = _getElementById (_nodeIdOrName)) ||
              (
                (_result = document.getElementsByName (_nodeIdOrName)).length < 2 &&
                (_result = _result [0] || _null)
              )
            ;
            if (_nodeCache) _nodeCache [_node] = _result;
          }
          return _result;
          /*?
            Static Methods
              Uize.Dom.Basics.getById
                Returns a reference to the specified node, where the node is specified by its ID or by the value of its =name= attribute.

                SYNTAX
                .................................................
                nodeOBJ = Uize.Dom.Basics.getById (nodeSTRorOBJ);
                .................................................

                If there are multiple nodes with the same value for their =name= attribute, then this method will return an array of node references.

                NOTES
                - in the event that the value of the =nodeSTRorOBJ= parameter is actually a reference to a node, then that value will simply be returned
                - in the event that a node specified by ID does not exist in the DOM, then the value =null= will be returned
                - see also the =Uize.Dom.Basics.find= static method
          */
        },

        getStyle:_getStyle = function (_node,_property) {
          var
            _typeofPropertyIsString = typeof _property == _typeString,
            _value = _typeofPropertyIsString ? '' : {}
          ;
          if (_node = _getById (_node)) {
            if (_typeofPropertyIsString) {
              var
                _opacityInIe = _isIe && _property == 'opacity',
                _documentDefaultView = document.defaultView,
                _computedStyle = _documentDefaultView && _documentDefaultView.getComputedStyle (_node,'')
              ;
              if (_opacityInIe) _property = 'filter';
              if (_computedStyle) {
                if (!(_value = _computedStyle [_property])) {
                  var _trblStylePropertyPrefixSuffix = _trblStylePropertiesMap [_property];
                  if (_trblStylePropertyPrefixSuffix) {
                    var
                      _stylePropertyPrefix = _trblStylePropertyPrefixSuffix [0] || _property,
                      _stylePropertySuffix = _trblStylePropertyPrefixSuffix [1] || '',
                      _top = _computedStyle [_stylePropertyPrefix + 'Top' + _stylePropertySuffix],
                      _right = _computedStyle [_stylePropertyPrefix + 'Right' + _stylePropertySuffix],
                      _bottom = _computedStyle [_stylePropertyPrefix + 'Bottom' + _stylePropertySuffix],
                      _left = _computedStyle [_stylePropertyPrefix + 'Left' + _stylePropertySuffix]
                    ;
                    _value = _top == _right && _right == _bottom && _bottom == _left
                      ? _left
                      : _top + ' ' + _right + ' ' + _bottom + ' ' + _left
                    ;
                  }
                }
              } else {
                var _nodeCurrentStyle = _node.currentStyle;
                _value = _nodeCurrentStyle
                  ? _nodeCurrentStyle.getAttribute (_property)
                  : _node.style [_property]
                ;
              }
              if (_opacityInIe) {
                var _match = (_value || '').match (/alpha\s*\(\s*opacity\s*=([^\)]*)\)/i);
                _value = _match ? _match [1] / 100 : 1;
              }
            } else {
              for (_property in _property)
                _value [_property] = _getStyle (_node,_property)
              ;
            }
          }
          return _value;
          /*?
            Static Methods
              Uize.Dom.Basics.getStyle
                Returns the value of the specified style property (or style properties) for the specified node.

                SYNTAX
                ...........................................................................
                propertyValueSTR = Uize.Dom.Basics.getStyle (nodeSTRorOBJ,propertyNameSTR);
                ...........................................................................

                Style properties for a node that are defined inside style sheets (whether inline or external) rather than in the node's =style= object are not reflected in the =style= property of the node in the DOM. This can be frustrating when trying to run code that may conditionalize based upon the values of certain style properties. This method acts as an abstraction to use the appropriate technique for the given browser to determine the value of a specified style property. In some browsers this may be done using the =getComputedStyle= method, while in other browsers it may be done using the =currentStyle= property.

                VARIATION
                ................................................................................
                stylePropertiesOBJ = Uize.Dom.Basics.getStyle (nodeSTRorOBJ,stylePropertiesOBJ);
                ................................................................................

                In order to get the values for multiple style properties in a single call, a style properties object can be specified using the =stylePropertiesOBJ= parameter. The value for this parameter should be an object, where each key is the name of a style property. The values for the individual properties in this object are not important - you can use any dummy values you like.

                Considerations for the value of the =stylePropertiesOBJ= parameter for the =Uize.Dom.Basics.getStyle= method are consistent with those for the =stylePropertiesOBJ= parameter of the =Uize.Dom.Basics.setStyle= method, and the values should be interchangeable between this pair of methods. Consider the following example...

                EXAMPLE
                ......................................................................................
                var styleProperties = {borderWidth:0,borderColor:0,backgroundColor:0};

                Uize.Dom.Basics.setStyle ('node2',Uize.Dom.Basics.getStyle ('node1',styleProperties));
                Uize.Dom.Basics.setStyle ('node4',Uize.Dom.Basics.getStyle ('node3',styleProperties));
                ......................................................................................

                In the above example, the variable =styleProperties= is defined to specify a set of style properties. The values for the individual properties in this object are not important - we use the dummy values =0=. The two statements that follow copy the values of the =borderWidth=, =borderColor=, and =backgroundColor= style properties from one node to another: in the first statement from the node with the id "node1" to the node with the id "node2", and in the second statement from the node with the id "node3" to the node with the id "node4".

                When provided with a =stylePropertiesOBJ= parameter, the =Uize.Dom.Basics.getStyle= method returns a value that is a style properties object, and this object can then be supplied to the =Uize.Dom.Basics.setStyle= method.

                Handling of Opacity
                  The =Uize.Dom.Basics.getStyle= method deals with the difference between Internet Explorer and browsers that support the CSS standard =opacity= style property.

                  For IE, the proprietary =filter= style property is queried, but as a developer you can specify =opacity= as if it were supported by IE.

                  EXAMPLE 1
                  .................................................................
                  var opacityValue = Uize.Dom.Basics.getStyle ('myNode','opacity');
                  .................................................................

                  EXAMPLE 2
                  .............................................................................................
                  var opacityAndBorderColorObj = Uize.Dom.Basics.getStyle ('myNode',{opacity:1,borderColor:1});
                  .............................................................................................

                NOTES
                - see also the companion =Uize.Dom.Basics.setStyle= static method
          */
        },

        getValue:function (_node) {
          var _value;
          if (_node = _getById (_node)) {
            if (_isNode (_node)) {
              var _nodeTagName = _node.tagName;
              if (_nodeTagName == 'TEXTAREA') {
                _value = _node.value;
              } else if (_nodeTagName == 'INPUT') {
                _value = _node.type == 'checkbox' ? _node.checked : _node.value;
              } else if (_nodeTagName == 'SELECT') {
                if (_node.multiple) {
                  _value = [];
                  _Uize.forEach (
                    _node.options,
                    function (_option) {_option.selected && _value.push (_option.value)}
                  );
                } else {
                  _value = _node.value;
                }
              } else if (_nodeTagName == 'IMG') {
                _value = _node.src;
              } else {
                _value = _node.innerHTML.replace (//gi,'\n').replace (/ /g,' ');
              }
            } else {
              _value = (_Uize.findRecord (_node,{tagName:'INPUT',type:'radio',checked:_true}) || {}).value;
            }
          }
          return _value;
          /*?
            Static Methods
              Uize.Dom.Basics.getValue
                Returns a string or boolean, representing the value of the specified node.

                SYNTAX
                .............................................................
                nodeValueSTRorBOOL = Uize.Dom.Basics.getValue (nodeSTRorOBJ);
                .............................................................

                This method provides a convenient abstraction that makes it easier to change a form's implementation, without having to worry about modifying the JavaScript application logic that gets values from the form's fields. For example, you could change the HTML of a form so that what was once a =select= tag becomes a =radio= button set, and the call to =Uize.Dom.Basics.getValue= could remain unchanged.

                Text Fields
                  For =textarea= tags and =input= tags of type =text= and =hidden=, this method returns the value of the node's =value= property.

                Select Boxes - Single Select
                  For =select= tags in single select mode (i.e. where the =multiple= attribute is absent), this method returns the value of the selected option's =value= property.

                  In the event that no option is selected, this method will return the value =''= (empty array).

                Select Boxes - Multiple Select
                  For =select= tags in multiple select mode (i.e. where the =multiple= attribute is set to the value ='multiple'=), this method returns an array containing the values of the all selected options, in the order in which they appear in the options array.

                  In the event that no options are selected, this method will return an empty array.

                Checkboxes
                  For checkboxes (=input= tags of type =checkbox=), this method returns the value of the node's =checked= property.

                Radio Buttons
                  For radio buttons (=input= tags of type =radio=), this method returns the value of the checked radio button's =value= property. If no radio button in the set is checked, then the value =undefined= is returned.

                Image Tags
                  For =img= tags, this method returns the value of the node's =src= property.

                Other HTML Tags
                  For all other HTML tags, this method returns value of the node's =innerHTML= property, with various characters decoded from HTML entities to reverse the effects of using the =Uize.Dom.Basics.setValue= static method.

                NOTES
                - see the corresponding =Uize.Dom.Basics.setValue= static method
          */
        },

        injectHtml:function (_nodeBlob,_htmlToInject,_mode) {
          if (_htmlToInject != _null) {
            var
              _isInnerReplace, _isOuterReplace, _isInnerTop, _isOuterTop, _isOuterBottom, _isInnerBottom,
              _areNodes =
                _Uize.isList (_htmlToInject) ||
                (_isNode (_htmlToInject) && (_htmlToInject = [_htmlToInject]))
            ;
            (
              (_isInnerReplace = _mode == 'inner replace') ||
              (_isOuterReplace = _mode == 'outer replace') ||
              (_isInnerTop = _mode == 'inner top') ||
              (_isOuterTop = _mode == 'outer top') ||
              (_isOuterBottom = _mode == 'outer bottom') ||
              (_isInnerBottom = _true)
            );
            _areNodes || (_htmlToInject += ''); // coerce to a string value by invoking valueOf method

            _doForAll (
              _nodeBlob,
              function (_node) {
                var _nodeChildNodes = _node.childNodes;
                function _htmlHasScript (_html) {
                  return _html && /