UNPKG

microbejs

Version:

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

1,891 lines (1,622 loc) 57.4 kB
/*! * Microbe JavaScript Library v0.5.2 * http://m.icro.be * * Copyright 2014-2016 Sociomantic Labs and other contributors * Released under the MIT license * http://m.icro.be/license * * Date: Tue May 03 2016 */ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.µ=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ /** * ## Microbe * * Builds the Microbe object * * @author Mouse Braun <mouse@knoblau.ch> * @author Nicolas Brugneaux <nicolas.brugneaux@gmail.com> * * @package Microbe */ /*jshint globalstrict: true*/ 'use strict'; var _type = '[object Microbe]'; var _version = require( './version' ) + '-selectorEngine'; var Microbe = function( selector, scope, elements ) { return new Microbe.core.__init__( selector, scope, elements ); }; require( './selectorEngine/init' )( Microbe, _type, _version ); module.exports = Microbe.core.constructor = Microbe; },{"./selectorEngine/init":4,"./version":7}],2:[function(require,module,exports){ /** * array.js * * methods based on the array prototype * * @author Mouse Braun <mouse@knoblau.ch> * @author Nicolas Brugneaux <nicolas.brugneaux@gmail.com> * @author Avraam Mavridis <avr.mav@gmail.com> * * @package Microbe */ /*jshint globalstrict: true*/ 'use strict'; /** * ## includes * * Determines if an element exists inside the array * * @return {boolean} */ var _includes = function() { var elemToSearch = arguments[0]; var indexToStart = arguments[1] >> 0; var array = Object(this); var len = this.length >> 0; if ( len === 0 ) { return false; } indexToStart = indexToStart >= 0 ? indexToStart : ( indexToStart + len ); indexToStart = indexToStart < 0 ? 0 : indexToStart; while ( indexToStart < len ) { if ( elemToSearch === array[ indexToStart ] || ( array[ indexToStart ] !== array[ indexToStart ] && elemToSearch !== elemToSearch ) ) { return true; } indexToStart++ } return false; } module.exports = function( Microbe ) { Microbe.core.every = Array.prototype.every; Microbe.core.findIndex = Array.prototype.findIndex; Microbe.core.each = Array.prototype.forEach; Microbe.core.forEach = Array.prototype.forEach; Microbe.core.includes = Array.prototype.includes ? Array.prototype.includes : _includes; Microbe.core.indexOf = Array.prototype.indexOf; Microbe.core.lastIndexOf = Array.prototype.lastIndexOf; Microbe.core.map = Array.prototype.map; Microbe.core.pop = Array.prototype.pop; Microbe.core.push = Array.prototype.push; Microbe.core.reverse = Array.prototype.reverse; Microbe.core.shift = Array.prototype.shift; Microbe.core.slice = Array.prototype.slice; Microbe.core.some = Array.prototype.some; Microbe.core.sort = Array.prototype.sort; Microbe.core.unshift = Array.prototype.unshift; /* * needed to be modified slightly to output a microbe */ Microbe.core.splice = function( start, deleteCount ) { return this.constructor( Array.prototype.splice.call( this, start, deleteCount ) ); }; }; },{}],3:[function(require,module,exports){ /** * pseudo.js * * @author Mouse Braun <mouse@knoblau.ch> * @author Nicolas Brugneaux <nicolas.brugneaux@gmail.com> * * @package Microbe */ var _cleanArray = function( _r ){ return !!( _r ); }; module.exports = function( Microbe ) { 'use strict'; /** * ## children * * Gets a microbe of all the given element's children * * @param {String} selector css selector string filter * * @example µ( '.example' ).children(); * @example µ( '.example' ).children( 'div' ); * * @return _Array_ array of microbes (value) */ Microbe.core.children = function( selector ) { var _constructor = this.constructor; var _children = function( _el ) { _el = _constructor( _el.children ); if ( typeof selector === 'string' ) { return _el.filter( selector ); } return _el; }; return this.map( _children ); }; /** * ## childrenFlat * * Gets an microbe of all children of all element's given * * @param {String} selector css selector string filter * * @example µ( '.example' ).childrenFlat(); * @example µ( '.example' ).childrenFlat( 'div' ); * * @return _Microbe_ value array of combined children */ Microbe.core.childrenFlat = function( selector ) { var i = 0, childrenArray = []; var _childrenFlat = function( _el ) { var arr = _el.children; var arrLength = arr.length; for ( var j = 0; j < arrLength; j++ ) { childrenArray[ i ] = arr[ j ]; i++; } }; this.each( _childrenFlat ); var _el = this.constructor( childrenArray ); if ( typeof selector === 'string' ) { return _el.filter( selector ); } return _el; }; /** * ## filter * * Filters the microbe by the given given selector or function. In the case * of a function, the element is passed as this. The inclusion on an element * into the set is based on the return of the function * * @param {Mixed} selector selector or function to filter by * * @example µ( '.example' ).filter( 'div' ); * @example µ( '.example' ).filter( function( _el ){ return _el.tagName === 'div'; } ); * * @return _Microbe_ new microbe containing only the filtered values */ Microbe.core.filter = function( filter ) { var pseudo, filters, self = this, _el, method; if ( this.length === 0 ) { return this; } if ( typeof filter === 'function' ) { var res = []; for ( var i = 0, lenI = this.length; i < lenI; i++ ) { res[ i ] = filter.call( this[ i ], i ) ? this[ i ] : null; } res = res.filter( _cleanArray ); return this.constructor( res ); } else { var _filter = function( _f, _self, i ) { if ( Microbe.pseudo[ _f[ 0 ] ] ) { return Microbe.pseudo[ _f[ 0 ] ]( _self, _f[ 1 ] ); } else { var resArray = [], _selector; _selector = i === 0 ? _f[ 0 ] : ':' + _f[ 0 ]; if ( _selector !== '' ) { if ( _f[ 1 ] !== '' ) { _selector += '(' + _f[ 1 ] + ')'; } for ( var j = 0, lenJ = _self.length; j < lenJ; j++ ) { _el = _self[ j ]; resArray[ j ] = Microbe.matches( _el, _selector ) === true ? _el : null; } resArray = resArray.filter( _cleanArray ); } return new Microbe( resArray ); } }; if ( filter && filter.indexOf( ':' ) !== -1 ) { pseudo = filter.split( ':' ); filters = [ [ pseudo.splice( 0, 1 ).toString(), '' ] ]; var _p, pseudoArray; for ( var h = 0, lenH = pseudo.length; h < lenH; h++ ) { _p = pseudo[ h ]; if ( _p.indexOf( '(' ) !== - 1 ) { _p = _p.split( '(' ); _p[ 1 ] = _p[ 1 ].replace( ')', '' ); } else { _p = [ _p, '' ]; } filters.push( _p ); } } else if ( filter ) { filters = [ [ filter, '' ] ]; } else { return this; } for ( var k = 0, lenK = filters.length; k < lenK; k++ ) { if ( self.length !== 0 ) { if ( filters[ k ][ 0 ] !== '' ) { self = _filter( filters[ k ], self, k ); } } else { return self; } } return self; } }; /** * ## find * * Finds a child element with the given selector inside the scope of the current microbe * * @param {String} selector selector to search for * * @example µ( '.example' ).find( 'div' ); * * @return _Microbe_ new microbe containing only the found children values */ Microbe.core.find = function( _selector ) { var _s = _selector[ 0 ]; if ( _s === ' ' ) { _selector = _selector.trim(); _s = _selector[ 0 ]; } if ( _s === '>' ) { _selector = _selector.slice( 1 ).trim(); return this.childrenFlat().filter( _selector ); } else if ( _s === '~' ) { _selector = _selector.slice( 1 ).trim(); return this.siblingsFlat().filter( _selector ); } else if ( _s === '!' ) { return this.parent(); } else if ( _s === '+' ) { _selector = _selector.slice( 1 ).trim(); var resArray = [], _el, els = this.children(); for ( var i = 0, lenI = els.length; i < lenI; i++ ) { _el = els[ i ][ 0 ]; resArray[ i ] = _el ? _el : null; } resArray.filter( _cleanArray ); return new Microbe( resArray ).filter( _selector ); } else if ( _selector.indexOf( ':' ) !== -1 ) { return this.constructor( _selector, this ); } var _children = new Microbe( _selector ), res = [], r = 0; for ( var j = 0, lenJ = this.length; j < lenJ; j++ ) { for ( var k = 0, lenK = _children.length; k < lenK; k++ ) { if ( Microbe.contains( _children[ k ], this[ j ] ) ) { res[ r ] = _children[ k ]; r++; } } } return this.constructor( res ); }; /** * ## first * * gets the first Element and wraps it in Microbe. * * @example µ( '.example' ).first(); * * @return _Microbe_ new Microbe containing only the first value */ Microbe.core.first = function() { if ( this.length !== 0 ) { return this.constructor( this[ 0 ] ); } return this.constructor( [] ); }; /** * ## last * * Gets the last Element and wraps it in Microbe. * * @example µ( '.example' ).last(); * * @return _Microbe_ new microbe containing only the last value */ Microbe.core.last = function() { var len = this.length; if ( len === 1 ) { return this; } else if ( len !== 0 ) { return this.constructor( this[ len - 1 ] ); } return this.constructor( [] ); }; /** * ## parent * * gets all elements in a microbe's parent nodes * * @example µ( '.example' ).parent(); * * @return _Microbe_ new microbe containing parent elements (index-preserved) */ Microbe.core.parent = function() { var _parent = function( _el ) { return _el.parentNode; }; var i, len, parentArray = new Array( this.length ); for ( i = 0, len = this.length; i < len; i++ ) { parentArray[ i ] = _parent( this[ i ] ); } return this.constructor( parentArray ); }; /** * ## siblings * * Gets an microbe of all of each given element's siblings * * @param {String} selector css selector string filter * * @example µ( '.example' ).siblings();; * @example µ( '.example' ).siblings( 'div' ); * * @return _Array_ array of microbes (value) */ Microbe.core.siblings = function( selector ) { var _constructor = this.constructor; var _siblings = function( _el ) { var res = [], r = 0; var sibling = _el.parentNode.firstElementChild; for ( ; sibling; ) { if ( sibling !== _el ) { res[ r ] = sibling; r++; } sibling = sibling.nextElementSibling; if ( !sibling ) { res = _constructor( res ); if ( typeof selector === 'string' ) { return res.filter( selector ); } return res; } } }; return this.map( _siblings ); }; /** * ## siblingsFlat * * Gets an microbe of all siblings of all element's given. 'next' and 'prev' * passed as direction return only the next or previous siblings of each element * * @param {String} direction direction modifier (optional) * * @example µ( '.example' ).siblingsFlat(); * @example µ( '.example' ).siblingsFlat( 'div' ); * * @return _Microbe_ value array of combined siblings */ Microbe.core.siblingsFlat = function( selector ) { var i = 0, siblingsArray = []; var isSiblingConnector = ( selector === '+' || selector === '~' ); var _siblingsFlat = function( _el ) { var sibling = _el; if ( !isSiblingConnector ) { sibling = _el.parentNode.firstElementChild; } else { sibling = _el.nextElementSibling; } for ( ; sibling; ) { if ( sibling !== _el && siblingsArray.indexOf( sibling ) === -1 ) { siblingsArray[ i ] = sibling; i++; } sibling = sibling.nextElementSibling; if ( !sibling || selector === '+' ) { break; } } }; this.each( _siblingsFlat ); var _el = this.constructor( siblingsArray ); if ( typeof selector === 'string' && !isSiblingConnector ) { return _el.filter( selector ); } return _el; }; /** * ## toString * * Methods returns the type of Microbe. * * @example µ( '.example' ).toString(); * * @return _String_ */ Microbe.core.toString = function() { return this.type; }; }; },{}],4:[function(require,module,exports){ /** * 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; }; },{"./array":2,"./core":3,"./pseudo":5,"./root":6}],5:[function(require,module,exports){ /** * pseudo.js * * @author Mouse Braun <mouse@knoblau.ch> * @author Nicolas Brugneaux <nicolas.brugneaux@gmail.com> * * @package Microbe */ module.exports = function( Microbe ) { 'use strict'; /** * ## _parseNth * * when supplied with a Microbe and a css style n selector (2n1), filters * and returns the result * * @param {Microbe} _el Microbe to be filtered * @param {String} _var number string * @param {Boolean} _last counting from the font or back * * @return _Microbe_ */ var _parseNth = function( _el, _var, _last ) { if ( _var === 'odd' ) { _var = '2n'; } else if ( _var === 'even' ) { _var = '2n1'; } if ( _var.indexOf( 'n' ) === -1 ) { switch ( _last ) { case true: case 'last': return new Microbe( _el[ _el.length - parseInt( _var ) ] ); } return new Microbe( _el[ parseInt( _var ) - 1 ] ); } else { _var = _var.split( 'n' ); var increment = parseInt( _var[0] ) || 1; var offset = parseInt( _var[1] ); var top; if ( _last === true || _last === 'last' ) { top = _el.length - parseInt( _var[1] ); offset = top % increment; } var _e, resArray = []; for ( var i = offset || 0, lenI = top || _el.length; i < lenI; ) { _e = _el[ i ]; if ( _e ) { resArray.push( _e ); } i += increment; } return new Microbe( resArray ); } }; /** * ## pseudo * * an extension to core.__init_ to handle custom pseusoselectors * * @param {Microbe} self half built Microbe * @param {String} selector pseudo-selector string * @param {Object} _scope scope element * @param {Function} _build build function from core * * @return _Microbe_ */ var pseudo = function( self, selector, _scope, _build ) { /** * ## _breakUpSelector * * pushes each selector through the pseudo-selector engine * * @param {Array} _selectors split selectors * * @return _Microbe_ */ function _breakUpSelector( _selectors ) { var next, resArray = []; for ( var i = 0, lenI = _selectors.length; i < lenI; i++ ) { if ( i === 0 ) { resArray = pseudo( self, _selectors[ i ], _scope, _build ); } else { next = pseudo( self, _selectors[ i ], _scope, _build ); for ( var j = 0, lenJ = next.length; j < lenJ; j++ ) { if ( Array.prototype.indexOf.call( resArray, next[ j ] ) === -1 ) { resArray[ resArray.length ] = next[ j ]; resArray.length++; } } } } return resArray; } /** * ## _buildObject * * builds the Microbe ready for return * * @return _Microbe_ */ function _buildObject() { var _pseudo = _parsePseudo( _selector ); var obj = _build( _scope.querySelectorAll( _pseudo[0] ), self ); _pseudo = _pseudo[ 1 ]; var _sel, _var; for ( var h = 0, lenH = _pseudo.length; h < lenH; h++ ) { _sel = _pseudo[ h ].split( '(' ); _var = _sel[ 1 ]; if ( _var ) { _var = _var.slice( 0, _var.length - 1 ); } _sel = _sel[ 0 ]; if ( Microbe.pseudo[ _sel ] ) { obj = Microbe.pseudo[ _sel ]( obj, _var, selector ); } } return obj; } /** * ## _cycleFilters * * filters multiple pseudo-selector selectors * * @param {Array} res array of results to be filtered * * @return _Microbe_ */ function _cycleFilters( res ) { var obj = Microbe.pseudo( self, res[ 0 ], _scope, _build ); var filter, connect = false; for ( var i = 1, lenI = res.length; i < lenI; i++ ) { filter = res[ i ].trim(); if ( filter[ 0 ] === '~' ) { obj = obj.siblingsFlat( '~' ); connect = true; } else if ( filter[ 0 ] === '+' ) { obj = obj.siblingsFlat( '+' ); connect = true; } else if ( connect ) { obj = obj.filter( filter ); connect = false; } else { obj = obj.find( filter ); connect = false; } if ( obj.length === 0 ) { return obj; } } return obj; } /** * ## _parsePseudo * * checks all pseudo-selectors to see if they're custom and * otherwise it reattaches it * * @param {String} _sel selector string * * @return _String_ modified selector */ function _parsePseudo( _sel ) { var _pseudoArray; var _pseudo = _sel.split( ':' ); _sel = _pseudo[ 0 ]; _pseudo.splice( 0, 1 ); for ( var k = 0, lenK = _pseudo.length; k < lenK; k++ ) { _pseudoArray = _pseudo[ k ].split( '(' ); if ( !Microbe.pseudo[ _pseudoArray[ 0 ] ] ) { _sel += ':' + _pseudo[ k ]; _pseudo.splice( k, 1 ); } } return [ _sel, _pseudo ]; } if ( selector.indexOf( ',' ) !== -1 ) { selector = selector.split( /,(?![a-zA-Z0-9-#.,\s]+\))/g ); if ( selector.length > 1 ) { return _breakUpSelector( selector ); } else { selector = selector[ 0 ]; } } var _selector = selector; if ( _selector[ 0 ] === ':' ) { _selector = '*' + _selector; } if ( _selector.trim().indexOf( ' ' ) !== -1 ) { var filterFunction = function( e ){ return e === ' ' ? false : e; }; var res = _selector.split( /((?:[A-Za-z0-9.#*\-_]+)?(?:\:[A-Za-z\-]+(?:\([\s\S]+\))?)?)?( )?/ ); res = res.filter( filterFunction ); if ( res.length > 1 ) { return _cycleFilters( res ); } else { _selector = res[ 0 ]; } } return _buildObject(); }; /** * ## _filteredIteration * * special iterator that dumps all results ito one array * * @param {Microbe} _el elements to cycle through * @param {Function} _cb callback * * @return _Microbe_ filtered microbe */ function _filteredIteration( _el, _cb, _recursive ) { var _r, resArray = [], _f = 0; for ( var i = 0, lenI = _el.length; i < lenI; i++ ) { _r = _cb( _el[ i ], resArray, i ); if ( _r ) { resArray[ _f ] = _r; _f++; } } if ( _recursive ) { return resArray; } return _el.constructor( resArray ); } /** * ## any-link * * match elements that act as the source anchors of hyperlinks * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:any-link' ); * * @return _Microbe_ */ pseudo[ 'any-link' ] = function( _el ) { return _el.filter( 'a' ); }; /** * ## blank * * matches elements that only contain content which consists of whitespace * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:blank' ); * * @return _Microbe_ */ pseudo.blank = function( _el ) { var _blank = function( _e, resArray ) { var _t = _e.textContent; if ( resArray.indexOf( _e ) === -1 ) { if ( /^\s*$/.test( _t || _e.value ) ) { return _e; } } }; return _filteredIteration( _el, _blank ); }; /** * ## column * * filters for columns with a suplied selector * * @param {Microbe} _el Microbe to be filtered * @param {String} _var string to search for * * @example µ( '.example:column' ); * * @return _Microbe_ */ pseudo.column = function( _el, _var ) { return _el.filter( 'col' ).filter( _var ); }; /** * ## contains * * Returns only elements that contain the given text. The supplied text * is compared ignoring case * * @param {Microbe} _el Microbe to be filtered * @param {String} _var string to search for * * @example µ( '.example:contains(moon)' ); * * @return _Microbe_ */ pseudo.contains = function( _el, _var ) { _var = _var.toLowerCase(); var _contains = function( _e ) { var _getText = function( _el ) { return document.all ? _el.innerText : _el.textContent; // ff }; var _elText = _getText( _e ); if ( _elText.toLowerCase().indexOf( _var ) !== -1 ) { return _e; } }; return _filteredIteration( _el, _contains ); }; /** * ## default * * selects all inputs and select boxes that are checked by dafeult * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:default' ); * * @return _Microbe_ */ pseudo.default = function( _el ) { _el = _el.filter( 'input, option' ); var _default = function( _e ) { if ( _e.defaultChecked === true ) { return _e; } }; return _filteredIteration( _el, _default ); }; /** * ## dir * * match elements by its directionality based on the document language * * @param {Microbe} _el Microbe to be filtered * @param {String} _var string to search for * * @example µ( '.example:dir(ltr)' ); * * @return _Microbe_ */ pseudo.dir = function( _el, _var ) { var _dir = function( _e ) { if ( getComputedStyle( _e ).direction === _var ) { return _e; } }; return _filteredIteration( _el, _dir ); }; /** * ## drop * * returns all elements that are drop targets. HTML has a dropzone * attribute which specifies that an element is a drop target. * * @param {Microbe} _el Microbe to be filtered * @param {String} _var trigger string * * @example µ( '.example:drop' ); * * @return _Microbe_ */ pseudo.drop = function( _el, _var ) { _el = _el.filter( '[dropzone]' ); if ( !_var ) { return _el; } else { switch ( _var ) { case 'active': return _el.filter( ':active' ); case 'invalid': return _el.filter(); case 'valid': return _el.filter(); } } }; /** * ## even * * Returns the even indexed elements of a Microbe (starting at 0) * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:even' ); * * @return _Microbe_ */ pseudo.even = function( _el ) { var _even = function( _e, resArray, i ) { if ( ( i + 1 ) % 2 === 0 ) { return _e; } }; return _filteredIteration( _el, _even ); }; /** * ## first * * returns the first element of a Microbe * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:first' ); * * @return _Microbe_ */ pseudo.first = function( _el ) { return _el.first(); }; /** * ## gt * * returns the last {_var} element * * @param {Microbe} _el Microbe to be filtered * @param {String} _var number of elements to return * * @example µ( '.example:gt(4)' ); * * @return _Microbe_ */ pseudo.gt = function( _el, _var ) { return _el.splice( _var, _el.length ); }; /** * ## has * * returns elements that have the passed selector as a child * * @param {Microbe} _el Microbe to be filtered * @param {String} _var selector string * * @example µ( '.example:has(span)' ); * * @return _Microbe_ */ pseudo.has = function( _el, _var ) { var _has = function( _e ) { if ( _e.querySelector( _var ) ) { return _e; } }; return _filteredIteration( _el, _has ); }; /** * ## in-range * * select the elements with a value inside the specified range * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:in-range' ); * * @return _Microbe_ */ pseudo[ 'in-range' ] = function( _el ) { _el = _el.filter( '[max],[min]' ); var _inRange = function( _e ) { var min = _e.getAttribute( 'min' ); var max = _e.getAttribute( 'max' ); var _v = parseInt( _e.value ); if ( _v ) { if ( min && max ) { if ( _v > min && _v < max ) { return _e; } } else if ( min && _v > min || max && _v < max ) { return _e; } } }; return _filteredIteration( _el, _inRange ); }; /** * ## lang * * match the elements based on the document language * * @param {Microbe} _el Microbe to be filtered * @param {String} _var specified language (accepts wildcards as *) * * @example µ( '.example:lang(gb-en)' ); * @example µ( '.example:lang(*-en)' ); * * @return _Microbe_ */ pseudo.lang = function( _el, _var ) { if ( _var ) { _el = _el.filter( '[lang]' ); _var = _var.replace( '*', '' ); var _lang = function( _e ) { if ( _e.getAttribute( 'lang' ).indexOf( _var ) !== -1 ) { return _e; } }; return _filteredIteration( _el, _lang ); } else { return _el.constructor( [] ); } }; /** * ## last * * returns the last element of a Microbe * * @param {Microbe} _el Microbe to be filtered * * @example µ( '.example:last' ); * * @return _Microbe_ */ pseudo.last = function( _el ) { return _el.last(); }; /** * ## local-link * * returns all link tags that go to local links. If specified a depth * filter can be added * * @param {Microbe} _el Microbe to be filtered * @param {String} _var specified depth * * @example µ( '.example:local-link' ); * @example µ( '.example:local-link(2)' ); * * @return _Microbe_ */ pseudo[ 'local-link' ] = function( _el, _var ) { _el = _el.filter( 'a' ); var here = document.location; var _localLink = function( _e ) { var url = _e.href; var urlShort = url.replace( here.protocol + '//', '' ).replace( here.host, '' ); urlShort = urlShort[ 0 ] === '/' ? urlShort.slice( 1 ) : urlShort; var depth = urlShort.split( '/' ).length - 1; if ( !/^https?:\/\//.test( urlShort ) && ( !_var || parseInt( _var ) === depth ) ) { return _e; } }; return _filteredIteration( _el, _localLink ); }; /** * ## lt * * returns the first [_var] elements * * @param {Microbe} _el Microbe to be filtered * @param {String} _var number of elements to return * * @example µ( '.example:lt(2)' ); * * @return _Microbe_ */ pseudo.lt = function( _el, _var ) { return _el.splice( 0, _var ); }; /** * ## matches * * returns elements that match either selector * * @param {Microbe} _el Microbe to be filtered * @param {String} _var selector filter * @param {String} _selector full original selector * * @example µ( '.example:matches(div)' ); * * @return _Microbe_ */ pseudo.matches = function( _el, _var, _selector ) { var _constructor = _el.constructor; var text = ':matches(' + _var + ')'; _var = _var.split( ',' ); _selector = _selector.replace( text, '' ); _selector = _selector === '*' ? '' : _selector; var res = _constructor( _selector + _var[ 0 ].trim() ); for ( var i = 1, lenI = _var.length; i < lenI; i++ ) { res.merge( _constructor( _selector + _var[ i ].trim() ), true ); } return res; }; /** * ## not * * returns all elements that do not match the given selector. As per * CSS4 spec, this accepts complex selectors seperated with a comma * * @param {Microbe} _el Microbe to be filtered * @param {String} _var null selector * @param {String} _recursive an indicator that it is calling itself. defines output * * @example µ( '.example:not(div)' ); * @example µ( '.example:not(div,#an--id)' ); * * @return _Microbe_ */ pseudo.not = function( _el, _var, _selector, _recursive ) { if ( _var.indexOf( ',' ) !== -1 ) { var _constructor = _el.constructor; _var = _var.split( ',' ); for ( var i = 0, lenI = _var.length; i < lenI; i++ ) { _el = this.not( _el, _var[ i ].trim(), _selector, true ); } return _constructor( _el ); } else { var _not = function( _e ) { if ( ! Microbe.matches( _e, _var ) ) { return _e; } }; return _filteredIteration( _el, _not, _recursive ); } }; /** * ## nth-column * * returns the nth column of the current Microbe * * @param {Microbe} _el Microbe to be filtered * @param {String} _var column number(s) return * * @example µ( '.example:nth-column(1)' ); * @example µ( '.example:nth-column(2n1)' ); * @example µ( '.example:nth-column(even)' ); * @example µ( '.example:nth-column(odd)' ); * * @return _Microbe_ */ pseudo[ 'nth-column' ] = function( _el, _var ) { _el = _el.filter( 'col' ); return _parseNth( _el, _var ); }; /** * ## nth-last-column * * returns the nth column of the current Microbe starting from the back * * @param {Microbe} _el Microbe to be filtered * @param {String} _var column number(s) return * * @example µ( '.example:nth-last-column(1)' ); * @example µ( '.example:nth-last-column(2n1)' ); * @example µ( '.example:nth-last-column(even)' ); * @example µ( '.example:nth-last-column(odd)' ); * * @return _Microbe_ */ pseudo[ 'nth-last-column' ] = function( _el, _var ) { _el = _el.filter( 'col' ); return _parseNth( _el, _var, true ); }; /** * ## nth-last-match * * returns the nth match(es) of the current Microbe starting from the back * * @param {Microbe} _el Microbe to be filtered * @param {String} _var match number(s) return * * @example µ( '.example:nth-last-match(1)' ); * @example µ( '.example:nth-last-match(2n1)' ); * @example µ( '.example:nth-last-match(even)' ); * @example µ( '.example:nth-last-match(odd)' ); * * @return _M