utils.js 5.9 KB

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