masonry.pkgd.js 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187
  1. /*!
  2. * Masonry PACKAGED v3.3.2
  3. * Cascading grid layout library
  4. * http://masonry.desandro.com
  5. * MIT License
  6. * by David DeSandro
  7. */
  8. /**
  9. * Bridget makes jQuery widgets
  10. * v1.1.0
  11. * MIT license
  12. */
  13. ( function( window ) {
  14. // -------------------------- utils -------------------------- //
  15. var slice = Array.prototype.slice;
  16. function noop() {}
  17. // -------------------------- definition -------------------------- //
  18. function defineBridget( $ ) {
  19. // bail if no jQuery
  20. if ( !$ ) {
  21. return;
  22. }
  23. // -------------------------- addOptionMethod -------------------------- //
  24. /**
  25. * adds option method -> $().plugin('option', {...})
  26. * @param {Function} PluginClass - constructor class
  27. */
  28. function addOptionMethod( PluginClass ) {
  29. // don't overwrite original option method
  30. if ( PluginClass.prototype.option ) {
  31. return;
  32. }
  33. // option setter
  34. PluginClass.prototype.option = function( opts ) {
  35. // bail out if not an object
  36. if ( !$.isPlainObject( opts ) ){
  37. return;
  38. }
  39. this.options = $.extend( true, this.options, opts );
  40. };
  41. }
  42. // -------------------------- plugin bridge -------------------------- //
  43. // helper function for logging errors
  44. // $.error breaks jQuery chaining
  45. var logError = typeof console === 'undefined' ? noop :
  46. function( message ) {
  47. console.error( message );
  48. };
  49. /**
  50. * jQuery plugin bridge, access methods like $elem.plugin('method')
  51. * @param {String} namespace - plugin name
  52. * @param {Function} PluginClass - constructor class
  53. */
  54. function bridge( namespace, PluginClass ) {
  55. // add to jQuery fn namespace
  56. $.fn[ namespace ] = function( options ) {
  57. if ( typeof options === 'string' ) {
  58. // call plugin method when first argument is a string
  59. // get arguments for method
  60. var args = slice.call( arguments, 1 );
  61. for ( var i=0, len = this.length; i < len; i++ ) {
  62. var elem = this[i];
  63. var instance = $.data( elem, namespace );
  64. if ( !instance ) {
  65. logError( "cannot call methods on " + namespace + " prior to initialization; " +
  66. "attempted to call '" + options + "'" );
  67. continue;
  68. }
  69. if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
  70. logError( "no such method '" + options + "' for " + namespace + " instance" );
  71. continue;
  72. }
  73. // trigger method with arguments
  74. var returnValue = instance[ options ].apply( instance, args );
  75. // break look and return first value if provided
  76. if ( returnValue !== undefined ) {
  77. return returnValue;
  78. }
  79. }
  80. // return this if no return value
  81. return this;
  82. } else {
  83. return this.each( function() {
  84. var instance = $.data( this, namespace );
  85. if ( instance ) {
  86. // apply options & init
  87. instance.option( options );
  88. instance._init();
  89. } else {
  90. // initialize new instance
  91. instance = new PluginClass( this, options );
  92. $.data( this, namespace, instance );
  93. }
  94. });
  95. }
  96. };
  97. }
  98. // -------------------------- bridget -------------------------- //
  99. /**
  100. * converts a Prototypical class into a proper jQuery plugin
  101. * the class must have a ._init method
  102. * @param {String} namespace - plugin name, used in $().pluginName
  103. * @param {Function} PluginClass - constructor class
  104. */
  105. $.bridget = function( namespace, PluginClass ) {
  106. addOptionMethod( PluginClass );
  107. bridge( namespace, PluginClass );
  108. };
  109. return $.bridget;
  110. }
  111. // transport
  112. if ( typeof define === 'function' && define.amd ) {
  113. // AMD
  114. define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
  115. } else if ( typeof exports === 'object' ) {
  116. defineBridget( require('jquery') );
  117. } else {
  118. // get jquery from browser global
  119. defineBridget( window.jQuery );
  120. }
  121. })( window );
  122. /*!
  123. * eventie v1.0.6
  124. * event binding helper
  125. * eventie.bind( elem, 'click', myFn )
  126. * eventie.unbind( elem, 'click', myFn )
  127. * MIT license
  128. */
  129. /*jshint browser: true, undef: true, unused: true */
  130. /*global define: false, module: false */
  131. ( function( window ) {
  132. var docElem = document.documentElement;
  133. var bind = function() {};
  134. function getIEEvent( obj ) {
  135. var event = window.event;
  136. // add event.target
  137. event.target = event.target || event.srcElement || obj;
  138. return event;
  139. }
  140. if ( docElem.addEventListener ) {
  141. bind = function( obj, type, fn ) {
  142. obj.addEventListener( type, fn, false );
  143. };
  144. } else if ( docElem.attachEvent ) {
  145. bind = function( obj, type, fn ) {
  146. obj[ type + fn ] = fn.handleEvent ?
  147. function() {
  148. var event = getIEEvent( obj );
  149. fn.handleEvent.call( fn, event );
  150. } :
  151. function() {
  152. var event = getIEEvent( obj );
  153. fn.call( obj, event );
  154. };
  155. obj.attachEvent( "on" + type, obj[ type + fn ] );
  156. };
  157. }
  158. var unbind = function() {};
  159. if ( docElem.removeEventListener ) {
  160. unbind = function( obj, type, fn ) {
  161. obj.removeEventListener( type, fn, false );
  162. };
  163. } else if ( docElem.detachEvent ) {
  164. unbind = function( obj, type, fn ) {
  165. obj.detachEvent( "on" + type, obj[ type + fn ] );
  166. try {
  167. delete obj[ type + fn ];
  168. } catch ( err ) {
  169. // can't delete window object properties
  170. obj[ type + fn ] = undefined;
  171. }
  172. };
  173. }
  174. var eventie = {
  175. bind: bind,
  176. unbind: unbind
  177. };
  178. // ----- module definition ----- //
  179. if ( typeof define === 'function' && define.amd ) {
  180. // AMD
  181. define( 'eventie/eventie',eventie );
  182. } else if ( typeof exports === 'object' ) {
  183. // CommonJS
  184. module.exports = eventie;
  185. } else {
  186. // browser global
  187. window.eventie = eventie;
  188. }
  189. })( window );
  190. /*!
  191. * EventEmitter v4.2.11 - git.io/ee
  192. * Unlicense - http://unlicense.org/
  193. * Oliver Caldwell - http://oli.me.uk/
  194. * @preserve
  195. */
  196. ;(function () {
  197. /**
  198. * Class for managing events.
  199. * Can be extended to provide event functionality in other classes.
  200. *
  201. * @class EventEmitter Manages event registering and emitting.
  202. */
  203. function EventEmitter() {}
  204. // Shortcuts to improve speed and size
  205. var proto = EventEmitter.prototype;
  206. var exports = this;
  207. var originalGlobalValue = exports.EventEmitter;
  208. /**
  209. * Finds the index of the listener for the event in its storage array.
  210. *
  211. * @param {Function[]} listeners Array of listeners to search through.
  212. * @param {Function} listener Method to look for.
  213. * @return {Number} Index of the specified listener, -1 if not found
  214. * @api private
  215. */
  216. function indexOfListener(listeners, listener) {
  217. var i = listeners.length;
  218. while (i--) {
  219. if (listeners[i].listener === listener) {
  220. return i;
  221. }
  222. }
  223. return -1;
  224. }
  225. /**
  226. * Alias a method while keeping the context correct, to allow for overwriting of target method.
  227. *
  228. * @param {String} name The name of the target method.
  229. * @return {Function} The aliased method
  230. * @api private
  231. */
  232. function alias(name) {
  233. return function aliasClosure() {
  234. return this[name].apply(this, arguments);
  235. };
  236. }
  237. /**
  238. * Returns the listener array for the specified event.
  239. * Will initialise the event object and listener arrays if required.
  240. * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
  241. * Each property in the object response is an array of listener functions.
  242. *
  243. * @param {String|RegExp} evt Name of the event to return the listeners from.
  244. * @return {Function[]|Object} All listener functions for the event.
  245. */
  246. proto.getListeners = function getListeners(evt) {
  247. var events = this._getEvents();
  248. var response;
  249. var key;
  250. // Return a concatenated array of all matching events if
  251. // the selector is a regular expression.
  252. if (evt instanceof RegExp) {
  253. response = {};
  254. for (key in events) {
  255. if (events.hasOwnProperty(key) && evt.test(key)) {
  256. response[key] = events[key];
  257. }
  258. }
  259. }
  260. else {
  261. response = events[evt] || (events[evt] = []);
  262. }
  263. return response;
  264. };
  265. /**
  266. * Takes a list of listener objects and flattens it into a list of listener functions.
  267. *
  268. * @param {Object[]} listeners Raw listener objects.
  269. * @return {Function[]} Just the listener functions.
  270. */
  271. proto.flattenListeners = function flattenListeners(listeners) {
  272. var flatListeners = [];
  273. var i;
  274. for (i = 0; i < listeners.length; i += 1) {
  275. flatListeners.push(listeners[i].listener);
  276. }
  277. return flatListeners;
  278. };
  279. /**
  280. * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
  281. *
  282. * @param {String|RegExp} evt Name of the event to return the listeners from.
  283. * @return {Object} All listener functions for an event in an object.
  284. */
  285. proto.getListenersAsObject = function getListenersAsObject(evt) {
  286. var listeners = this.getListeners(evt);
  287. var response;
  288. if (listeners instanceof Array) {
  289. response = {};
  290. response[evt] = listeners;
  291. }
  292. return response || listeners;
  293. };
  294. /**
  295. * Adds a listener function to the specified event.
  296. * The listener will not be added if it is a duplicate.
  297. * If the listener returns true then it will be removed after it is called.
  298. * If you pass a regular expression as the event name then the listener will be added to all events that match it.
  299. *
  300. * @param {String|RegExp} evt Name of the event to attach the listener to.
  301. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  302. * @return {Object} Current instance of EventEmitter for chaining.
  303. */
  304. proto.addListener = function addListener(evt, listener) {
  305. var listeners = this.getListenersAsObject(evt);
  306. var listenerIsWrapped = typeof listener === 'object';
  307. var key;
  308. for (key in listeners) {
  309. if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
  310. listeners[key].push(listenerIsWrapped ? listener : {
  311. listener: listener,
  312. once: false
  313. });
  314. }
  315. }
  316. return this;
  317. };
  318. /**
  319. * Alias of addListener
  320. */
  321. proto.on = alias('addListener');
  322. /**
  323. * Semi-alias of addListener. It will add a listener that will be
  324. * automatically removed after its first execution.
  325. *
  326. * @param {String|RegExp} evt Name of the event to attach the listener to.
  327. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  328. * @return {Object} Current instance of EventEmitter for chaining.
  329. */
  330. proto.addOnceListener = function addOnceListener(evt, listener) {
  331. return this.addListener(evt, {
  332. listener: listener,
  333. once: true
  334. });
  335. };
  336. /**
  337. * Alias of addOnceListener.
  338. */
  339. proto.once = alias('addOnceListener');
  340. /**
  341. * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
  342. * You need to tell it what event names should be matched by a regex.
  343. *
  344. * @param {String} evt Name of the event to create.
  345. * @return {Object} Current instance of EventEmitter for chaining.
  346. */
  347. proto.defineEvent = function defineEvent(evt) {
  348. this.getListeners(evt);
  349. return this;
  350. };
  351. /**
  352. * Uses defineEvent to define multiple events.
  353. *
  354. * @param {String[]} evts An array of event names to define.
  355. * @return {Object} Current instance of EventEmitter for chaining.
  356. */
  357. proto.defineEvents = function defineEvents(evts) {
  358. for (var i = 0; i < evts.length; i += 1) {
  359. this.defineEvent(evts[i]);
  360. }
  361. return this;
  362. };
  363. /**
  364. * Removes a listener function from the specified event.
  365. * When passed a regular expression as the event name, it will remove the listener from all events that match it.
  366. *
  367. * @param {String|RegExp} evt Name of the event to remove the listener from.
  368. * @param {Function} listener Method to remove from the event.
  369. * @return {Object} Current instance of EventEmitter for chaining.
  370. */
  371. proto.removeListener = function removeListener(evt, listener) {
  372. var listeners = this.getListenersAsObject(evt);
  373. var index;
  374. var key;
  375. for (key in listeners) {
  376. if (listeners.hasOwnProperty(key)) {
  377. index = indexOfListener(listeners[key], listener);
  378. if (index !== -1) {
  379. listeners[key].splice(index, 1);
  380. }
  381. }
  382. }
  383. return this;
  384. };
  385. /**
  386. * Alias of removeListener
  387. */
  388. proto.off = alias('removeListener');
  389. /**
  390. * Adds listeners in bulk using the manipulateListeners method.
  391. * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
  392. * You can also pass it a regular expression to add the array of listeners to all events that match it.
  393. * Yeah, this function does quite a bit. That's probably a bad thing.
  394. *
  395. * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
  396. * @param {Function[]} [listeners] An optional array of listener functions to add.
  397. * @return {Object} Current instance of EventEmitter for chaining.
  398. */
  399. proto.addListeners = function addListeners(evt, listeners) {
  400. // Pass through to manipulateListeners
  401. return this.manipulateListeners(false, evt, listeners);
  402. };
  403. /**
  404. * Removes listeners in bulk using the manipulateListeners method.
  405. * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
  406. * You can also pass it an event name and an array of listeners to be removed.
  407. * You can also pass it a regular expression to remove the listeners from all events that match it.
  408. *
  409. * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
  410. * @param {Function[]} [listeners] An optional array of listener functions to remove.
  411. * @return {Object} Current instance of EventEmitter for chaining.
  412. */
  413. proto.removeListeners = function removeListeners(evt, listeners) {
  414. // Pass through to manipulateListeners
  415. return this.manipulateListeners(true, evt, listeners);
  416. };
  417. /**
  418. * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
  419. * The first argument will determine if the listeners are removed (true) or added (false).
  420. * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
  421. * You can also pass it an event name and an array of listeners to be added/removed.
  422. * You can also pass it a regular expression to manipulate the listeners of all events that match it.
  423. *
  424. * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
  425. * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
  426. * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
  427. * @return {Object} Current instance of EventEmitter for chaining.
  428. */
  429. proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
  430. var i;
  431. var value;
  432. var single = remove ? this.removeListener : this.addListener;
  433. var multiple = remove ? this.removeListeners : this.addListeners;
  434. // If evt is an object then pass each of its properties to this method
  435. if (typeof evt === 'object' && !(evt instanceof RegExp)) {
  436. for (i in evt) {
  437. if (evt.hasOwnProperty(i) && (value = evt[i])) {
  438. // Pass the single listener straight through to the singular method
  439. if (typeof value === 'function') {
  440. single.call(this, i, value);
  441. }
  442. else {
  443. // Otherwise pass back to the multiple function
  444. multiple.call(this, i, value);
  445. }
  446. }
  447. }
  448. }
  449. else {
  450. // So evt must be a string
  451. // And listeners must be an array of listeners
  452. // Loop over it and pass each one to the multiple method
  453. i = listeners.length;
  454. while (i--) {
  455. single.call(this, evt, listeners[i]);
  456. }
  457. }
  458. return this;
  459. };
  460. /**
  461. * Removes all listeners from a specified event.
  462. * If you do not specify an event then all listeners will be removed.
  463. * That means every event will be emptied.
  464. * You can also pass a regex to remove all events that match it.
  465. *
  466. * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
  467. * @return {Object} Current instance of EventEmitter for chaining.
  468. */
  469. proto.removeEvent = function removeEvent(evt) {
  470. var type = typeof evt;
  471. var events = this._getEvents();
  472. var key;
  473. // Remove different things depending on the state of evt
  474. if (type === 'string') {
  475. // Remove all listeners for the specified event
  476. delete events[evt];
  477. }
  478. else if (evt instanceof RegExp) {
  479. // Remove all events matching the regex.
  480. for (key in events) {
  481. if (events.hasOwnProperty(key) && evt.test(key)) {
  482. delete events[key];
  483. }
  484. }
  485. }
  486. else {
  487. // Remove all listeners in all events
  488. delete this._events;
  489. }
  490. return this;
  491. };
  492. /**
  493. * Alias of removeEvent.
  494. *
  495. * Added to mirror the node API.
  496. */
  497. proto.removeAllListeners = alias('removeEvent');
  498. /**
  499. * Emits an event of your choice.
  500. * When emitted, every listener attached to that event will be executed.
  501. * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
  502. * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
  503. * So they will not arrive within the array on the other side, they will be separate.
  504. * You can also pass a regular expression to emit to all events that match it.
  505. *
  506. * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  507. * @param {Array} [args] Optional array of arguments to be passed to each listener.
  508. * @return {Object} Current instance of EventEmitter for chaining.
  509. */
  510. proto.emitEvent = function emitEvent(evt, args) {
  511. var listeners = this.getListenersAsObject(evt);
  512. var listener;
  513. var i;
  514. var key;
  515. var response;
  516. for (key in listeners) {
  517. if (listeners.hasOwnProperty(key)) {
  518. i = listeners[key].length;
  519. while (i--) {
  520. // If the listener returns true then it shall be removed from the event
  521. // The function is executed either with a basic call or an apply if there is an args array
  522. listener = listeners[key][i];
  523. if (listener.once === true) {
  524. this.removeListener(evt, listener.listener);
  525. }
  526. response = listener.listener.apply(this, args || []);
  527. if (response === this._getOnceReturnValue()) {
  528. this.removeListener(evt, listener.listener);
  529. }
  530. }
  531. }
  532. }
  533. return this;
  534. };
  535. /**
  536. * Alias of emitEvent
  537. */
  538. proto.trigger = alias('emitEvent');
  539. /**
  540. * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
  541. * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
  542. *
  543. * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  544. * @param {...*} Optional additional arguments to be passed to each listener.
  545. * @return {Object} Current instance of EventEmitter for chaining.
  546. */
  547. proto.emit = function emit(evt) {
  548. var args = Array.prototype.slice.call(arguments, 1);
  549. return this.emitEvent(evt, args);
  550. };
  551. /**
  552. * Sets the current value to check against when executing listeners. If a
  553. * listeners return value matches the one set here then it will be removed
  554. * after execution. This value defaults to true.
  555. *
  556. * @param {*} value The new value to check for when executing listeners.
  557. * @return {Object} Current instance of EventEmitter for chaining.
  558. */
  559. proto.setOnceReturnValue = function setOnceReturnValue(value) {
  560. this._onceReturnValue = value;
  561. return this;
  562. };
  563. /**
  564. * Fetches the current value to check against when executing listeners. If
  565. * the listeners return value matches this one then it should be removed
  566. * automatically. It will return true by default.
  567. *
  568. * @return {*|Boolean} The current value to check for or the default, true.
  569. * @api private
  570. */
  571. proto._getOnceReturnValue = function _getOnceReturnValue() {
  572. if (this.hasOwnProperty('_onceReturnValue')) {
  573. return this._onceReturnValue;
  574. }
  575. else {
  576. return true;
  577. }
  578. };
  579. /**
  580. * Fetches the events object and creates one if required.
  581. *
  582. * @return {Object} The events storage object.
  583. * @api private
  584. */
  585. proto._getEvents = function _getEvents() {
  586. return this._events || (this._events = {});
  587. };
  588. /**
  589. * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
  590. *
  591. * @return {Function} Non conflicting EventEmitter class.
  592. */
  593. EventEmitter.noConflict = function noConflict() {
  594. exports.EventEmitter = originalGlobalValue;
  595. return EventEmitter;
  596. };
  597. // Expose the class either via AMD, CommonJS or the global object
  598. if (typeof define === 'function' && define.amd) {
  599. define('eventEmitter/EventEmitter',[],function () {
  600. return EventEmitter;
  601. });
  602. }
  603. else if (typeof module === 'object' && module.exports){
  604. module.exports = EventEmitter;
  605. }
  606. else {
  607. exports.EventEmitter = EventEmitter;
  608. }
  609. }.call(this));
  610. /*!
  611. * getStyleProperty v1.0.4
  612. * original by kangax
  613. * http://perfectionkills.com/feature-testing-css-properties/
  614. * MIT license
  615. */
  616. /*jshint browser: true, strict: true, undef: true */
  617. /*global define: false, exports: false, module: false */
  618. ( function( window ) {
  619. var prefixes = 'Webkit Moz ms Ms O'.split(' ');
  620. var docElemStyle = document.documentElement.style;
  621. function getStyleProperty( propName ) {
  622. if ( !propName ) {
  623. return;
  624. }
  625. // test standard property first
  626. if ( typeof docElemStyle[ propName ] === 'string' ) {
  627. return propName;
  628. }
  629. // capitalize
  630. propName = propName.charAt(0).toUpperCase() + propName.slice(1);
  631. // test vendor specific properties
  632. var prefixed;
  633. for ( var i=0, len = prefixes.length; i < len; i++ ) {
  634. prefixed = prefixes[i] + propName;
  635. if ( typeof docElemStyle[ prefixed ] === 'string' ) {
  636. return prefixed;
  637. }
  638. }
  639. }
  640. // transport
  641. if ( typeof define === 'function' && define.amd ) {
  642. // AMD
  643. define( 'get-style-property/get-style-property',[],function() {
  644. return getStyleProperty;
  645. });
  646. } else if ( typeof exports === 'object' ) {
  647. // CommonJS for Component
  648. module.exports = getStyleProperty;
  649. } else {
  650. // browser global
  651. window.getStyleProperty = getStyleProperty;
  652. }
  653. })( window );
  654. /*!
  655. * getSize v1.2.2
  656. * measure size of elements
  657. * MIT license
  658. */
  659. /*jshint browser: true, strict: true, undef: true, unused: true */
  660. /*global define: false, exports: false, require: false, module: false, console: false */
  661. ( function( window, undefined ) {
  662. // -------------------------- helpers -------------------------- //
  663. // get a number from a string, not a percentage
  664. function getStyleSize( value ) {
  665. var num = parseFloat( value );
  666. // not a percent like '100%', and a number
  667. var isValid = value.indexOf('%') === -1 && !isNaN( num );
  668. return isValid && num;
  669. }
  670. function noop() {}
  671. var logError = typeof console === 'undefined' ? noop :
  672. function( message ) {
  673. console.error( message );
  674. };
  675. // -------------------------- measurements -------------------------- //
  676. var measurements = [
  677. 'paddingLeft',
  678. 'paddingRight',
  679. 'paddingTop',
  680. 'paddingBottom',
  681. 'marginLeft',
  682. 'marginRight',
  683. 'marginTop',
  684. 'marginBottom',
  685. 'borderLeftWidth',
  686. 'borderRightWidth',
  687. 'borderTopWidth',
  688. 'borderBottomWidth'
  689. ];
  690. function getZeroSize() {
  691. var size = {
  692. width: 0,
  693. height: 0,
  694. innerWidth: 0,
  695. innerHeight: 0,
  696. outerWidth: 0,
  697. outerHeight: 0
  698. };
  699. for ( var i=0, len = measurements.length; i < len; i++ ) {
  700. var measurement = measurements[i];
  701. size[ measurement ] = 0;
  702. }
  703. return size;
  704. }
  705. function defineGetSize( getStyleProperty ) {
  706. // -------------------------- setup -------------------------- //
  707. var isSetup = false;
  708. var getStyle, boxSizingProp, isBoxSizeOuter;
  709. /**
  710. * setup vars and functions
  711. * do it on initial getSize(), rather than on script load
  712. * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  713. */
  714. function setup() {
  715. // setup once
  716. if ( isSetup ) {
  717. return;
  718. }
  719. isSetup = true;
  720. var getComputedStyle = window.getComputedStyle;
  721. getStyle = ( function() {
  722. var getStyleFn = getComputedStyle ?
  723. function( elem ) {
  724. return getComputedStyle( elem, null );
  725. } :
  726. function( elem ) {
  727. return elem.currentStyle;
  728. };
  729. return function getStyle( elem ) {
  730. var style = getStyleFn( elem );
  731. if ( !style ) {
  732. logError( 'Style returned ' + style +
  733. '. Are you running this code in a hidden iframe on Firefox? ' +
  734. 'See http://bit.ly/getsizebug1' );
  735. }
  736. return style;
  737. };
  738. })();
  739. // -------------------------- box sizing -------------------------- //
  740. boxSizingProp = getStyleProperty('boxSizing');
  741. /**
  742. * WebKit measures the outer-width on style.width on border-box elems
  743. * IE & Firefox measures the inner-width
  744. */
  745. if ( boxSizingProp ) {
  746. var div = document.createElement('div');
  747. div.style.width = '200px';
  748. div.style.padding = '1px 2px 3px 4px';
  749. div.style.borderStyle = 'solid';
  750. div.style.borderWidth = '1px 2px 3px 4px';
  751. div.style[ boxSizingProp ] = 'border-box';
  752. var body = document.body || document.documentElement;
  753. body.appendChild( div );
  754. var style = getStyle( div );
  755. isBoxSizeOuter = getStyleSize( style.width ) === 200;
  756. body.removeChild( div );
  757. }
  758. }
  759. // -------------------------- getSize -------------------------- //
  760. function getSize( elem ) {
  761. setup();
  762. // use querySeletor if elem is string
  763. if ( typeof elem === 'string' ) {
  764. elem = document.querySelector( elem );
  765. }
  766. // do not proceed on non-objects
  767. if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
  768. return;
  769. }
  770. var style = getStyle( elem );
  771. // if hidden, everything is 0
  772. if ( style.display === 'none' ) {
  773. return getZeroSize();
  774. }
  775. var size = {};
  776. size.width = elem.offsetWidth;
  777. size.height = elem.offsetHeight;
  778. var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
  779. style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
  780. // get all measurements
  781. for ( var i=0, len = measurements.length; i < len; i++ ) {
  782. var measurement = measurements[i];
  783. var value = style[ measurement ];
  784. value = mungeNonPixel( elem, value );
  785. var num = parseFloat( value );
  786. // any 'auto', 'medium' value will be 0
  787. size[ measurement ] = !isNaN( num ) ? num : 0;
  788. }
  789. var paddingWidth = size.paddingLeft + size.paddingRight;
  790. var paddingHeight = size.paddingTop + size.paddingBottom;
  791. var marginWidth = size.marginLeft + size.marginRight;
  792. var marginHeight = size.marginTop + size.marginBottom;
  793. var borderWidth = size.borderLeftWidth + size.borderRightWidth;
  794. var borderHeight = size.borderTopWidth + size.borderBottomWidth;
  795. var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
  796. // overwrite width and height if we can get it from style
  797. var styleWidth = getStyleSize( style.width );
  798. if ( styleWidth !== false ) {
  799. size.width = styleWidth +
  800. // add padding and border unless it's already including it
  801. ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
  802. }
  803. var styleHeight = getStyleSize( style.height );
  804. if ( styleHeight !== false ) {
  805. size.height = styleHeight +
  806. // add padding and border unless it's already including it
  807. ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
  808. }
  809. size.innerWidth = size.width - ( paddingWidth + borderWidth );
  810. size.innerHeight = size.height - ( paddingHeight + borderHeight );
  811. size.outerWidth = size.width + marginWidth;
  812. size.outerHeight = size.height + marginHeight;
  813. return size;
  814. }
  815. // IE8 returns percent values, not pixels
  816. // taken from jQuery's curCSS
  817. function mungeNonPixel( elem, value ) {
  818. // IE8 and has percent value
  819. if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
  820. return value;
  821. }
  822. var style = elem.style;
  823. // Remember the original values
  824. var left = style.left;
  825. var rs = elem.runtimeStyle;
  826. var rsLeft = rs && rs.left;
  827. // Put in the new values to get a computed value out
  828. if ( rsLeft ) {
  829. rs.left = elem.currentStyle.left;
  830. }
  831. style.left = value;
  832. value = style.pixelLeft;
  833. // Revert the changed values
  834. style.left = left;
  835. if ( rsLeft ) {
  836. rs.left = rsLeft;
  837. }
  838. return value;
  839. }
  840. return getSize;
  841. }
  842. // transport
  843. if ( typeof define === 'function' && define.amd ) {
  844. // AMD for RequireJS
  845. define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
  846. } else if ( typeof exports === 'object' ) {
  847. // CommonJS for Component
  848. module.exports = defineGetSize( require('desandro-get-style-property') );
  849. } else {
  850. // browser global
  851. window.getSize = defineGetSize( window.getStyleProperty );
  852. }
  853. })( window );
  854. /*!
  855. * docReady v1.0.4
  856. * Cross browser DOMContentLoaded event emitter
  857. * MIT license
  858. */
  859. /*jshint browser: true, strict: true, undef: true, unused: true*/
  860. /*global define: false, require: false, module: false */
  861. ( function( window ) {
  862. var document = window.document;
  863. // collection of functions to be triggered on ready
  864. var queue = [];
  865. function docReady( fn ) {
  866. // throw out non-functions
  867. if ( typeof fn !== 'function' ) {
  868. return;
  869. }
  870. if ( docReady.isReady ) {
  871. // ready now, hit it
  872. fn();
  873. } else {
  874. // queue function when ready
  875. queue.push( fn );
  876. }
  877. }
  878. docReady.isReady = false;
  879. // triggered on various doc ready events
  880. function onReady( event ) {
  881. // bail if already triggered or IE8 document is not ready just yet
  882. var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
  883. if ( docReady.isReady || isIE8NotReady ) {
  884. return;
  885. }
  886. trigger();
  887. }
  888. function trigger() {
  889. docReady.isReady = true;
  890. // process queue
  891. for ( var i=0, len = queue.length; i < len; i++ ) {
  892. var fn = queue[i];
  893. fn();
  894. }
  895. }
  896. function defineDocReady( eventie ) {
  897. // trigger ready if page is ready
  898. if ( document.readyState === 'complete' ) {
  899. trigger();
  900. } else {
  901. // listen for events
  902. eventie.bind( document, 'DOMContentLoaded', onReady );
  903. eventie.bind( document, 'readystatechange', onReady );
  904. eventie.bind( window, 'load', onReady );
  905. }
  906. return docReady;
  907. }
  908. // transport
  909. if ( typeof define === 'function' && define.amd ) {
  910. // AMD
  911. define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
  912. } else if ( typeof exports === 'object' ) {
  913. module.exports = defineDocReady( require('eventie') );
  914. } else {
  915. // browser global
  916. window.docReady = defineDocReady( window.eventie );
  917. }
  918. })( window );
  919. /**
  920. * matchesSelector v1.0.3
  921. * matchesSelector( element, '.selector' )
  922. * MIT license
  923. */
  924. /*jshint browser: true, strict: true, undef: true, unused: true */
  925. /*global define: false, module: false */
  926. ( function( ElemProto ) {
  927. var matchesMethod = ( function() {
  928. // check for the standard method name first
  929. if ( ElemProto.matches ) {
  930. return 'matches';
  931. }
  932. // check un-prefixed
  933. if ( ElemProto.matchesSelector ) {
  934. return 'matchesSelector';
  935. }
  936. // check vendor prefixes
  937. var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
  938. for ( var i=0, len = prefixes.length; i < len; i++ ) {
  939. var prefix = prefixes[i];
  940. var method = prefix + 'MatchesSelector';
  941. if ( ElemProto[ method ] ) {
  942. return method;
  943. }
  944. }
  945. })();
  946. // ----- match ----- //
  947. function match( elem, selector ) {
  948. return elem[ matchesMethod ]( selector );
  949. }
  950. // ----- appendToFragment ----- //
  951. function checkParent( elem ) {
  952. // not needed if already has parent
  953. if ( elem.parentNode ) {
  954. return;
  955. }
  956. var fragment = document.createDocumentFragment();
  957. fragment.appendChild( elem );
  958. }
  959. // ----- query ----- //
  960. // fall back to using QSA
  961. // thx @jonathantneal https://gist.github.com/3062955
  962. function query( elem, selector ) {
  963. // append to fragment if no parent
  964. checkParent( elem );
  965. // match elem with all selected elems of parent
  966. var elems = elem.parentNode.querySelectorAll( selector );
  967. for ( var i=0, len = elems.length; i < len; i++ ) {
  968. // return true if match
  969. if ( elems[i] === elem ) {
  970. return true;
  971. }
  972. }
  973. // otherwise return false
  974. return false;
  975. }
  976. // ----- matchChild ----- //
  977. function matchChild( elem, selector ) {
  978. checkParent( elem );
  979. return match( elem, selector );
  980. }
  981. // ----- matchesSelector ----- //
  982. var matchesSelector;
  983. if ( matchesMethod ) {
  984. // IE9 supports matchesSelector, but doesn't work on orphaned elems
  985. // check for that
  986. var div = document.createElement('div');
  987. var supportsOrphans = match( div, 'div' );
  988. matchesSelector = supportsOrphans ? match : matchChild;
  989. } else {
  990. matchesSelector = query;
  991. }
  992. // transport
  993. if ( typeof define === 'function' && define.amd ) {
  994. // AMD
  995. define( 'matches-selector/matches-selector',[],function() {
  996. return matchesSelector;
  997. });
  998. } else if ( typeof exports === 'object' ) {
  999. module.exports = matchesSelector;
  1000. }
  1001. else {
  1002. // browser global
  1003. window.matchesSelector = matchesSelector;
  1004. }
  1005. })( Element.prototype );
  1006. /**
  1007. * Fizzy UI utils v1.0.1
  1008. * MIT license
  1009. */
  1010. /*jshint browser: true, undef: true, unused: true, strict: true */
  1011. ( function( window, factory ) {
  1012. /*global define: false, module: false, require: false */
  1013. // universal module definition
  1014. if ( typeof define == 'function' && define.amd ) {
  1015. // AMD
  1016. define( 'fizzy-ui-utils/utils',[
  1017. 'doc-ready/doc-ready',
  1018. 'matches-selector/matches-selector'
  1019. ], function( docReady, matchesSelector ) {
  1020. return factory( window, docReady, matchesSelector );
  1021. });
  1022. } else if ( typeof exports == 'object' ) {
  1023. // CommonJS
  1024. module.exports = factory(
  1025. window,
  1026. require('doc-ready'),
  1027. require('desandro-matches-selector')
  1028. );
  1029. } else {
  1030. // browser global
  1031. window.fizzyUIUtils = factory(
  1032. window,
  1033. window.docReady,
  1034. window.matchesSelector
  1035. );
  1036. }
  1037. }( window, function factory( window, docReady, matchesSelector ) {
  1038. var utils = {};
  1039. // ----- extend ----- //
  1040. // extends objects
  1041. utils.extend = function( a, b ) {
  1042. for ( var prop in b ) {
  1043. a[ prop ] = b[ prop ];
  1044. }
  1045. return a;
  1046. };
  1047. // ----- modulo ----- //
  1048. utils.modulo = function( num, div ) {
  1049. return ( ( num % div ) + div ) % div;
  1050. };
  1051. // ----- isArray ----- //
  1052. var objToString = Object.prototype.toString;
  1053. utils.isArray = function( obj ) {
  1054. return objToString.call( obj ) == '[object Array]';
  1055. };
  1056. // ----- makeArray ----- //
  1057. // turn element or nodeList into an array
  1058. utils.makeArray = function( obj ) {
  1059. var ary = [];
  1060. if ( utils.isArray( obj ) ) {
  1061. // use object if already an array
  1062. ary = obj;
  1063. } else if ( obj && typeof obj.length == 'number' ) {
  1064. // convert nodeList to array
  1065. for ( var i=0, len = obj.length; i < len; i++ ) {
  1066. ary.push( obj[i] );
  1067. }
  1068. } else {
  1069. // array of single index
  1070. ary.push( obj );
  1071. }
  1072. return ary;
  1073. };
  1074. // ----- indexOf ----- //
  1075. // index of helper cause IE8
  1076. utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
  1077. return ary.indexOf( obj );
  1078. } : function( ary, obj ) {
  1079. for ( var i=0, len = ary.length; i < len; i++ ) {
  1080. if ( ary[i] === obj ) {
  1081. return i;
  1082. }
  1083. }
  1084. return -1;
  1085. };
  1086. // ----- removeFrom ----- //
  1087. utils.removeFrom = function( ary, obj ) {
  1088. var index = utils.indexOf( ary, obj );
  1089. if ( index != -1 ) {
  1090. ary.splice( index, 1 );
  1091. }
  1092. };
  1093. // ----- isElement ----- //
  1094. // http://stackoverflow.com/a/384380/182183
  1095. utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
  1096. function isElementDOM2( obj ) {
  1097. return obj instanceof HTMLElement;
  1098. } :
  1099. function isElementQuirky( obj ) {
  1100. return obj && typeof obj == 'object' &&
  1101. obj.nodeType == 1 && typeof obj.nodeName == 'string';
  1102. };
  1103. // ----- setText ----- //
  1104. utils.setText = ( function() {
  1105. var setTextProperty;
  1106. function setText( elem, text ) {
  1107. // only check setTextProperty once
  1108. setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
  1109. elem[ setTextProperty ] = text;
  1110. }
  1111. return setText;
  1112. })();
  1113. // ----- getParent ----- //
  1114. utils.getParent = function( elem, selector ) {
  1115. while ( elem != document.body ) {
  1116. elem = elem.parentNode;
  1117. if ( matchesSelector( elem, selector ) ) {
  1118. return elem;
  1119. }
  1120. }
  1121. };
  1122. // ----- getQueryElement ----- //
  1123. // use element as selector string
  1124. utils.getQueryElement = function( elem ) {
  1125. if ( typeof elem == 'string' ) {
  1126. return document.querySelector( elem );
  1127. }
  1128. return elem;
  1129. };
  1130. // ----- handleEvent ----- //
  1131. // enable .ontype to trigger from .addEventListener( elem, 'type' )
  1132. utils.handleEvent = function( event ) {
  1133. var method = 'on' + event.type;
  1134. if ( this[ method ] ) {
  1135. this[ method ]( event );
  1136. }
  1137. };
  1138. // ----- filterFindElements ----- //
  1139. utils.filterFindElements = function( elems, selector ) {
  1140. // make array of elems
  1141. elems = utils.makeArray( elems );
  1142. var ffElems = [];
  1143. for ( var i=0, len = elems.length; i < len; i++ ) {
  1144. var elem = elems[i];
  1145. // check that elem is an actual element
  1146. if ( !utils.isElement( elem ) ) {
  1147. continue;
  1148. }
  1149. // filter & find items if we have a selector
  1150. if ( selector ) {
  1151. // filter siblings
  1152. if ( matchesSelector( elem, selector ) ) {
  1153. ffElems.push( elem );
  1154. }
  1155. // find children
  1156. var childElems = elem.querySelectorAll( selector );
  1157. // concat childElems to filterFound array
  1158. for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
  1159. ffElems.push( childElems[j] );
  1160. }
  1161. } else {
  1162. ffElems.push( elem );
  1163. }
  1164. }
  1165. return ffElems;
  1166. };
  1167. // ----- debounceMethod ----- //
  1168. utils.debounceMethod = function( _class, methodName, threshold ) {
  1169. // original method
  1170. var method = _class.prototype[ methodName ];
  1171. var timeoutName = methodName + 'Timeout';
  1172. _class.prototype[ methodName ] = function() {
  1173. var timeout = this[ timeoutName ];
  1174. if ( timeout ) {
  1175. clearTimeout( timeout );
  1176. }
  1177. var args = arguments;
  1178. var _this = this;
  1179. this[ timeoutName ] = setTimeout( function() {
  1180. method.apply( _this, args );
  1181. delete _this[ timeoutName ];
  1182. }, threshold || 100 );
  1183. };
  1184. };
  1185. // ----- htmlInit ----- //
  1186. // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
  1187. utils.toDashed = function( str ) {
  1188. return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
  1189. return $1 + '-' + $2;
  1190. }).toLowerCase();
  1191. };
  1192. var console = window.console;
  1193. /**
  1194. * allow user to initialize classes via .js-namespace class
  1195. * htmlInit( Widget, 'widgetName' )
  1196. * options are parsed from data-namespace-option attribute
  1197. */
  1198. utils.htmlInit = function( WidgetClass, namespace ) {
  1199. docReady( function() {
  1200. var dashedNamespace = utils.toDashed( namespace );
  1201. var elems = document.querySelectorAll( '.js-' + dashedNamespace );
  1202. var dataAttr = 'data-' + dashedNamespace + '-options';
  1203. for ( var i=0, len = elems.length; i < len; i++ ) {
  1204. var elem = elems[i];
  1205. var attr = elem.getAttribute( dataAttr );
  1206. var options;
  1207. try {
  1208. options = attr && JSON.parse( attr );
  1209. } catch ( error ) {
  1210. // log error, do not initialize
  1211. if ( console ) {
  1212. console.error( 'Error parsing ' + dataAttr + ' on ' +
  1213. elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
  1214. error );
  1215. }
  1216. continue;
  1217. }
  1218. // initialize
  1219. var instance = new WidgetClass( elem, options );
  1220. // make available via $().data('layoutname')
  1221. var jQuery = window.jQuery;
  1222. if ( jQuery ) {
  1223. jQuery.data( elem, namespace, instance );
  1224. }
  1225. }
  1226. });
  1227. };
  1228. // ----- ----- //
  1229. return utils;
  1230. }));
  1231. /**
  1232. * Outlayer Item
  1233. */
  1234. ( function( window, factory ) {
  1235. // universal module definition
  1236. if ( typeof define === 'function' && define.amd ) {
  1237. // AMD
  1238. define( 'outlayer/item',[
  1239. 'eventEmitter/EventEmitter',
  1240. 'get-size/get-size',
  1241. 'get-style-property/get-style-property',
  1242. 'fizzy-ui-utils/utils'
  1243. ],
  1244. function( EventEmitter, getSize, getStyleProperty, utils ) {
  1245. return factory( window, EventEmitter, getSize, getStyleProperty, utils );
  1246. }
  1247. );
  1248. } else if (typeof exports === 'object') {
  1249. // CommonJS
  1250. module.exports = factory(
  1251. window,
  1252. require('wolfy87-eventemitter'),
  1253. require('get-size'),
  1254. require('desandro-get-style-property'),
  1255. require('fizzy-ui-utils')
  1256. );
  1257. } else {
  1258. // browser global
  1259. window.Outlayer = {};
  1260. window.Outlayer.Item = factory(
  1261. window,
  1262. window.EventEmitter,
  1263. window.getSize,
  1264. window.getStyleProperty,
  1265. window.fizzyUIUtils
  1266. );
  1267. }
  1268. }( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) {
  1269. // ----- helpers ----- //
  1270. var getComputedStyle = window.getComputedStyle;
  1271. var getStyle = getComputedStyle ?
  1272. function( elem ) {
  1273. return getComputedStyle( elem, null );
  1274. } :
  1275. function( elem ) {
  1276. return elem.currentStyle;
  1277. };
  1278. function isEmptyObj( obj ) {
  1279. for ( var prop in obj ) {
  1280. return false;
  1281. }
  1282. prop = null;
  1283. return true;
  1284. }
  1285. // -------------------------- CSS3 support -------------------------- //
  1286. var transitionProperty = getStyleProperty('transition');
  1287. var transformProperty = getStyleProperty('transform');
  1288. var supportsCSS3 = transitionProperty && transformProperty;
  1289. var is3d = !!getStyleProperty('perspective');
  1290. var transitionEndEvent = {
  1291. WebkitTransition: 'webkitTransitionEnd',
  1292. MozTransition: 'transitionend',
  1293. OTransition: 'otransitionend',
  1294. transition: 'transitionend'
  1295. }[ transitionProperty ];
  1296. // properties that could have vendor prefix
  1297. var prefixableProperties = [
  1298. 'transform',
  1299. 'transition',
  1300. 'transitionDuration',
  1301. 'transitionProperty'
  1302. ];
  1303. // cache all vendor properties
  1304. var vendorProperties = ( function() {
  1305. var cache = {};
  1306. for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
  1307. var prop = prefixableProperties[i];
  1308. var supportedProp = getStyleProperty( prop );
  1309. if ( supportedProp && supportedProp !== prop ) {
  1310. cache[ prop ] = supportedProp;
  1311. }
  1312. }
  1313. return cache;
  1314. })();
  1315. // -------------------------- Item -------------------------- //
  1316. function Item( element, layout ) {
  1317. if ( !element ) {
  1318. return;
  1319. }
  1320. this.element = element;
  1321. // parent layout class, i.e. Masonry, Isotope, or Packery
  1322. this.layout = layout;
  1323. this.position = {
  1324. x: 0,
  1325. y: 0
  1326. };
  1327. this._create();
  1328. }
  1329. // inherit EventEmitter
  1330. utils.extend( Item.prototype, EventEmitter.prototype );
  1331. Item.prototype._create = function() {
  1332. // transition objects
  1333. this._transn = {
  1334. ingProperties: {},
  1335. clean: {},
  1336. onEnd: {}
  1337. };
  1338. this.css({
  1339. position: 'absolute'
  1340. });
  1341. };
  1342. // trigger specified handler for event type
  1343. Item.prototype.handleEvent = function( event ) {
  1344. var method = 'on' + event.type;
  1345. if ( this[ method ] ) {
  1346. this[ method ]( event );
  1347. }
  1348. };
  1349. Item.prototype.getSize = function() {
  1350. this.size = getSize( this.element );
  1351. };
  1352. /**
  1353. * apply CSS styles to element
  1354. * @param {Object} style
  1355. */
  1356. Item.prototype.css = function( style ) {
  1357. var elemStyle = this.element.style;
  1358. for ( var prop in style ) {
  1359. // use vendor property if available
  1360. var supportedProp = vendorProperties[ prop ] || prop;
  1361. elemStyle[ supportedProp ] = style[ prop ];
  1362. }
  1363. };
  1364. // measure position, and sets it
  1365. Item.prototype.getPosition = function() {
  1366. var style = getStyle( this.element );
  1367. var layoutOptions = this.layout.options;
  1368. var isOriginLeft = layoutOptions.isOriginLeft;
  1369. var isOriginTop = layoutOptions.isOriginTop;
  1370. var xValue = style[ isOriginLeft ? 'left' : 'right' ];
  1371. var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
  1372. // convert percent to pixels
  1373. var layoutSize = this.layout.size;
  1374. var x = xValue.indexOf('%') != -1 ?
  1375. ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 );
  1376. var y = yValue.indexOf('%') != -1 ?
  1377. ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 );
  1378. // clean up 'auto' or other non-integer values
  1379. x = isNaN( x ) ? 0 : x;
  1380. y = isNaN( y ) ? 0 : y;
  1381. // remove padding from measurement
  1382. x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
  1383. y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
  1384. this.position.x = x;
  1385. this.position.y = y;
  1386. };
  1387. // set settled position, apply padding
  1388. Item.prototype.layoutPosition = function() {
  1389. var layoutSize = this.layout.size;
  1390. var layoutOptions = this.layout.options;
  1391. var style = {};
  1392. // x
  1393. var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight';
  1394. var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right';
  1395. var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left';
  1396. var x = this.position.x + layoutSize[ xPadding ];
  1397. // set in percentage or pixels
  1398. style[ xProperty ] = this.getXValue( x );
  1399. // reset other property
  1400. style[ xResetProperty ] = '';
  1401. // y
  1402. var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom';
  1403. var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom';
  1404. var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top';
  1405. var y = this.position.y + layoutSize[ yPadding ];
  1406. // set in percentage or pixels
  1407. style[ yProperty ] = this.getYValue( y );
  1408. // reset other property
  1409. style[ yResetProperty ] = '';
  1410. this.css( style );
  1411. this.emitEvent( 'layout', [ this ] );
  1412. };
  1413. Item.prototype.getXValue = function( x ) {
  1414. var layoutOptions = this.layout.options;
  1415. return layoutOptions.percentPosition && !layoutOptions.isHorizontal ?
  1416. ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
  1417. };
  1418. Item.prototype.getYValue = function( y ) {
  1419. var layoutOptions = this.layout.options;
  1420. return layoutOptions.percentPosition && layoutOptions.isHorizontal ?
  1421. ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
  1422. };
  1423. Item.prototype._transitionTo = function( x, y ) {
  1424. this.getPosition();
  1425. // get current x & y from top/left
  1426. var curX = this.position.x;
  1427. var curY = this.position.y;
  1428. var compareX = parseInt( x, 10 );
  1429. var compareY = parseInt( y, 10 );
  1430. var didNotMove = compareX === this.position.x && compareY === this.position.y;
  1431. // save end position
  1432. this.setPosition( x, y );
  1433. // if did not move and not transitioning, just go to layout
  1434. if ( didNotMove && !this.isTransitioning ) {
  1435. this.layoutPosition();
  1436. return;
  1437. }
  1438. var transX = x - curX;
  1439. var transY = y - curY;
  1440. var transitionStyle = {};
  1441. transitionStyle.transform = this.getTranslate( transX, transY );
  1442. this.transition({
  1443. to: transitionStyle,
  1444. onTransitionEnd: {
  1445. transform: this.layoutPosition
  1446. },
  1447. isCleaning: true
  1448. });
  1449. };
  1450. Item.prototype.getTranslate = function( x, y ) {
  1451. // flip cooridinates if origin on right or bottom
  1452. var layoutOptions = this.layout.options;
  1453. x = layoutOptions.isOriginLeft ? x : -x;
  1454. y = layoutOptions.isOriginTop ? y : -y;
  1455. if ( is3d ) {
  1456. return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
  1457. }
  1458. return 'translate(' + x + 'px, ' + y + 'px)';
  1459. };
  1460. // non transition + transform support
  1461. Item.prototype.goTo = function( x, y ) {
  1462. this.setPosition( x, y );
  1463. this.layoutPosition();
  1464. };
  1465. // use transition and transforms if supported
  1466. Item.prototype.moveTo = supportsCSS3 ?
  1467. Item.prototype._transitionTo : Item.prototype.goTo;
  1468. Item.prototype.setPosition = function( x, y ) {
  1469. this.position.x = parseInt( x, 10 );
  1470. this.position.y = parseInt( y, 10 );
  1471. };
  1472. // ----- transition ----- //
  1473. /**
  1474. * @param {Object} style - CSS
  1475. * @param {Function} onTransitionEnd
  1476. */
  1477. // non transition, just trigger callback
  1478. Item.prototype._nonTransition = function( args ) {
  1479. this.css( args.to );
  1480. if ( args.isCleaning ) {
  1481. this._removeStyles( args.to );
  1482. }
  1483. for ( var prop in args.onTransitionEnd ) {
  1484. args.onTransitionEnd[ prop ].call( this );
  1485. }
  1486. };
  1487. /**
  1488. * proper transition
  1489. * @param {Object} args - arguments
  1490. * @param {Object} to - style to transition to
  1491. * @param {Object} from - style to start transition from
  1492. * @param {Boolean} isCleaning - removes transition styles after transition
  1493. * @param {Function} onTransitionEnd - callback
  1494. */
  1495. Item.prototype._transition = function( args ) {
  1496. // redirect to nonTransition if no transition duration
  1497. if ( !parseFloat( this.layout.options.transitionDuration ) ) {
  1498. this._nonTransition( args );
  1499. return;
  1500. }
  1501. var _transition = this._transn;
  1502. // keep track of onTransitionEnd callback by css property
  1503. for ( var prop in args.onTransitionEnd ) {
  1504. _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
  1505. }
  1506. // keep track of properties that are transitioning
  1507. for ( prop in args.to ) {
  1508. _transition.ingProperties[ prop ] = true;
  1509. // keep track of properties to clean up when transition is done
  1510. if ( args.isCleaning ) {
  1511. _transition.clean[ prop ] = true;
  1512. }
  1513. }
  1514. // set from styles
  1515. if ( args.from ) {
  1516. this.css( args.from );
  1517. // force redraw. http://blog.alexmaccaw.com/css-transitions
  1518. var h = this.element.offsetHeight;
  1519. // hack for JSHint to hush about unused var
  1520. h = null;
  1521. }
  1522. // enable transition
  1523. this.enableTransition( args.to );
  1524. // set styles that are transitioning
  1525. this.css( args.to );
  1526. this.isTransitioning = true;
  1527. };
  1528. // dash before all cap letters, including first for
  1529. // WebkitTransform => -webkit-transform
  1530. function toDashedAll( str ) {
  1531. return str.replace( /([A-Z])/g, function( $1 ) {
  1532. return '-' + $1.toLowerCase();
  1533. });
  1534. }
  1535. var transitionProps = 'opacity,' +
  1536. toDashedAll( vendorProperties.transform || 'transform' );
  1537. Item.prototype.enableTransition = function(/* style */) {
  1538. // HACK changing transitionProperty during a transition
  1539. // will cause transition to jump
  1540. if ( this.isTransitioning ) {
  1541. return;
  1542. }
  1543. // make `transition: foo, bar, baz` from style object
  1544. // HACK un-comment this when enableTransition can work
  1545. // while a transition is happening
  1546. // var transitionValues = [];
  1547. // for ( var prop in style ) {
  1548. // // dash-ify camelCased properties like WebkitTransition
  1549. // prop = vendorProperties[ prop ] || prop;
  1550. // transitionValues.push( toDashedAll( prop ) );
  1551. // }
  1552. // enable transition styles
  1553. this.css({
  1554. transitionProperty: transitionProps,
  1555. transitionDuration: this.layout.options.transitionDuration
  1556. });
  1557. // listen for transition end event
  1558. this.element.addEventListener( transitionEndEvent, this, false );
  1559. };
  1560. Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
  1561. // ----- events ----- //
  1562. Item.prototype.onwebkitTransitionEnd = function( event ) {
  1563. this.ontransitionend( event );
  1564. };
  1565. Item.prototype.onotransitionend = function( event ) {
  1566. this.ontransitionend( event );
  1567. };
  1568. // properties that I munge to make my life easier
  1569. var dashedVendorProperties = {
  1570. '-webkit-transform': 'transform',
  1571. '-moz-transform': 'transform',
  1572. '-o-transform': 'transform'
  1573. };
  1574. Item.prototype.ontransitionend = function( event ) {
  1575. // disregard bubbled events from children
  1576. if ( event.target !== this.element ) {
  1577. return;
  1578. }
  1579. var _transition = this._transn;
  1580. // get property name of transitioned property, convert to prefix-free
  1581. var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
  1582. // remove property that has completed transitioning
  1583. delete _transition.ingProperties[ propertyName ];
  1584. // check if any properties are still transitioning
  1585. if ( isEmptyObj( _transition.ingProperties ) ) {
  1586. // all properties have completed transitioning
  1587. this.disableTransition();
  1588. }
  1589. // clean style
  1590. if ( propertyName in _transition.clean ) {
  1591. // clean up style
  1592. this.element.style[ event.propertyName ] = '';
  1593. delete _transition.clean[ propertyName ];
  1594. }
  1595. // trigger onTransitionEnd callback
  1596. if ( propertyName in _transition.onEnd ) {
  1597. var onTransitionEnd = _transition.onEnd[ propertyName ];
  1598. onTransitionEnd.call( this );
  1599. delete _transition.onEnd[ propertyName ];
  1600. }
  1601. this.emitEvent( 'transitionEnd', [ this ] );
  1602. };
  1603. Item.prototype.disableTransition = function() {
  1604. this.removeTransitionStyles();
  1605. this.element.removeEventListener( transitionEndEvent, this, false );
  1606. this.isTransitioning = false;
  1607. };
  1608. /**
  1609. * removes style property from element
  1610. * @param {Object} style
  1611. **/
  1612. Item.prototype._removeStyles = function( style ) {
  1613. // clean up transition styles
  1614. var cleanStyle = {};
  1615. for ( var prop in style ) {
  1616. cleanStyle[ prop ] = '';
  1617. }
  1618. this.css( cleanStyle );
  1619. };
  1620. var cleanTransitionStyle = {
  1621. transitionProperty: '',
  1622. transitionDuration: ''
  1623. };
  1624. Item.prototype.removeTransitionStyles = function() {
  1625. // remove transition
  1626. this.css( cleanTransitionStyle );
  1627. };
  1628. // ----- show/hide/remove ----- //
  1629. // remove element from DOM
  1630. Item.prototype.removeElem = function() {
  1631. this.element.parentNode.removeChild( this.element );
  1632. // remove display: none
  1633. this.css({ display: '' });
  1634. this.emitEvent( 'remove', [ this ] );
  1635. };
  1636. Item.prototype.remove = function() {
  1637. // just remove element if no transition support or no transition
  1638. if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
  1639. this.removeElem();
  1640. return;
  1641. }
  1642. // start transition
  1643. var _this = this;
  1644. this.once( 'transitionEnd', function() {
  1645. _this.removeElem();
  1646. });
  1647. this.hide();
  1648. };
  1649. Item.prototype.reveal = function() {
  1650. delete this.isHidden;
  1651. // remove display: none
  1652. this.css({ display: '' });
  1653. var options = this.layout.options;
  1654. var onTransitionEnd = {};
  1655. var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
  1656. onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
  1657. this.transition({
  1658. from: options.hiddenStyle,
  1659. to: options.visibleStyle,
  1660. isCleaning: true,
  1661. onTransitionEnd: onTransitionEnd
  1662. });
  1663. };
  1664. Item.prototype.onRevealTransitionEnd = function() {
  1665. // check if still visible
  1666. // during transition, item may have been hidden
  1667. if ( !this.isHidden ) {
  1668. this.emitEvent('reveal');
  1669. }
  1670. };
  1671. /**
  1672. * get style property use for hide/reveal transition end
  1673. * @param {String} styleProperty - hiddenStyle/visibleStyle
  1674. * @returns {String}
  1675. */
  1676. Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) {
  1677. var optionStyle = this.layout.options[ styleProperty ];
  1678. // use opacity
  1679. if ( optionStyle.opacity ) {
  1680. return 'opacity';
  1681. }
  1682. // get first property
  1683. for ( var prop in optionStyle ) {
  1684. return prop;
  1685. }
  1686. };
  1687. Item.prototype.hide = function() {
  1688. // set flag
  1689. this.isHidden = true;
  1690. // remove display: none
  1691. this.css({ display: '' });
  1692. var options = this.layout.options;
  1693. var onTransitionEnd = {};
  1694. var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
  1695. onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
  1696. this.transition({
  1697. from: options.visibleStyle,
  1698. to: options.hiddenStyle,
  1699. // keep hidden stuff hidden
  1700. isCleaning: true,
  1701. onTransitionEnd: onTransitionEnd
  1702. });
  1703. };
  1704. Item.prototype.onHideTransitionEnd = function() {
  1705. // check if still hidden
  1706. // during transition, item may have been un-hidden
  1707. if ( this.isHidden ) {
  1708. this.css({ display: 'none' });
  1709. this.emitEvent('hide');
  1710. }
  1711. };
  1712. Item.prototype.destroy = function() {
  1713. this.css({
  1714. position: '',
  1715. left: '',
  1716. right: '',
  1717. top: '',
  1718. bottom: '',
  1719. transition: '',
  1720. transform: ''
  1721. });
  1722. };
  1723. return Item;
  1724. }));
  1725. /*!
  1726. * Outlayer v1.4.2
  1727. * the brains and guts of a layout library
  1728. * MIT license
  1729. */
  1730. ( function( window, factory ) {
  1731. // universal module definition
  1732. if ( typeof define == 'function' && define.amd ) {
  1733. // AMD
  1734. define( 'outlayer/outlayer',[
  1735. 'eventie/eventie',
  1736. 'eventEmitter/EventEmitter',
  1737. 'get-size/get-size',
  1738. 'fizzy-ui-utils/utils',
  1739. './item'
  1740. ],
  1741. function( eventie, EventEmitter, getSize, utils, Item ) {
  1742. return factory( window, eventie, EventEmitter, getSize, utils, Item);
  1743. }
  1744. );
  1745. } else if ( typeof exports == 'object' ) {
  1746. // CommonJS
  1747. module.exports = factory(
  1748. window,
  1749. require('eventie'),
  1750. require('wolfy87-eventemitter'),
  1751. require('get-size'),
  1752. require('fizzy-ui-utils'),
  1753. require('./item')
  1754. );
  1755. } else {
  1756. // browser global
  1757. window.Outlayer = factory(
  1758. window,
  1759. window.eventie,
  1760. window.EventEmitter,
  1761. window.getSize,
  1762. window.fizzyUIUtils,
  1763. window.Outlayer.Item
  1764. );
  1765. }
  1766. }( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) {
  1767. // ----- vars ----- //
  1768. var console = window.console;
  1769. var jQuery = window.jQuery;
  1770. var noop = function() {};
  1771. // -------------------------- Outlayer -------------------------- //
  1772. // globally unique identifiers
  1773. var GUID = 0;
  1774. // internal store of all Outlayer intances
  1775. var instances = {};
  1776. /**
  1777. * @param {Element, String} element
  1778. * @param {Object} options
  1779. * @constructor
  1780. */
  1781. function Outlayer( element, options ) {
  1782. var queryElement = utils.getQueryElement( element );
  1783. if ( !queryElement ) {
  1784. if ( console ) {
  1785. console.error( 'Bad element for ' + this.constructor.namespace +
  1786. ': ' + ( queryElement || element ) );
  1787. }
  1788. return;
  1789. }
  1790. this.element = queryElement;
  1791. // add jQuery
  1792. if ( jQuery ) {
  1793. this.$element = jQuery( this.element );
  1794. }
  1795. // options
  1796. this.options = utils.extend( {}, this.constructor.defaults );
  1797. this.option( options );
  1798. // add id for Outlayer.getFromElement
  1799. var id = ++GUID;
  1800. this.element.outlayerGUID = id; // expando
  1801. instances[ id ] = this; // associate via id
  1802. // kick it off
  1803. this._create();
  1804. if ( this.options.isInitLayout ) {
  1805. this.layout();
  1806. }
  1807. }
  1808. // settings are for internal use only
  1809. Outlayer.namespace = 'outlayer';
  1810. Outlayer.Item = Item;
  1811. // default options
  1812. Outlayer.defaults = {
  1813. containerStyle: {
  1814. position: 'relative'
  1815. },
  1816. isInitLayout: true,
  1817. isOriginLeft: true,
  1818. isOriginTop: true,
  1819. isResizeBound: true,
  1820. isResizingContainer: true,
  1821. // item options
  1822. transitionDuration: '0.4s',
  1823. hiddenStyle: {
  1824. opacity: 0,
  1825. transform: 'scale(0.001)'
  1826. },
  1827. visibleStyle: {
  1828. opacity: 1,
  1829. transform: 'scale(1)'
  1830. }
  1831. };
  1832. // inherit EventEmitter
  1833. utils.extend( Outlayer.prototype, EventEmitter.prototype );
  1834. /**
  1835. * set options
  1836. * @param {Object} opts
  1837. */
  1838. Outlayer.prototype.option = function( opts ) {
  1839. utils.extend( this.options, opts );
  1840. };
  1841. Outlayer.prototype._create = function() {
  1842. // get items from children
  1843. this.reloadItems();
  1844. // elements that affect layout, but are not laid out
  1845. this.stamps = [];
  1846. this.stamp( this.options.stamp );
  1847. // set container style
  1848. utils.extend( this.element.style, this.options.containerStyle );
  1849. // bind resize method
  1850. if ( this.options.isResizeBound ) {
  1851. this.bindResize();
  1852. }
  1853. };
  1854. // goes through all children again and gets bricks in proper order
  1855. Outlayer.prototype.reloadItems = function() {
  1856. // collection of item elements
  1857. this.items = this._itemize( this.element.children );
  1858. };
  1859. /**
  1860. * turn elements into Outlayer.Items to be used in layout
  1861. * @param {Array or NodeList or HTMLElement} elems
  1862. * @returns {Array} items - collection of new Outlayer Items
  1863. */
  1864. Outlayer.prototype._itemize = function( elems ) {
  1865. var itemElems = this._filterFindItemElements( elems );
  1866. var Item = this.constructor.Item;
  1867. // create new Outlayer Items for collection
  1868. var items = [];
  1869. for ( var i=0, len = itemElems.length; i < len; i++ ) {
  1870. var elem = itemElems[i];
  1871. var item = new Item( elem, this );
  1872. items.push( item );
  1873. }
  1874. return items;
  1875. };
  1876. /**
  1877. * get item elements to be used in layout
  1878. * @param {Array or NodeList or HTMLElement} elems
  1879. * @returns {Array} items - item elements
  1880. */
  1881. Outlayer.prototype._filterFindItemElements = function( elems ) {
  1882. return utils.filterFindElements( elems, this.options.itemSelector );
  1883. };
  1884. /**
  1885. * getter method for getting item elements
  1886. * @returns {Array} elems - collection of item elements
  1887. */
  1888. Outlayer.prototype.getItemElements = function() {
  1889. var elems = [];
  1890. for ( var i=0, len = this.items.length; i < len; i++ ) {
  1891. elems.push( this.items[i].element );
  1892. }
  1893. return elems;
  1894. };
  1895. // ----- init & layout ----- //
  1896. /**
  1897. * lays out all items
  1898. */
  1899. Outlayer.prototype.layout = function() {
  1900. this._resetLayout();
  1901. this._manageStamps();
  1902. // don't animate first layout
  1903. var isInstant = this.options.isLayoutInstant !== undefined ?
  1904. this.options.isLayoutInstant : !this._isLayoutInited;
  1905. this.layoutItems( this.items, isInstant );
  1906. // flag for initalized
  1907. this._isLayoutInited = true;
  1908. };
  1909. // _init is alias for layout
  1910. Outlayer.prototype._init = Outlayer.prototype.layout;
  1911. /**
  1912. * logic before any new layout
  1913. */
  1914. Outlayer.prototype._resetLayout = function() {
  1915. this.getSize();
  1916. };
  1917. Outlayer.prototype.getSize = function() {
  1918. this.size = getSize( this.element );
  1919. };
  1920. /**
  1921. * get measurement from option, for columnWidth, rowHeight, gutter
  1922. * if option is String -> get element from selector string, & get size of element
  1923. * if option is Element -> get size of element
  1924. * else use option as a number
  1925. *
  1926. * @param {String} measurement
  1927. * @param {String} size - width or height
  1928. * @private
  1929. */
  1930. Outlayer.prototype._getMeasurement = function( measurement, size ) {
  1931. var option = this.options[ measurement ];
  1932. var elem;
  1933. if ( !option ) {
  1934. // default to 0
  1935. this[ measurement ] = 0;
  1936. } else {
  1937. // use option as an element
  1938. if ( typeof option === 'string' ) {
  1939. elem = this.element.querySelector( option );
  1940. } else if ( utils.isElement( option ) ) {
  1941. elem = option;
  1942. }
  1943. // use size of element, if element
  1944. this[ measurement ] = elem ? getSize( elem )[ size ] : option;
  1945. }
  1946. };
  1947. /**
  1948. * layout a collection of item elements
  1949. * @api public
  1950. */
  1951. Outlayer.prototype.layoutItems = function( items, isInstant ) {
  1952. items = this._getItemsForLayout( items );
  1953. this._layoutItems( items, isInstant );
  1954. this._postLayout();
  1955. };
  1956. /**
  1957. * get the items to be laid out
  1958. * you may want to skip over some items
  1959. * @param {Array} items
  1960. * @returns {Array} items
  1961. */
  1962. Outlayer.prototype._getItemsForLayout = function( items ) {
  1963. var layoutItems = [];
  1964. for ( var i=0, len = items.length; i < len; i++ ) {
  1965. var item = items[i];
  1966. if ( !item.isIgnored ) {
  1967. layoutItems.push( item );
  1968. }
  1969. }
  1970. return layoutItems;
  1971. };
  1972. /**
  1973. * layout items
  1974. * @param {Array} items
  1975. * @param {Boolean} isInstant
  1976. */
  1977. Outlayer.prototype._layoutItems = function( items, isInstant ) {
  1978. this._emitCompleteOnItems( 'layout', items );
  1979. if ( !items || !items.length ) {
  1980. // no items, emit event with empty array
  1981. return;
  1982. }
  1983. var queue = [];
  1984. for ( var i=0, len = items.length; i < len; i++ ) {
  1985. var item = items[i];
  1986. // get x/y object from method
  1987. var position = this._getItemLayoutPosition( item );
  1988. // enqueue
  1989. position.item = item;
  1990. position.isInstant = isInstant || item.isLayoutInstant;
  1991. queue.push( position );
  1992. }
  1993. this._processLayoutQueue( queue );
  1994. };
  1995. /**
  1996. * get item layout position
  1997. * @param {Outlayer.Item} item
  1998. * @returns {Object} x and y position
  1999. */
  2000. Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
  2001. return {
  2002. x: 0,
  2003. y: 0
  2004. };
  2005. };
  2006. /**
  2007. * iterate over array and position each item
  2008. * Reason being - separating this logic prevents 'layout invalidation'
  2009. * thx @paul_irish
  2010. * @param {Array} queue
  2011. */
  2012. Outlayer.prototype._processLayoutQueue = function( queue ) {
  2013. for ( var i=0, len = queue.length; i < len; i++ ) {
  2014. var obj = queue[i];
  2015. this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
  2016. }
  2017. };
  2018. /**
  2019. * Sets position of item in DOM
  2020. * @param {Outlayer.Item} item
  2021. * @param {Number} x - horizontal position
  2022. * @param {Number} y - vertical position
  2023. * @param {Boolean} isInstant - disables transitions
  2024. */
  2025. Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
  2026. if ( isInstant ) {
  2027. // if not transition, just set CSS
  2028. item.goTo( x, y );
  2029. } else {
  2030. item.moveTo( x, y );
  2031. }
  2032. };
  2033. /**
  2034. * Any logic you want to do after each layout,
  2035. * i.e. size the container
  2036. */
  2037. Outlayer.prototype._postLayout = function() {
  2038. this.resizeContainer();
  2039. };
  2040. Outlayer.prototype.resizeContainer = function() {
  2041. if ( !this.options.isResizingContainer ) {
  2042. return;
  2043. }
  2044. var size = this._getContainerSize();
  2045. if ( size ) {
  2046. this._setContainerMeasure( size.width, true );
  2047. this._setContainerMeasure( size.height, false );
  2048. }
  2049. };
  2050. /**
  2051. * Sets width or height of container if returned
  2052. * @returns {Object} size
  2053. * @param {Number} width
  2054. * @param {Number} height
  2055. */
  2056. Outlayer.prototype._getContainerSize = noop;
  2057. /**
  2058. * @param {Number} measure - size of width or height
  2059. * @param {Boolean} isWidth
  2060. */
  2061. Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
  2062. if ( measure === undefined ) {
  2063. return;
  2064. }
  2065. var elemSize = this.size;
  2066. // add padding and border width if border box
  2067. if ( elemSize.isBorderBox ) {
  2068. measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
  2069. elemSize.borderLeftWidth + elemSize.borderRightWidth :
  2070. elemSize.paddingBottom + elemSize.paddingTop +
  2071. elemSize.borderTopWidth + elemSize.borderBottomWidth;
  2072. }
  2073. measure = Math.max( measure, 0 );
  2074. this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
  2075. };
  2076. /**
  2077. * emit eventComplete on a collection of items events
  2078. * @param {String} eventName
  2079. * @param {Array} items - Outlayer.Items
  2080. */
  2081. Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) {
  2082. var _this = this;
  2083. function onComplete() {
  2084. _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
  2085. }
  2086. var count = items.length;
  2087. if ( !items || !count ) {
  2088. onComplete();
  2089. return;
  2090. }
  2091. var doneCount = 0;
  2092. function tick() {
  2093. doneCount++;
  2094. if ( doneCount === count ) {
  2095. onComplete();
  2096. }
  2097. }
  2098. // bind callback
  2099. for ( var i=0, len = items.length; i < len; i++ ) {
  2100. var item = items[i];
  2101. item.once( eventName, tick );
  2102. }
  2103. };
  2104. /**
  2105. * emits events via eventEmitter and jQuery events
  2106. * @param {String} type - name of event
  2107. * @param {Event} event - original event
  2108. * @param {Array} args - extra arguments
  2109. */
  2110. Outlayer.prototype.dispatchEvent = function( type, event, args ) {
  2111. // add original event to arguments
  2112. var emitArgs = event ? [ event ].concat( args ) : args;
  2113. this.emitEvent( type, emitArgs );
  2114. if ( jQuery ) {
  2115. // set this.$element
  2116. this.$element = this.$element || jQuery( this.element );
  2117. if ( event ) {
  2118. // create jQuery event
  2119. var $event = jQuery.Event( event );
  2120. $event.type = type;
  2121. this.$element.trigger( $event, args );
  2122. } else {
  2123. // just trigger with type if no event available
  2124. this.$element.trigger( type, args );
  2125. }
  2126. }
  2127. };
  2128. // -------------------------- ignore & stamps -------------------------- //
  2129. /**
  2130. * keep item in collection, but do not lay it out
  2131. * ignored items do not get skipped in layout
  2132. * @param {Element} elem
  2133. */
  2134. Outlayer.prototype.ignore = function( elem ) {
  2135. var item = this.getItem( elem );
  2136. if ( item ) {
  2137. item.isIgnored = true;
  2138. }
  2139. };
  2140. /**
  2141. * return item to layout collection
  2142. * @param {Element} elem
  2143. */
  2144. Outlayer.prototype.unignore = function( elem ) {
  2145. var item = this.getItem( elem );
  2146. if ( item ) {
  2147. delete item.isIgnored;
  2148. }
  2149. };
  2150. /**
  2151. * adds elements to stamps
  2152. * @param {NodeList, Array, Element, or String} elems
  2153. */
  2154. Outlayer.prototype.stamp = function( elems ) {
  2155. elems = this._find( elems );
  2156. if ( !elems ) {
  2157. return;
  2158. }
  2159. this.stamps = this.stamps.concat( elems );
  2160. // ignore
  2161. for ( var i=0, len = elems.length; i < len; i++ ) {
  2162. var elem = elems[i];
  2163. this.ignore( elem );
  2164. }
  2165. };
  2166. /**
  2167. * removes elements to stamps
  2168. * @param {NodeList, Array, or Element} elems
  2169. */
  2170. Outlayer.prototype.unstamp = function( elems ) {
  2171. elems = this._find( elems );
  2172. if ( !elems ){
  2173. return;
  2174. }
  2175. for ( var i=0, len = elems.length; i < len; i++ ) {
  2176. var elem = elems[i];
  2177. // filter out removed stamp elements
  2178. utils.removeFrom( this.stamps, elem );
  2179. this.unignore( elem );
  2180. }
  2181. };
  2182. /**
  2183. * finds child elements
  2184. * @param {NodeList, Array, Element, or String} elems
  2185. * @returns {Array} elems
  2186. */
  2187. Outlayer.prototype._find = function( elems ) {
  2188. if ( !elems ) {
  2189. return;
  2190. }
  2191. // if string, use argument as selector string
  2192. if ( typeof elems === 'string' ) {
  2193. elems = this.element.querySelectorAll( elems );
  2194. }
  2195. elems = utils.makeArray( elems );
  2196. return elems;
  2197. };
  2198. Outlayer.prototype._manageStamps = function() {
  2199. if ( !this.stamps || !this.stamps.length ) {
  2200. return;
  2201. }
  2202. this._getBoundingRect();
  2203. for ( var i=0, len = this.stamps.length; i < len; i++ ) {
  2204. var stamp = this.stamps[i];
  2205. this._manageStamp( stamp );
  2206. }
  2207. };
  2208. // update boundingLeft / Top
  2209. Outlayer.prototype._getBoundingRect = function() {
  2210. // get bounding rect for container element
  2211. var boundingRect = this.element.getBoundingClientRect();
  2212. var size = this.size;
  2213. this._boundingRect = {
  2214. left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
  2215. top: boundingRect.top + size.paddingTop + size.borderTopWidth,
  2216. right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
  2217. bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
  2218. };
  2219. };
  2220. /**
  2221. * @param {Element} stamp
  2222. **/
  2223. Outlayer.prototype._manageStamp = noop;
  2224. /**
  2225. * get x/y position of element relative to container element
  2226. * @param {Element} elem
  2227. * @returns {Object} offset - has left, top, right, bottom
  2228. */
  2229. Outlayer.prototype._getElementOffset = function( elem ) {
  2230. var boundingRect = elem.getBoundingClientRect();
  2231. var thisRect = this._boundingRect;
  2232. var size = getSize( elem );
  2233. var offset = {
  2234. left: boundingRect.left - thisRect.left - size.marginLeft,
  2235. top: boundingRect.top - thisRect.top - size.marginTop,
  2236. right: thisRect.right - boundingRect.right - size.marginRight,
  2237. bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
  2238. };
  2239. return offset;
  2240. };
  2241. // -------------------------- resize -------------------------- //
  2242. // enable event handlers for listeners
  2243. // i.e. resize -> onresize
  2244. Outlayer.prototype.handleEvent = function( event ) {
  2245. var method = 'on' + event.type;
  2246. if ( this[ method ] ) {
  2247. this[ method ]( event );
  2248. }
  2249. };
  2250. /**
  2251. * Bind layout to window resizing
  2252. */
  2253. Outlayer.prototype.bindResize = function() {
  2254. // bind just one listener
  2255. if ( this.isResizeBound ) {
  2256. return;
  2257. }
  2258. eventie.bind( window, 'resize', this );
  2259. this.isResizeBound = true;
  2260. };
  2261. /**
  2262. * Unbind layout to window resizing
  2263. */
  2264. Outlayer.prototype.unbindResize = function() {
  2265. if ( this.isResizeBound ) {
  2266. eventie.unbind( window, 'resize', this );
  2267. }
  2268. this.isResizeBound = false;
  2269. };
  2270. // original debounce by John Hann
  2271. // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
  2272. // this fires every resize
  2273. Outlayer.prototype.onresize = function() {
  2274. if ( this.resizeTimeout ) {
  2275. clearTimeout( this.resizeTimeout );
  2276. }
  2277. var _this = this;
  2278. function delayed() {
  2279. _this.resize();
  2280. delete _this.resizeTimeout;
  2281. }
  2282. this.resizeTimeout = setTimeout( delayed, 100 );
  2283. };
  2284. // debounced, layout on resize
  2285. Outlayer.prototype.resize = function() {
  2286. // don't trigger if size did not change
  2287. // or if resize was unbound. See #9
  2288. if ( !this.isResizeBound || !this.needsResizeLayout() ) {
  2289. return;
  2290. }
  2291. this.layout();
  2292. };
  2293. /**
  2294. * check if layout is needed post layout
  2295. * @returns Boolean
  2296. */
  2297. Outlayer.prototype.needsResizeLayout = function() {
  2298. var size = getSize( this.element );
  2299. // check that this.size and size are there
  2300. // IE8 triggers resize on body size change, so they might not be
  2301. var hasSizes = this.size && size;
  2302. return hasSizes && size.innerWidth !== this.size.innerWidth;
  2303. };
  2304. // -------------------------- methods -------------------------- //
  2305. /**
  2306. * add items to Outlayer instance
  2307. * @param {Array or NodeList or Element} elems
  2308. * @returns {Array} items - Outlayer.Items
  2309. **/
  2310. Outlayer.prototype.addItems = function( elems ) {
  2311. var items = this._itemize( elems );
  2312. // add items to collection
  2313. if ( items.length ) {
  2314. this.items = this.items.concat( items );
  2315. }
  2316. return items;
  2317. };
  2318. /**
  2319. * Layout newly-appended item elements
  2320. * @param {Array or NodeList or Element} elems
  2321. */
  2322. Outlayer.prototype.appended = function( elems ) {
  2323. var items = this.addItems( elems );
  2324. if ( !items.length ) {
  2325. return;
  2326. }
  2327. // layout and reveal just the new items
  2328. this.layoutItems( items, true );
  2329. this.reveal( items );
  2330. };
  2331. /**
  2332. * Layout prepended elements
  2333. * @param {Array or NodeList or Element} elems
  2334. */
  2335. Outlayer.prototype.prepended = function( elems ) {
  2336. var items = this._itemize( elems );
  2337. if ( !items.length ) {
  2338. return;
  2339. }
  2340. // add items to beginning of collection
  2341. var previousItems = this.items.slice(0);
  2342. this.items = items.concat( previousItems );
  2343. // start new layout
  2344. this._resetLayout();
  2345. this._manageStamps();
  2346. // layout new stuff without transition
  2347. this.layoutItems( items, true );
  2348. this.reveal( items );
  2349. // layout previous items
  2350. this.layoutItems( previousItems );
  2351. };
  2352. /**
  2353. * reveal a collection of items
  2354. * @param {Array of Outlayer.Items} items
  2355. */
  2356. Outlayer.prototype.reveal = function( items ) {
  2357. this._emitCompleteOnItems( 'reveal', items );
  2358. var len = items && items.length;
  2359. for ( var i=0; len && i < len; i++ ) {
  2360. var item = items[i];
  2361. item.reveal();
  2362. }
  2363. };
  2364. /**
  2365. * hide a collection of items
  2366. * @param {Array of Outlayer.Items} items
  2367. */
  2368. Outlayer.prototype.hide = function( items ) {
  2369. this._emitCompleteOnItems( 'hide', items );
  2370. var len = items && items.length;
  2371. for ( var i=0; len && i < len; i++ ) {
  2372. var item = items[i];
  2373. item.hide();
  2374. }
  2375. };
  2376. /**
  2377. * reveal item elements
  2378. * @param {Array}, {Element}, {NodeList} items
  2379. */
  2380. Outlayer.prototype.revealItemElements = function( elems ) {
  2381. var items = this.getItems( elems );
  2382. this.reveal( items );
  2383. };
  2384. /**
  2385. * hide item elements
  2386. * @param {Array}, {Element}, {NodeList} items
  2387. */
  2388. Outlayer.prototype.hideItemElements = function( elems ) {
  2389. var items = this.getItems( elems );
  2390. this.hide( items );
  2391. };
  2392. /**
  2393. * get Outlayer.Item, given an Element
  2394. * @param {Element} elem
  2395. * @param {Function} callback
  2396. * @returns {Outlayer.Item} item
  2397. */
  2398. Outlayer.prototype.getItem = function( elem ) {
  2399. // loop through items to get the one that matches
  2400. for ( var i=0, len = this.items.length; i < len; i++ ) {
  2401. var item = this.items[i];
  2402. if ( item.element === elem ) {
  2403. // return item
  2404. return item;
  2405. }
  2406. }
  2407. };
  2408. /**
  2409. * get collection of Outlayer.Items, given Elements
  2410. * @param {Array} elems
  2411. * @returns {Array} items - Outlayer.Items
  2412. */
  2413. Outlayer.prototype.getItems = function( elems ) {
  2414. elems = utils.makeArray( elems );
  2415. var items = [];
  2416. for ( var i=0, len = elems.length; i < len; i++ ) {
  2417. var elem = elems[i];
  2418. var item = this.getItem( elem );
  2419. if ( item ) {
  2420. items.push( item );
  2421. }
  2422. }
  2423. return items;
  2424. };
  2425. /**
  2426. * remove element(s) from instance and DOM
  2427. * @param {Array or NodeList or Element} elems
  2428. */
  2429. Outlayer.prototype.remove = function( elems ) {
  2430. var removeItems = this.getItems( elems );
  2431. this._emitCompleteOnItems( 'remove', removeItems );
  2432. // bail if no items to remove
  2433. if ( !removeItems || !removeItems.length ) {
  2434. return;
  2435. }
  2436. for ( var i=0, len = removeItems.length; i < len; i++ ) {
  2437. var item = removeItems[i];
  2438. item.remove();
  2439. // remove item from collection
  2440. utils.removeFrom( this.items, item );
  2441. }
  2442. };
  2443. // ----- destroy ----- //
  2444. // remove and disable Outlayer instance
  2445. Outlayer.prototype.destroy = function() {
  2446. // clean up dynamic styles
  2447. var style = this.element.style;
  2448. style.height = '';
  2449. style.position = '';
  2450. style.width = '';
  2451. // destroy items
  2452. for ( var i=0, len = this.items.length; i < len; i++ ) {
  2453. var item = this.items[i];
  2454. item.destroy();
  2455. }
  2456. this.unbindResize();
  2457. var id = this.element.outlayerGUID;
  2458. delete instances[ id ]; // remove reference to instance by id
  2459. delete this.element.outlayerGUID;
  2460. // remove data for jQuery
  2461. if ( jQuery ) {
  2462. jQuery.removeData( this.element, this.constructor.namespace );
  2463. }
  2464. };
  2465. // -------------------------- data -------------------------- //
  2466. /**
  2467. * get Outlayer instance from element
  2468. * @param {Element} elem
  2469. * @returns {Outlayer}
  2470. */
  2471. Outlayer.data = function( elem ) {
  2472. elem = utils.getQueryElement( elem );
  2473. var id = elem && elem.outlayerGUID;
  2474. return id && instances[ id ];
  2475. };
  2476. // -------------------------- create Outlayer class -------------------------- //
  2477. /**
  2478. * create a layout class
  2479. * @param {String} namespace
  2480. */
  2481. Outlayer.create = function( namespace, options ) {
  2482. // sub-class Outlayer
  2483. function Layout() {
  2484. Outlayer.apply( this, arguments );
  2485. }
  2486. // inherit Outlayer prototype, use Object.create if there
  2487. if ( Object.create ) {
  2488. Layout.prototype = Object.create( Outlayer.prototype );
  2489. } else {
  2490. utils.extend( Layout.prototype, Outlayer.prototype );
  2491. }
  2492. // set contructor, used for namespace and Item
  2493. Layout.prototype.constructor = Layout;
  2494. Layout.defaults = utils.extend( {}, Outlayer.defaults );
  2495. // apply new options
  2496. utils.extend( Layout.defaults, options );
  2497. // keep prototype.settings for backwards compatibility (Packery v1.2.0)
  2498. Layout.prototype.settings = {};
  2499. Layout.namespace = namespace;
  2500. Layout.data = Outlayer.data;
  2501. // sub-class Item
  2502. Layout.Item = function LayoutItem() {
  2503. Item.apply( this, arguments );
  2504. };
  2505. Layout.Item.prototype = new Item();
  2506. // -------------------------- declarative -------------------------- //
  2507. utils.htmlInit( Layout, namespace );
  2508. // -------------------------- jQuery bridge -------------------------- //
  2509. // make into jQuery plugin
  2510. if ( jQuery && jQuery.bridget ) {
  2511. jQuery.bridget( namespace, Layout );
  2512. }
  2513. return Layout;
  2514. };
  2515. // ----- fin ----- //
  2516. // back in global
  2517. Outlayer.Item = Item;
  2518. return Outlayer;
  2519. }));
  2520. /*!
  2521. * Masonry v3.3.2
  2522. * Cascading grid layout library
  2523. * http://masonry.desandro.com
  2524. * MIT License
  2525. * by David DeSandro
  2526. */
  2527. ( function( window, factory ) {
  2528. // universal module definition
  2529. if ( typeof define === 'function' && define.amd ) {
  2530. // AMD
  2531. define( [
  2532. 'outlayer/outlayer',
  2533. 'get-size/get-size',
  2534. 'fizzy-ui-utils/utils'
  2535. ],
  2536. factory );
  2537. } else if ( typeof exports === 'object' ) {
  2538. // CommonJS
  2539. module.exports = factory(
  2540. require('outlayer'),
  2541. require('get-size'),
  2542. require('fizzy-ui-utils')
  2543. );
  2544. } else {
  2545. // browser global
  2546. window.Masonry = factory(
  2547. window.Outlayer,
  2548. window.getSize,
  2549. window.fizzyUIUtils
  2550. );
  2551. }
  2552. }( window, function factory( Outlayer, getSize, utils ) {
  2553. // -------------------------- masonryDefinition -------------------------- //
  2554. // create an Outlayer layout class
  2555. var Masonry = Outlayer.create('masonry');
  2556. Masonry.prototype._resetLayout = function() {
  2557. this.getSize();
  2558. this._getMeasurement( 'columnWidth', 'outerWidth' );
  2559. this._getMeasurement( 'gutter', 'outerWidth' );
  2560. this.measureColumns();
  2561. // reset column Y
  2562. var i = this.cols;
  2563. this.colYs = [];
  2564. while (i--) {
  2565. this.colYs.push( 0 );
  2566. }
  2567. this.maxY = 0;
  2568. };
  2569. Masonry.prototype.measureColumns = function() {
  2570. this.getContainerWidth();
  2571. // if columnWidth is 0, default to outerWidth of first item
  2572. if ( !this.columnWidth ) {
  2573. var firstItem = this.items[0];
  2574. var firstItemElem = firstItem && firstItem.element;
  2575. // columnWidth fall back to item of first element
  2576. this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
  2577. // if first elem has no width, default to size of container
  2578. this.containerWidth;
  2579. }
  2580. var columnWidth = this.columnWidth += this.gutter;
  2581. // calculate columns
  2582. var containerWidth = this.containerWidth + this.gutter;
  2583. var cols = containerWidth / columnWidth;
  2584. // fix rounding errors, typically with gutters
  2585. var excess = columnWidth - containerWidth % columnWidth;
  2586. // if overshoot is less than a pixel, round up, otherwise floor it
  2587. var mathMethod = excess && excess < 1 ? 'round' : 'floor';
  2588. cols = Math[ mathMethod ]( cols );
  2589. this.cols = Math.max( cols, 1 );
  2590. };
  2591. Masonry.prototype.getContainerWidth = function() {
  2592. // container is parent if fit width
  2593. var container = this.options.isFitWidth ? this.element.parentNode : this.element;
  2594. // check that this.size and size are there
  2595. // IE8 triggers resize on body size change, so they might not be
  2596. var size = getSize( container );
  2597. this.containerWidth = size && size.innerWidth;
  2598. };
  2599. Masonry.prototype._getItemLayoutPosition = function( item ) {
  2600. item.getSize();
  2601. // how many columns does this brick span
  2602. var remainder = item.size.outerWidth % this.columnWidth;
  2603. var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
  2604. // round if off by 1 pixel, otherwise use ceil
  2605. var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
  2606. colSpan = Math.min( colSpan, this.cols );
  2607. var colGroup = this._getColGroup( colSpan );
  2608. // get the minimum Y value from the columns
  2609. var minimumY = Math.min.apply( Math, colGroup );
  2610. var shortColIndex = utils.indexOf( colGroup, minimumY );
  2611. // position the brick
  2612. var position = {
  2613. x: this.columnWidth * shortColIndex,
  2614. y: minimumY
  2615. };
  2616. // apply setHeight to necessary columns
  2617. var setHeight = minimumY + item.size.outerHeight;
  2618. var setSpan = this.cols + 1 - colGroup.length;
  2619. for ( var i = 0; i < setSpan; i++ ) {
  2620. this.colYs[ shortColIndex + i ] = setHeight;
  2621. }
  2622. return position;
  2623. };
  2624. /**
  2625. * @param {Number} colSpan - number of columns the element spans
  2626. * @returns {Array} colGroup
  2627. */
  2628. Masonry.prototype._getColGroup = function( colSpan ) {
  2629. if ( colSpan < 2 ) {
  2630. // if brick spans only one column, use all the column Ys
  2631. return this.colYs;
  2632. }
  2633. var colGroup = [];
  2634. // how many different places could this brick fit horizontally
  2635. var groupCount = this.cols + 1 - colSpan;
  2636. // for each group potential horizontal position
  2637. for ( var i = 0; i < groupCount; i++ ) {
  2638. // make an array of colY values for that one group
  2639. var groupColYs = this.colYs.slice( i, i + colSpan );
  2640. // and get the max value of the array
  2641. colGroup[i] = Math.max.apply( Math, groupColYs );
  2642. }
  2643. return colGroup;
  2644. };
  2645. Masonry.prototype._manageStamp = function( stamp ) {
  2646. var stampSize = getSize( stamp );
  2647. var offset = this._getElementOffset( stamp );
  2648. // get the columns that this stamp affects
  2649. var firstX = this.options.isOriginLeft ? offset.left : offset.right;
  2650. var lastX = firstX + stampSize.outerWidth;
  2651. var firstCol = Math.floor( firstX / this.columnWidth );
  2652. firstCol = Math.max( 0, firstCol );
  2653. var lastCol = Math.floor( lastX / this.columnWidth );
  2654. // lastCol should not go over if multiple of columnWidth #425
  2655. lastCol -= lastX % this.columnWidth ? 0 : 1;
  2656. lastCol = Math.min( this.cols - 1, lastCol );
  2657. // set colYs to bottom of the stamp
  2658. var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
  2659. stampSize.outerHeight;
  2660. for ( var i = firstCol; i <= lastCol; i++ ) {
  2661. this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
  2662. }
  2663. };
  2664. Masonry.prototype._getContainerSize = function() {
  2665. this.maxY = Math.max.apply( Math, this.colYs );
  2666. var size = {
  2667. height: this.maxY
  2668. };
  2669. if ( this.options.isFitWidth ) {
  2670. size.width = this._getContainerFitWidth();
  2671. }
  2672. return size;
  2673. };
  2674. Masonry.prototype._getContainerFitWidth = function() {
  2675. var unusedCols = 0;
  2676. // count unused columns
  2677. var i = this.cols;
  2678. while ( --i ) {
  2679. if ( this.colYs[i] !== 0 ) {
  2680. break;
  2681. }
  2682. unusedCols++;
  2683. }
  2684. // fit container to columns that have been used
  2685. return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
  2686. };
  2687. Masonry.prototype.needsResizeLayout = function() {
  2688. var previousWidth = this.containerWidth;
  2689. this.getContainerWidth();
  2690. return previousWidth !== this.containerWidth;
  2691. };
  2692. return Masonry;
  2693. }));