packery.pkgd.js 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089
  1. /*!
  2. * Packery PACKAGED v1.4.3
  3. * bin-packing layout library
  4. *
  5. * Licensed GPLv3 for open source use
  6. * or Flickity Commercial License for commercial use
  7. *
  8. * http://packery.metafizzy.co
  9. * Copyright 2015 Metafizzy
  10. */
  11. /**
  12. * Bridget makes jQuery widgets
  13. * v1.1.0
  14. * MIT license
  15. */
  16. ( function( window ) {
  17. // -------------------------- utils -------------------------- //
  18. var slice = Array.prototype.slice;
  19. function noop() {}
  20. // -------------------------- definition -------------------------- //
  21. function defineBridget( $ ) {
  22. // bail if no jQuery
  23. if ( !$ ) {
  24. return;
  25. }
  26. // -------------------------- addOptionMethod -------------------------- //
  27. /**
  28. * adds option method -> $().plugin('option', {...})
  29. * @param {Function} PluginClass - constructor class
  30. */
  31. function addOptionMethod( PluginClass ) {
  32. // don't overwrite original option method
  33. if ( PluginClass.prototype.option ) {
  34. return;
  35. }
  36. // option setter
  37. PluginClass.prototype.option = function( opts ) {
  38. // bail out if not an object
  39. if ( !$.isPlainObject( opts ) ){
  40. return;
  41. }
  42. this.options = $.extend( true, this.options, opts );
  43. };
  44. }
  45. // -------------------------- plugin bridge -------------------------- //
  46. // helper function for logging errors
  47. // $.error breaks jQuery chaining
  48. var logError = typeof console === 'undefined' ? noop :
  49. function( message ) {
  50. console.error( message );
  51. };
  52. /**
  53. * jQuery plugin bridge, access methods like $elem.plugin('method')
  54. * @param {String} namespace - plugin name
  55. * @param {Function} PluginClass - constructor class
  56. */
  57. function bridge( namespace, PluginClass ) {
  58. // add to jQuery fn namespace
  59. $.fn[ namespace ] = function( options ) {
  60. if ( typeof options === 'string' ) {
  61. // call plugin method when first argument is a string
  62. // get arguments for method
  63. var args = slice.call( arguments, 1 );
  64. for ( var i=0, len = this.length; i < len; i++ ) {
  65. var elem = this[i];
  66. var instance = $.data( elem, namespace );
  67. if ( !instance ) {
  68. logError( "cannot call methods on " + namespace + " prior to initialization; " +
  69. "attempted to call '" + options + "'" );
  70. continue;
  71. }
  72. if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
  73. logError( "no such method '" + options + "' for " + namespace + " instance" );
  74. continue;
  75. }
  76. // trigger method with arguments
  77. var returnValue = instance[ options ].apply( instance, args );
  78. // break look and return first value if provided
  79. if ( returnValue !== undefined ) {
  80. return returnValue;
  81. }
  82. }
  83. // return this if no return value
  84. return this;
  85. } else {
  86. return this.each( function() {
  87. var instance = $.data( this, namespace );
  88. if ( instance ) {
  89. // apply options & init
  90. instance.option( options );
  91. instance._init();
  92. } else {
  93. // initialize new instance
  94. instance = new PluginClass( this, options );
  95. $.data( this, namespace, instance );
  96. }
  97. });
  98. }
  99. };
  100. }
  101. // -------------------------- bridget -------------------------- //
  102. /**
  103. * converts a Prototypical class into a proper jQuery plugin
  104. * the class must have a ._init method
  105. * @param {String} namespace - plugin name, used in $().pluginName
  106. * @param {Function} PluginClass - constructor class
  107. */
  108. $.bridget = function( namespace, PluginClass ) {
  109. addOptionMethod( PluginClass );
  110. bridge( namespace, PluginClass );
  111. };
  112. return $.bridget;
  113. }
  114. // transport
  115. if ( typeof define === 'function' && define.amd ) {
  116. // AMD
  117. define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
  118. } else if ( typeof exports === 'object' ) {
  119. defineBridget( require('jquery') );
  120. } else {
  121. // get jquery from browser global
  122. defineBridget( window.jQuery );
  123. }
  124. defineBridget( window.jQuery );
  125. })( window );
  126. /*!
  127. * classie v1.0.1
  128. * class helper functions
  129. * from bonzo https://github.com/ded/bonzo
  130. * MIT license
  131. *
  132. * classie.has( elem, 'my-class' ) -> true/false
  133. * classie.add( elem, 'my-new-class' )
  134. * classie.remove( elem, 'my-unwanted-class' )
  135. * classie.toggle( elem, 'my-class' )
  136. */
  137. /*jshint browser: true, strict: true, undef: true, unused: true */
  138. /*global define: false, module: false */
  139. ( function( window ) {
  140. // class helper functions from bonzo https://github.com/ded/bonzo
  141. function classReg( className ) {
  142. return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
  143. }
  144. // classList support for class management
  145. // altho to be fair, the api sucks because it won't accept multiple classes at once
  146. var hasClass, addClass, removeClass;
  147. if ( 'classList' in document.documentElement ) {
  148. hasClass = function( elem, c ) {
  149. return elem.classList.contains( c );
  150. };
  151. addClass = function( elem, c ) {
  152. elem.classList.add( c );
  153. };
  154. removeClass = function( elem, c ) {
  155. elem.classList.remove( c );
  156. };
  157. }
  158. else {
  159. hasClass = function( elem, c ) {
  160. return classReg( c ).test( elem.className );
  161. };
  162. addClass = function( elem, c ) {
  163. if ( !hasClass( elem, c ) ) {
  164. elem.className = elem.className + ' ' + c;
  165. }
  166. };
  167. removeClass = function( elem, c ) {
  168. elem.className = elem.className.replace( classReg( c ), ' ' );
  169. };
  170. }
  171. function toggleClass( elem, c ) {
  172. var fn = hasClass( elem, c ) ? removeClass : addClass;
  173. fn( elem, c );
  174. }
  175. var classie = {
  176. // full names
  177. hasClass: hasClass,
  178. addClass: addClass,
  179. removeClass: removeClass,
  180. toggleClass: toggleClass,
  181. // short names
  182. has: hasClass,
  183. add: addClass,
  184. remove: removeClass,
  185. toggle: toggleClass
  186. };
  187. // transport
  188. if ( typeof define === 'function' && define.amd ) {
  189. // AMD
  190. define( 'classie/classie',classie );
  191. } else if ( typeof exports === 'object' ) {
  192. // CommonJS
  193. module.exports = classie;
  194. } else {
  195. // browser global
  196. window.classie = classie;
  197. }
  198. })( window );
  199. /*!
  200. * getStyleProperty v1.0.4
  201. * original by kangax
  202. * http://perfectionkills.com/feature-testing-css-properties/
  203. * MIT license
  204. */
  205. /*jshint browser: true, strict: true, undef: true */
  206. /*global define: false, exports: false, module: false */
  207. ( function( window ) {
  208. var prefixes = 'Webkit Moz ms Ms O'.split(' ');
  209. var docElemStyle = document.documentElement.style;
  210. function getStyleProperty( propName ) {
  211. if ( !propName ) {
  212. return;
  213. }
  214. // test standard property first
  215. if ( typeof docElemStyle[ propName ] === 'string' ) {
  216. return propName;
  217. }
  218. // capitalize
  219. propName = propName.charAt(0).toUpperCase() + propName.slice(1);
  220. // test vendor specific properties
  221. var prefixed;
  222. for ( var i=0, len = prefixes.length; i < len; i++ ) {
  223. prefixed = prefixes[i] + propName;
  224. if ( typeof docElemStyle[ prefixed ] === 'string' ) {
  225. return prefixed;
  226. }
  227. }
  228. }
  229. // transport
  230. if ( typeof define === 'function' && define.amd ) {
  231. // AMD
  232. define( 'get-style-property/get-style-property',[],function() {
  233. return getStyleProperty;
  234. });
  235. } else if ( typeof exports === 'object' ) {
  236. // CommonJS for Component
  237. module.exports = getStyleProperty;
  238. } else {
  239. // browser global
  240. window.getStyleProperty = getStyleProperty;
  241. }
  242. })( window );
  243. /*!
  244. * getSize v1.2.2
  245. * measure size of elements
  246. * MIT license
  247. */
  248. /*jshint browser: true, strict: true, undef: true, unused: true */
  249. /*global define: false, exports: false, require: false, module: false, console: false */
  250. ( function( window, undefined ) {
  251. // -------------------------- helpers -------------------------- //
  252. // get a number from a string, not a percentage
  253. function getStyleSize( value ) {
  254. var num = parseFloat( value );
  255. // not a percent like '100%', and a number
  256. var isValid = value.indexOf('%') === -1 && !isNaN( num );
  257. return isValid && num;
  258. }
  259. function noop() {}
  260. var logError = typeof console === 'undefined' ? noop :
  261. function( message ) {
  262. console.error( message );
  263. };
  264. // -------------------------- measurements -------------------------- //
  265. var measurements = [
  266. 'paddingLeft',
  267. 'paddingRight',
  268. 'paddingTop',
  269. 'paddingBottom',
  270. 'marginLeft',
  271. 'marginRight',
  272. 'marginTop',
  273. 'marginBottom',
  274. 'borderLeftWidth',
  275. 'borderRightWidth',
  276. 'borderTopWidth',
  277. 'borderBottomWidth'
  278. ];
  279. function getZeroSize() {
  280. var size = {
  281. width: 0,
  282. height: 0,
  283. innerWidth: 0,
  284. innerHeight: 0,
  285. outerWidth: 0,
  286. outerHeight: 0
  287. };
  288. for ( var i=0, len = measurements.length; i < len; i++ ) {
  289. var measurement = measurements[i];
  290. size[ measurement ] = 0;
  291. }
  292. return size;
  293. }
  294. function defineGetSize( getStyleProperty ) {
  295. // -------------------------- setup -------------------------- //
  296. var isSetup = false;
  297. var getStyle, boxSizingProp, isBoxSizeOuter;
  298. /**
  299. * setup vars and functions
  300. * do it on initial getSize(), rather than on script load
  301. * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  302. */
  303. function setup() {
  304. // setup once
  305. if ( isSetup ) {
  306. return;
  307. }
  308. isSetup = true;
  309. var getComputedStyle = window.getComputedStyle;
  310. getStyle = ( function() {
  311. var getStyleFn = getComputedStyle ?
  312. function( elem ) {
  313. return getComputedStyle( elem, null );
  314. } :
  315. function( elem ) {
  316. return elem.currentStyle;
  317. };
  318. return function getStyle( elem ) {
  319. var style = getStyleFn( elem );
  320. if ( !style ) {
  321. logError( 'Style returned ' + style +
  322. '. Are you running this code in a hidden iframe on Firefox? ' +
  323. 'See http://bit.ly/getsizebug1' );
  324. }
  325. return style;
  326. };
  327. })();
  328. // -------------------------- box sizing -------------------------- //
  329. boxSizingProp = getStyleProperty('boxSizing');
  330. /**
  331. * WebKit measures the outer-width on style.width on border-box elems
  332. * IE & Firefox measures the inner-width
  333. */
  334. if ( boxSizingProp ) {
  335. var div = document.createElement('div');
  336. div.style.width = '200px';
  337. div.style.padding = '1px 2px 3px 4px';
  338. div.style.borderStyle = 'solid';
  339. div.style.borderWidth = '1px 2px 3px 4px';
  340. div.style[ boxSizingProp ] = 'border-box';
  341. var body = document.body || document.documentElement;
  342. body.appendChild( div );
  343. var style = getStyle( div );
  344. isBoxSizeOuter = getStyleSize( style.width ) === 200;
  345. body.removeChild( div );
  346. }
  347. }
  348. // -------------------------- getSize -------------------------- //
  349. function getSize( elem ) {
  350. setup();
  351. // use querySeletor if elem is string
  352. if ( typeof elem === 'string' ) {
  353. elem = document.querySelector( elem );
  354. }
  355. // do not proceed on non-objects
  356. if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
  357. return;
  358. }
  359. var style = getStyle( elem );
  360. // if hidden, everything is 0
  361. if ( style.display === 'none' ) {
  362. return getZeroSize();
  363. }
  364. var size = {};
  365. size.width = elem.offsetWidth;
  366. size.height = elem.offsetHeight;
  367. var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
  368. style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
  369. // get all measurements
  370. for ( var i=0, len = measurements.length; i < len; i++ ) {
  371. var measurement = measurements[i];
  372. var value = style[ measurement ];
  373. value = mungeNonPixel( elem, value );
  374. var num = parseFloat( value );
  375. // any 'auto', 'medium' value will be 0
  376. size[ measurement ] = !isNaN( num ) ? num : 0;
  377. }
  378. var paddingWidth = size.paddingLeft + size.paddingRight;
  379. var paddingHeight = size.paddingTop + size.paddingBottom;
  380. var marginWidth = size.marginLeft + size.marginRight;
  381. var marginHeight = size.marginTop + size.marginBottom;
  382. var borderWidth = size.borderLeftWidth + size.borderRightWidth;
  383. var borderHeight = size.borderTopWidth + size.borderBottomWidth;
  384. var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
  385. // overwrite width and height if we can get it from style
  386. var styleWidth = getStyleSize( style.width );
  387. if ( styleWidth !== false ) {
  388. size.width = styleWidth +
  389. // add padding and border unless it's already including it
  390. ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
  391. }
  392. var styleHeight = getStyleSize( style.height );
  393. if ( styleHeight !== false ) {
  394. size.height = styleHeight +
  395. // add padding and border unless it's already including it
  396. ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
  397. }
  398. size.innerWidth = size.width - ( paddingWidth + borderWidth );
  399. size.innerHeight = size.height - ( paddingHeight + borderHeight );
  400. size.outerWidth = size.width + marginWidth;
  401. size.outerHeight = size.height + marginHeight;
  402. return size;
  403. }
  404. // IE8 returns percent values, not pixels
  405. // taken from jQuery's curCSS
  406. function mungeNonPixel( elem, value ) {
  407. // IE8 and has percent value
  408. if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
  409. return value;
  410. }
  411. var style = elem.style;
  412. // Remember the original values
  413. var left = style.left;
  414. var rs = elem.runtimeStyle;
  415. var rsLeft = rs && rs.left;
  416. // Put in the new values to get a computed value out
  417. if ( rsLeft ) {
  418. rs.left = elem.currentStyle.left;
  419. }
  420. style.left = value;
  421. value = style.pixelLeft;
  422. // Revert the changed values
  423. style.left = left;
  424. if ( rsLeft ) {
  425. rs.left = rsLeft;
  426. }
  427. return value;
  428. }
  429. return getSize;
  430. }
  431. // transport
  432. if ( typeof define === 'function' && define.amd ) {
  433. // AMD for RequireJS
  434. define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
  435. } else if ( typeof exports === 'object' ) {
  436. // CommonJS for Component
  437. module.exports = defineGetSize( require('desandro-get-style-property') );
  438. } else {
  439. // browser global
  440. window.getSize = defineGetSize( window.getStyleProperty );
  441. }
  442. })( window );
  443. /*!
  444. * eventie v1.0.6
  445. * event binding helper
  446. * eventie.bind( elem, 'click', myFn )
  447. * eventie.unbind( elem, 'click', myFn )
  448. * MIT license
  449. */
  450. /*jshint browser: true, undef: true, unused: true */
  451. /*global define: false, module: false */
  452. ( function( window ) {
  453. var docElem = document.documentElement;
  454. var bind = function() {};
  455. function getIEEvent( obj ) {
  456. var event = window.event;
  457. // add event.target
  458. event.target = event.target || event.srcElement || obj;
  459. return event;
  460. }
  461. if ( docElem.addEventListener ) {
  462. bind = function( obj, type, fn ) {
  463. obj.addEventListener( type, fn, false );
  464. };
  465. } else if ( docElem.attachEvent ) {
  466. bind = function( obj, type, fn ) {
  467. obj[ type + fn ] = fn.handleEvent ?
  468. function() {
  469. var event = getIEEvent( obj );
  470. fn.handleEvent.call( fn, event );
  471. } :
  472. function() {
  473. var event = getIEEvent( obj );
  474. fn.call( obj, event );
  475. };
  476. obj.attachEvent( "on" + type, obj[ type + fn ] );
  477. };
  478. }
  479. var unbind = function() {};
  480. if ( docElem.removeEventListener ) {
  481. unbind = function( obj, type, fn ) {
  482. obj.removeEventListener( type, fn, false );
  483. };
  484. } else if ( docElem.detachEvent ) {
  485. unbind = function( obj, type, fn ) {
  486. obj.detachEvent( "on" + type, obj[ type + fn ] );
  487. try {
  488. delete obj[ type + fn ];
  489. } catch ( err ) {
  490. // can't delete window object properties
  491. obj[ type + fn ] = undefined;
  492. }
  493. };
  494. }
  495. var eventie = {
  496. bind: bind,
  497. unbind: unbind
  498. };
  499. // ----- module definition ----- //
  500. if ( typeof define === 'function' && define.amd ) {
  501. // AMD
  502. define( 'eventie/eventie',eventie );
  503. } else if ( typeof exports === 'object' ) {
  504. // CommonJS
  505. module.exports = eventie;
  506. } else {
  507. // browser global
  508. window.eventie = eventie;
  509. }
  510. window.eventie = eventie;
  511. })( window );
  512. /*!
  513. * EventEmitter v4.2.11 - git.io/ee
  514. * Unlicense - http://unlicense.org/
  515. * Oliver Caldwell - http://oli.me.uk/
  516. * @preserve
  517. */
  518. ;(function () {
  519. /**
  520. * Class for managing events.
  521. * Can be extended to provide event functionality in other classes.
  522. *
  523. * @class EventEmitter Manages event registering and emitting.
  524. */
  525. function EventEmitter() {}
  526. // Shortcuts to improve speed and size
  527. var proto = EventEmitter.prototype;
  528. var exports = this;
  529. var originalGlobalValue = exports.EventEmitter;
  530. /**
  531. * Finds the index of the listener for the event in its storage array.
  532. *
  533. * @param {Function[]} listeners Array of listeners to search through.
  534. * @param {Function} listener Method to look for.
  535. * @return {Number} Index of the specified listener, -1 if not found
  536. * @api private
  537. */
  538. function indexOfListener(listeners, listener) {
  539. var i = listeners.length;
  540. while (i--) {
  541. if (listeners[i].listener === listener) {
  542. return i;
  543. }
  544. }
  545. return -1;
  546. }
  547. /**
  548. * Alias a method while keeping the context correct, to allow for overwriting of target method.
  549. *
  550. * @param {String} name The name of the target method.
  551. * @return {Function} The aliased method
  552. * @api private
  553. */
  554. function alias(name) {
  555. return function aliasClosure() {
  556. return this[name].apply(this, arguments);
  557. };
  558. }
  559. /**
  560. * Returns the listener array for the specified event.
  561. * Will initialise the event object and listener arrays if required.
  562. * 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.
  563. * Each property in the object response is an array of listener functions.
  564. *
  565. * @param {String|RegExp} evt Name of the event to return the listeners from.
  566. * @return {Function[]|Object} All listener functions for the event.
  567. */
  568. proto.getListeners = function getListeners(evt) {
  569. var events = this._getEvents();
  570. var response;
  571. var key;
  572. // Return a concatenated array of all matching events if
  573. // the selector is a regular expression.
  574. if (evt instanceof RegExp) {
  575. response = {};
  576. for (key in events) {
  577. if (events.hasOwnProperty(key) && evt.test(key)) {
  578. response[key] = events[key];
  579. }
  580. }
  581. }
  582. else {
  583. response = events[evt] || (events[evt] = []);
  584. }
  585. return response;
  586. };
  587. /**
  588. * Takes a list of listener objects and flattens it into a list of listener functions.
  589. *
  590. * @param {Object[]} listeners Raw listener objects.
  591. * @return {Function[]} Just the listener functions.
  592. */
  593. proto.flattenListeners = function flattenListeners(listeners) {
  594. var flatListeners = [];
  595. var i;
  596. for (i = 0; i < listeners.length; i += 1) {
  597. flatListeners.push(listeners[i].listener);
  598. }
  599. return flatListeners;
  600. };
  601. /**
  602. * 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.
  603. *
  604. * @param {String|RegExp} evt Name of the event to return the listeners from.
  605. * @return {Object} All listener functions for an event in an object.
  606. */
  607. proto.getListenersAsObject = function getListenersAsObject(evt) {
  608. var listeners = this.getListeners(evt);
  609. var response;
  610. if (listeners instanceof Array) {
  611. response = {};
  612. response[evt] = listeners;
  613. }
  614. return response || listeners;
  615. };
  616. /**
  617. * Adds a listener function to the specified event.
  618. * The listener will not be added if it is a duplicate.
  619. * If the listener returns true then it will be removed after it is called.
  620. * If you pass a regular expression as the event name then the listener will be added to all events that match it.
  621. *
  622. * @param {String|RegExp} evt Name of the event to attach the listener to.
  623. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  624. * @return {Object} Current instance of EventEmitter for chaining.
  625. */
  626. proto.addListener = function addListener(evt, listener) {
  627. var listeners = this.getListenersAsObject(evt);
  628. var listenerIsWrapped = typeof listener === 'object';
  629. var key;
  630. for (key in listeners) {
  631. if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
  632. listeners[key].push(listenerIsWrapped ? listener : {
  633. listener: listener,
  634. once: false
  635. });
  636. }
  637. }
  638. return this;
  639. };
  640. /**
  641. * Alias of addListener
  642. */
  643. proto.on = alias('addListener');
  644. /**
  645. * Semi-alias of addListener. It will add a listener that will be
  646. * automatically removed after its first execution.
  647. *
  648. * @param {String|RegExp} evt Name of the event to attach the listener to.
  649. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  650. * @return {Object} Current instance of EventEmitter for chaining.
  651. */
  652. proto.addOnceListener = function addOnceListener(evt, listener) {
  653. return this.addListener(evt, {
  654. listener: listener,
  655. once: true
  656. });
  657. };
  658. /**
  659. * Alias of addOnceListener.
  660. */
  661. proto.once = alias('addOnceListener');
  662. /**
  663. * 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.
  664. * You need to tell it what event names should be matched by a regex.
  665. *
  666. * @param {String} evt Name of the event to create.
  667. * @return {Object} Current instance of EventEmitter for chaining.
  668. */
  669. proto.defineEvent = function defineEvent(evt) {
  670. this.getListeners(evt);
  671. return this;
  672. };
  673. /**
  674. * Uses defineEvent to define multiple events.
  675. *
  676. * @param {String[]} evts An array of event names to define.
  677. * @return {Object} Current instance of EventEmitter for chaining.
  678. */
  679. proto.defineEvents = function defineEvents(evts) {
  680. for (var i = 0; i < evts.length; i += 1) {
  681. this.defineEvent(evts[i]);
  682. }
  683. return this;
  684. };
  685. /**
  686. * Removes a listener function from the specified event.
  687. * When passed a regular expression as the event name, it will remove the listener from all events that match it.
  688. *
  689. * @param {String|RegExp} evt Name of the event to remove the listener from.
  690. * @param {Function} listener Method to remove from the event.
  691. * @return {Object} Current instance of EventEmitter for chaining.
  692. */
  693. proto.removeListener = function removeListener(evt, listener) {
  694. var listeners = this.getListenersAsObject(evt);
  695. var index;
  696. var key;
  697. for (key in listeners) {
  698. if (listeners.hasOwnProperty(key)) {
  699. index = indexOfListener(listeners[key], listener);
  700. if (index !== -1) {
  701. listeners[key].splice(index, 1);
  702. }
  703. }
  704. }
  705. return this;
  706. };
  707. /**
  708. * Alias of removeListener
  709. */
  710. proto.off = alias('removeListener');
  711. /**
  712. * Adds listeners in bulk using the manipulateListeners method.
  713. * 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.
  714. * You can also pass it a regular expression to add the array of listeners to all events that match it.
  715. * Yeah, this function does quite a bit. That's probably a bad thing.
  716. *
  717. * @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.
  718. * @param {Function[]} [listeners] An optional array of listener functions to add.
  719. * @return {Object} Current instance of EventEmitter for chaining.
  720. */
  721. proto.addListeners = function addListeners(evt, listeners) {
  722. // Pass through to manipulateListeners
  723. return this.manipulateListeners(false, evt, listeners);
  724. };
  725. /**
  726. * Removes listeners in bulk using the manipulateListeners method.
  727. * 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.
  728. * You can also pass it an event name and an array of listeners to be removed.
  729. * You can also pass it a regular expression to remove the listeners from all events that match it.
  730. *
  731. * @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.
  732. * @param {Function[]} [listeners] An optional array of listener functions to remove.
  733. * @return {Object} Current instance of EventEmitter for chaining.
  734. */
  735. proto.removeListeners = function removeListeners(evt, listeners) {
  736. // Pass through to manipulateListeners
  737. return this.manipulateListeners(true, evt, listeners);
  738. };
  739. /**
  740. * 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.
  741. * The first argument will determine if the listeners are removed (true) or added (false).
  742. * 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.
  743. * You can also pass it an event name and an array of listeners to be added/removed.
  744. * You can also pass it a regular expression to manipulate the listeners of all events that match it.
  745. *
  746. * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
  747. * @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.
  748. * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
  749. * @return {Object} Current instance of EventEmitter for chaining.
  750. */
  751. proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
  752. var i;
  753. var value;
  754. var single = remove ? this.removeListener : this.addListener;
  755. var multiple = remove ? this.removeListeners : this.addListeners;
  756. // If evt is an object then pass each of its properties to this method
  757. if (typeof evt === 'object' && !(evt instanceof RegExp)) {
  758. for (i in evt) {
  759. if (evt.hasOwnProperty(i) && (value = evt[i])) {
  760. // Pass the single listener straight through to the singular method
  761. if (typeof value === 'function') {
  762. single.call(this, i, value);
  763. }
  764. else {
  765. // Otherwise pass back to the multiple function
  766. multiple.call(this, i, value);
  767. }
  768. }
  769. }
  770. }
  771. else {
  772. // So evt must be a string
  773. // And listeners must be an array of listeners
  774. // Loop over it and pass each one to the multiple method
  775. i = listeners.length;
  776. while (i--) {
  777. single.call(this, evt, listeners[i]);
  778. }
  779. }
  780. return this;
  781. };
  782. /**
  783. * Removes all listeners from a specified event.
  784. * If you do not specify an event then all listeners will be removed.
  785. * That means every event will be emptied.
  786. * You can also pass a regex to remove all events that match it.
  787. *
  788. * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
  789. * @return {Object} Current instance of EventEmitter for chaining.
  790. */
  791. proto.removeEvent = function removeEvent(evt) {
  792. var type = typeof evt;
  793. var events = this._getEvents();
  794. var key;
  795. // Remove different things depending on the state of evt
  796. if (type === 'string') {
  797. // Remove all listeners for the specified event
  798. delete events[evt];
  799. }
  800. else if (evt instanceof RegExp) {
  801. // Remove all events matching the regex.
  802. for (key in events) {
  803. if (events.hasOwnProperty(key) && evt.test(key)) {
  804. delete events[key];
  805. }
  806. }
  807. }
  808. else {
  809. // Remove all listeners in all events
  810. delete this._events;
  811. }
  812. return this;
  813. };
  814. /**
  815. * Alias of removeEvent.
  816. *
  817. * Added to mirror the node API.
  818. */
  819. proto.removeAllListeners = alias('removeEvent');
  820. /**
  821. * Emits an event of your choice.
  822. * When emitted, every listener attached to that event will be executed.
  823. * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
  824. * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
  825. * So they will not arrive within the array on the other side, they will be separate.
  826. * You can also pass a regular expression to emit to all events that match it.
  827. *
  828. * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  829. * @param {Array} [args] Optional array of arguments to be passed to each listener.
  830. * @return {Object} Current instance of EventEmitter for chaining.
  831. */
  832. proto.emitEvent = function emitEvent(evt, args) {
  833. var listeners = this.getListenersAsObject(evt);
  834. var listener;
  835. var i;
  836. var key;
  837. var response;
  838. for (key in listeners) {
  839. if (listeners.hasOwnProperty(key)) {
  840. i = listeners[key].length;
  841. while (i--) {
  842. // If the listener returns true then it shall be removed from the event
  843. // The function is executed either with a basic call or an apply if there is an args array
  844. listener = listeners[key][i];
  845. if (listener.once === true) {
  846. this.removeListener(evt, listener.listener);
  847. }
  848. response = listener.listener.apply(this, args || []);
  849. if (response === this._getOnceReturnValue()) {
  850. this.removeListener(evt, listener.listener);
  851. }
  852. }
  853. }
  854. }
  855. return this;
  856. };
  857. /**
  858. * Alias of emitEvent
  859. */
  860. proto.trigger = alias('emitEvent');
  861. /**
  862. * 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.
  863. * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
  864. *
  865. * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  866. * @param {...*} Optional additional arguments to be passed to each listener.
  867. * @return {Object} Current instance of EventEmitter for chaining.
  868. */
  869. proto.emit = function emit(evt) {
  870. var args = Array.prototype.slice.call(arguments, 1);
  871. return this.emitEvent(evt, args);
  872. };
  873. /**
  874. * Sets the current value to check against when executing listeners. If a
  875. * listeners return value matches the one set here then it will be removed
  876. * after execution. This value defaults to true.
  877. *
  878. * @param {*} value The new value to check for when executing listeners.
  879. * @return {Object} Current instance of EventEmitter for chaining.
  880. */
  881. proto.setOnceReturnValue = function setOnceReturnValue(value) {
  882. this._onceReturnValue = value;
  883. return this;
  884. };
  885. /**
  886. * Fetches the current value to check against when executing listeners. If
  887. * the listeners return value matches this one then it should be removed
  888. * automatically. It will return true by default.
  889. *
  890. * @return {*|Boolean} The current value to check for or the default, true.
  891. * @api private
  892. */
  893. proto._getOnceReturnValue = function _getOnceReturnValue() {
  894. if (this.hasOwnProperty('_onceReturnValue')) {
  895. return this._onceReturnValue;
  896. }
  897. else {
  898. return true;
  899. }
  900. };
  901. /**
  902. * Fetches the events object and creates one if required.
  903. *
  904. * @return {Object} The events storage object.
  905. * @api private
  906. */
  907. proto._getEvents = function _getEvents() {
  908. return this._events || (this._events = {});
  909. };
  910. /**
  911. * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
  912. *
  913. * @return {Function} Non conflicting EventEmitter class.
  914. */
  915. EventEmitter.noConflict = function noConflict() {
  916. exports.EventEmitter = originalGlobalValue;
  917. return EventEmitter;
  918. };
  919. // Expose the class either via AMD, CommonJS or the global object
  920. if (typeof define === 'function' && define.amd) {
  921. define('eventEmitter/EventEmitter',[],function () {
  922. return EventEmitter;
  923. });
  924. }
  925. else if (typeof module === 'object' && module.exports){
  926. module.exports = EventEmitter;
  927. }
  928. else {
  929. exports.EventEmitter = EventEmitter;
  930. }
  931. }.call(this));
  932. /*!
  933. * docReady v1.0.4
  934. * Cross browser DOMContentLoaded event emitter
  935. * MIT license
  936. */
  937. /*jshint browser: true, strict: true, undef: true, unused: true*/
  938. /*global define: false, require: false, module: false */
  939. ( function( window ) {
  940. var document = window.document;
  941. // collection of functions to be triggered on ready
  942. var queue = [];
  943. function docReady( fn ) {
  944. // throw out non-functions
  945. if ( typeof fn !== 'function' ) {
  946. return;
  947. }
  948. if ( docReady.isReady ) {
  949. // ready now, hit it
  950. fn();
  951. } else {
  952. // queue function when ready
  953. queue.push( fn );
  954. }
  955. }
  956. docReady.isReady = false;
  957. // triggered on various doc ready events
  958. function onReady( event ) {
  959. // bail if already triggered or IE8 document is not ready just yet
  960. var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
  961. if ( docReady.isReady || isIE8NotReady ) {
  962. return;
  963. }
  964. trigger();
  965. }
  966. function trigger() {
  967. docReady.isReady = true;
  968. // process queue
  969. for ( var i=0, len = queue.length; i < len; i++ ) {
  970. var fn = queue[i];
  971. fn();
  972. }
  973. }
  974. function defineDocReady( eventie ) {
  975. // trigger ready if page is ready
  976. if ( document.readyState === 'complete' ) {
  977. trigger();
  978. } else {
  979. // listen for events
  980. window.eventie.bind( document, 'DOMContentLoaded', onReady );
  981. window.eventie.bind( document, 'readystatechange', onReady );
  982. window.eventie.bind( window, 'load', onReady );
  983. }
  984. return docReady;
  985. }
  986. // transport
  987. if ( typeof define === 'function' && define.amd ) {
  988. // AMD
  989. define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
  990. } else if ( typeof exports === 'object' ) {
  991. module.exports = defineDocReady( require('eventie') );
  992. } else {
  993. // browser global
  994. window.docReady = defineDocReady( window.eventie );
  995. }
  996. })( window );
  997. /**
  998. * matchesSelector v1.0.3
  999. * matchesSelector( element, '.selector' )
  1000. * MIT license
  1001. */
  1002. /*jshint browser: true, strict: true, undef: true, unused: true */
  1003. /*global define: false, module: false */
  1004. ( function( ElemProto ) {
  1005. var matchesMethod = ( function() {
  1006. // check for the standard method name first
  1007. if ( ElemProto.matches ) {
  1008. return 'matches';
  1009. }
  1010. // check un-prefixed
  1011. if ( ElemProto.matchesSelector ) {
  1012. return 'matchesSelector';
  1013. }
  1014. // check vendor prefixes
  1015. var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
  1016. for ( var i=0, len = prefixes.length; i < len; i++ ) {
  1017. var prefix = prefixes[i];
  1018. var method = prefix + 'MatchesSelector';
  1019. if ( ElemProto[ method ] ) {
  1020. return method;
  1021. }
  1022. }
  1023. })();
  1024. // ----- match ----- //
  1025. function match( elem, selector ) {
  1026. return elem[ matchesMethod ]( selector );
  1027. }
  1028. // ----- appendToFragment ----- //
  1029. function checkParent( elem ) {
  1030. // not needed if already has parent
  1031. if ( elem.parentNode ) {
  1032. return;
  1033. }
  1034. var fragment = document.createDocumentFragment();
  1035. fragment.appendChild( elem );
  1036. }
  1037. // ----- query ----- //
  1038. // fall back to using QSA
  1039. // thx @jonathantneal https://gist.github.com/3062955
  1040. function query( elem, selector ) {
  1041. // append to fragment if no parent
  1042. checkParent( elem );
  1043. // match elem with all selected elems of parent
  1044. var elems = elem.parentNode.querySelectorAll( selector );
  1045. for ( var i=0, len = elems.length; i < len; i++ ) {
  1046. // return true if match
  1047. if ( elems[i] === elem ) {
  1048. return true;
  1049. }
  1050. }
  1051. // otherwise return false
  1052. return false;
  1053. }
  1054. // ----- matchChild ----- //
  1055. function matchChild( elem, selector ) {
  1056. checkParent( elem );
  1057. return match( elem, selector );
  1058. }
  1059. // ----- matchesSelector ----- //
  1060. var matchesSelector;
  1061. if ( matchesMethod ) {
  1062. // IE9 supports matchesSelector, but doesn't work on orphaned elems
  1063. // check for that
  1064. var div = document.createElement('div');
  1065. var supportsOrphans = match( div, 'div' );
  1066. matchesSelector = supportsOrphans ? match : matchChild;
  1067. } else {
  1068. matchesSelector = query;
  1069. }
  1070. // transport
  1071. if ( typeof define === 'function' && define.amd ) {
  1072. // AMD
  1073. define( 'matches-selector/matches-selector',[],function() {
  1074. return matchesSelector;
  1075. });
  1076. } else if ( typeof exports === 'object' ) {
  1077. module.exports = matchesSelector;
  1078. }
  1079. else {
  1080. // browser global
  1081. window.matchesSelector = matchesSelector;
  1082. }
  1083. })( Element.prototype );
  1084. /**
  1085. * Fizzy UI utils v1.0.1
  1086. * MIT license
  1087. */
  1088. /*jshint browser: true, undef: true, unused: true, strict: true */
  1089. ( function( window, factory ) {
  1090. /*global define: false, module: false, require: false */
  1091. // universal module definition
  1092. if ( typeof define == 'function' && define.amd ) {
  1093. // AMD
  1094. define( 'fizzy-ui-utils/utils',[
  1095. 'doc-ready/doc-ready',
  1096. 'matches-selector/matches-selector'
  1097. ], function( docReady, matchesSelector ) {
  1098. return factory( window, docReady, matchesSelector );
  1099. });
  1100. } else if ( typeof exports == 'object' ) {
  1101. // CommonJS
  1102. module.exports = factory(
  1103. window,
  1104. require('doc-ready'),
  1105. require('desandro-matches-selector')
  1106. );
  1107. } else {
  1108. // browser global
  1109. window.fizzyUIUtils = factory(
  1110. window,
  1111. window.docReady,
  1112. window.matchesSelector
  1113. );
  1114. }
  1115. }( window, function factory( window, docReady, matchesSelector ) {
  1116. var utils = {};
  1117. // ----- extend ----- //
  1118. // extends objects
  1119. utils.extend = function( a, b ) {
  1120. for ( var prop in b ) {
  1121. a[ prop ] = b[ prop ];
  1122. }
  1123. return a;
  1124. };
  1125. // ----- modulo ----- //
  1126. utils.modulo = function( num, div ) {
  1127. return ( ( num % div ) + div ) % div;
  1128. };
  1129. // ----- isArray ----- //
  1130. var objToString = Object.prototype.toString;
  1131. utils.isArray = function( obj ) {
  1132. return objToString.call( obj ) == '[object Array]';
  1133. };
  1134. // ----- makeArray ----- //
  1135. // turn element or nodeList into an array
  1136. utils.makeArray = function( obj ) {
  1137. var ary = [];
  1138. if ( utils.isArray( obj ) ) {
  1139. // use object if already an array
  1140. ary = obj;
  1141. } else if ( obj && typeof obj.length == 'number' ) {
  1142. // convert nodeList to array
  1143. for ( var i=0, len = obj.length; i < len; i++ ) {
  1144. ary.push( obj[i] );
  1145. }
  1146. } else {
  1147. // array of single index
  1148. ary.push( obj );
  1149. }
  1150. return ary;
  1151. };
  1152. // ----- indexOf ----- //
  1153. // index of helper cause IE8
  1154. utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
  1155. return ary.indexOf( obj );
  1156. } : function( ary, obj ) {
  1157. for ( var i=0, len = ary.length; i < len; i++ ) {
  1158. if ( ary[i] === obj ) {
  1159. return i;
  1160. }
  1161. }
  1162. return -1;
  1163. };
  1164. // ----- removeFrom ----- //
  1165. utils.removeFrom = function( ary, obj ) {
  1166. var index = utils.indexOf( ary, obj );
  1167. if ( index != -1 ) {
  1168. ary.splice( index, 1 );
  1169. }
  1170. };
  1171. // ----- isElement ----- //
  1172. // http://stackoverflow.com/a/384380/182183
  1173. utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
  1174. function isElementDOM2( obj ) {
  1175. return obj instanceof HTMLElement;
  1176. } :
  1177. function isElementQuirky( obj ) {
  1178. return obj && typeof obj == 'object' &&
  1179. obj.nodeType == 1 && typeof obj.nodeName == 'string';
  1180. };
  1181. // ----- setText ----- //
  1182. utils.setText = ( function() {
  1183. var setTextProperty;
  1184. function setText( elem, text ) {
  1185. // only check setTextProperty once
  1186. setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
  1187. elem[ setTextProperty ] = text;
  1188. }
  1189. return setText;
  1190. })();
  1191. // ----- getParent ----- //
  1192. utils.getParent = function( elem, selector ) {
  1193. while ( elem != document.body ) {
  1194. elem = elem.parentNode;
  1195. if ( matchesSelector( elem, selector ) ) {
  1196. return elem;
  1197. }
  1198. }
  1199. };
  1200. // ----- getQueryElement ----- //
  1201. // use element as selector string
  1202. utils.getQueryElement = function( elem ) {
  1203. if ( typeof elem == 'string' ) {
  1204. return document.querySelector( elem );
  1205. }
  1206. return elem;
  1207. };
  1208. // ----- handleEvent ----- //
  1209. // enable .ontype to trigger from .addEventListener( elem, 'type' )
  1210. utils.handleEvent = function( event ) {
  1211. var method = 'on' + event.type;
  1212. if ( this[ method ] ) {
  1213. this[ method ]( event );
  1214. }
  1215. };
  1216. // ----- filterFindElements ----- //
  1217. utils.filterFindElements = function( elems, selector ) {
  1218. // make array of elems
  1219. elems = utils.makeArray( elems );
  1220. var ffElems = [];
  1221. for ( var i=0, len = elems.length; i < len; i++ ) {
  1222. var elem = elems[i];
  1223. // check that elem is an actual element
  1224. if ( !utils.isElement( elem ) ) {
  1225. continue;
  1226. }
  1227. // filter & find items if we have a selector
  1228. if ( selector ) {
  1229. // filter siblings
  1230. if ( matchesSelector( elem, selector ) ) {
  1231. ffElems.push( elem );
  1232. }
  1233. // find children
  1234. var childElems = elem.querySelectorAll( selector );
  1235. // concat childElems to filterFound array
  1236. for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
  1237. ffElems.push( childElems[j] );
  1238. }
  1239. } else {
  1240. ffElems.push( elem );
  1241. }
  1242. }
  1243. return ffElems;
  1244. };
  1245. // ----- debounceMethod ----- //
  1246. utils.debounceMethod = function( _class, methodName, threshold ) {
  1247. // original method
  1248. var method = _class.prototype[ methodName ];
  1249. var timeoutName = methodName + 'Timeout';
  1250. _class.prototype[ methodName ] = function() {
  1251. var timeout = this[ timeoutName ];
  1252. if ( timeout ) {
  1253. clearTimeout( timeout );
  1254. }
  1255. var args = arguments;
  1256. var _this = this;
  1257. this[ timeoutName ] = setTimeout( function() {
  1258. method.apply( _this, args );
  1259. delete _this[ timeoutName ];
  1260. }, threshold || 100 );
  1261. };
  1262. };
  1263. // ----- htmlInit ----- //
  1264. // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
  1265. utils.toDashed = function( str ) {
  1266. return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
  1267. return $1 + '-' + $2;
  1268. }).toLowerCase();
  1269. };
  1270. var console = window.console;
  1271. /**
  1272. * allow user to initialize classes via .js-namespace class
  1273. * htmlInit( Widget, 'widgetName' )
  1274. * options are parsed from data-namespace-option attribute
  1275. */
  1276. utils.htmlInit = function( WidgetClass, namespace ) {
  1277. docReady( function() {
  1278. var dashedNamespace = utils.toDashed( namespace );
  1279. var elems = document.querySelectorAll( '.js-' + dashedNamespace );
  1280. var dataAttr = 'data-' + dashedNamespace + '-options';
  1281. for ( var i=0, len = elems.length; i < len; i++ ) {
  1282. var elem = elems[i];
  1283. var attr = elem.getAttribute( dataAttr );
  1284. var options;
  1285. try {
  1286. options = attr && JSON.parse( attr );
  1287. } catch ( error ) {
  1288. // log error, do not initialize
  1289. if ( console ) {
  1290. console.error( 'Error parsing ' + dataAttr + ' on ' +
  1291. elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
  1292. error );
  1293. }
  1294. continue;
  1295. }
  1296. // initialize
  1297. var instance = new WidgetClass( elem, options );
  1298. // make available via $().data('layoutname')
  1299. var jQuery = window.jQuery;
  1300. if ( jQuery ) {
  1301. jQuery.data( elem, namespace, instance );
  1302. }
  1303. }
  1304. });
  1305. };
  1306. // ----- ----- //
  1307. return utils;
  1308. }));
  1309. /**
  1310. * Outlayer Item
  1311. */
  1312. ( function( window, factory ) {
  1313. // universal module definition
  1314. if ( typeof define === 'function' && define.amd ) {
  1315. // AMD
  1316. define( 'outlayer/item',[
  1317. 'eventEmitter/EventEmitter',
  1318. 'get-size/get-size',
  1319. 'get-style-property/get-style-property',
  1320. 'fizzy-ui-utils/utils'
  1321. ],
  1322. function( EventEmitter, getSize, getStyleProperty, utils ) {
  1323. return factory( window, EventEmitter, getSize, getStyleProperty, utils );
  1324. }
  1325. );
  1326. } else if (typeof exports === 'object') {
  1327. // CommonJS
  1328. module.exports = factory(
  1329. window,
  1330. require('wolfy87-eventemitter'),
  1331. require('get-size'),
  1332. require('desandro-get-style-property'),
  1333. require('fizzy-ui-utils')
  1334. );
  1335. } else {
  1336. // browser global
  1337. window.Outlayer = {};
  1338. window.Outlayer.Item = factory(
  1339. window,
  1340. window.EventEmitter,
  1341. window.getSize,
  1342. window.getStyleProperty,
  1343. window.fizzyUIUtils
  1344. );
  1345. }
  1346. }( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) {
  1347. // ----- helpers ----- //
  1348. var getComputedStyle = window.getComputedStyle;
  1349. var getStyle = getComputedStyle ?
  1350. function( elem ) {
  1351. return getComputedStyle( elem, null );
  1352. } :
  1353. function( elem ) {
  1354. return elem.currentStyle;
  1355. };
  1356. function isEmptyObj( obj ) {
  1357. for ( var prop in obj ) {
  1358. return false;
  1359. }
  1360. prop = null;
  1361. return true;
  1362. }
  1363. // -------------------------- CSS3 support -------------------------- //
  1364. var transitionProperty = getStyleProperty('transition');
  1365. var transformProperty = getStyleProperty('transform');
  1366. var supportsCSS3 = transitionProperty && transformProperty;
  1367. var is3d = !!getStyleProperty('perspective');
  1368. var transitionEndEvent = {
  1369. WebkitTransition: 'webkitTransitionEnd',
  1370. MozTransition: 'transitionend',
  1371. OTransition: 'otransitionend',
  1372. transition: 'transitionend'
  1373. }[ transitionProperty ];
  1374. // properties that could have vendor prefix
  1375. var prefixableProperties = [
  1376. 'transform',
  1377. 'transition',
  1378. 'transitionDuration',
  1379. 'transitionProperty'
  1380. ];
  1381. // cache all vendor properties
  1382. var vendorProperties = ( function() {
  1383. var cache = {};
  1384. for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
  1385. var prop = prefixableProperties[i];
  1386. var supportedProp = getStyleProperty( prop );
  1387. if ( supportedProp && supportedProp !== prop ) {
  1388. cache[ prop ] = supportedProp;
  1389. }
  1390. }
  1391. return cache;
  1392. })();
  1393. // -------------------------- Item -------------------------- //
  1394. function Item( element, layout ) {
  1395. if ( !element ) {
  1396. return;
  1397. }
  1398. this.element = element;
  1399. // parent layout class, i.e. Masonry, Isotope, or Packery
  1400. this.layout = layout;
  1401. this.position = {
  1402. x: 0,
  1403. y: 0
  1404. };
  1405. this._create();
  1406. }
  1407. // inherit EventEmitter
  1408. utils.extend( Item.prototype, EventEmitter.prototype );
  1409. Item.prototype._create = function() {
  1410. // transition objects
  1411. this._transn = {
  1412. ingProperties: {},
  1413. clean: {},
  1414. onEnd: {}
  1415. };
  1416. this.css({
  1417. position: 'absolute'
  1418. });
  1419. };
  1420. // trigger specified handler for event type
  1421. Item.prototype.handleEvent = function( event ) {
  1422. var method = 'on' + event.type;
  1423. if ( this[ method ] ) {
  1424. this[ method ]( event );
  1425. }
  1426. };
  1427. Item.prototype.getSize = function() {
  1428. this.size = getSize( this.element );
  1429. };
  1430. /**
  1431. * apply CSS styles to element
  1432. * @param {Object} style
  1433. */
  1434. Item.prototype.css = function( style ) {
  1435. var elemStyle = this.element.style;
  1436. for ( var prop in style ) {
  1437. // use vendor property if available
  1438. var supportedProp = vendorProperties[ prop ] || prop;
  1439. elemStyle[ supportedProp ] = style[ prop ];
  1440. }
  1441. };
  1442. // measure position, and sets it
  1443. Item.prototype.getPosition = function() {
  1444. var style = getStyle( this.element );
  1445. var layoutOptions = this.layout.options;
  1446. var isOriginLeft = layoutOptions.isOriginLeft;
  1447. var isOriginTop = layoutOptions.isOriginTop;
  1448. var xValue = style[ isOriginLeft ? 'left' : 'right' ];
  1449. var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
  1450. // convert percent to pixels
  1451. var layoutSize = this.layout.size;
  1452. var x = xValue.indexOf('%') != -1 ?
  1453. ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 );
  1454. var y = yValue.indexOf('%') != -1 ?
  1455. ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 );
  1456. // clean up 'auto' or other non-integer values
  1457. x = isNaN( x ) ? 0 : x;
  1458. y = isNaN( y ) ? 0 : y;
  1459. // remove padding from measurement
  1460. x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
  1461. y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
  1462. this.position.x = x;
  1463. this.position.y = y;
  1464. };
  1465. // set settled position, apply padding
  1466. Item.prototype.layoutPosition = function() {
  1467. var layoutSize = this.layout.size;
  1468. var layoutOptions = this.layout.options;
  1469. var style = {};
  1470. // x
  1471. var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight';
  1472. var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right';
  1473. var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left';
  1474. var x = this.position.x + layoutSize[ xPadding ];
  1475. // set in percentage or pixels
  1476. style[ xProperty ] = this.getXValue( x );
  1477. // reset other property
  1478. style[ xResetProperty ] = '';
  1479. // y
  1480. var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom';
  1481. var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom';
  1482. var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top';
  1483. var y = this.position.y + layoutSize[ yPadding ];
  1484. // set in percentage or pixels
  1485. style[ yProperty ] = this.getYValue( y );
  1486. // reset other property
  1487. style[ yResetProperty ] = '';
  1488. this.css( style );
  1489. this.emitEvent( 'layout', [ this ] );
  1490. };
  1491. Item.prototype.getXValue = function( x ) {
  1492. var layoutOptions = this.layout.options;
  1493. return layoutOptions.percentPosition && !layoutOptions.isHorizontal ?
  1494. ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
  1495. };
  1496. Item.prototype.getYValue = function( y ) {
  1497. var layoutOptions = this.layout.options;
  1498. return layoutOptions.percentPosition && layoutOptions.isHorizontal ?
  1499. ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
  1500. };
  1501. Item.prototype._transitionTo = function( x, y ) {
  1502. this.getPosition();
  1503. // get current x & y from top/left
  1504. var curX = this.position.x;
  1505. var curY = this.position.y;
  1506. var compareX = parseInt( x, 10 );
  1507. var compareY = parseInt( y, 10 );
  1508. var didNotMove = compareX === this.position.x && compareY === this.position.y;
  1509. // save end position
  1510. this.setPosition( x, y );
  1511. // if did not move and not transitioning, just go to layout
  1512. if ( didNotMove && !this.isTransitioning ) {
  1513. this.layoutPosition();
  1514. return;
  1515. }
  1516. var transX = x - curX;
  1517. var transY = y - curY;
  1518. var transitionStyle = {};
  1519. transitionStyle.transform = this.getTranslate( transX, transY );
  1520. this.transition({
  1521. to: transitionStyle,
  1522. onTransitionEnd: {
  1523. transform: this.layoutPosition
  1524. },
  1525. isCleaning: true
  1526. });
  1527. };
  1528. Item.prototype.getTranslate = function( x, y ) {
  1529. // flip cooridinates if origin on right or bottom
  1530. var layoutOptions = this.layout.options;
  1531. x = layoutOptions.isOriginLeft ? x : -x;
  1532. y = layoutOptions.isOriginTop ? y : -y;
  1533. if ( is3d ) {
  1534. return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
  1535. }
  1536. return 'translate(' + x + 'px, ' + y + 'px)';
  1537. };
  1538. // non transition + transform support
  1539. Item.prototype.goTo = function( x, y ) {
  1540. this.setPosition( x, y );
  1541. this.layoutPosition();
  1542. };
  1543. // use transition and transforms if supported
  1544. Item.prototype.moveTo = supportsCSS3 ?
  1545. Item.prototype._transitionTo : Item.prototype.goTo;
  1546. Item.prototype.setPosition = function( x, y ) {
  1547. this.position.x = parseInt( x, 10 );
  1548. this.position.y = parseInt( y, 10 );
  1549. };
  1550. // ----- transition ----- //
  1551. /**
  1552. * @param {Object} style - CSS
  1553. * @param {Function} onTransitionEnd
  1554. */
  1555. // non transition, just trigger callback
  1556. Item.prototype._nonTransition = function( args ) {
  1557. this.css( args.to );
  1558. if ( args.isCleaning ) {
  1559. this._removeStyles( args.to );
  1560. }
  1561. for ( var prop in args.onTransitionEnd ) {
  1562. args.onTransitionEnd[ prop ].call( this );
  1563. }
  1564. };
  1565. /**
  1566. * proper transition
  1567. * @param {Object} args - arguments
  1568. * @param {Object} to - style to transition to
  1569. * @param {Object} from - style to start transition from
  1570. * @param {Boolean} isCleaning - removes transition styles after transition
  1571. * @param {Function} onTransitionEnd - callback
  1572. */
  1573. Item.prototype._transition = function( args ) {
  1574. // redirect to nonTransition if no transition duration
  1575. if ( !parseFloat( this.layout.options.transitionDuration ) ) {
  1576. this._nonTransition( args );
  1577. return;
  1578. }
  1579. var _transition = this._transn;
  1580. // keep track of onTransitionEnd callback by css property
  1581. for ( var prop in args.onTransitionEnd ) {
  1582. _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
  1583. }
  1584. // keep track of properties that are transitioning
  1585. for ( prop in args.to ) {
  1586. _transition.ingProperties[ prop ] = true;
  1587. // keep track of properties to clean up when transition is done
  1588. if ( args.isCleaning ) {
  1589. _transition.clean[ prop ] = true;
  1590. }
  1591. }
  1592. // set from styles
  1593. if ( args.from ) {
  1594. this.css( args.from );
  1595. // force redraw. http://blog.alexmaccaw.com/css-transitions
  1596. var h = this.element.offsetHeight;
  1597. // hack for JSHint to hush about unused var
  1598. h = null;
  1599. }
  1600. // enable transition
  1601. this.enableTransition( args.to );
  1602. // set styles that are transitioning
  1603. this.css( args.to );
  1604. this.isTransitioning = true;
  1605. };
  1606. // dash before all cap letters, including first for
  1607. // WebkitTransform => -webkit-transform
  1608. function toDashedAll( str ) {
  1609. return str.replace( /([A-Z])/g, function( $1 ) {
  1610. return '-' + $1.toLowerCase();
  1611. });
  1612. }
  1613. var transitionProps = 'opacity,' +
  1614. toDashedAll( vendorProperties.transform || 'transform' );
  1615. Item.prototype.enableTransition = function(/* style */) {
  1616. // HACK changing transitionProperty during a transition
  1617. // will cause transition to jump
  1618. if ( this.isTransitioning ) {
  1619. return;
  1620. }
  1621. // make `transition: foo, bar, baz` from style object
  1622. // HACK un-comment this when enableTransition can work
  1623. // while a transition is happening
  1624. // var transitionValues = [];
  1625. // for ( var prop in style ) {
  1626. // // dash-ify camelCased properties like WebkitTransition
  1627. // prop = vendorProperties[ prop ] || prop;
  1628. // transitionValues.push( toDashedAll( prop ) );
  1629. // }
  1630. // enable transition styles
  1631. this.css({
  1632. transitionProperty: transitionProps,
  1633. transitionDuration: this.layout.options.transitionDuration
  1634. });
  1635. // listen for transition end event
  1636. this.element.addEventListener( transitionEndEvent, this, false );
  1637. };
  1638. Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
  1639. // ----- events ----- //
  1640. Item.prototype.onwebkitTransitionEnd = function( event ) {
  1641. this.ontransitionend( event );
  1642. };
  1643. Item.prototype.onotransitionend = function( event ) {
  1644. this.ontransitionend( event );
  1645. };
  1646. // properties that I munge to make my life easier
  1647. var dashedVendorProperties = {
  1648. '-webkit-transform': 'transform',
  1649. '-moz-transform': 'transform',
  1650. '-o-transform': 'transform'
  1651. };
  1652. Item.prototype.ontransitionend = function( event ) {
  1653. // disregard bubbled events from children
  1654. if ( event.target !== this.element ) {
  1655. return;
  1656. }
  1657. var _transition = this._transn;
  1658. // get property name of transitioned property, convert to prefix-free
  1659. var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
  1660. // remove property that has completed transitioning
  1661. delete _transition.ingProperties[ propertyName ];
  1662. // check if any properties are still transitioning
  1663. if ( isEmptyObj( _transition.ingProperties ) ) {
  1664. // all properties have completed transitioning
  1665. this.disableTransition();
  1666. }
  1667. // clean style
  1668. if ( propertyName in _transition.clean ) {
  1669. // clean up style
  1670. this.element.style[ event.propertyName ] = '';
  1671. delete _transition.clean[ propertyName ];
  1672. }
  1673. // trigger onTransitionEnd callback
  1674. if ( propertyName in _transition.onEnd ) {
  1675. var onTransitionEnd = _transition.onEnd[ propertyName ];
  1676. onTransitionEnd.call( this );
  1677. delete _transition.onEnd[ propertyName ];
  1678. }
  1679. this.emitEvent( 'transitionEnd', [ this ] );
  1680. };
  1681. Item.prototype.disableTransition = function() {
  1682. this.removeTransitionStyles();
  1683. this.element.removeEventListener( transitionEndEvent, this, false );
  1684. this.isTransitioning = false;
  1685. };
  1686. /**
  1687. * removes style property from element
  1688. * @param {Object} style
  1689. **/
  1690. Item.prototype._removeStyles = function( style ) {
  1691. // clean up transition styles
  1692. var cleanStyle = {};
  1693. for ( var prop in style ) {
  1694. cleanStyle[ prop ] = '';
  1695. }
  1696. this.css( cleanStyle );
  1697. };
  1698. var cleanTransitionStyle = {
  1699. transitionProperty: '',
  1700. transitionDuration: ''
  1701. };
  1702. Item.prototype.removeTransitionStyles = function() {
  1703. // remove transition
  1704. this.css( cleanTransitionStyle );
  1705. };
  1706. // ----- show/hide/remove ----- //
  1707. // remove element from DOM
  1708. Item.prototype.removeElem = function() {
  1709. this.element.parentNode.removeChild( this.element );
  1710. // remove display: none
  1711. this.css({ display: '' });
  1712. this.emitEvent( 'remove', [ this ] );
  1713. };
  1714. Item.prototype.remove = function() {
  1715. // just remove element if no transition support or no transition
  1716. if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
  1717. this.removeElem();
  1718. return;
  1719. }
  1720. // start transition
  1721. var _this = this;
  1722. this.once( 'transitionEnd', function() {
  1723. _this.removeElem();
  1724. });
  1725. this.hide();
  1726. };
  1727. Item.prototype.reveal = function() {
  1728. delete this.isHidden;
  1729. // remove display: none
  1730. this.css({ display: '' });
  1731. var options = this.layout.options;
  1732. var onTransitionEnd = {};
  1733. var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
  1734. onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
  1735. this.transition({
  1736. from: options.hiddenStyle,
  1737. to: options.visibleStyle,
  1738. isCleaning: true,
  1739. onTransitionEnd: onTransitionEnd
  1740. });
  1741. };
  1742. Item.prototype.onRevealTransitionEnd = function() {
  1743. // check if still visible
  1744. // during transition, item may have been hidden
  1745. if ( !this.isHidden ) {
  1746. this.emitEvent('reveal');
  1747. }
  1748. };
  1749. /**
  1750. * get style property use for hide/reveal transition end
  1751. * @param {String} styleProperty - hiddenStyle/visibleStyle
  1752. * @returns {String}
  1753. */
  1754. Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) {
  1755. var optionStyle = this.layout.options[ styleProperty ];
  1756. // use opacity
  1757. if ( optionStyle.opacity ) {
  1758. return 'opacity';
  1759. }
  1760. // get first property
  1761. for ( var prop in optionStyle ) {
  1762. return prop;
  1763. }
  1764. };
  1765. Item.prototype.hide = function() {
  1766. // set flag
  1767. this.isHidden = true;
  1768. // remove display: none
  1769. this.css({ display: '' });
  1770. var options = this.layout.options;
  1771. var onTransitionEnd = {};
  1772. var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
  1773. onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
  1774. this.transition({
  1775. from: options.visibleStyle,
  1776. to: options.hiddenStyle,
  1777. // keep hidden stuff hidden
  1778. isCleaning: true,
  1779. onTransitionEnd: onTransitionEnd
  1780. });
  1781. };
  1782. Item.prototype.onHideTransitionEnd = function() {
  1783. // check if still hidden
  1784. // during transition, item may have been un-hidden
  1785. if ( this.isHidden ) {
  1786. this.css({ display: 'none' });
  1787. this.emitEvent('hide');
  1788. }
  1789. };
  1790. Item.prototype.destroy = function() {
  1791. this.css({
  1792. position: '',
  1793. left: '',
  1794. right: '',
  1795. top: '',
  1796. bottom: '',
  1797. transition: '',
  1798. transform: ''
  1799. });
  1800. };
  1801. return Item;
  1802. }));
  1803. /*!
  1804. * Outlayer v1.4.2
  1805. * the brains and guts of a layout library
  1806. * MIT license
  1807. */
  1808. ( function( window, factory ) {
  1809. // universal module definition
  1810. if ( typeof define == 'function' && define.amd ) {
  1811. // AMD
  1812. define( 'outlayer/outlayer',[
  1813. 'eventie/eventie',
  1814. 'eventEmitter/EventEmitter',
  1815. 'get-size/get-size',
  1816. 'fizzy-ui-utils/utils',
  1817. './item'
  1818. ],
  1819. function( eventie, EventEmitter, getSize, utils, Item ) {
  1820. return factory( window, eventie, EventEmitter, getSize, utils, Item);
  1821. }
  1822. );
  1823. } else if ( typeof exports == 'object' ) {
  1824. // CommonJS
  1825. module.exports = factory(
  1826. window,
  1827. require('eventie'),
  1828. require('wolfy87-eventemitter'),
  1829. require('get-size'),
  1830. require('fizzy-ui-utils'),
  1831. require('./item')
  1832. );
  1833. } else {
  1834. // browser global
  1835. window.Outlayer = factory(
  1836. window,
  1837. window.eventie,
  1838. window.EventEmitter,
  1839. window.getSize,
  1840. window.fizzyUIUtils,
  1841. window.Outlayer.Item
  1842. );
  1843. }
  1844. }( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) {
  1845. // ----- vars ----- //
  1846. var console = window.console;
  1847. var jQuery = window.jQuery;
  1848. var noop = function() {};
  1849. // -------------------------- Outlayer -------------------------- //
  1850. // globally unique identifiers
  1851. var GUID = 0;
  1852. // internal store of all Outlayer intances
  1853. var instances = {};
  1854. /**
  1855. * @param {Element, String} element
  1856. * @param {Object} options
  1857. * @constructor
  1858. */
  1859. function Outlayer( element, options ) {
  1860. var queryElement = utils.getQueryElement( element );
  1861. if ( !queryElement ) {
  1862. if ( console ) {
  1863. console.error( 'Bad element for ' + this.constructor.namespace +
  1864. ': ' + ( queryElement || element ) );
  1865. }
  1866. return;
  1867. }
  1868. this.element = queryElement;
  1869. // add jQuery
  1870. if ( jQuery ) {
  1871. this.$element = jQuery( this.element );
  1872. }
  1873. // options
  1874. this.options = utils.extend( {}, this.constructor.defaults );
  1875. this.option( options );
  1876. // add id for Outlayer.getFromElement
  1877. var id = ++GUID;
  1878. this.element.outlayerGUID = id; // expando
  1879. instances[ id ] = this; // associate via id
  1880. // kick it off
  1881. this._create();
  1882. if ( this.options.isInitLayout ) {
  1883. this.layout();
  1884. }
  1885. }
  1886. // settings are for internal use only
  1887. Outlayer.namespace = 'outlayer';
  1888. Outlayer.Item = Item;
  1889. // default options
  1890. Outlayer.defaults = {
  1891. containerStyle: {
  1892. position: 'relative'
  1893. },
  1894. isInitLayout: true,
  1895. isOriginLeft: true,
  1896. isOriginTop: true,
  1897. isResizeBound: true,
  1898. isResizingContainer: true,
  1899. // item options
  1900. transitionDuration: '0.4s',
  1901. hiddenStyle: {
  1902. opacity: 0,
  1903. transform: 'scale(0.001)'
  1904. },
  1905. visibleStyle: {
  1906. opacity: 1,
  1907. transform: 'scale(1)'
  1908. }
  1909. };
  1910. // inherit EventEmitter
  1911. utils.extend( Outlayer.prototype, EventEmitter.prototype );
  1912. /**
  1913. * set options
  1914. * @param {Object} opts
  1915. */
  1916. Outlayer.prototype.option = function( opts ) {
  1917. utils.extend( this.options, opts );
  1918. };
  1919. Outlayer.prototype._create = function() {
  1920. // get items from children
  1921. this.reloadItems();
  1922. // elements that affect layout, but are not laid out
  1923. this.stamps = [];
  1924. this.stamp( this.options.stamp );
  1925. // set container style
  1926. utils.extend( this.element.style, this.options.containerStyle );
  1927. // bind resize method
  1928. if ( this.options.isResizeBound ) {
  1929. this.bindResize();
  1930. }
  1931. };
  1932. // goes through all children again and gets bricks in proper order
  1933. Outlayer.prototype.reloadItems = function() {
  1934. // collection of item elements
  1935. this.items = this._itemize( this.element.children );
  1936. };
  1937. /**
  1938. * turn elements into Outlayer.Items to be used in layout
  1939. * @param {Array or NodeList or HTMLElement} elems
  1940. * @returns {Array} items - collection of new Outlayer Items
  1941. */
  1942. Outlayer.prototype._itemize = function( elems ) {
  1943. var itemElems = this._filterFindItemElements( elems );
  1944. var Item = this.constructor.Item;
  1945. // create new Outlayer Items for collection
  1946. var items = [];
  1947. for ( var i=0, len = itemElems.length; i < len; i++ ) {
  1948. var elem = itemElems[i];
  1949. var item = new Item( elem, this );
  1950. items.push( item );
  1951. }
  1952. return items;
  1953. };
  1954. /**
  1955. * get item elements to be used in layout
  1956. * @param {Array or NodeList or HTMLElement} elems
  1957. * @returns {Array} items - item elements
  1958. */
  1959. Outlayer.prototype._filterFindItemElements = function( elems ) {
  1960. return utils.filterFindElements( elems, this.options.itemSelector );
  1961. };
  1962. /**
  1963. * getter method for getting item elements
  1964. * @returns {Array} elems - collection of item elements
  1965. */
  1966. Outlayer.prototype.getItemElements = function() {
  1967. var elems = [];
  1968. for ( var i=0, len = this.items.length; i < len; i++ ) {
  1969. elems.push( this.items[i].element );
  1970. }
  1971. return elems;
  1972. };
  1973. // ----- init & layout ----- //
  1974. /**
  1975. * lays out all items
  1976. */
  1977. Outlayer.prototype.layout = function() {
  1978. this._resetLayout();
  1979. this._manageStamps();
  1980. // don't animate first layout
  1981. var isInstant = this.options.isLayoutInstant !== undefined ?
  1982. this.options.isLayoutInstant : !this._isLayoutInited;
  1983. this.layoutItems( this.items, isInstant );
  1984. // flag for initalized
  1985. this._isLayoutInited = true;
  1986. };
  1987. // _init is alias for layout
  1988. Outlayer.prototype._init = Outlayer.prototype.layout;
  1989. /**
  1990. * logic before any new layout
  1991. */
  1992. Outlayer.prototype._resetLayout = function() {
  1993. this.getSize();
  1994. };
  1995. Outlayer.prototype.getSize = function() {
  1996. this.size = getSize( this.element );
  1997. };
  1998. /**
  1999. * get measurement from option, for columnWidth, rowHeight, gutter
  2000. * if option is String -> get element from selector string, & get size of element
  2001. * if option is Element -> get size of element
  2002. * else use option as a number
  2003. *
  2004. * @param {String} measurement
  2005. * @param {String} size - width or height
  2006. * @private
  2007. */
  2008. Outlayer.prototype._getMeasurement = function( measurement, size ) {
  2009. var option = this.options[ measurement ];
  2010. var elem;
  2011. if ( !option ) {
  2012. // default to 0
  2013. this[ measurement ] = 0;
  2014. } else {
  2015. // use option as an element
  2016. if ( typeof option === 'string' ) {
  2017. elem = this.element.querySelector( option );
  2018. } else if ( utils.isElement( option ) ) {
  2019. elem = option;
  2020. }
  2021. // use size of element, if element
  2022. this[ measurement ] = elem ? getSize( elem )[ size ] : option;
  2023. }
  2024. };
  2025. /**
  2026. * layout a collection of item elements
  2027. * @api public
  2028. */
  2029. Outlayer.prototype.layoutItems = function( items, isInstant ) {
  2030. items = this._getItemsForLayout( items );
  2031. this._layoutItems( items, isInstant );
  2032. this._postLayout();
  2033. };
  2034. /**
  2035. * get the items to be laid out
  2036. * you may want to skip over some items
  2037. * @param {Array} items
  2038. * @returns {Array} items
  2039. */
  2040. Outlayer.prototype._getItemsForLayout = function( items ) {
  2041. var layoutItems = [];
  2042. for ( var i=0, len = items.length; i < len; i++ ) {
  2043. var item = items[i];
  2044. if ( !item.isIgnored ) {
  2045. layoutItems.push( item );
  2046. }
  2047. }
  2048. return layoutItems;
  2049. };
  2050. /**
  2051. * layout items
  2052. * @param {Array} items
  2053. * @param {Boolean} isInstant
  2054. */
  2055. Outlayer.prototype._layoutItems = function( items, isInstant ) {
  2056. this._emitCompleteOnItems( 'layout', items );
  2057. if ( !items || !items.length ) {
  2058. // no items, emit event with empty array
  2059. return;
  2060. }
  2061. var queue = [];
  2062. for ( var i=0, len = items.length; i < len; i++ ) {
  2063. var item = items[i];
  2064. // get x/y object from method
  2065. var position = this._getItemLayoutPosition( item );
  2066. // enqueue
  2067. position.item = item;
  2068. position.isInstant = isInstant || item.isLayoutInstant;
  2069. queue.push( position );
  2070. }
  2071. this._processLayoutQueue( queue );
  2072. };
  2073. /**
  2074. * get item layout position
  2075. * @param {Outlayer.Item} item
  2076. * @returns {Object} x and y position
  2077. */
  2078. Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
  2079. return {
  2080. x: 0,
  2081. y: 0
  2082. };
  2083. };
  2084. /**
  2085. * iterate over array and position each item
  2086. * Reason being - separating this logic prevents 'layout invalidation'
  2087. * thx @paul_irish
  2088. * @param {Array} queue
  2089. */
  2090. Outlayer.prototype._processLayoutQueue = function( queue ) {
  2091. for ( var i=0, len = queue.length; i < len; i++ ) {
  2092. var obj = queue[i];
  2093. this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
  2094. }
  2095. };
  2096. /**
  2097. * Sets position of item in DOM
  2098. * @param {Outlayer.Item} item
  2099. * @param {Number} x - horizontal position
  2100. * @param {Number} y - vertical position
  2101. * @param {Boolean} isInstant - disables transitions
  2102. */
  2103. Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
  2104. if ( isInstant ) {
  2105. // if not transition, just set CSS
  2106. item.goTo( x, y );
  2107. } else {
  2108. item.moveTo( x, y );
  2109. }
  2110. };
  2111. /**
  2112. * Any logic you want to do after each layout,
  2113. * i.e. size the container
  2114. */
  2115. Outlayer.prototype._postLayout = function() {
  2116. this.resizeContainer();
  2117. };
  2118. Outlayer.prototype.resizeContainer = function() {
  2119. if ( !this.options.isResizingContainer ) {
  2120. return;
  2121. }
  2122. var size = this._getContainerSize();
  2123. if ( size ) {
  2124. this._setContainerMeasure( size.width, true );
  2125. this._setContainerMeasure( size.height, false );
  2126. }
  2127. };
  2128. /**
  2129. * Sets width or height of container if returned
  2130. * @returns {Object} size
  2131. * @param {Number} width
  2132. * @param {Number} height
  2133. */
  2134. Outlayer.prototype._getContainerSize = noop;
  2135. /**
  2136. * @param {Number} measure - size of width or height
  2137. * @param {Boolean} isWidth
  2138. */
  2139. Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
  2140. if ( measure === undefined ) {
  2141. return;
  2142. }
  2143. var elemSize = this.size;
  2144. // add padding and border width if border box
  2145. if ( elemSize.isBorderBox ) {
  2146. measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
  2147. elemSize.borderLeftWidth + elemSize.borderRightWidth :
  2148. elemSize.paddingBottom + elemSize.paddingTop +
  2149. elemSize.borderTopWidth + elemSize.borderBottomWidth;
  2150. }
  2151. measure = Math.max( measure, 0 );
  2152. this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
  2153. };
  2154. /**
  2155. * emit eventComplete on a collection of items events
  2156. * @param {String} eventName
  2157. * @param {Array} items - Outlayer.Items
  2158. */
  2159. Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) {
  2160. var _this = this;
  2161. function onComplete() {
  2162. _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
  2163. }
  2164. var count = items.length;
  2165. if ( !items || !count ) {
  2166. onComplete();
  2167. return;
  2168. }
  2169. var doneCount = 0;
  2170. function tick() {
  2171. doneCount++;
  2172. if ( doneCount === count ) {
  2173. onComplete();
  2174. }
  2175. }
  2176. // bind callback
  2177. for ( var i=0, len = items.length; i < len; i++ ) {
  2178. var item = items[i];
  2179. item.once( eventName, tick );
  2180. }
  2181. };
  2182. /**
  2183. * emits events via eventEmitter and jQuery events
  2184. * @param {String} type - name of event
  2185. * @param {Event} event - original event
  2186. * @param {Array} args - extra arguments
  2187. */
  2188. Outlayer.prototype.dispatchEvent = function( type, event, args ) {
  2189. // add original event to arguments
  2190. var emitArgs = event ? [ event ].concat( args ) : args;
  2191. this.emitEvent( type, emitArgs );
  2192. if ( jQuery ) {
  2193. // set this.$element
  2194. this.$element = this.$element || jQuery( this.element );
  2195. if ( event ) {
  2196. // create jQuery event
  2197. var $event = jQuery.Event( event );
  2198. $event.type = type;
  2199. this.$element.trigger( $event, args );
  2200. } else {
  2201. // just trigger with type if no event available
  2202. this.$element.trigger( type, args );
  2203. }
  2204. }
  2205. };
  2206. // -------------------------- ignore & stamps -------------------------- //
  2207. /**
  2208. * keep item in collection, but do not lay it out
  2209. * ignored items do not get skipped in layout
  2210. * @param {Element} elem
  2211. */
  2212. Outlayer.prototype.ignore = function( elem ) {
  2213. var item = this.getItem( elem );
  2214. if ( item ) {
  2215. item.isIgnored = true;
  2216. }
  2217. };
  2218. /**
  2219. * return item to layout collection
  2220. * @param {Element} elem
  2221. */
  2222. Outlayer.prototype.unignore = function( elem ) {
  2223. var item = this.getItem( elem );
  2224. if ( item ) {
  2225. delete item.isIgnored;
  2226. }
  2227. };
  2228. /**
  2229. * adds elements to stamps
  2230. * @param {NodeList, Array, Element, or String} elems
  2231. */
  2232. Outlayer.prototype.stamp = function( elems ) {
  2233. elems = this._find( elems );
  2234. if ( !elems ) {
  2235. return;
  2236. }
  2237. this.stamps = this.stamps.concat( elems );
  2238. // ignore
  2239. for ( var i=0, len = elems.length; i < len; i++ ) {
  2240. var elem = elems[i];
  2241. this.ignore( elem );
  2242. }
  2243. };
  2244. /**
  2245. * removes elements to stamps
  2246. * @param {NodeList, Array, or Element} elems
  2247. */
  2248. Outlayer.prototype.unstamp = function( elems ) {
  2249. elems = this._find( elems );
  2250. if ( !elems ){
  2251. return;
  2252. }
  2253. for ( var i=0, len = elems.length; i < len; i++ ) {
  2254. var elem = elems[i];
  2255. // filter out removed stamp elements
  2256. utils.removeFrom( this.stamps, elem );
  2257. this.unignore( elem );
  2258. }
  2259. };
  2260. /**
  2261. * finds child elements
  2262. * @param {NodeList, Array, Element, or String} elems
  2263. * @returns {Array} elems
  2264. */
  2265. Outlayer.prototype._find = function( elems ) {
  2266. if ( !elems ) {
  2267. return;
  2268. }
  2269. // if string, use argument as selector string
  2270. if ( typeof elems === 'string' ) {
  2271. elems = this.element.querySelectorAll( elems );
  2272. }
  2273. elems = utils.makeArray( elems );
  2274. return elems;
  2275. };
  2276. Outlayer.prototype._manageStamps = function() {
  2277. if ( !this.stamps || !this.stamps.length ) {
  2278. return;
  2279. }
  2280. this._getBoundingRect();
  2281. for ( var i=0, len = this.stamps.length; i < len; i++ ) {
  2282. var stamp = this.stamps[i];
  2283. this._manageStamp( stamp );
  2284. }
  2285. };
  2286. // update boundingLeft / Top
  2287. Outlayer.prototype._getBoundingRect = function() {
  2288. // get bounding rect for container element
  2289. var boundingRect = this.element.getBoundingClientRect();
  2290. var size = this.size;
  2291. this._boundingRect = {
  2292. left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
  2293. top: boundingRect.top + size.paddingTop + size.borderTopWidth,
  2294. right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
  2295. bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
  2296. };
  2297. };
  2298. /**
  2299. * @param {Element} stamp
  2300. **/
  2301. Outlayer.prototype._manageStamp = noop;
  2302. /**
  2303. * get x/y position of element relative to container element
  2304. * @param {Element} elem
  2305. * @returns {Object} offset - has left, top, right, bottom
  2306. */
  2307. Outlayer.prototype._getElementOffset = function( elem ) {
  2308. var boundingRect = elem.getBoundingClientRect();
  2309. var thisRect = this._boundingRect;
  2310. var size = getSize( elem );
  2311. var offset = {
  2312. left: boundingRect.left - thisRect.left - size.marginLeft,
  2313. top: boundingRect.top - thisRect.top - size.marginTop,
  2314. right: thisRect.right - boundingRect.right - size.marginRight,
  2315. bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
  2316. };
  2317. return offset;
  2318. };
  2319. // -------------------------- resize -------------------------- //
  2320. // enable event handlers for listeners
  2321. // i.e. resize -> onresize
  2322. Outlayer.prototype.handleEvent = function( event ) {
  2323. var method = 'on' + event.type;
  2324. if ( this[ method ] ) {
  2325. this[ method ]( event );
  2326. }
  2327. };
  2328. /**
  2329. * Bind layout to window resizing
  2330. */
  2331. Outlayer.prototype.bindResize = function() {
  2332. // bind just one listener
  2333. if ( this.isResizeBound ) {
  2334. return;
  2335. }
  2336. window.eventie.bind( window, 'resize', this );
  2337. this.isResizeBound = true;
  2338. };
  2339. /**
  2340. * Unbind layout to window resizing
  2341. */
  2342. Outlayer.prototype.unbindResize = function() {
  2343. if ( this.isResizeBound ) {
  2344. window.eventie.unbind( window, 'resize', this );
  2345. }
  2346. this.isResizeBound = false;
  2347. };
  2348. // original debounce by John Hann
  2349. // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
  2350. // this fires every resize
  2351. Outlayer.prototype.onresize = function() {
  2352. if ( this.resizeTimeout ) {
  2353. clearTimeout( this.resizeTimeout );
  2354. }
  2355. var _this = this;
  2356. function delayed() {
  2357. _this.resize();
  2358. delete _this.resizeTimeout;
  2359. }
  2360. this.resizeTimeout = setTimeout( delayed, 100 );
  2361. };
  2362. // debounced, layout on resize
  2363. Outlayer.prototype.resize = function() {
  2364. // don't trigger if size did not change
  2365. // or if resize was unbound. See #9
  2366. if ( !this.isResizeBound || !this.needsResizeLayout() ) {
  2367. return;
  2368. }
  2369. this.layout();
  2370. };
  2371. /**
  2372. * check if layout is needed post layout
  2373. * @returns Boolean
  2374. */
  2375. Outlayer.prototype.needsResizeLayout = function() {
  2376. var size = getSize( this.element );
  2377. // check that this.size and size are there
  2378. // IE8 triggers resize on body size change, so they might not be
  2379. var hasSizes = this.size && size;
  2380. return hasSizes && size.innerWidth !== this.size.innerWidth;
  2381. };
  2382. // -------------------------- methods -------------------------- //
  2383. /**
  2384. * add items to Outlayer instance
  2385. * @param {Array or NodeList or Element} elems
  2386. * @returns {Array} items - Outlayer.Items
  2387. **/
  2388. Outlayer.prototype.addItems = function( elems ) {
  2389. var items = this._itemize( elems );
  2390. // add items to collection
  2391. if ( items.length ) {
  2392. this.items = this.items.concat( items );
  2393. }
  2394. return items;
  2395. };
  2396. /**
  2397. * Layout newly-appended item elements
  2398. * @param {Array or NodeList or Element} elems
  2399. */
  2400. Outlayer.prototype.appended = function( elems ) {
  2401. var items = this.addItems( elems );
  2402. if ( !items.length ) {
  2403. return;
  2404. }
  2405. // layout and reveal just the new items
  2406. this.layoutItems( items, true );
  2407. this.reveal( items );
  2408. };
  2409. /**
  2410. * Layout prepended elements
  2411. * @param {Array or NodeList or Element} elems
  2412. */
  2413. Outlayer.prototype.prepended = function( elems ) {
  2414. var items = this._itemize( elems );
  2415. if ( !items.length ) {
  2416. return;
  2417. }
  2418. // add items to beginning of collection
  2419. var previousItems = this.items.slice(0);
  2420. this.items = items.concat( previousItems );
  2421. // start new layout
  2422. this._resetLayout();
  2423. this._manageStamps();
  2424. // layout new stuff without transition
  2425. this.layoutItems( items, true );
  2426. this.reveal( items );
  2427. // layout previous items
  2428. this.layoutItems( previousItems );
  2429. };
  2430. /**
  2431. * reveal a collection of items
  2432. * @param {Array of Outlayer.Items} items
  2433. */
  2434. Outlayer.prototype.reveal = function( items ) {
  2435. this._emitCompleteOnItems( 'reveal', items );
  2436. var len = items && items.length;
  2437. for ( var i=0; len && i < len; i++ ) {
  2438. var item = items[i];
  2439. item.reveal();
  2440. }
  2441. };
  2442. /**
  2443. * hide a collection of items
  2444. * @param {Array of Outlayer.Items} items
  2445. */
  2446. Outlayer.prototype.hide = function( items ) {
  2447. this._emitCompleteOnItems( 'hide', items );
  2448. var len = items && items.length;
  2449. for ( var i=0; len && i < len; i++ ) {
  2450. var item = items[i];
  2451. item.hide();
  2452. }
  2453. };
  2454. /**
  2455. * reveal item elements
  2456. * @param {Array}, {Element}, {NodeList} items
  2457. */
  2458. Outlayer.prototype.revealItemElements = function( elems ) {
  2459. var items = this.getItems( elems );
  2460. this.reveal( items );
  2461. };
  2462. /**
  2463. * hide item elements
  2464. * @param {Array}, {Element}, {NodeList} items
  2465. */
  2466. Outlayer.prototype.hideItemElements = function( elems ) {
  2467. var items = this.getItems( elems );
  2468. this.hide( items );
  2469. };
  2470. /**
  2471. * get Outlayer.Item, given an Element
  2472. * @param {Element} elem
  2473. * @param {Function} callback
  2474. * @returns {Outlayer.Item} item
  2475. */
  2476. Outlayer.prototype.getItem = function( elem ) {
  2477. // loop through items to get the one that matches
  2478. for ( var i=0, len = this.items.length; i < len; i++ ) {
  2479. var item = this.items[i];
  2480. if ( item.element === elem ) {
  2481. // return item
  2482. return item;
  2483. }
  2484. }
  2485. };
  2486. /**
  2487. * get collection of Outlayer.Items, given Elements
  2488. * @param {Array} elems
  2489. * @returns {Array} items - Outlayer.Items
  2490. */
  2491. Outlayer.prototype.getItems = function( elems ) {
  2492. elems = utils.makeArray( elems );
  2493. var items = [];
  2494. for ( var i=0, len = elems.length; i < len; i++ ) {
  2495. var elem = elems[i];
  2496. var item = this.getItem( elem );
  2497. if ( item ) {
  2498. items.push( item );
  2499. }
  2500. }
  2501. return items;
  2502. };
  2503. /**
  2504. * remove element(s) from instance and DOM
  2505. * @param {Array or NodeList or Element} elems
  2506. */
  2507. Outlayer.prototype.remove = function( elems ) {
  2508. var removeItems = this.getItems( elems );
  2509. this._emitCompleteOnItems( 'remove', removeItems );
  2510. // bail if no items to remove
  2511. if ( !removeItems || !removeItems.length ) {
  2512. return;
  2513. }
  2514. for ( var i=0, len = removeItems.length; i < len; i++ ) {
  2515. var item = removeItems[i];
  2516. item.remove();
  2517. // remove item from collection
  2518. utils.removeFrom( this.items, item );
  2519. }
  2520. };
  2521. // ----- destroy ----- //
  2522. // remove and disable Outlayer instance
  2523. Outlayer.prototype.destroy = function() {
  2524. // clean up dynamic styles
  2525. var style = this.element.style;
  2526. style.height = '';
  2527. style.position = '';
  2528. style.width = '';
  2529. // destroy items
  2530. for ( var i=0, len = this.items.length; i < len; i++ ) {
  2531. var item = this.items[i];
  2532. item.destroy();
  2533. }
  2534. this.unbindResize();
  2535. var id = this.element.outlayerGUID;
  2536. delete instances[ id ]; // remove reference to instance by id
  2537. delete this.element.outlayerGUID;
  2538. // remove data for jQuery
  2539. if ( jQuery ) {
  2540. jQuery.removeData( this.element, this.constructor.namespace );
  2541. }
  2542. };
  2543. // -------------------------- data -------------------------- //
  2544. /**
  2545. * get Outlayer instance from element
  2546. * @param {Element} elem
  2547. * @returns {Outlayer}
  2548. */
  2549. Outlayer.data = function( elem ) {
  2550. elem = utils.getQueryElement( elem );
  2551. var id = elem && elem.outlayerGUID;
  2552. return id && instances[ id ];
  2553. };
  2554. // -------------------------- create Outlayer class -------------------------- //
  2555. /**
  2556. * create a layout class
  2557. * @param {String} namespace
  2558. */
  2559. Outlayer.create = function( namespace, options ) {
  2560. // sub-class Outlayer
  2561. function Layout() {
  2562. Outlayer.apply( this, arguments );
  2563. }
  2564. // inherit Outlayer prototype, use Object.create if there
  2565. if ( Object.create ) {
  2566. Layout.prototype = Object.create( Outlayer.prototype );
  2567. } else {
  2568. utils.extend( Layout.prototype, Outlayer.prototype );
  2569. }
  2570. // set contructor, used for namespace and Item
  2571. Layout.prototype.constructor = Layout;
  2572. Layout.defaults = utils.extend( {}, Outlayer.defaults );
  2573. // apply new options
  2574. utils.extend( Layout.defaults, options );
  2575. // keep prototype.settings for backwards compatibility (Packery v1.2.0)
  2576. Layout.prototype.settings = {};
  2577. Layout.namespace = namespace;
  2578. Layout.data = Outlayer.data;
  2579. // sub-class Item
  2580. Layout.Item = function LayoutItem() {
  2581. Item.apply( this, arguments );
  2582. };
  2583. Layout.Item.prototype = new Item();
  2584. // -------------------------- declarative -------------------------- //
  2585. utils.htmlInit( Layout, namespace );
  2586. // -------------------------- jQuery bridge -------------------------- //
  2587. // make into jQuery plugin
  2588. if ( jQuery && jQuery.bridget ) {
  2589. jQuery.bridget( namespace, Layout );
  2590. }
  2591. return Layout;
  2592. };
  2593. // ----- fin ----- //
  2594. // back in global
  2595. Outlayer.Item = Item;
  2596. return Outlayer;
  2597. }));
  2598. /**
  2599. * Rect
  2600. * low-level utility class for basic geometry
  2601. */
  2602. ( function( window, factory ) {
  2603. // universal module definition
  2604. if ( typeof define == 'function' && define.amd ) {
  2605. // AMD
  2606. define( 'packery/js/rect',factory );
  2607. } else if ( typeof exports == 'object' ) {
  2608. // CommonJS
  2609. module.exports = factory();
  2610. } else {
  2611. // browser global
  2612. window.Packery = window.Packery || {};
  2613. window.Packery.Rect = factory();
  2614. }
  2615. }( window, function factory() {
  2616. // -------------------------- Packery -------------------------- //
  2617. // global namespace
  2618. var Packery = window.Packery = function() {};
  2619. // -------------------------- Rect -------------------------- //
  2620. function Rect( props ) {
  2621. // extend properties from defaults
  2622. for ( var prop in Rect.defaults ) {
  2623. this[ prop ] = Rect.defaults[ prop ];
  2624. }
  2625. for ( prop in props ) {
  2626. this[ prop ] = props[ prop ];
  2627. }
  2628. }
  2629. // make available
  2630. Packery.Rect = Rect;
  2631. Rect.defaults = {
  2632. x: 0,
  2633. y: 0,
  2634. width: 0,
  2635. height: 0
  2636. };
  2637. /**
  2638. * Determines whether or not this rectangle wholly encloses another rectangle or point.
  2639. * @param {Rect} rect
  2640. * @returns {Boolean}
  2641. **/
  2642. Rect.prototype.contains = function( rect ) {
  2643. // points don't have width or height
  2644. var otherWidth = rect.width || 0;
  2645. var otherHeight = rect.height || 0;
  2646. return this.x <= rect.x &&
  2647. this.y <= rect.y &&
  2648. this.x + this.width >= rect.x + otherWidth &&
  2649. this.y + this.height >= rect.y + otherHeight;
  2650. };
  2651. /**
  2652. * Determines whether or not the rectangle intersects with another.
  2653. * @param {Rect} rect
  2654. * @returns {Boolean}
  2655. **/
  2656. Rect.prototype.overlaps = function( rect ) {
  2657. var thisRight = this.x + this.width;
  2658. var thisBottom = this.y + this.height;
  2659. var rectRight = rect.x + rect.width;
  2660. var rectBottom = rect.y + rect.height;
  2661. // http://stackoverflow.com/a/306332
  2662. return this.x < rectRight &&
  2663. thisRight > rect.x &&
  2664. this.y < rectBottom &&
  2665. thisBottom > rect.y;
  2666. };
  2667. /**
  2668. * @param {Rect} rect - the overlapping rect
  2669. * @returns {Array} freeRects - rects representing the area around the rect
  2670. **/
  2671. Rect.prototype.getMaximalFreeRects = function( rect ) {
  2672. // if no intersection, return false
  2673. if ( !this.overlaps( rect ) ) {
  2674. return false;
  2675. }
  2676. var freeRects = [];
  2677. var freeRect;
  2678. var thisRight = this.x + this.width;
  2679. var thisBottom = this.y + this.height;
  2680. var rectRight = rect.x + rect.width;
  2681. var rectBottom = rect.y + rect.height;
  2682. // top
  2683. if ( this.y < rect.y ) {
  2684. freeRect = new Rect({
  2685. x: this.x,
  2686. y: this.y,
  2687. width: this.width,
  2688. height: rect.y - this.y
  2689. });
  2690. freeRects.push( freeRect );
  2691. }
  2692. // right
  2693. if ( thisRight > rectRight ) {
  2694. freeRect = new Rect({
  2695. x: rectRight,
  2696. y: this.y,
  2697. width: thisRight - rectRight,
  2698. height: this.height
  2699. });
  2700. freeRects.push( freeRect );
  2701. }
  2702. // bottom
  2703. if ( thisBottom > rectBottom ) {
  2704. freeRect = new Rect({
  2705. x: this.x,
  2706. y: rectBottom,
  2707. width: this.width,
  2708. height: thisBottom - rectBottom
  2709. });
  2710. freeRects.push( freeRect );
  2711. }
  2712. // left
  2713. if ( this.x < rect.x ) {
  2714. freeRect = new Rect({
  2715. x: this.x,
  2716. y: this.y,
  2717. width: rect.x - this.x,
  2718. height: this.height
  2719. });
  2720. freeRects.push( freeRect );
  2721. }
  2722. return freeRects;
  2723. };
  2724. Rect.prototype.canFit = function( rect ) {
  2725. return this.width >= rect.width && this.height >= rect.height;
  2726. };
  2727. return Rect;
  2728. }));
  2729. /**
  2730. * Packer
  2731. * bin-packing algorithm
  2732. */
  2733. ( function( window, factory ) {
  2734. // universal module definition
  2735. if ( typeof define == 'function' && define.amd ) {
  2736. // AMD
  2737. define( 'packery/js/packer',[ './rect' ], factory );
  2738. } else if ( typeof exports == 'object' ) {
  2739. // CommonJS
  2740. module.exports = factory(
  2741. require('./rect')
  2742. );
  2743. } else {
  2744. // browser global
  2745. var Packery = window.Packery = window.Packery || {};
  2746. Packery.Packer = factory( Packery.Rect );
  2747. }
  2748. }( window, function factory( Rect ) {
  2749. // -------------------------- Packer -------------------------- //
  2750. /**
  2751. * @param {Number} width
  2752. * @param {Number} height
  2753. * @param {String} sortDirection
  2754. * topLeft for vertical, leftTop for horizontal
  2755. */
  2756. function Packer( width, height, sortDirection ) {
  2757. this.width = width || 0;
  2758. this.height = height || 0;
  2759. this.sortDirection = sortDirection || 'downwardLeftToRight';
  2760. this.reset();
  2761. }
  2762. Packer.prototype.reset = function() {
  2763. this.spaces = [];
  2764. this.newSpaces = [];
  2765. var initialSpace = new Rect({
  2766. x: 0,
  2767. y: 0,
  2768. width: this.width,
  2769. height: this.height
  2770. });
  2771. this.spaces.push( initialSpace );
  2772. // set sorter
  2773. this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
  2774. };
  2775. // change x and y of rect to fit with in Packer's available spaces
  2776. Packer.prototype.pack = function( rect ) {
  2777. for ( var i=0, len = this.spaces.length; i < len; i++ ) {
  2778. var space = this.spaces[i];
  2779. if ( space.canFit( rect ) ) {
  2780. this.placeInSpace( rect, space );
  2781. break;
  2782. }
  2783. }
  2784. };
  2785. Packer.prototype.placeInSpace = function( rect, space ) {
  2786. // place rect in space
  2787. rect.x = space.x;
  2788. rect.y = space.y;
  2789. this.placed( rect );
  2790. };
  2791. // update spaces with placed rect
  2792. Packer.prototype.placed = function( rect ) {
  2793. // update spaces
  2794. var revisedSpaces = [];
  2795. for ( var i=0, len = this.spaces.length; i < len; i++ ) {
  2796. var space = this.spaces[i];
  2797. var newSpaces = space.getMaximalFreeRects( rect );
  2798. // add either the original space or the new spaces to the revised spaces
  2799. if ( newSpaces ) {
  2800. revisedSpaces.push.apply( revisedSpaces, newSpaces );
  2801. } else {
  2802. revisedSpaces.push( space );
  2803. }
  2804. }
  2805. this.spaces = revisedSpaces;
  2806. this.mergeSortSpaces();
  2807. };
  2808. Packer.prototype.mergeSortSpaces = function() {
  2809. // remove redundant spaces
  2810. Packer.mergeRects( this.spaces );
  2811. this.spaces.sort( this.sorter );
  2812. };
  2813. // add a space back
  2814. Packer.prototype.addSpace = function( rect ) {
  2815. this.spaces.push( rect );
  2816. this.mergeSortSpaces();
  2817. };
  2818. // -------------------------- utility functions -------------------------- //
  2819. /**
  2820. * Remove redundant rectangle from array of rectangles
  2821. * @param {Array} rects: an array of Rects
  2822. * @returns {Array} rects: an array of Rects
  2823. **/
  2824. Packer.mergeRects = function( rects ) {
  2825. for ( var i=0, len = rects.length; i < len; i++ ) {
  2826. var rect = rects[i];
  2827. // skip over this rect if it was already removed
  2828. if ( !rect ) {
  2829. continue;
  2830. }
  2831. // clone rects we're testing, remove this rect
  2832. var compareRects = rects.slice(0);
  2833. // do not compare with self
  2834. compareRects.splice( i, 1 );
  2835. // compare this rect with others
  2836. var removedCount = 0;
  2837. for ( var j=0, jLen = compareRects.length; j < jLen; j++ ) {
  2838. var compareRect = compareRects[j];
  2839. // if this rect contains another,
  2840. // remove that rect from test collection
  2841. var indexAdjust = i > j ? 0 : 1;
  2842. if ( rect.contains( compareRect ) ) {
  2843. // console.log( 'current test rects:' + testRects.length, testRects );
  2844. // console.log( i, j, indexAdjust, rect, compareRect );
  2845. rects.splice( j + indexAdjust - removedCount, 1 );
  2846. removedCount++;
  2847. }
  2848. }
  2849. }
  2850. return rects;
  2851. };
  2852. // -------------------------- sorters -------------------------- //
  2853. // functions for sorting rects in order
  2854. var sorters = {
  2855. // top down, then left to right
  2856. downwardLeftToRight: function( a, b ) {
  2857. return a.y - b.y || a.x - b.x;
  2858. },
  2859. // left to right, then top down
  2860. rightwardTopToBottom: function( a, b ) {
  2861. return a.x - b.x || a.y - b.y;
  2862. }
  2863. };
  2864. // -------------------------- -------------------------- //
  2865. return Packer;
  2866. }));
  2867. /**
  2868. * Packery Item Element
  2869. **/
  2870. ( function( window, factory ) {
  2871. // universal module definition
  2872. if ( typeof define == 'function' && define.amd ) {
  2873. // AMD
  2874. define( 'packery/js/item',[
  2875. 'get-style-property/get-style-property',
  2876. 'outlayer/outlayer',
  2877. './rect'
  2878. ],
  2879. factory );
  2880. } else if ( typeof exports == 'object' ) {
  2881. // CommonJS
  2882. module.exports = factory(
  2883. require('desandro-get-style-property'),
  2884. require('outlayer'),
  2885. require('./rect')
  2886. );
  2887. } else {
  2888. // browser global
  2889. window.Packery.Item = factory(
  2890. window.getStyleProperty,
  2891. window.Outlayer,
  2892. window.Packery.Rect
  2893. );
  2894. }
  2895. }( window, function factory( getStyleProperty, Outlayer, Rect ) {
  2896. // -------------------------- Item -------------------------- //
  2897. var transformProperty = getStyleProperty('transform');
  2898. // sub-class Item
  2899. var Item = function PackeryItem() {
  2900. Outlayer.Item.apply( this, arguments );
  2901. };
  2902. Item.prototype = new Outlayer.Item();
  2903. var protoCreate = Item.prototype._create;
  2904. Item.prototype._create = function() {
  2905. // call default _create logic
  2906. protoCreate.call( this );
  2907. this.rect = new Rect();
  2908. // rect used for placing, in drag or Packery.fit()
  2909. this.placeRect = new Rect();
  2910. };
  2911. // -------------------------- drag -------------------------- //
  2912. Item.prototype.dragStart = function() {
  2913. this.getPosition();
  2914. this.removeTransitionStyles();
  2915. // remove transform property from transition
  2916. if ( this.isTransitioning && transformProperty ) {
  2917. this.element.style[ transformProperty ] = 'none';
  2918. }
  2919. this.getSize();
  2920. // create place rect, used for position when dragged then dropped
  2921. // or when positioning
  2922. this.isPlacing = true;
  2923. this.needsPositioning = false;
  2924. this.positionPlaceRect( this.position.x, this.position.y );
  2925. this.isTransitioning = false;
  2926. this.didDrag = false;
  2927. };
  2928. /**
  2929. * handle item when it is dragged
  2930. * @param {Number} x - horizontal position of dragged item
  2931. * @param {Number} y - vertical position of dragged item
  2932. */
  2933. Item.prototype.dragMove = function( x, y ) {
  2934. this.didDrag = true;
  2935. var packerySize = this.layout.size;
  2936. x -= packerySize.paddingLeft;
  2937. y -= packerySize.paddingTop;
  2938. this.positionPlaceRect( x, y );
  2939. };
  2940. Item.prototype.dragStop = function() {
  2941. this.getPosition();
  2942. var isDiffX = this.position.x != this.placeRect.x;
  2943. var isDiffY = this.position.y != this.placeRect.y;
  2944. // set post-drag positioning flag
  2945. this.needsPositioning = isDiffX || isDiffY;
  2946. // reset flag
  2947. this.didDrag = false;
  2948. };
  2949. // -------------------------- placing -------------------------- //
  2950. /**
  2951. * position a rect that will occupy space in the packer
  2952. * @param {Number} x
  2953. * @param {Number} y
  2954. * @param {Boolean} isMaxYContained
  2955. */
  2956. Item.prototype.positionPlaceRect = function( x, y, isMaxYOpen ) {
  2957. this.placeRect.x = this.getPlaceRectCoord( x, true );
  2958. this.placeRect.y = this.getPlaceRectCoord( y, false, isMaxYOpen );
  2959. };
  2960. /**
  2961. * get x/y coordinate for place rect
  2962. * @param {Number} coord - x or y
  2963. * @param {Boolean} isX
  2964. * @param {Boolean} isMaxOpen - does not limit value to outer bound
  2965. * @returns {Number} coord - processed x or y
  2966. */
  2967. Item.prototype.getPlaceRectCoord = function( coord, isX, isMaxOpen ) {
  2968. var measure = isX ? 'Width' : 'Height';
  2969. var size = this.size[ 'outer' + measure ];
  2970. var segment = this.layout[ isX ? 'columnWidth' : 'rowHeight' ];
  2971. var parentSize = this.layout.size[ 'inner' + measure ];
  2972. // additional parentSize calculations for Y
  2973. if ( !isX ) {
  2974. parentSize = Math.max( parentSize, this.layout.maxY );
  2975. // prevent gutter from bumping up height when non-vertical grid
  2976. if ( !this.layout.rowHeight ) {
  2977. parentSize -= this.layout.gutter;
  2978. }
  2979. }
  2980. var max;
  2981. if ( segment ) {
  2982. segment += this.layout.gutter;
  2983. // allow for last column to reach the edge
  2984. parentSize += isX ? this.layout.gutter : 0;
  2985. // snap to closest segment
  2986. coord = Math.round( coord / segment );
  2987. // contain to outer bound
  2988. // contain non-growing bound, allow growing bound to grow
  2989. var mathMethod;
  2990. if ( this.layout.options.isHorizontal ) {
  2991. mathMethod = !isX ? 'floor' : 'ceil';
  2992. } else {
  2993. mathMethod = isX ? 'floor' : 'ceil';
  2994. }
  2995. var maxSegments = Math[ mathMethod ]( parentSize / segment );
  2996. maxSegments -= Math.ceil( size / segment );
  2997. max = maxSegments;
  2998. } else {
  2999. max = parentSize - size;
  3000. }
  3001. coord = isMaxOpen ? coord : Math.min( coord, max );
  3002. coord *= segment || 1;
  3003. return Math.max( 0, coord );
  3004. };
  3005. Item.prototype.copyPlaceRectPosition = function() {
  3006. this.rect.x = this.placeRect.x;
  3007. this.rect.y = this.placeRect.y;
  3008. };
  3009. // ----- ----- //
  3010. // remove element from DOM
  3011. Item.prototype.removeElem = function() {
  3012. this.element.parentNode.removeChild( this.element );
  3013. // add space back to packer
  3014. this.layout.packer.addSpace( this.rect );
  3015. this.emitEvent( 'remove', [ this ] );
  3016. };
  3017. // ----- ----- //
  3018. return Item;
  3019. }));
  3020. /*!
  3021. * Packery v1.4.3
  3022. * bin-packing layout library
  3023. *
  3024. * Licensed GPLv3 for open source use
  3025. * or Flickity Commercial License for commercial use
  3026. *
  3027. * http://packery.metafizzy.co
  3028. * Copyright 2015 Metafizzy
  3029. */
  3030. ( function( window, factory ) {
  3031. // universal module definition
  3032. if ( typeof define == 'function' && define.amd ) {
  3033. // AMD
  3034. define( [
  3035. 'classie/classie',
  3036. 'get-size/get-size',
  3037. 'outlayer/outlayer',
  3038. 'packery/js/rect',
  3039. 'packery/js/packer',
  3040. 'packery/js/item'
  3041. ],
  3042. factory );
  3043. } else if ( typeof exports == 'object' ) {
  3044. // CommonJS
  3045. module.exports = factory(
  3046. require('desandro-classie'),
  3047. require('get-size'),
  3048. require('outlayer'),
  3049. require('./rect'),
  3050. require('./packer'),
  3051. require('./item')
  3052. );
  3053. } else {
  3054. // browser global
  3055. window.Packery = factory(
  3056. window.classie,
  3057. window.getSize,
  3058. window.Outlayer,
  3059. window.Packery.Rect,
  3060. window.Packery.Packer,
  3061. window.Packery.Item
  3062. );
  3063. }
  3064. }( window, function factory( classie, getSize, Outlayer, Rect, Packer, Item ) {
  3065. // ----- Rect ----- //
  3066. // allow for pixel rounding errors IE8-IE11 & Firefox; #227
  3067. Rect.prototype.canFit = function( rect ) {
  3068. return this.width >= rect.width - 1 && this.height >= rect.height - 1;
  3069. };
  3070. // -------------------------- Packery -------------------------- //
  3071. // create an Outlayer layout class
  3072. var Packery = Outlayer.create('packery');
  3073. Packery.Item = Item;
  3074. Packery.prototype._create = function() {
  3075. // call super
  3076. Outlayer.prototype._create.call( this );
  3077. // initial properties
  3078. this.packer = new Packer();
  3079. // Left over from v1.0
  3080. this.stamp( this.options.stamped );
  3081. // create drag handlers
  3082. var _this = this;
  3083. this.handleDraggabilly = {
  3084. dragStart: function() {
  3085. _this.itemDragStart( this.element );
  3086. },
  3087. dragMove: function() {
  3088. _this.itemDragMove( this.element, this.position.x, this.position.y );
  3089. },
  3090. dragEnd: function() {
  3091. _this.itemDragEnd( this.element );
  3092. }
  3093. };
  3094. this.handleUIDraggable = {
  3095. start: function handleUIDraggableStart( event, ui ) {
  3096. // HTML5 may trigger dragstart, dismiss HTML5 dragging
  3097. if ( !ui ) {
  3098. return;
  3099. }
  3100. _this.itemDragStart( event.currentTarget );
  3101. },
  3102. drag: function handleUIDraggableDrag( event, ui ) {
  3103. if ( !ui ) {
  3104. return;
  3105. }
  3106. _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
  3107. },
  3108. stop: function handleUIDraggableStop( event, ui ) {
  3109. if ( !ui ) {
  3110. return;
  3111. }
  3112. _this.itemDragEnd( event.currentTarget );
  3113. }
  3114. };
  3115. };
  3116. // ----- init & layout ----- //
  3117. /**
  3118. * logic before any new layout
  3119. */
  3120. Packery.prototype._resetLayout = function() {
  3121. this.getSize();
  3122. this._getMeasurements();
  3123. // reset packer
  3124. var packer = this.packer;
  3125. // packer settings, if horizontal or vertical
  3126. if ( this.options.isHorizontal ) {
  3127. packer.width = Number.POSITIVE_INFINITY;
  3128. packer.height = this.size.innerHeight + this.gutter;
  3129. packer.sortDirection = 'rightwardTopToBottom';
  3130. } else {
  3131. packer.width = this.size.innerWidth + this.gutter;
  3132. packer.height = Number.POSITIVE_INFINITY;
  3133. packer.sortDirection = 'downwardLeftToRight';
  3134. }
  3135. packer.reset();
  3136. // layout
  3137. this.maxY = 0;
  3138. this.maxX = 0;
  3139. };
  3140. /**
  3141. * update columnWidth, rowHeight, & gutter
  3142. * @private
  3143. */
  3144. Packery.prototype._getMeasurements = function() {
  3145. this._getMeasurement( 'columnWidth', 'width' );
  3146. this._getMeasurement( 'rowHeight', 'height' );
  3147. this._getMeasurement( 'gutter', 'width' );
  3148. };
  3149. Packery.prototype._getItemLayoutPosition = function( item ) {
  3150. this._packItem( item );
  3151. return item.rect;
  3152. };
  3153. /**
  3154. * layout item in packer
  3155. * @param {Packery.Item} item
  3156. */
  3157. Packery.prototype._packItem = function( item ) {
  3158. this._setRectSize( item.element, item.rect );
  3159. // pack the rect in the packer
  3160. this.packer.pack( item.rect );
  3161. this._setMaxXY( item.rect );
  3162. };
  3163. /**
  3164. * set max X and Y value, for size of container
  3165. * @param {Packery.Rect} rect
  3166. * @private
  3167. */
  3168. Packery.prototype._setMaxXY = function( rect ) {
  3169. this.maxX = Math.max( rect.x + rect.width, this.maxX );
  3170. this.maxY = Math.max( rect.y + rect.height, this.maxY );
  3171. };
  3172. /**
  3173. * set the width and height of a rect, applying columnWidth and rowHeight
  3174. * @param {Element} elem
  3175. * @param {Packery.Rect} rect
  3176. */
  3177. Packery.prototype._setRectSize = function( elem, rect ) {
  3178. var size = getSize( elem );
  3179. var w = size.outerWidth;
  3180. var h = size.outerHeight;
  3181. // size for columnWidth and rowHeight, if available
  3182. // only check if size is non-zero, #177
  3183. if ( w || h ) {
  3184. w = this._applyGridGutter( w, this.columnWidth );
  3185. h = this._applyGridGutter( h, this.rowHeight );
  3186. }
  3187. // rect must fit in packer
  3188. rect.width = Math.min( w, this.packer.width );
  3189. rect.height = Math.min( h, this.packer.height );
  3190. };
  3191. /**
  3192. * fits item to columnWidth/rowHeight and adds gutter
  3193. * @param {Number} measurement - item width or height
  3194. * @param {Number} gridSize - columnWidth or rowHeight
  3195. * @returns measurement
  3196. */
  3197. Packery.prototype._applyGridGutter = function( measurement, gridSize ) {
  3198. // just add gutter if no gridSize
  3199. if ( !gridSize ) {
  3200. return measurement + this.gutter;
  3201. }
  3202. gridSize += this.gutter;
  3203. // fit item to columnWidth/rowHeight
  3204. var remainder = measurement % gridSize;
  3205. var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
  3206. measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
  3207. return measurement;
  3208. };
  3209. Packery.prototype._getContainerSize = function() {
  3210. if ( this.options.isHorizontal ) {
  3211. return {
  3212. width: this.maxX - this.gutter
  3213. };
  3214. } else {
  3215. return {
  3216. height: this.maxY - this.gutter
  3217. };
  3218. }
  3219. };
  3220. // -------------------------- stamp -------------------------- //
  3221. /**
  3222. * makes space for element
  3223. * @param {Element} elem
  3224. */
  3225. Packery.prototype._manageStamp = function( elem ) {
  3226. var item = this.getItem( elem );
  3227. var rect;
  3228. if ( item && item.isPlacing ) {
  3229. rect = item.placeRect;
  3230. } else {
  3231. var offset = this._getElementOffset( elem );
  3232. rect = new Rect({
  3233. x: this.options.isOriginLeft ? offset.left : offset.right,
  3234. y: this.options.isOriginTop ? offset.top : offset.bottom
  3235. });
  3236. }
  3237. this._setRectSize( elem, rect );
  3238. // save its space in the packer
  3239. this.packer.placed( rect );
  3240. this._setMaxXY( rect );
  3241. };
  3242. // -------------------------- methods -------------------------- //
  3243. function verticalSorter( a, b ) {
  3244. return a.position.y - b.position.y || a.position.x - b.position.x;
  3245. }
  3246. function horizontalSorter( a, b ) {
  3247. return a.position.x - b.position.x || a.position.y - b.position.y;
  3248. }
  3249. Packery.prototype.sortItemsByPosition = function() {
  3250. var sorter = this.options.isHorizontal ? horizontalSorter : verticalSorter;
  3251. this.items.sort( sorter );
  3252. };
  3253. /**
  3254. * Fit item element in its current position
  3255. * Packery will position elements around it
  3256. * useful for expanding elements
  3257. *
  3258. * @param {Element} elem
  3259. * @param {Number} x - horizontal destination position, optional
  3260. * @param {Number} y - vertical destination position, optional
  3261. */
  3262. Packery.prototype.fit = function( elem, x, y ) {
  3263. var item = this.getItem( elem );
  3264. if ( !item ) {
  3265. return;
  3266. }
  3267. // prepare internal properties
  3268. this._getMeasurements();
  3269. // stamp item to get it out of layout
  3270. this.stamp( item.element );
  3271. // required for positionPlaceRect
  3272. item.getSize();
  3273. // set placing flag
  3274. item.isPlacing = true;
  3275. // fall back to current position for fitting
  3276. x = x === undefined ? item.rect.x: x;
  3277. y = y === undefined ? item.rect.y: y;
  3278. // position it best at its destination
  3279. item.positionPlaceRect( x, y, true );
  3280. this._bindFitEvents( item );
  3281. item.moveTo( item.placeRect.x, item.placeRect.y );
  3282. // layout everything else
  3283. this.layout();
  3284. // return back to regularly scheduled programming
  3285. this.unstamp( item.element );
  3286. this.sortItemsByPosition();
  3287. // un set placing flag, back to normal
  3288. item.isPlacing = false;
  3289. // copy place rect position
  3290. item.copyPlaceRectPosition();
  3291. };
  3292. /**
  3293. * emit event when item is fit and other items are laid out
  3294. * @param {Packery.Item} item
  3295. * @private
  3296. */
  3297. Packery.prototype._bindFitEvents = function( item ) {
  3298. var _this = this;
  3299. var ticks = 0;
  3300. function tick() {
  3301. ticks++;
  3302. if ( ticks != 2 ) {
  3303. return;
  3304. }
  3305. _this.dispatchEvent( 'fitComplete', null, [ item ] );
  3306. }
  3307. // when item is laid out
  3308. item.on( 'layout', function() {
  3309. tick();
  3310. return true;
  3311. });
  3312. // when all items are laid out
  3313. this.on( 'layoutComplete', function() {
  3314. tick();
  3315. return true;
  3316. });
  3317. };
  3318. // -------------------------- resize -------------------------- //
  3319. // debounced, layout on resize
  3320. Packery.prototype.resize = function() {
  3321. // don't trigger if size did not change
  3322. var size = getSize( this.element );
  3323. // check that this.size and size are there
  3324. // IE8 triggers resize on body size change, so they might not be
  3325. var hasSizes = this.size && size;
  3326. var innerSize = this.options.isHorizontal ? 'innerHeight' : 'innerWidth';
  3327. if ( hasSizes && size[ innerSize ] == this.size[ innerSize ] ) {
  3328. return;
  3329. }
  3330. this.layout();
  3331. };
  3332. // -------------------------- drag -------------------------- //
  3333. /**
  3334. * handle an item drag start event
  3335. * @param {Element} elem
  3336. */
  3337. Packery.prototype.itemDragStart = function( elem ) {
  3338. this.stamp( elem );
  3339. var item = this.getItem( elem );
  3340. if ( item ) {
  3341. item.dragStart();
  3342. }
  3343. };
  3344. /**
  3345. * handle an item drag move event
  3346. * @param {Element} elem
  3347. * @param {Number} x - horizontal change in position
  3348. * @param {Number} y - vertical change in position
  3349. */
  3350. Packery.prototype.itemDragMove = function( elem, x, y ) {
  3351. var item = this.getItem( elem );
  3352. if ( item ) {
  3353. item.dragMove( x, y );
  3354. }
  3355. // debounce
  3356. var _this = this;
  3357. // debounce triggering layout
  3358. function delayed() {
  3359. _this.layout();
  3360. delete _this.dragTimeout;
  3361. }
  3362. this.clearDragTimeout();
  3363. this.dragTimeout = setTimeout( delayed, 40 );
  3364. };
  3365. Packery.prototype.clearDragTimeout = function() {
  3366. if ( this.dragTimeout ) {
  3367. clearTimeout( this.dragTimeout );
  3368. }
  3369. };
  3370. /**
  3371. * handle an item drag end event
  3372. * @param {Element} elem
  3373. */
  3374. Packery.prototype.itemDragEnd = function( elem ) {
  3375. var item = this.getItem( elem );
  3376. var itemDidDrag;
  3377. if ( item ) {
  3378. itemDidDrag = item.didDrag;
  3379. item.dragStop();
  3380. }
  3381. // if elem didn't move, or if it doesn't need positioning
  3382. // unignore and unstamp and call it a day
  3383. if ( !item || ( !itemDidDrag && !item.needsPositioning ) ) {
  3384. this.unstamp( elem );
  3385. return;
  3386. }
  3387. // procced with dragged item
  3388. classie.add( item.element, 'is-positioning-post-drag' );
  3389. // save this var, as it could get reset in dragStart
  3390. var onLayoutComplete = this._getDragEndLayoutComplete( elem, item );
  3391. if ( item.needsPositioning ) {
  3392. item.on( 'layout', onLayoutComplete );
  3393. item.moveTo( item.placeRect.x, item.placeRect.y );
  3394. } else if ( item ) {
  3395. // item didn't need placement
  3396. item.copyPlaceRectPosition();
  3397. }
  3398. this.clearDragTimeout();
  3399. this.on( 'layoutComplete', onLayoutComplete );
  3400. this.layout();
  3401. };
  3402. /**
  3403. * get drag end callback
  3404. * @param {Element} elem
  3405. * @param {Packery.Item} item
  3406. * @returns {Function} onLayoutComplete
  3407. */
  3408. Packery.prototype._getDragEndLayoutComplete = function( elem, item ) {
  3409. var itemNeedsPositioning = item && item.needsPositioning;
  3410. var completeCount = 0;
  3411. var asyncCount = itemNeedsPositioning ? 2 : 1;
  3412. var _this = this;
  3413. return function onLayoutComplete() {
  3414. completeCount++;
  3415. // don't proceed if not complete
  3416. if ( completeCount != asyncCount ) {
  3417. return true;
  3418. }
  3419. // reset item
  3420. if ( item ) {
  3421. classie.remove( item.element, 'is-positioning-post-drag' );
  3422. item.isPlacing = false;
  3423. item.copyPlaceRectPosition();
  3424. }
  3425. _this.unstamp( elem );
  3426. // only sort when item moved
  3427. _this.sortItemsByPosition();
  3428. // emit item drag event now that everything is done
  3429. if ( itemNeedsPositioning ) {
  3430. _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
  3431. }
  3432. // listen once
  3433. return true;
  3434. };
  3435. };
  3436. /**
  3437. * binds Draggabilly events
  3438. * @param {Draggabilly} draggie
  3439. */
  3440. Packery.prototype.bindDraggabillyEvents = function( draggie ) {
  3441. draggie.on( 'dragStart', this.handleDraggabilly.dragStart );
  3442. draggie.on( 'dragMove', this.handleDraggabilly.dragMove );
  3443. draggie.on( 'dragEnd', this.handleDraggabilly.dragEnd );
  3444. };
  3445. /**
  3446. * binds jQuery UI Draggable events
  3447. * @param {jQuery} $elems
  3448. */
  3449. Packery.prototype.bindUIDraggableEvents = function( $elems ) {
  3450. $elems
  3451. .on( 'dragstart', this.handleUIDraggable.start )
  3452. .on( 'drag', this.handleUIDraggable.drag )
  3453. .on( 'dragstop', this.handleUIDraggable.stop );
  3454. };
  3455. Packery.Rect = Rect;
  3456. Packery.Packer = Packer;
  3457. return Packery;
  3458. }));