UNPKG

microbejs

Version:

microbe.js - A modular JS library for DOM manipulation, and more

415 lines (345 loc) 12 kB
/** * Microbe.js * * @author Mouse Braun <mouse@knoblau.ch> * @author Nicolas Brugneaux <nicolas.brugneaux@gmail.com> * * @package Microbe */ var slice = Array.prototype.slice; module.exports = function( Microbe, _type, _version ) { 'use strict'; Microbe.core = { get type() { return _type; }, get isMicrobe() { return true; }, get version() { return _version; } }; Object.defineProperty( Microbe, 'version', { get : function() { return _version; } } ); var trigger, _shortSelector; var selectorRegex = Microbe.prototype.__selectorRegex = /(?:[\s]*\.([\w-_\.]+)|#([\w-_]+)|([^#\.:<][\w-_]*)|(<[\w-_#\.]+>)|:([^#\.<][\w-()_]*))/g; // TODO: Check if we hit the duck /** * ## _build * * Builds and returns the final Microbe * * @param {Array} _elements array of elements * @param {String} _selector selector * * @return _Microbe_ Microbe wrapped elements */ function _build( _elements, self ) { var i = 0, lenI = _elements.length; for ( ; i < lenI; i++ ) { self[ i ] = _elements[ i ]; } self.length = i; return self; } /** * ## _create * * Method creates Microbe from a passed string, and returns it * * @param {String} _el element to create * @param {Object} this reference to pass on to _build * * @return _Microbe_ */ function _create( _el, self ) { var resultsRegex = _el.match( selectorRegex ), _id = '', _tag = '', _class = ''; var i = 0, lenI = resultsRegex.length; for ( ; i < lenI; i++ ) { var trigger = resultsRegex[ i ][ 0 ]; switch ( trigger ) { case '#': _id += resultsRegex[ i ]; break; case '.': _class += resultsRegex[ i ]; break; default: _tag += resultsRegex[ i ]; break; } } if ( typeof _tag === 'string' ) { _el = document.createElement( _tag ); if ( _id ) { _el.id = _id.slice( 1 ); } if ( _class ) { _class = _class.split( '.' ); for ( i = 1, lenI = _class.length; i < lenI; i++ ) { _el.classList.add( _class[ i ] ); } } } return _build( [ _el ], self ); } /** * ## _createHtml * * Method creates a Microbe from an html string, and returns it * * @param {String} _el element to create * @param {Object} this reference to pass on to _build * * @return _Microbe_ */ function _createHtml( _el, self ) { var _ghost = document.createElement( 'div' ); _ghost.innerHTML = _el; _el = slice.call( _ghost.children ); for ( var i = 0, lenI = _el.length; i < lenI; i++ ) { _ghost.removeChild( _el[ i ] ); } return _build( _el, self ); } /** * ## _css4StringReplace * * translates css4 strings * * @param {String} _string pre substitution string * * @return _String_ post substitution string */ function _css4StringReplace( _string ) { if ( _string.indexOf( '>>' ) !== -1 ) { _string = _string.replace( />>/g, ' ' ); } if ( _string.indexOf( '!' ) !== -1 ) { _string = _string.replace( /!/g, ':parent' ); } return _string; } /** * ## _noScopeSimple * * if ther is no scope and there is only a simple selector * * @param {String} _s selector string * @param {Object} self this empty Microbe * * @return _Microbe_ */ function _noScopeSimple( _s, self ) { if ( typeof _s === 'string' && _s.indexOf( ':' ) === -1 && _s.indexOf( '!' ) === -1 && _s.indexOf( ' ' ) === -1 ) { switch ( _s[0] ) { case '#': if ( _s.indexOf( '.' ) === -1 ) { var id = document.getElementById( _s.slice( 1 ) ); return id === null ? _build( [], self ) : _build( [ id ], self ); } break; case '.': if ( _s.indexOf( '#' ) === -1 ) { var clss = _s.slice( 1 ); if ( clss.indexOf( '.' ) === -1 ) { return _build( document.getElementsByClassName( clss ), self ); } else { clss = clss.split( '.' ); var res, _r, _el = document.getElementsByClassName( clss[ 0 ] ); for ( var c = 1, lenC = clss.length; c < lenC; c++ ) { res = slice.call( document.getElementsByClassName( clss[ c ] ) ); for ( var r = 0, lenR = _el.length; r < lenR; r++ ) { _r = _el[ r ]; if ( res.indexOf( _r ) === -1 ) { _el[ r ] = null; } } } return _build( _el, self ).filter( function( _e ){ return _e !== null; } ); } } break; default: if ( _s && _s.indexOf( '[' ) === -1 && _s.indexOf( '<' ) === -1 && _s.indexOf( '#' ) === -1 && _s.indexOf( '.' ) === -1 ) { return _build( document.getElementsByTagName( _s ), self ); } break; } } else if ( typeof _s === 'function' && Microbe && typeof Microbe.ready === 'function' ) { Microbe.ready( _s ); } return false; } /** * ## \_\_init\_\_ * * Constructor. * * Either selects or creates an HTML element and wraps it into a Microbe instance. * * @param {Mixed} _selector HTML selector (Element String Array) * @param {Mixed} _scope scope to look inside (Element String Microbe) * @param {Mixed} _elements elements to fill Microbe with (optional) (Element or Array) * * @example µ() ---> empty * @example µ( '' ) ---> empty * @example µ( [] ) ---> empty * @example µ( 'div#test' ) ---> selection * @example µ( elDiv ) ---> selection * @example µ( [ elDiv1, elDiv2, elDiv3 ] ) ---> selection * @example µ( '&lt;div#test>' ) ---> creation * @example µ( '&lt;div id="test">&lt;/div>' ) ---> creation * * @return _Microbe_ */ var Init = Microbe.core.__init__ = function( _selector, _scope, _elements ) { var res; if ( !_scope ) { res = _noScopeSimple( _selector, this ); if ( res ) { return res; } } if ( typeof _selector === 'string' ) { _selector = _css4StringReplace( _selector ); } if ( typeof _scope === 'string' ) { _scope = _css4StringReplace( _scope ); } _selector = _selector || ''; if ( _scope && _scope.type === _type ) { res = _build( [], this ); var next; for ( var n = 0, lenN = _scope.length; n < lenN; n++ ) { next = new Init( _selector, _scope[ n ] ); for ( var i = 0, lenI = next.length; i < lenI; i++ ) { if ( Array.prototype.indexOf.call( res, next[ i ] ) === -1 ) { res[ res.length ] = next[ i ]; res.length++; } } } return res; } /* * fast tracks element based queries */ var isArr, isHTMLCollection; if ( _selector.nodeType === 1 || ( isArr = Array.isArray( _selector ) || _selector.jquery ) || _selector === window || _selector === document || ( isHTMLCollection = _selector.toString() === '[object HTMLCollection]' ) ) { if ( !isArr && !isHTMLCollection ) { _selector = [ _selector ]; } return _build( _selector, this ); } _scope = _scope === undefined ? document : _scope; if ( _scope !== document ) { if ( typeof _scope === 'string' && typeof _selector === 'string' ) { return this.constructor( _scope ).find( _selector ); } } var scopeNodeType = _scope.nodeType; if ( ( !_selector || typeof _selector !== 'string' ) || ( scopeNodeType !== 1 && scopeNodeType !== 9 ) ) { return _build( [], this ); } var resultsRegex = _selector.match( selectorRegex ); if ( resultsRegex && resultsRegex.length === 1 && resultsRegex[ 0 ][ 0 ] !== ':' ) { trigger = resultsRegex[0][0]; _shortSelector = _selector.slice( 1 ); switch( trigger ) { case '.': // non-document scoped classname search var _classesCount = ( _selector || '' ).slice( 1 ).split( '.' ).length; if ( _classesCount === 1 ) { return _build( _scope.getElementsByClassName( _shortSelector ), this ); } break; case '#': // non-document scoped id search var _id = document.getElementById( _shortSelector ); if ( _scope.ownerDocument && this.contains( _id, _scope ) ) { return _build( [ _id ], this ); } else { return _build( [], this ); } break; case '<': // element creation return _create( _selector.substring( 1, _selector.length - 1 ), this ); default: return _build( _scope.getElementsByTagName( _selector ), this ); } } if ( !( this instanceof Init ) ) { return new Init( _selector, _scope, _elements ); } if ( _selector.indexOf( ':' ) !== -1 && _pseudo ) { return _pseudo( this, _selector, _scope, _build ); } // html creation string if ( _selector.indexOf( '/' ) !== -1 ) { return _createHtml( _selector, this ); } return _build( _scope.querySelectorAll( _selector ), this ); }; Microbe.core.__init__.prototype = Microbe.core; require( './core' )( Microbe ); require( './root' )( Microbe ); require( './pseudo' )( Microbe ); require( './array' )( Microbe ); var _pseudo = Microbe.pseudo; };