utils.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /**
  2. * Fizzy UI utils v1.0.1
  3. * MIT license
  4. */
  5. /*jshint browser: true, undef: true, unused: true, strict: true */
  6. ( function( window, factory ) {
  7. /*global define: false, module: false, require: false */
  8. 'use strict';
  9. // universal module definition
  10. if ( typeof define == 'function' && define.amd ) {
  11. // AMD
  12. define( [
  13. 'doc-ready/doc-ready',
  14. 'matches-selector/matches-selector'
  15. ], function( docReady, matchesSelector ) {
  16. return factory( window, docReady, matchesSelector );
  17. });
  18. } else if ( typeof exports == 'object' ) {
  19. // CommonJS
  20. module.exports = factory(
  21. window,
  22. require('doc-ready'),
  23. require('desandro-matches-selector')
  24. );
  25. } else {
  26. // browser global
  27. window.fizzyUIUtils = factory(
  28. window,
  29. window.docReady,
  30. window.matchesSelector
  31. );
  32. }
  33. }( window, function factory( window, docReady, matchesSelector ) {
  34. 'use strict';
  35. var utils = {};
  36. // ----- extend ----- //
  37. // extends objects
  38. utils.extend = function( a, b ) {
  39. for ( var prop in b ) {
  40. a[ prop ] = b[ prop ];
  41. }
  42. return a;
  43. };
  44. // ----- modulo ----- //
  45. utils.modulo = function( num, div ) {
  46. return ( ( num % div ) + div ) % div;
  47. };
  48. // ----- isArray ----- //
  49. var objToString = Object.prototype.toString;
  50. utils.isArray = function( obj ) {
  51. return objToString.call( obj ) == '[object Array]';
  52. };
  53. // ----- makeArray ----- //
  54. // turn element or nodeList into an array
  55. utils.makeArray = function( obj ) {
  56. var ary = [];
  57. if ( utils.isArray( obj ) ) {
  58. // use object if already an array
  59. ary = obj;
  60. } else if ( obj && typeof obj.length == 'number' ) {
  61. // convert nodeList to array
  62. for ( var i=0, len = obj.length; i < len; i++ ) {
  63. ary.push( obj[i] );
  64. }
  65. } else {
  66. // array of single index
  67. ary.push( obj );
  68. }
  69. return ary;
  70. };
  71. // ----- indexOf ----- //
  72. // index of helper cause IE8
  73. utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
  74. return ary.indexOf( obj );
  75. } : function( ary, obj ) {
  76. for ( var i=0, len = ary.length; i < len; i++ ) {
  77. if ( ary[i] === obj ) {
  78. return i;
  79. }
  80. }
  81. return -1;
  82. };
  83. // ----- removeFrom ----- //
  84. utils.removeFrom = function( ary, obj ) {
  85. var index = utils.indexOf( ary, obj );
  86. if ( index != -1 ) {
  87. ary.splice( index, 1 );
  88. }
  89. };
  90. // ----- isElement ----- //
  91. // http://stackoverflow.com/a/384380/182183
  92. utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
  93. function isElementDOM2( obj ) {
  94. return obj instanceof HTMLElement;
  95. } :
  96. function isElementQuirky( obj ) {
  97. return obj && typeof obj == 'object' &&
  98. obj.nodeType == 1 && typeof obj.nodeName == 'string';
  99. };
  100. // ----- setText ----- //
  101. utils.setText = ( function() {
  102. var setTextProperty;
  103. function setText( elem, text ) {
  104. // only check setTextProperty once
  105. setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
  106. elem[ setTextProperty ] = text;
  107. }
  108. return setText;
  109. })();
  110. // ----- getParent ----- //
  111. utils.getParent = function( elem, selector ) {
  112. while ( elem != document.body ) {
  113. elem = elem.parentNode;
  114. if ( matchesSelector( elem, selector ) ) {
  115. return elem;
  116. }
  117. }
  118. };
  119. // ----- getQueryElement ----- //
  120. // use element as selector string
  121. utils.getQueryElement = function( elem ) {
  122. if ( typeof elem == 'string' ) {
  123. return document.querySelector( elem );
  124. }
  125. return elem;
  126. };
  127. // ----- handleEvent ----- //
  128. // enable .ontype to trigger from .addEventListener( elem, 'type' )
  129. utils.handleEvent = function( event ) {
  130. var method = 'on' + event.type;
  131. if ( this[ method ] ) {
  132. this[ method ]( event );
  133. }
  134. };
  135. // ----- filterFindElements ----- //
  136. utils.filterFindElements = function( elems, selector ) {
  137. // make array of elems
  138. elems = utils.makeArray( elems );
  139. var ffElems = [];
  140. for ( var i=0, len = elems.length; i < len; i++ ) {
  141. var elem = elems[i];
  142. // check that elem is an actual element
  143. if ( !utils.isElement( elem ) ) {
  144. continue;
  145. }
  146. // filter & find items if we have a selector
  147. if ( selector ) {
  148. // filter siblings
  149. if ( matchesSelector( elem, selector ) ) {
  150. ffElems.push( elem );
  151. }
  152. // find children
  153. var childElems = elem.querySelectorAll( selector );
  154. // concat childElems to filterFound array
  155. for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
  156. ffElems.push( childElems[j] );
  157. }
  158. } else {
  159. ffElems.push( elem );
  160. }
  161. }
  162. return ffElems;
  163. };
  164. // ----- debounceMethod ----- //
  165. utils.debounceMethod = function( _class, methodName, threshold ) {
  166. // original method
  167. var method = _class.prototype[ methodName ];
  168. var timeoutName = methodName + 'Timeout';
  169. _class.prototype[ methodName ] = function() {
  170. var timeout = this[ timeoutName ];
  171. if ( timeout ) {
  172. clearTimeout( timeout );
  173. }
  174. var args = arguments;
  175. var _this = this;
  176. this[ timeoutName ] = setTimeout( function() {
  177. method.apply( _this, args );
  178. delete _this[ timeoutName ];
  179. }, threshold || 100 );
  180. };
  181. };
  182. // ----- htmlInit ----- //
  183. // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
  184. utils.toDashed = function( str ) {
  185. return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
  186. return $1 + '-' + $2;
  187. }).toLowerCase();
  188. };
  189. var console = window.console;
  190. /**
  191. * allow user to initialize classes via .js-namespace class
  192. * htmlInit( Widget, 'widgetName' )
  193. * options are parsed from data-namespace-option attribute
  194. */
  195. utils.htmlInit = function( WidgetClass, namespace ) {
  196. docReady( function() {
  197. var dashedNamespace = utils.toDashed( namespace );
  198. var elems = document.querySelectorAll( '.js-' + dashedNamespace );
  199. var dataAttr = 'data-' + dashedNamespace + '-options';
  200. for ( var i=0, len = elems.length; i < len; i++ ) {
  201. var elem = elems[i];
  202. var attr = elem.getAttribute( dataAttr );
  203. var options;
  204. try {
  205. options = attr && JSON.parse( attr );
  206. } catch ( error ) {
  207. // log error, do not initialize
  208. if ( console ) {
  209. console.error( 'Error parsing ' + dataAttr + ' on ' +
  210. elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
  211. error );
  212. }
  213. continue;
  214. }
  215. // initialize
  216. var instance = new WidgetClass( elem, options );
  217. // make available via $().data('layoutname')
  218. var jQuery = window.jQuery;
  219. if ( jQuery ) {
  220. jQuery.data( elem, namespace, instance );
  221. }
  222. }
  223. });
  224. };
  225. // ----- ----- //
  226. return utils;
  227. }));