1/* global wpcom_reblog */ 2 3var jetpackLikesWidgetBatch = []; 4var jetpackLikesMasterReady = false; 5 6// Due to performance problems on pages with a large number of widget iframes that need to be loaded, 7// we are limiting the processing at any instant to unloaded widgets that are currently in viewport, 8// plus this constant that will allow processing of widgets above and bellow the current fold. 9// This aim of it is to improve the UX and hide the transition from unloaded to loaded state from users. 10var jetpackLikesLookAhead = 2000; // pixels 11 12// Keeps track of loaded comment likes widget so we can unload them when they are scrolled out of view. 13var jetpackCommentLikesLoadedWidgets = []; 14 15var jetpackLikesDocReadyPromise = new Promise( resolve => { 16 if ( document.readyState !== 'loading' ) { 17 resolve(); 18 } else { 19 window.addEventListener( 'DOMContentLoaded', () => resolve() ); 20 } 21} ); 22 23function JetpackLikesPostMessage( message, target ) { 24 if ( typeof message === 'string' ) { 25 try { 26 message = JSON.parse( message ); 27 } catch ( e ) { 28 return; 29 } 30 } 31 32 if ( target && typeof target.postMessage === 'function' ) { 33 try { 34 target.postMessage( 35 JSON.stringify( { 36 type: 'likesMessage', 37 data: message, 38 } ), 39 '*' 40 ); 41 } catch ( e ) { 42 return; 43 } 44 } 45} 46 47function JetpackLikesBatchHandler() { 48 const requests = []; 49 document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' ).forEach( widget => { 50 if ( jetpackLikesWidgetBatch.indexOf( widget.id ) > -1 ) { 51 return; 52 } 53 54 if ( ! jetpackIsScrolledIntoView( widget ) ) { 55 return; 56 } 57 58 jetpackLikesWidgetBatch.push( widget.id ); 59 60 var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/, 61 match = regex.exec( widget.id ), 62 info; 63 64 if ( ! match || match.length !== 5 ) { 65 return; 66 } 67 68 info = { 69 blog_id: match[ 2 ], 70 width: widget.width, 71 }; 72 73 if ( 'post' === match[ 1 ] ) { 74 info.post_id = match[ 3 ]; 75 } else if ( 'comment' === match[ 1 ] ) { 76 info.comment_id = match[ 3 ]; 77 } 78 79 info.obj_id = match[ 4 ]; 80 81 requests.push( info ); 82 } ); 83 84 if ( requests.length > 0 ) { 85 JetpackLikesPostMessage( 86 { event: 'initialBatch', requests: requests }, 87 window.frames[ 'likes-master' ] 88 ); 89 } 90} 91 92function JetpackLikesMessageListener( event ) { 93 let message = event && event.data; 94 if ( typeof message === 'string' ) { 95 try { 96 message = JSON.parse( message ); 97 } catch ( err ) { 98 return; 99 } 100 } 101 102 const type = message && message.type; 103 const data = message && message.data; 104 105 if ( type !== 'likesMessage' || typeof data.event === 'undefined' ) { 106 return; 107 } 108 109 // We only allow messages from one origin 110 const allowedOrigin = 'https://widgets.wp.com'; 111 if ( allowedOrigin !== event.origin ) { 112 return; 113 } 114 115 switch ( data.event ) { 116 case 'masterReady': 117 jetpackLikesDocReadyPromise.then( () => { 118 jetpackLikesMasterReady = true; 119 120 const stylesData = { 121 event: 'injectStyles', 122 }; 123 const sdTextColor = document.querySelector( '.sd-text-color' ); 124 const sdLinkColor = document.querySelector( '.sd-link-color' ); 125 const sdTextColorStyles = ( sdTextColor && getComputedStyle( sdTextColor ) ) || {}; 126 const sdLinkColorStyles = ( sdLinkColor && getComputedStyle( sdLinkColor ) ) || {}; 127 128 // enable reblogs if they are enabled for the page 129 if ( document.body.classList.contains( 'jetpack-reblog-enabled' ) ) { 130 JetpackLikesPostMessage( { event: 'reblogsEnabled' }, window.frames[ 'likes-master' ] ); 131 } 132 133 stylesData.textStyles = { 134 color: sdTextColorStyles[ 'color' ],
135 fontFamily: sdTextColorStyles[ 'font-family' ], 136 fontSize: sdTextColorStyles[ 'font-size' ], 137 direction: sdTextColorStyles[ 'direction' ], 138 fontWeight: sdTextColorStyles[ 'font-weight' ], 139 fontStyle: sdTextColorStyles[ 'font-style' ], 140 textDecoration: sdTextColorStyles[ 'text-decoration' ], 141 }; 142 143 stylesData.linkStyles = { 144 color: sdLinkColorStyles[ 'color' ], 145 fontFamily: sdLinkColorStyles[ 'font-family' ], 146 fontSize: sdLinkColorStyles[ 'font-size' ], 147 textDecoration: sdLinkColorStyles[ 'text-decoration' ], 148 fontWeight: sdLinkColorStyles[ 'font-weight' ], 149 fontStyle: sdLinkColorStyles[ 'font-style' ], 150 }; 151 152 JetpackLikesPostMessage( stylesData, window.frames[ 'likes-master' ] ); 153 154 JetpackLikesBatchHandler(); 155 } ); 156 157 break; 158 159 // We're keeping this for planned future follow ups. 160 // @see: https://github.com/Automattic/jetpack/pull/42361#discussion_r1995338815 161 case 'showLikeWidget': 162 break; 163 164 // We're keeping this for planned future follow ups. 165 // @see: https://github.com/Automattic/jetpack/pull/42361#discussion_r1995338815 166 case 'showCommentLikeWidget': 167 break; 168 169 case 'killCommentLikes': 170 // If kill switch for comment likes is enabled remove all widgets wrappers and `Loading...` placeholders. 171 document 172 .querySelectorAll( '.jetpack-comment-likes-widget-wrapper' ) 173 .forEach( wrapper => wrapper.remove() ); 174 break; 175 176 case 'clickReblogFlair': 177 if ( wpcom_reblog && typeof wpcom_reblog.toggle_reblog_box_flair === 'function' ) { 178 wpcom_reblog.toggle_reblog_box_flair( data.obj_id, data.post_id ); 179 } 180 break; 181 182 case 'hideOtherGravatars': { 183 hideLikersPopover(); 184 break; 185 } 186 187 case 'showOtherGravatars': { 188 const container = document.querySelector( '#likes-other-gravatars' ); 189 190 if ( ! container ) { 191 break; 192 } 193 194 const list = container.querySelector( 'ul' ); 195 196 container.style.display = 'none'; 197 list.innerHTML = ''; 198 199 container 200 .querySelectorAll( '.likes-text span' ) 201 .forEach( item => ( item.textContent = data.totalLikesLabel ) ); 202 203 ( data.likers || [] ).forEach( async ( liker, index ) => { 204 if ( liker.profile_URL.substr( 0, 4 ) !== 'http' ) { 205 // We only display gravatars with http or https schema 206 return; 207 } 208 209 const element = document.createElement( 'li' ); 210 list.append( element ); 211 212 element.innerHTML = ` 213 <a href="${ encodeURI( liker.profile_URL ) }" rel="nofollow" target="_parent" class="wpl-liker"> 214 <img src="${ encodeURI( liker.avatar_URL ) }" 215 alt="" 216 style="width: 28px; height: 28px;" /> 217 <span></span> 218 </a> 219 `; 220 221 222 // Add some extra attributes through native methods, to ensure strings are sanitized. 223 element.classList.add( liker.css_class ); 224 element.querySelector( 'img' ).alt = data.avatarAltTitle.replace( '%s', liker.name ); 225 element.querySelector( 'span' ).innerText = liker.name; 226 227 if ( index === data.likers.length - 1 ) { 228 element.addEventListener( 'keydown', ( e ) => { 229 if ( e.key === 'Tab' && ! e.shiftKey ) { 230 e.preventDefault(); 231 hideLikersPopover(); 232 233 JetpackLikesPostMessage( 234 { event: 'focusLikesCount', parent: data.parent }, 235 window.frames[ 'likes-master' ] 236 ); 237 } 238 } ); 239 } 240 } ); 241 242 const positionPopup = function() { 243 const containerStyle = getComputedStyle(container); 244 const isRtl = containerStyle.direction === 'rtl'; 245 246 const el = document.querySelector( `*[name='${ data.parent }']` ); 247 const rect = el.getBoundingClientRect(); 248 const win = el.ownerDocument.defaultView; 249 250 const offset = { 251 top: rect.top + win.pageYOffset, 252 left: rect.left + win.pageXOffset, 253 }; 254 255 // don't display yet or we get skewed window.innerWidth later 256 container.style.display = 'none'; 257 258 let containerLeft = 0; 259 container.style.top = offset.top + data.position.top - 1 + 'px'; 260 261 if ( isRtl ) { 262 const visibleAvatarsCount = data && data.likers ? Math.min( data.likers.length, 5 ) : 0; 263 // 24px is the width of the avatar + 4px is the padding between avatars 264 containerLeft = offset.left + data.position.left + 24 * visibleAvatarsCount + 4; 265 container.style.transform = 'translateX(-100%)'; 266 } else { 267 containerLeft = offset.left + data.position.left; 268 } 269 container.style.left = containerLeft + 'px'; 270 271 // Container width - padding
272 const initContainerWidth = data.width - 20; 273 const rowLength = Math.floor( initContainerWidth / 37 ); 274 // # of rows + (avatar + avatar padding) + text above + container padding 275 let height = Math.ceil( data.likers.length / rowLength ) * 37 + 17 + 22; 276 if ( height > 204 ) { 277 height = 204; 278 } 279 280 // If the popup is overflows viewport width, we should show it on the next line 281 // Push it offscreen to calculated rendered width 282 const windowWidth = win.innerWidth; 283 container.style.left = '-9999px'; 284 container.style.display = 'block'; 285 286 // If the popup exceeds the viewport width, 287 // flip the position of the popup. 288 const containerWidth = container.offsetWidth; 289 const containerRight = containerLeft + containerWidth; 290 291 if ( containerRight > windowWidth && ! isRtl) { 292 containerLeft = rect.left + rect.width - containerWidth; 293 } else if ( containerLeft - containerWidth < 0 && isRtl ) { 294 container.style.transform = 'none'; 295 containerLeft = rect.left; 296 } 297 // Set the container left 298 container.style.left = containerLeft + 'px'; 299 300 container.setAttribute( 'aria-hidden', 'false' ); 301 } 302 303 positionPopup(); 304 container.focus(); 305 306 const debounce = function( func, wait ) { 307 var timeout; 308 return function() { 309 var context = this; 310 var args = arguments; 311 clearTimeout( timeout ); 312 timeout = setTimeout( function() { 313 func.apply( context, args ); 314 }, wait ); 315 }; 316 }; 317 318 const debouncedPositionPopup = debounce( positionPopup, 100 ); 319 320 // Keep a reference of this function in the element itself 321 // so that we can destroy it later 322 container.__resizeHandler = debouncedPositionPopup; 323 324 // When window is resized, resize the popup. 325 window.addEventListener( "resize", debouncedPositionPopup ); 326 } 327 } 328} 329 330window.addEventListener( 'message', JetpackLikesMessageListener ); 331 332function hideLikersPopover() { 333 const container = document.querySelector( '#likes-other-gravatars' ); 334 335 if ( container ) { 336 container.style.display = 'none'; 337 container.setAttribute( 'aria-hidden', 'true' ); 338 339 // Remove the resize event listener and cleanup. 340 const resizeHandler = container.__resizeHandler; 341 if ( resizeHandler ) { 342 window.removeEventListener( "resize", resizeHandler ); 343 delete container.__resizeHandler; 344 } 345 } 346} 347 348document.addEventListener( 'click', hideLikersPopover ); 349 350function JetpackLikesWidgetQueueHandler() { 351 var wrapperID; 352 353 if ( ! jetpackLikesMasterReady ) { 354 setTimeout( JetpackLikesWidgetQueueHandler, 500 ); 355 return; 356 } 357 358 // Restore widgets to initial unloaded state when they are scrolled out of view. 359 jetpackUnloadScrolledOutWidgets(); 360 361 var unloadedWidgetsInView = jetpackGetUnloadedWidgetsInView(); 362 363 if ( unloadedWidgetsInView.length > 0 ) { 364 // Grab any unloaded widgets for a batch request 365 JetpackLikesBatchHandler(); 366 } 367 368 for ( var i = 0, length = unloadedWidgetsInView.length; i <= length - 1; i++ ) { 369 wrapperID = unloadedWidgetsInView[ i ].id; 370 371 if ( ! wrapperID ) { 372 continue; 373 } 374 375 jetpackLoadLikeWidgetIframe( wrapperID ); 376 } 377} 378 379function jetpackLoadLikeWidgetIframe( wrapperID ) { 380 if ( typeof wrapperID === 'undefined' ) { 381 return; 382 } 383 384 const wrapper = document.querySelector( '#' + wrapperID ); 385 wrapper.querySelectorAll( 'iframe' ).forEach( iFrame => iFrame.remove() ); 386 387 const placeholder = wrapper.querySelector( '.likes-widget-placeholder' ); 388 389 // Post like iframe 390 if ( placeholder && placeholder.classList.contains( 'post-likes-widget-placeholder' ) ) { 391 const postLikesFrame = document.createElement( 'iframe' ); 392 393 postLikesFrame.classList.add( 'post-likes-widget', 'jetpack-likes-widget' ); 394 postLikesFrame.name = wrapper.dataset.name; 395 postLikesFrame.src = wrapper.dataset.src; 396 postLikesFrame.height = '55px'; 397 postLikesFrame.width = '100%'; 398 postLikesFrame.frameBorder = '0'; 399 postLikesFrame.scrolling = 'no'; 400 postLikesFrame.title = wrapper.dataset.title; 401 402 placeholder.after( postLikesFrame ); 403 } 404 405 // Comment like iframe 406 if ( placeholder.classList.contains( 'comment-likes-widget-placeholder' ) ) { 407 const commentLikesFrame = document.createElement( 'iframe' ); 408 409 commentLikesFrame.class = 'comment-likes-widget-frame jetpack-likes-widget-frame'; 410 commentLikesFrame.name = wrapper.dataset.name; 411 commentLikesFrame.src = wrapper.dataset.src; 412 commentLikesFrame.height = '18px'; 413 commentLikesFrame.width = '100%'; 414 commentLikesFrame.frameBorder = '0'; 415 commentLikesFrame.scrolling = 'no'; 416 417 wrapper.querySelector( '.comment-like-feedback' ).after( commentLikesFrame ); 418 419 jetpackCommentLikesLoadedWidgets.push( commentLikesFrame ); 420 } 421 422 wrapper.classList.remove( 'jetpack-likes-widget-unloaded' ); 423 wrapper.classList.add( 'jetpack-likes-widget-loading' ); 424 425 wrapper.querySelector( 'iframe' ).addEventListener( 'load', e => { 426 JetpackLikesPostMessage( 427 { event: 'loadLikeWidget', name: e.target.name, width: e.target.width }, 428 window.frames[ 'likes-master' ] 429 ); 430 431 wrapper.classList.remove( 'jetpack-likes-widget-loading' ); 432 wrapper.classList.add( 'jetpack-likes-widget-loaded' ); 433 } ); 434} 435 436function jetpackGetUnloadedWidgetsInView() { 437 const unloadedWidgets = document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' ); 438 439 return [ ...unloadedWidgets ].filter( item => jetpackIsScrolledIntoView( item ) ); 440} 441 442function jetpackIsScrolledIntoView( element ) { 443 const top = element.getBoundingClientRect().top; 444 const bottom = element.getBoundingClientRect().bottom; 445
446 // Allow some slack above and bellow the fold with jetpackLikesLookAhead, 447 // with the aim of hiding the transition from unloaded to loaded widget from users. 448 return top + jetpackLikesLookAhead >= 0 && bottom <= window.innerHeight + jetpackLikesLookAhead; 449} 450 451function jetpackUnloadScrolledOutWidgets() { 452 for ( let i = jetpackCommentLikesLoadedWidgets.length - 1; i >= 0; i-- ) { 453 const currentWidgetIframe = jetpackCommentLikesLoadedWidgets[ i ]; 454 455 if ( ! jetpackIsScrolledIntoView( currentWidgetIframe ) ) { 456 const widgetWrapper = 457 currentWidgetIframe && 458 currentWidgetIframe.parentElement && 459 currentWidgetIframe.parentElement.parentElement; 460 461 // Restore parent class to 'unloaded' so this widget can be picked up by queue manager again if needed. 462 widgetWrapper.classList.remove( 'jetpack-likes-widget-loaded' ); 463 widgetWrapper.classList.remove( 'jetpack-likes-widget-loading' ); 464 widgetWrapper.classList.add( 'jetpack-likes-widget-unloaded' ); 465 466 // Bring back the loading placeholder into view. 467 widgetWrapper 468 .querySelectorAll( '.comment-likes-widget-placeholder' ) 469 .forEach( item => ( item.style.display = 'block' ) ); 470 471 // Remove it from the list of loaded widgets. 472 jetpackCommentLikesLoadedWidgets.splice( i, 1 ); 473 474 // Remove comment like widget iFrame. 475 currentWidgetIframe.remove(); 476 } 477 } 478} 479 480var jetpackWidgetsDelayedExec = function ( after, fn ) { 481 var timer; 482 return function () { 483 clearTimeout( timer ); 484 timer = setTimeout( fn, after ); 485 }; 486}; 487 488var jetpackOnScrollStopped = jetpackWidgetsDelayedExec( 250, JetpackLikesWidgetQueueHandler ); 489 490// Load initial batch of widgets, prior to any scrolling events. 491JetpackLikesWidgetQueueHandler(); 492 493// Add event listener to execute queue handler after scroll. 494window.addEventListener( 'scroll', jetpackOnScrollStopped, true ); 495; 496!function(e){var o={};function n(t){if(o[t])return o[t].exports;var r=o[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=o,n.d=function(e,o,t){n.o(e,o)||Object.defineProperty(e,o,{enumerable:!0,get:t})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,o){if(1&o&&(e=n(e)),8&o)return e;if(4&o&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(n.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&o&&"string"!=typeof e)for(var r in e)n.d(t,r,function(o){return e[o]}.bind(null,r));return t},n.n=function(e){var o=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(o,"a",o),o},n.o=function(e,o){return Object.prototype.hasOwnProperty.call(e,o)},n.p="",n(n.s=273)}({273:function(e,o){!function(){"use strict";let e,o;function n(e){return new Promise((o,n)=>{const t=document.createElement("script");t.onload=()=>o(),t.onerror=e=>n(e),t.src=e,document.body.appendChild(t)})}function t(){if(e)return e;const o=window.wpcom_coblocks_js;return e=n(o.coblocks_lightbox_js),e}function r(){if(o)return o;window.wpcomJQueryUsageLoggerDisabled=!0;const e=window.wpcom_coblocks_js,t=window.jQuery?Promise.resolve():n(e.jquery_core_js).then(()=>n(e.jquery_migrate_js)),r=t.then(()=>window.imagesLoaded?Promise.resolve():n(e.imagesloaded_js)),c=t.then(()=>window.Masonry?Promise.resolve():n(e.masonry_js)),u=Promise.all([t,r,c]).then(()=>n(e.coblocks_masonry_js));return o=u,o}function c(){document.querySelector(".wp-block-coblocks-gallery-masonry")&&r(),document.querySelector(".has-lightbox")&&t(),document.body.classList.contains("block-editor-page")&&(r(),t())}"loading"!==document.readyState?c():document.addEventListener("DOMContentLoaded",c)}()}});; 497/*! This file is auto-generated */ 498/*! 499 * imagesLoaded PACKAGED v5.0.0 500 * JavaScript is all like "You images are done yet or what?" 501 * MIT License 502 */ 503!function(t,e){"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}let e=t.prototype;return e.on=function(t,e){if(!t||!e)return this;let i=this._events=this._events||{},s=i[t]=i[t]||[];return s.includes(e)||s.push(e),this},e.once=function(t,e){if(!t||!e)return this;this.on(t,e);let i=this._onceEvents=this._onceEvents||{};return(i[t]=i[t]||{})[e]=!0,this},e.off=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;let s=i.indexOf(e);return-1!=s&&i.splice(s,1),this},e.emitEvent=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;i=i.slice(0),e=e||[];let s=this._onceEvents&&this._onceEvents[t];for(let n of i){s&&s[n]&&(this.off(t,n),delete s[n]),n.apply(this,e)}return this},e.allOff=function(){return delete this._events,delete this._onceEvents,this},t})), 504/*! 505 * imagesLoaded v5.0.0 506 * JavaScript is all like "You images are done yet or what?" 507 * MIT License 508 */ 509function(t,e){"object"==typeof module&&module.exports?module.exports=e(t,require("ev-emitter")):t.imagesLoaded=e(t,t.EvEmitter)}("undefined"!=typeof window?window:this,(function(t,e){let i=t.jQuery,s=t.console;
vendor: 4,185 bytes, lines 509-510
509function n(t,e,o){if(!(this instanceof n))return new n(t,e,o);let r=t;var h;("string"==typeof t&&(r=document.querySelectorAll(t)),r)?(this.elements=(h=r,Array.isArray(h)?h:"object"==typeof h&&"number"==typeof h.length?[...h]:[h]),this.options={},"function"==typeof e?o=e:Object.assign(this.options,e),o&&this.on("always",o),this.getImages(),i&&(this.jqDeferred=new i.Deferred),setTimeout(this.check.bind(this))):s.error(`Bad element for imagesLoaded ${r||t}`)}n.prototype=Object.create(e.prototype),n.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)};const o=[1,9,11];n.prototype.addElementImages=function(t){"IMG"===t.nodeName&&this.addImage(t),!0===this.options.background&&this.addElementBackgroundImages(t);let{nodeType:e}=t;if(!e||!o.includes(e))return;let i=t.querySelectorAll("img");for(let t of i)this.addImage(t);if("string"==typeof this.options.background){let e=t.querySelectorAll(this.options.background);for(let t of e)this.addElementBackgroundImages(t)}};const r=/url\((['"])?(.*?)\1\)/gi;function h(t){this.img=t}function d(t,e){this.url=t,this.element=e,this.img=new Image}return n.prototype.addElementBackgroundImages=function(t){let e=getComputedStyle(t);if(!e)return;let i=r.exec(e.backgroundImage);for(;null!==i;){let s=i&&i[2];s&&this.addBackground(s,t),i=r.exec(e.backgroundImage)}},n.prototype.addImage=function(t){let e=new h(t);this.images.push(e)},n.prototype.addBackground=function(t,e){let i=new d(t,e);this.images.push(i)},n.prototype.check=function(){if(this.progressedCount=0,this.hasAnyBroken=!1,!this.images.length)return void this.complete();let t=(t,e,i)=>{setTimeout((()=>{this.progress(t,e,i)}))};this.images.forEach((function(e){e.once("progress",t),e.check()}))},n.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent("progress",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount===this.images.length&&this.complete(),this.options.debug&&s&&s.log(`progress: ${i}`,t,e)},n.prototype.complete=function(){let t=this.hasAnyBroken?"fail":"done";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent("always",[this]),this.jqDeferred){let t=this.hasAnyBroken?"reject":"resolve";this.jqDeferred[t](this)}},h.prototype=Object.create(e.prototype),h.prototype.check=function(){this.getIsImageComplete()?this.confirm(0!==this.img.naturalWidth,"naturalWidth"):(this.proxyImage=new Image,this.img.crossOrigin&&(this.proxyImage.crossOrigin=this.img.crossOrigin),this.proxyImage.addEventListener("load",this),this.proxyImage.addEventListener("error",this),this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.proxyImage.src=this.img.currentSrc||this.img.src)},h.prototype.getIsImageComplete=function(){return this.img.complete&&this.img.naturalWidth},h.prototype.confirm=function(t,e){this.isLoaded=t;let{parentNode:i}=this.img,s="PICTURE"===i.nodeName?i:this.img;this.emitEvent("progress",[this,s,e])},h.prototype.handleEvent=function(t){let e="on"+t.type;this[e]&&this[e](t)},h.prototype.onload=function(){this.confirm(!0,"onload"),this.unbindEvents()},h.prototype.onerror=function(){this.confirm(!1,"onerror"),this.unbindEvents()},h.prototype.unbindEvents=function(){this.proxyImage.removeEventListener("load",this),this.proxyImage.removeEventListener("error",this),this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype=Object.create(h.prototype),d.prototype.check=function(){this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.img.src=this.url,this.getIsImageComplete()&&(this.confirm(0!==this.img.naturalWidth,"naturalWidth"),this.unbindEvents())},d.prototype.unbindEvents=function(){this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent("progress",[this,this.element,e])},n.makeJQueryPlugin=function(e){(e=e||t.jQuery)&&(i=e,i.fn.imagesLoaded=function(t,e){return new n(this,t,e).jqDeferred.promise(i(this))})},n.makeJQueryPlugin(),n}));; 510/*! This file is auto-generated */
vendor: 24,103 bytes, lines 511-519
511/*! 512 * Masonry PACKAGED v4.2.2 513 * Cascading grid layout library 514 * https://masonry.desandro.com 515 * MIT License 516 * by David DeSandro 517 */ 518 519!function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,r,a){function h(t,e,n){var o,r="$()."+i+'("'+e+'")';return t.each(function(t,h){var u=a.data(h,i);if(!u)return void s(i+" not initialized. Cannot call methods, i.e. "+r);var d=u[e];if(!d||"_"==e.charAt(0))return void s(r+" is not a valid method");var l=d.apply(u,n);o=void 0===o?l:o}),void 0!==o?o:t}function u(t,e){t.each(function(t,n){var o=a.data(n,i);o?(o.option(e),o._init()):(o=new r(n,e),a.data(n,i,o))})}a=a||e||t.jQuery,a&&(r.prototype.option||(r.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=o.call(arguments,1);return h(this,t,e)}return u(this,t),this},n(a))}function n(t){!t||t&&t.bridget||(t.bridget=i)}var o=Array.prototype.slice,r=t.console,s="undefined"==typeof r?function(){}:function(t){r.error(t)};return n(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},n=i[t]=i[t]||[];return-1==n.indexOf(e)&&n.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},n=i[t]=i[t]||{};return n[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var n=i.indexOf(e);return-1!=n&&i.splice(n,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var n=this._onceEvents&&this._onceEvents[t],o=0;o<i.length;o++){var r=i[o],s=n&&n[r];s&&(this.off(t,r),delete n[r]),r.apply(this,e)}return this}},e.allOff=function(){delete this._events,delete this._onceEvents},t}),function(t,e){"function"==typeof define&&define.amd?define("get-size/get-size",e):"object"==typeof module&&module.exports?module.exports=e():t.getSize=e()}(window,function(){"use strict";function t(t){var e=parseFloat(t),i=-1==t.indexOf("%")&&!isNaN(e);return i&&e}function e(){}function i(){for(var t={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},e=0;u>e;e++){var i=h[e];t[i]=0}return t}function n(t){var e=getComputedStyle(t);return e||a("Style returned "+e+". Are you running this code in a hidden iframe on Firefox? See https://bit.ly/getsizebug1"),e}function o(){if(!d){d=!0;var e=document.createElement("div");e.style.width="200px",e.style.padding="1px 2px 3px 4px",e.style.borderStyle="solid",e.style.borderWidth="1px 2px 3px 4px",e.style.boxSizing="border-box";var i=document.body||document.documentElement;i.appendChild(e);var o=n(e);s=200==Math.round(t(o.width)),r.isBoxSizeOuter=s,i.removeChild(e)}}function r(e){if(o(),"string"==typeof e&&(e=document.querySelector(e)),e&&"object"==typeof e&&e.nodeType){var r=n(e);if("none"==r.display)return i();var a={};a.width=e.offsetWidth,a.height=e.offsetHeight;for(var d=a.isBorderBox="border-box"==r.boxSizing,l=0;u>l;l++){var c=h[l],f=r[c],m=parseFloat(f);a[c]=isNaN(m)?0:m}var p=a.paddingLeft+a.paddingRight,g=a.paddingTop+a.paddingBottom,y=a.marginLeft+a.marginRight,v=a.marginTop+a.marginBottom,_=a.borderLeftWidth+a.borderRightWidth,z=a.borderTopWidth+a.borderBottomWidth,E=d&&s,b=t(r.width);b!==!1&&(a.width=b+(E?0:p+_));var x=t(r.height);return x!==!1&&(a.height=x+(E?0:g+z)),a.innerWidth=a.width-(p+_),a.innerHeight=a.height-(g+z),a.outerWidth=a.width+y,a.outerHeight=a.height+v,a}}var s,a="undefined"==typeof console?e:function(t){console.error(t)},h=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"],u=h.length,d=!1;return r}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("desandro-matches-selector/matches-selector",e):"object"==typeof module&&module.exports?module.exports=e():t.matchesSelector=e()}(window,function(){"use strict";var t=function(){var t=window.Element.prototype;if(t.matches)return"matches";if(t.matchesSelector)return"matchesSelector";for(var e=["webkit","moz","ms","o"],i=0;i<e.length;i++){var n=e[i],o=n+"MatchesSelector";if(t[o])return o}}();return function(e,i){return e[t](i)}}),function(t,e){"function"==typeof define&&define.amd?define("fizzy-ui-utils/utils",["desandro-matches-selector/matches-selector"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("desandro-matches-selector")):t.fizzyUIUtils=e(t,t.matchesSelector)}(window,function(t,e){var i={};i.extend=function(t,e){for(var i in e)t[i]=e[i];return t},i.modulo=function(t,e){return(t%e+e)%e};var n=Array.prototype.slice;i.makeArray=function(t){if(Array.isArray(t))return t;if(null===t||void 0===t)return[];var e="object"==typeof t&&"number"==typeof t.length;return e?n.call(t):[t]},i.removeFrom=function(t,e){var i=t.indexOf(e);-1!=i&&t.splice(i,1)},i.getParent=function(t,i){for(;t.parentNode&&t!=document.body;)if(t=t.parentNode,e(t,i))return t},i.getQueryElement=function(t){return"string"==typeof t?document.querySelector(t):t},i.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},i.filterFindElements=function(t,n){t=i.makeArray(t);var o=[];return t.forEach(function(t){if(t instanceof HTMLElement){if(!n)return void o.push(t);e(t,n)&&o.push(t);for(var i=t.querySelectorAll(n),r=0;r<i.length;r++)o.push(i[r])}}),o},i.debounceMethod=function(t,e,i){i=i||100;var n=t.prototype[e],o=e+"Timeout";t.prototype[e]=function(){var t=this[o];clearTimeout(t);var e=arguments,r=this;this[o]=setTimeout(function(){n.apply(r,e),delete r[o]},i)}},i.docReady=function(t){var e=document.readyState;"complete"==e||"interactive"==e?setTimeout(t):document.addEventListener("DOMContentLoaded",t)},i.toDashed=function(t){return t.replace(/(.)([A-Z])/g,function(t,e,i){return e+"-"+i}).toLowerCase()};var o=t.console;return i.htmlInit=function(e,n){i.docReady(function(){var r=i.toDashed(n),s="data-"+r,a=document.querySelectorAll("["+s+"]"),h=document.querySelectorAll(".js-"+r),u=i.makeArray(a).concat(i.makeArray(h)),d=s+"-options",l=t.jQuery;u.forEach(function(t){var i,r=t.getAttribute(s)||t.getAttribute(d);try{i=r&&JSON.parse(r)}catch(a){return void(o&&o.error("Error parsing "+s+" on "+t.className+": "+a))}var h=new e(t,i);l&&l.data(t,n,h)})})},i}),function(t,e){"function"==typeof define&&define.amd?define("outlayer/item",["ev-emitter/ev-emitter","get-size/get-size"],e):"object"==typeof module&&module.exports?module.exports=e(require("ev-emitter"),require("get-size")):(t.Outlayer={},t.Outlayer.Item=e(t.EvEmitter,t.getSize))}(window,function(t,e){"use strict";function i(t){for(var e in t)return!1;return e=null,!0}function n(t,e){t&&(this.element=t,this.layout=e,this.position={x:0,y:0},this._create())}function o(t){return t.replace(/([A-Z])/g,function(t){return"-"+t.toLowerCase()})}var r=document.documentElement.style,s="string"==typeof r.transition?"transition":"WebkitTransition",a="string"==typeof r.transform?"transform":"WebkitTransform",h={WebkitTransition:"webkitTransitionEnd",transition:"transitionend"}[s],u={transform:a,transition:s,transitionDuration:s+"Duration",transitionProperty:s+"Property",transitionDelay:s+"Delay"},d=n.prototype=Object.create(t.prototype);d.constructor=n,d._create=function(){this._transn={ingProperties:{},clean:{},onEnd:{}},this.css({position:"absolute"})},d.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},d.getSize=function(){this.size=e(this.element)},d.css=function(t){var e=this.element.style;for(var i in t){var n=u[i]||i;e[n]=t[i]}},d.getPosition=function(){var t=getComputedStyle(this.element),e=this.layout._getOption("originLeft"),i=this.layout._getOption("originTop"),n=t[e?"left":"right"],o=t[i?"top":"bottom"],r=parseFloat(n),s=parseFloat(o),a=this.layout.size;-1!=n.indexOf("%")&&(r=r/100*a.width),-1!=o.indexOf("%")&&(s=s/100*a.height),r=isNaN(r)?0:r,s=isNaN(s)?0:s,r-=e?a.paddingLeft:a.paddingRight,s-=i?a.paddingTop:a.paddingBottom,this.position.x=r,this.position.y=s},d.layoutPosition=function(){var t=this.layout.size,e={},i=this.layout._getOption("originLeft"),n=this.layout._getOption("originTop"),o=i?"paddingLeft":"paddingRight",r=i?"left":"right",s=i?"right":"left",a=this.position.x+t[o];e[r]=this.getXValue(a),e[s]="";var h=n?"paddingTop":"paddingBottom",u=n?"top":"bottom",d=n?"bottom":"top",l=this.position.y+t[h];e[u]=this.getYValue(l),e[d]="",this.css(e),this.emitEvent("layout",[this])},d.getXValue=function(t){var e=this.layout._getOption("horizontal");return this.layout.options.percentPosition&&!e?t/this.layout.size.width*100+"%":t+"px"},d.getYValue=function(t){var e=this.layout._getOption("horizontal");return this.layout.options.percentPosition&&e?t/this.layout.size.height*100+"%":t+"px"},d._transitionTo=function(t,e){this.getPosition();var i=this.position.x,n=this.position.y,o=t==this.position.x&&e==this.position.y;if(this.setPosition(t,e),o&&!this.isTransitioning)return void this.layoutPosition();var r=t-i,s=e-n,a={};a.transform=this.getTranslate(r,s),this.transition({to:a,onTransitionEnd:{transform:this.layoutPosition},isCleaning:!0})},d.getTranslate=function(t,e){var i=this.layout._getOption("originLeft"),n=this.layout._getOption("originTop");return t=i?t:-t,e=n?e:-e,"translate3d("+t+"px, "+e+"px, 0)"},d.goTo=function(t,e){this.setPosition(t,e),this.layoutPosition()},d.moveTo=d._transitionTo,d.setPosition=function(t,e){this.position.x=parseFloat(t),this.position.y=parseFloat(e)},d._nonTransition=function(t){this.css(t.to),t.isCleaning&&this._removeStyles(t.to);for(var e in t.onTransitionEnd)t.onTransitionEnd[e].call(this)},d.transition=function(t){if(!parseFloat(this.layout.options.transitionDuration))return void this._nonTransition(t);var e=this._transn;for(var i in t.onTransitionEnd)e.onEnd[i]=t.onTransitionEnd[i];for(i in t.to)e.ingProperties[i]=!0,t.isCleaning&&(e.clean[i]=!0);if(t.from){this.css(t.from);var n=this.element.offsetHeight;n=null}this.enableTransition(t.to),this.css(t.to),this.isTransitioning=!0};var l="opacity,"+o(a);d.enableTransition=function(){if(!this.isTransitioning){var t=this.layout.options.transitionDuration;t="number"==typeof t?t+"ms":t,this.css({transitionProperty:l,transitionDuration:t,transitionDelay:this.staggerDelay||0}),this.element.addEventListener(h,this,!1)}},d.onwebkitTransitionEnd=function(t){this.ontransitionend(t)},d.onotransitionend=function(t){this.ontransitionend(t)};var c={"-webkit-transform":"transform"};d.ontransitionend=function(t){if(t.target===this.element){var e=this._transn,n=c[t.propertyName]||t.propertyName;if(delete e.ingProperties[n],i(e.ingProperties)&&this.disableTransition(),n in e.clean&&(this.element.style[t.propertyName]="",delete e.clean[n]),n in e.onEnd){var o=e.onEnd[n];o.call(this),delete e.onEnd[n]}this.emitEvent("transitionEnd",[this])}},d.disableTransition=function(){this.removeTransitionStyles(),this.element.removeEventListener(h,this,!1),this.isTransitioning=!1},d._removeStyles=function(t){var e={};for(var i in t)e[i]="";this.css(e)};var f={transitionProperty:"",transitionDuration:"",transitionDelay:""};return d.removeTransitionStyles=function(){this.css(f)},d.stagger=function(t){t=isNaN(t)?0:t,this.staggerDelay=t+"ms"},d.removeElem=function(){this.element.parentNode.removeChild(this.element),this.css({display:""}),this.emitEvent("remove",[this])},d.remove=function(){return s&&parseFloat(this.layout.options.transitionDuration)?(this.once("transitionEnd",function(){this.removeElem()}),void this.hide()):void this.removeElem()},d.reveal=function(){delete this.isHidden,this.css({display:""});var t=this.layout.options,e={},i=this.getHideRevealTransitionEndProperty("visibleStyle");e[i]=this.onRevealTransitionEnd,this.transition({from:t.hiddenStyle,to:t.visibleStyle,isCleaning:!0,onTransitionEnd:e})},d.onRevealTransitionEnd=function(){this.isHidden||this.emitEvent("reveal")},d.getHideRevealTransitionEndProperty=function(t){var e=this.layout.options[t];if(e.opacity)return"opacity";for(var i in e)return i},d.hide=function(){this.isHidden=!0,this.css({display:""});var t=this.layout.options,e={},i=this.getHideRevealTransitionEndProperty("hiddenStyle");e[i]=this.onHideTransitionEnd,this.transition({from:t.visibleStyle,to:t.hiddenStyle,isCleaning:!0,onTransitionEnd:e})},d.onHideTransitionEnd=function(){this.isHidden&&(this.css({display:"none"}),this.emitEvent("hide"))},d.destroy=function(){this.css({position:"",left:"",right:"",top:"",bottom:"",transition:"",transform:""})},n}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("outlayer/outlayer",["ev-emitter/ev-emitter","get-size/get-size","fizzy-ui-utils/utils","./item"],function(i,n,o,r){return e(t,i,n,o,r)}):"object"==typeof module&&module.exports?module.exports=e(t,require("ev-emitter"),require("get-size"),require("fizzy-ui-utils"),require("./item")):t.Outlayer=e(t,t.EvEmitter,t.getSize,t.fizzyUIUtils,t.Outlayer.Item)}(window,function(t,e,i,n,o){"use strict";function r(t,e){var i=n.getQueryElement(t);if(!i)return void(h&&h.error("Bad element for "+this.constructor.namespace+": "+(i||t)));this.element=i,u&&(this.$element=u(this.element)),this.options=n.extend({},this.constructor.defaults),this.option(e);var o=++l;this.element.outlayerGUID=o,c[o]=this,this._create();var r=this._getOption("initLayout");r&&this.layout()}function s(t){function e(){t.apply(this,arguments)}return e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e}function a(t){if("number"==typeof t)return t;var e=t.match(/(^\d*\.?\d*)(\w*)/),i=e&&e[1],n=e&&e[2];if(!i.length)return 0;i=parseFloat(i);var o=m[n]||1;return i*o}var h=t.console,u=t.jQuery,d=function(){},l=0,c={};r.namespace="outlayer",r.Item=o,r.defaults={containerStyle:{position:"relative"},initLayout:!0,originLeft:!0,originTop:!0,resize:!0,resizeContainer:!0,transitionDuration:"0.4s",hiddenStyle:{opacity:0,transform:"scale(0.001)"},visibleStyle:{opacity:1,transform:"scale(1)"}};var f=r.prototype;n.extend(f,e.prototype),f.option=function(t){n.extend(this.options,t)},f._getOption=function(t){var e=this.constructor.compatOptions[t];return e&&void 0!==this.options[e]?this.options[e]:this.options[t]},r.compatOptions={initLayout:"isInitLayout",horizontal:"isHorizontal",layoutInstant:"isLayoutInstant",originLeft:"isOriginLeft",originTop:"isOriginTop",resize:"isResizeBound",resizeContainer:"isResizingContainer"},f._create=function(){this.reloadItems(),this.stamps=[],this.stamp(this.options.stamp),n.extend(this.element.style,this.options.containerStyle);var t=this._getOption("resize");t&&this.bindResize()},f.reloadItems=function(){this.items=this._itemize(this.element.children)},f._itemize=function(t){for(var e=this._filterFindItemElements(t),i=this.constructor.Item,n=[],o=0;o<e.length;o++){var r=e[o],s=new i(r,this);n.push(s)}return n},f._filterFindItemElements=function(t){return n.filterFindElements(t,this.options.itemSelector)},f.getItemElements=function(){return this.items.map(function(t){return t.element})},f.layout=function(){this._resetLayout(),this._manageStamps();var t=this._getOption("layoutInstant"),e=void 0!==t?t:!this._isLayoutInited;this.layoutItems(this.items,e),this._isLayoutInited=!0},f._init=f.layout,f._resetLayout=function(){this.getSize()},f.getSize=function(){this.size=i(this.element)},f._getMeasurement=function(t,e){var n,o=this.options[t];o?("string"==typeof o?n=this.element.querySelector(o):o instanceof HTMLElement&&(n=o),this[t]=n?i(n)[e]:o):this[t]=0},f.layoutItems=function(t,e){t=this._getItemsForLayout(t),this._layoutItems(t,e),this._postLayout()},f._getItemsForLayout=function(t){return t.filter(function(t){return!t.isIgnored})},f._layoutItems=function(t,e){if(this._emitCompleteOnItems("layout",t),t&&t.length){var i=[];t.forEach(function(t){var n=this._getItemLayoutPosition(t);n.item=t,n.isInstant=e||t.isLayoutInstant,i.push(n)},this),this._processLayoutQueue(i)}},f._getItemLayoutPosition=function(){return{x:0,y:0}},f._processLayoutQueue=function(t){this.updateStagger(),t.forEach(function(t,e){this._positionItem(t.item,t.x,t.y,t.isInstant,e)},this)},f.updateStagger=function(){var t=this.options.stagger;return null===t||void 0===t?void(this.stagger=0):(this.stagger=a(t),this.stagger)},f._positionItem=function(t,e,i,n,o){n?t.goTo(e,i):(t.stagger(o*this.stagger),t.moveTo(e,i))},f._postLayout=function(){this.resizeContainer()},f.resizeContainer=function(){var t=this._getOption("resizeContainer");if(t){var e=this._getContainerSize();e&&(this._setContainerMeasure(e.width,!0),this._setContainerMeasure(e.height,!1))}},f._getContainerSize=d,f._setContainerMeasure=function(t,e){if(void 0!==t){var i=this.size;i.isBorderBox&&(t+=e?i.paddingLeft+i.paddingRight+i.borderLeftWidth+i.borderRightWidth:i.paddingBottom+i.paddingTop+i.borderTopWidth+i.borderBottomWidth),t=Math.max(t,0),this.element.style[e?"width":"height"]=t+"px"}},f._emitCompleteOnItems=function(t,e){function i(){o.dispatchEvent(t+"Complete",null,[e])}function n(){s++,s==r&&i()}var o=this,r=e.length;if(!e||!r)return void i();var s=0;e.forEach(function(e){e.once(t,n)})},f.dispatchEvent=function(t,e,i){var n=e?[e].concat(i):i;if(this.emitEvent(t,n),u)if(this.$element=this.$element||u(this.element),e){var o=u.Event(e);o.type=t,this.$element.trigger(o,i)}else this.$element.trigger(t,i)},f.ignore=function(t){var e=this.getItem(t);e&&(e.isIgnored=!0)},f.unignore=function(t){var e=this.getItem(t);e&&delete e.isIgnored},f.stamp=function(t){t=this._find(t),t&&(this.stamps=this.stamps.concat(t),t.forEach(this.ignore,this))},f.unstamp=function(t){t=this._find(t),t&&t.forEach(function(t){n.removeFrom(this.stamps,t),this.unignore(t)},this)},f._find=function(t){return t?("string"==typeof t&&(t=this.element.querySelectorAll(t)),t=n.makeArray(t)):void 0},f._manageStamps=function(){this.stamps&&this.stamps.length&&(this._getBoundingRect(),this.stamps.forEach(this._manageStamp,this))},f._getBoundingRect=function(){var t=this.element.getBoundingClientRect(),e=this.size;this._boundingRect={left:t.left+e.paddingLeft+e.borderLeftWidth,top:t.top+e.paddingTop+e.borderTopWidth,right:t.right-(e.paddingRight+e.borderRightWidth),bottom:t.bottom-(e.paddingBottom+e.borderBottomWidth)}},f._manageStamp=d,f._getElementOffset=function(t){var e=t.getBoundingClientRect(),n=this._boundingRect,o=i(t),r={left:e.left-n.left-o.marginLeft,top:e.top-n.top-o.marginTop,right:n.right-e.right-o.marginRight,bottom:n.bottom-e.bottom-o.marginBottom};return r},f.handleEvent=n.handleEvent,f.bindResize=function(){t.addEventListener("resize",this),this.isResizeBound=!0},f.unbindResize=function(){t.removeEventListener("resize",this),this.isResizeBound=!1},f.onresize=function(){this.resize()},n.debounceMethod(r,"onresize",100),f.resize=function(){this.isResizeBound&&this.needsResizeLayout()&&this.layout()},f.needsResizeLayout=function(){var t=i(this.element),e=this.size&&t;return e&&t.innerWidth!==this.size.innerWidth},f.addItems=function(t){var e=this._itemize(t);return e.length&&(this.items=this.items.concat(e)),e},f.appended=function(t){var e=this.addItems(t);e.length&&(this.layoutItems(e,!0),this.reveal(e))},f.prepended=function(t){var e=this._itemize(t);if(e.length){var i=this.items.slice(0);this.items=e.concat(i),this._resetLayout(),this._manageStamps(),this.layoutItems(e,!0),this.reveal(e),this.layoutItems(i)}},f.reveal=function(t){if(this._emitCompleteOnItems("reveal",t),t&&t.length){var e=this.updateStagger();t.forEach(function(t,i){t.stagger(i*e),t.reveal()})}},f.hide=function(t){if(this._emitCompleteOnItems("hide",t),t&&t.length){var e=this.updateStagger();t.forEach(function(t,i){t.stagger(i*e),t.hide()})}},f.revealItemElements=function(t){var e=this.getItems(t);this.reveal(e)},f.hideItemElements=function(t){var e=this.getItems(t);this.hide(e)},f.getItem=function(t){for(var e=0;e<this.items.length;e++){var i=this.items[e];if(i.element==t)return i}},f.getItems=function(t){t=n.makeArray(t);var e=[];return t.forEach(function(t){var i=this.getItem(t);i&&e.push(i)},this),e},f.remove=function(t){var e=this.getItems(t);this._emitCompleteOnItems("remove",e),e&&e.length&&e.forEach(function(t){t.remove(),n.removeFrom(this.items,t)},this)},f.destroy=function(){var t=this.element.style;t.height="",t.position="",t.width="",this.items.forEach(function(t){t.destroy()}),this.unbindResize();var e=this.element.outlayerGUID;delete c[e],delete this.element.outlayerGUID,u&&u.removeData(this.element,this.constructor.namespace)},r.data=function(t){t=n.getQueryElement(t);var e=t&&t.outlayerGUID;return e&&c[e]},r.create=function(t,e){var i=s(r);return i.defaults=n.extend({},r.defaults),n.extend(i.defaults,e),i.compatOptions=n.extend({},r.compatOptions),i.namespace=t,i.data=r.data,i.Item=s(o),n.htmlInit(i,t),u&&u.bridget&&u.bridget(t,i),i};var m={ms:1,s:1e3};return r.Item=o,r}),function(t,e){"function"==typeof define&&define.amd?define(["outlayer/outlayer","get-size/get-size"],e):"object"==typeof module&&module.exports?module.exports=e(require("outlayer"),require("get-size")):t.Masonry=e(t.Outlayer,t.getSize)}(window,function(t,e){var i=t.create("masonry");i.compatOptions.fitWidth="isFitWidth";var n=i.prototype;return n._resetLayout=function(){this.getSize(),this._getMeasurement("columnWidth","outerWidth"),this._getMeasurement("gutter","outerWidth"),this.measureColumns(),this.colYs=[];for(var t=0;t<this.cols;t++)this.colYs.push(0);this.maxY=0,this.horizontalColIndex=0},n.measureColumns=function(){if(this.getContainerWidth(),!this.columnWidth){var t=this.items[0],i=t&&t.element;this.columnWidth=i&&e(i).outerWidth||this.containerWidth}var n=this.columnWidth+=this.gutter,o=this.containerWidth+this.gutter,r=o/n,s=n-o%n,a=s&&1>s?"round":"floor";r=Math[a](r),this.cols=Math.max(r,1)},n.getContainerWidth=function(){var t=this._getOption("fitWidth"),i=t?this.element.parentNode:this.element,n=e(i);this.containerWidth=n&&n.innerWidth},n._getItemLayoutPosition=function(t){t.getSize();var e=t.size.outerWidth%this.columnWidth,i=e&&1>e?"round":"ceil",n=Math[i](t.size.outerWidth/this.columnWidth);n=Math.min(n,this.cols);for(var o=this.options.horizontalOrder?"_getHorizontalColPosition":"_getTopColPosition",r=this[o](n,t),s={x:this.columnWidth*r.col,y:r.y},a=r.y+t.size.outerHeight,h=n+r.col,u=r.col;h>u;u++)this.colYs[u]=a;return s},n._getTopColPosition=function(t){var e=this._getTopColGroup(t),i=Math.min.apply(Math,e);return{col:e.indexOf(i),y:i}},n._getTopColGroup=function(t){if(2>t)return this.colYs;for(var e=[],i=this.cols+1-t,n=0;i>n;n++)e[n]=this._getColGroupY(n,t);return e},n._getColGroupY=function(t,e){if(2>e)return this.colYs[t];var i=this.colYs.slice(t,t+e);return Math.max.apply(Math,i)},n._getHorizontalColPosition=function(t,e){var i=this.horizontalColIndex%this.cols,n=t>1&&i+t>this.cols;i=n?0:i;var o=e.size.outerWidth&&e.size.outerHeight;return this.horizontalColIndex=o?i+t:this.horizontalColIndex,{col:i,y:this._getColGroupY(i,t)}},n._manageStamp=function(t){var i=e(t),n=this._getElementOffset(t),o=this._getOption("originLeft"),r=o?n.left:n.right,s=r+i.outerWidth,a=Math.floor(r/this.columnWidth);a=Math.max(0,a);var h=Math.floor(s/this.columnWidth);h-=s%this.columnWidth?0:1,h=Math.min(this.cols-1,h);for(var u=this._getOption("originTop"),d=(u?n.top:n.bottom)+i.outerHeight,l=a;h>=l;l++)this.colYs[l]=Math.max(d,this.colYs[l])},n._getContainerSize=function(){this.maxY=Math.max.apply(Math,this.colYs);var t={height:this.maxY};return this._getOption("fitWidth")&&(t.width=this._getContainerFitWidth()),t},n._getContainerFitWidth=function(){for(var t=0,e=this.cols;--e&&0===this.colYs[e];)t++;return(this.cols-t)*this.columnWidth-this.gutter},n.needsResizeLayout=function(){var t=this.containerWidth;return this.getContainerWidth(),t!=this.containerWidth},i});
519; 520/*! 521 * imagesLoaded PACKAGED v3.1.8 522 * JavaScript is all like "You images are done yet or what?" 523 * MIT License 524 */ 525 526 527/*! 528 * EventEmitter v4.2.6 - git.io/ee 529 * Oliver Caldwell 530 * MIT license 531 * @preserve 532 */ 533 534(function () { 535 536 537 /** 538 * Class for managing events. 539 * Can be extended to provide event functionality in other classes. 540 * 541 * @class EventEmitter Manages event registering and emitting. 542 */ 543 function EventEmitter() {} 544 545 // Shortcuts to improve speed and size 546 var proto = EventEmitter.prototype; 547 var exports = this; 548 var originalGlobalValue = exports.EventEmitter; 549 550 /** 551 * Finds the index of the listener for the event in it's storage array. 552 * 553 * @param {Function[]} listeners Array of listeners to search through. 554 * @param {Function} listener Method to look for. 555 * @return {Number} Index of the specified listener, -1 if not found 556 * @api private 557 */ 558 function indexOfListener(listeners, listener) { 559 var i = listeners.length; 560 while (i--) { 561 if (listeners[i].listener === listener) { 562 return i; 563 } 564 } 565 566 return -1; 567 } 568 569 /** 570 * Alias a method while keeping the context correct, to allow for over
vendor: 11,346 bytes, lines 570-878
570writing of target method. 571 * 572 * @param {String} name The name of the target method. 573 * @return {Function} The aliased method 574 * @api private 575 */ 576 function alias(name) { 577 return function aliasClosure() { 578 return this[name].apply(this, arguments); 579 }; 580 } 581 582 /** 583 * Returns the listener array for the specified event. 584 * Will initialise the event object and listener arrays if required. 585 * 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. 586 * Each property in the object response is an array of listener functions. 587 * 588 * @param {String|RegExp} evt Name of the event to return the listeners from. 589 * @return {Function[]|Object} All listener functions for the event. 590 */ 591 proto.getListeners = function getListeners(evt) { 592 var events = this._getEvents(); 593 var response; 594 var key; 595 596 // Return a concatenated array of all matching events if 597 // the selector is a regular expression. 598 if (typeof evt === 'object') { 599 response = {}; 600 for (key in events) { 601 if (events.hasOwnProperty(key) && evt.test(key)) { 602 response[key] = events[key]; 603 } 604 } 605 } 606 else { 607 response = events[evt] || (events[evt] = []); 608 } 609 610 return response; 611 }; 612 613 /** 614 * Takes a list of listener objects and flattens it into a list of listener functions. 615 * 616 * @param {Object[]} listeners Raw listener objects. 617 * @return {Function[]} Just the listener functions. 618 */ 619 proto.flattenListeners = function flattenListeners(listeners) { 620 var flatListeners = []; 621 var i; 622 623 for (i = 0; i < listeners.length; i += 1) { 624 flatListeners.push(listeners[i].listener); 625 } 626 627 return flatListeners; 628 }; 629 630 /** 631 * 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. 632 * 633 * @param {String|RegExp} evt Name of the event to return the listeners from. 634 * @return {Object} All listener functions for an event in an object. 635 */ 636 proto.getListenersAsObject = function getListenersAsObject(evt) { 637 var listeners = this.getListeners(evt); 638 var response; 639 640 if (listeners instanceof Array) { 641 response = {}; 642 response[evt] = listeners; 643 } 644 645 return response || listeners; 646 }; 647 648 /** 649 * Adds a listener function to the specified event. 650 * The listener will not be added if it is a duplicate. 651 * If the listener returns true then it will be removed after it is called. 652 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 653 * 654 * @param {String|RegExp} evt Name of the event to attach the listener to. 655 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 656 * @return {Object} Current instance of EventEmitter for chaining. 657 */ 658 proto.addListener = function addListener(evt, listener) { 659 var listeners = this.getListenersAsObject(evt); 660 var listenerIsWrapped = typeof listener === 'object'; 661 var key; 662 663 for (key in listeners) { 664 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 665 listeners[key].push(listenerIsWrapped ? listener : { 666 listener: listener, 667 once: false 668 }); 669 } 670 } 671 672 return this; 673 }; 674 675 /** 676 * Alias of addListener 677 */ 678 proto.on = alias('addListener'); 679 680 /** 681 * Semi-alias of addListener. It will add a listener that will be 682 * automatically removed after it's first execution. 683 * 684 * @param {String|RegExp} evt Name of the event to attach the listener to. 685 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 686 * @return {Object} Current instance of EventEmitter for chaining. 687 */ 688 proto.addOnceListener = function addOnceListener(evt, listener) { 689 return this.addListener(evt, { 690 listener: listener, 691 once: true 692 }); 693 }; 694 695 /** 696 * Alias of addOnceListener. 697 */ 698 proto.once = alias('addOnceListener'); 699 700 /** 701 * 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. 702 * You need to tell it what event names should be matched by a regex. 703 * 704 * @param {String} evt Name of the event to create. 705 * @return {Object} Current instance of EventEmitter for chaining. 706 */ 707 proto.defineEvent = function defineEvent(evt) { 708 this.getListeners(evt); 709 return this; 710 }; 711 712 /** 713 * Uses defineEvent to define multiple events. 714 * 715 * @param {String[]} evts An array of event names to define. 716 * @return {Object} Current instance of EventEmitter for chaining. 717 */ 718 proto.defineEvents = function defineEvents(evts) { 719 for (var i = 0; i < evts.length; i += 1) { 720 this.defineEvent(evts[i]); 721 } 722 return this; 723 }; 724 725 /** 726 * Removes a listener function from the specified event. 727 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 728 * 729 * @param {String|RegExp} evt Name of the event to remove the listener from. 730 * @param {Function} listener Method to remove from the event. 731 * @return {Object} Current instance of EventEmitter for chaining. 732 */ 733 proto.removeListener = function removeListener(evt, listener) { 734 var listeners = this.getListenersAsObject(evt); 735 var index; 736 var key; 737 738 for (key in listeners) { 739 if (listeners.hasOwnProperty(key)) { 740 index = indexOfListener(listeners[key], listener); 741 742 if (index !== -1) { 743 listeners[key].splice(index, 1); 744 } 745 } 746 } 747 748 return this; 749 }; 750 751 /** 752 * Alias of removeListener 753 */ 754 proto.off = alias('removeListener'); 755 756 /** 757 * Adds listeners in bulk using the manipulateListeners method. 758 * 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. 759 * You can also pass it a regular expression to add the array of listeners to all events that match it. 760 * Yeah, this function does quite a bit. That's probably a bad thing. 761 * 762 * @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. 763 * @param {Function[]} [listeners] An optional array of listener functions to add. 764 * @return {Object} Current instance of EventEmitter for chaining. 765 */ 766 proto.addListeners = function addListeners(evt, listeners) { 767 // Pass through to manipulateListeners 768 return this.manipulateListeners(false, evt, listeners); 769 }; 770 771 /** 772 * Removes listeners in bulk using the manipulateListeners method. 773 * 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. 774 * You can also pass it an event name and an array of listeners to be removed. 775 * You can also pass it a regular expression to remove the listeners from all events that match it. 776 * 777 * @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. 778 * @param {Function[]} [listeners] An optional array of listener functions to remove. 779 * @return {Object} Current instance of EventEmitter for chaining. 780 */ 781 proto.removeListeners = function removeListeners(evt, listeners) { 782 // Pass through to manipulateListeners 783 return this.manipulateListeners(true, evt, listeners); 784 }; 785 786 /** 787 * 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. 788 * The first argument will determine if the listeners are removed (true) or added (false). 789 * 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. 790 * You can also pass it an event name and an array of listeners to be added/removed. 791 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 792 * 793 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 794 * @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. 795 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 796 * @return {Object} Current instance of EventEmitter for chaining. 797 */ 798 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 799 var i; 800 var value; 801 var single = remove ? this.removeListener : this.addListener; 802 var multiple = remove ? this.removeListeners : this.addListeners; 803 804 // If evt is an object then pass each of it's properties to this method 805 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 806 for (i in evt) { 807 if (evt.hasOwnProperty(i) && (value = evt[i])) { 808 // Pass the single listener straight through to the singular method 809 if (typeof value === 'function') { 810 single.call(this, i, value); 811 } 812 else { 813 // Otherwise pass back to the multiple function 814 multiple.call(this, i, value); 815 } 816 } 817 } 818 } 819 else { 820 // So evt must be a string 821 // And listeners must be an array of listeners 822 // Loop over it and pass each one to the multiple method 823 i = listeners.length; 824 while (i--) { 825 single.call(this, evt, listeners[i]); 826 } 827 } 828 829 return this; 830 }; 831 832 /** 833 * Removes all listeners from a specified event. 834 * If you do not specify an event then all listeners will be removed. 835 * That means every event will be emptied. 836 * You can also pass a regex to remove all events that match it. 837 * 838 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 839 * @return {Object} Current instance of EventEmitter for chaining. 840 */ 841 proto.removeEvent = function removeEvent(evt) { 842 var type = typeof evt; 843 var events = this._getEvents(); 844 var key; 845 846 // Remove different things depending on the state of evt 847 if (type === 'string') { 848 // Remove all listeners for the specified event 849 delete events[evt]; 850 } 851 else if (type === 'object') { 852 // Remove all events matching the regex. 853 for (key in events) { 854 if (events.hasOwnProperty(key) && evt.test(key)) { 855 delete events[key]; 856 } 857 } 858 } 859 else { 860 // Remove all listeners in all events 861 delete this._events; 862 } 863 864 return this; 865 }; 866 867 /** 868 * Alias of removeEvent. 869 * 870 * Added to mirror the node API. 871 */ 872 proto.removeAllListeners = alias('removeEvent'); 873 874 /** 875 * Emits an event of your choice. 876 * When emitted, every listener attached to that event will be executed. 877 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 878 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
879 * So they will not arrive within the array on the other side, they will be separate. 880 * You can also pass a regular expression to emit to all events that match it. 881 * 882 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 883 * @param {Array} [args] Optional array of arguments to be passed to each listener. 884 * @return {Object} Current instance of EventEmitter for chaining. 885 */ 886 proto.emitEvent = function emitEvent(evt, args) { 887 var listeners = this.getListenersAsObject(evt); 888 var listener; 889 var i; 890 var key; 891 var response; 892 893 for (key in listeners) { 894 if (listeners.hasOwnProperty(key)) { 895 i = listeners[key].length; 896 897 while (i--) { 898 // If the listener returns true then it shall be removed from the event 899 // The function is executed either with a basic call or an apply if there is an args array 900 listener = listeners[key][i]; 901 902 if (listener.once === true) { 903 this.removeListener(evt, listener.listener); 904 } 905 906 response = listener.listener.apply(this, args || []); 907 908 if (response === this._getOnceReturnValue()) { 909 this.removeListener(evt, listener.listener); 910 } 911 } 912 } 913 } 914 915 return this; 916 }; 917 918 /** 919 * Alias of emitEvent 920 */ 921 proto.trigger = alias('emitEvent'); 922 923 /** 924 * 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. 925 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 926 * 927 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 928 * @param {...*} Optional additional arguments to be passed to each listener. 929 * @return {Object} Current instance of EventEmitter for chaining. 930 */ 931 proto.emit = function emit(evt) { 932 var args = Array.prototype.slice.call(arguments, 1); 933 return this.emitEvent(evt, args); 934 }; 935 936 /** 937 * Sets the current value to check against when executing listeners. If a 938 * listeners return value matches the one set here then it will be removed 939 * after execution. This value defaults to true. 940 * 941 * @param {*} value The new value to check for when executing listeners. 942 * @return {Object} Current instance of EventEmitter for chaining. 943 */ 944 proto.setOnceReturnValue = function setOnceReturnValue(value) { 945 this._onceReturnValue = value; 946 return this; 947 }; 948 949 /** 950 * Fetches the current value to check against when executing listeners. If 951 * the listeners return value matches this one then it should be removed 952 * automatically. It will return true by default. 953 * 954 * @return {*|Boolean} The current value to check for or the default, true. 955 * @api private 956 */ 957 proto._getOnceReturnValue = function _getOnceReturnValue() { 958 if (this.hasOwnProperty('_onceReturnValue')) { 959 return this._onceReturnValue; 960 } 961 else { 962 return true; 963 } 964 }; 965 966 /** 967 * Fetches the events object and creates one if required. 968 * 969 * @return {Object} The events storage object. 970 * @api private 971 */ 972 proto._getEvents = function _getEvents() { 973 return this._events || (this._events = {}); 974 }; 975 976 /** 977 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 978 * 979 * @return {Function} Non conflicting EventEmitter class. 980 */ 981 EventEmitter.noConflict = function noConflict() { 982 exports.EventEmitter = originalGlobalValue; 983 return EventEmitter; 984 }; 985 986 // Expose the class either via AMD, CommonJS or the global object 987 if (typeof define === 'function' && define.amd) { 988 define('eventEmitter/EventEmitter',[],function () { 989 return EventEmitter; 990 }); 991 } 992 else if (typeof module === 'object' && module.exports){ 993 module.exports = EventEmitter; 994 } 995 else { 996 this.EventEmitter = EventEmitter; 997 } 998}.call(this)); 999 1000/*! 1001 * eventie v1.0.4 1002 * event binding helper 1003 * eventie.bind( elem, 'click', myFn ) 1004 * eventie.unbind( elem, 'click', myFn ) 1005 */ 1006 1007/*jshint browser: true, undef: true, unused: true */ 1008/*global define: false */ 1009 1010( function( window ) { 1011 1012 1013 1014var docElem = document.documentElement; 1015 1016var bind = function() {}; 1017 1018function getIEEvent( obj ) { 1019 var event = window.event; 1020 // add event.target 1021 event.target = event.target || event.srcElement || obj; 1022 return event; 1023} 1024 1025if ( docElem.addEventListener ) { 1026 bind = function( obj, type, fn ) { 1027 obj.addEventListener( type, fn, false ); 1028 }; 1029} else if ( docElem.attachEvent ) { 1030 bind = function( obj, type, fn ) { 1031 obj[ type + fn ] = fn.handleEvent ? 1032 function() { 1033 var event = getIEEvent( obj ); 1034 fn.handleEvent.call( fn, event ); 1035 } : 1036 function() { 1037 var event = getIEEvent( obj ); 1038 fn.call( obj, event ); 1039 }; 1040 obj.attachEvent( "on" + type, obj[ type + fn ] ); 1041 }; 1042} 1043 1044var unbind = function() {}; 1045 1046if ( docElem.removeEventListener ) { 1047 unbind = function( obj, type, fn ) { 1048 obj.removeEventListener( type, fn, false ); 1049 }; 1050} else if ( docElem.detachEvent ) { 1051 unbind = function( obj, type, fn ) { 1052 obj.detachEvent( "on" + type, obj[ type + fn ] ); 1053 try { 1054 delete obj[ type + fn ]; 1055 } catch ( err ) { 1056 // can't delete window object properties 1057 obj[ type + fn ] = undefined; 1058 } 1059 }; 1060} 1061 1062var eventie = { 1063 bind: bind, 1064 unbind: unbind 1065}; 1066 1067// transport 1068if ( typeof define === 'function' && define.amd ) { 1069 // AMD 1070 define( 'eventie/eventie',eventie ); 1071} else { 1072 // browser global 1073 window.eventie = eventie; 1074} 1075 1076})( this ); 1077 1078/*! 1079 * imagesLoaded v3.1.8 1080 * JavaScript is all like "You images are done yet or what?" 1081 * MIT License 1082 */ 1083 1084( function( window, factory ) { 1085 // universal module definition 1086 1087 /*global define: false, module: false, require: false */ 1088 1089 if ( typeof define === 'function' && define.amd ) { 1090 // AMD 1091 define( [ 1092 'eventEmitter/EventEmitter', 1093 'eventie/eventie' 1094 ], function( EventEmitter, eventie ) { 1095 return factory( window, EventEmitter, eventie ); 1096 }); 1097 } else if ( typeof exports === 'object' ) { 1098 // CommonJS 1099 module.exports = factory( 1100 window, 1101 require('wolfy87-eventemitter'), 1102 require('eventie') 1103 ); 1104 } else { 1105 // browser global 1106 window.imagesLoaded = factory( 1107 window, 1108 window.EventEmitter, 1109 window.eventie 1110 ); 1111 } 1112 1113})( window, 1114 1115// -------------------------- factory -------------------------- // 1116 1117function factory( window, EventEmitter, eventie ) { 1118 1119 1120 1121var $ = window.jQuery; 1122var console = window.console; 1123var hasConsole = typeof console !== 'undefined'; 1124 1125// -------------------------- helpers -------------------------- // 1126 1127// extend objects 1128function extend( a, b ) { 1129 for ( var prop in b ) { 1130 a[ prop ] = b[ prop ]; 1131 } 1132 return a; 1133} 1134 1135var objToString = Object.prototype.toString; 1136function isArray( obj ) { 1137 return objToString.call( obj ) === '[object Array]'; 1138} 1139 1140// turn element or nodeList into an array 1141function makeArray( obj ) { 1142 var ary = []; 1143 if ( isArray( obj ) ) { 1144 // use object if already an array 1145 ary = obj; 1146 } else if ( typeof obj.length === 'number' ) { 1147 // convert nodeList to array 1148 for ( var i=0, len = obj.length; i < len; i++ ) { 1149 ary.push( obj[i] ); 1150 } 1151 } else { 1152 // array of single index 1153 ary.push( obj ); 1154 } 1155 return ary; 1156} 1157 1158 // -------------------------- imagesLoaded -------------------------- // 1159 1160 /** 1161 * @param {Array, Element, NodeList, String} elem 1162 * @param {Object or Function} options - if function, use as callback 1163 * @param {Function} onAlways - callback function 1164 */ 1165 function ImagesLoaded( elem, options, onAlways ) { 1166 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 1167 if ( !( this instanceof ImagesLoaded ) ) { 1168 return new ImagesLoaded( elem, options ); 1169 } 1170 // use elem as selector string 1171 if ( typeof elem === 'string' ) { 1172 elem = document.querySelectorAll( elem ); 1173 } 1174 1175 this.elements = makeArray( elem ); 1176 this.options = extend( {}, this.options ); 1177 1178 if ( typeof options === 'function' ) { 1179 onAlways = options; 1180 } else { 1181 extend( this.options, options ); 1182 } 1183 1184 if ( onAlways ) { 1185 this.on( 'always', onAlways ); 1186 } 1187 1188 this.getImages(); 1189 1190 if ( $ ) { 1191 // add jQuery Deferred object 1192 this.jqDeferred = new $.Deferred(); 1193 } 1194 1195 // HACK check async to allow time to bind listeners 1196 var _this = this; 1197 setTimeout( function() { 1198 _this.check(); 1199 }); 1200 } 1201 1202 ImagesLoaded.prototype = new EventEmitter(); 1203 1204 ImagesLoaded.prototype.options = {}; 1205 1206 ImagesLoaded.prototype.getImages = function() { 1207 this.images = []; 1208 1209 // filter & find items if we have an item selector 1210 for ( var i=0, len = this.elements.length; i < len; i++ ) { 1211 var elem = this.elements[i]; 1212 // filter siblings 1213 if ( elem.nodeName === 'IMG' ) { 1214 this.addImage( elem ); 1215 } 1216 // find children 1217 // no non-element nodes, #143 1218 var nodeType = elem.nodeType; 1219 if ( !nodeType || !( nodeType === 1 || nodeType === 9 || nodeType === 11 ) ) { 1220 continue; 1221 } 1222 var childElems = elem.querySelectorAll('img'); 1223 // concat childElems to filterFound array 1224 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 1225 var img = childElems[j]; 1226 this.addImage( img ); 1227 } 1228 } 1229 }; 1230 1231 /** 1232 * @param {Image} img 1233 */ 1234 ImagesLoaded.prototype.addImage = function( img ) { 1235 var loadingImage = new LoadingImage( img ); 1236 this.images.push( loadingImage ); 1237 }; 1238
1239 ImagesLoaded.prototype.check = function() { 1240 var _this = this; 1241 var checkedCount = 0; 1242 var length = this.images.length; 1243 this.hasAnyBroken = false; 1244 // complete if no images 1245 if ( !length ) { 1246 this.complete(); 1247 return; 1248 } 1249 1250 function onConfirm( image, message ) { 1251 if ( _this.options.debug && hasConsole ) { 1252 console.log( 'confirm', image, message ); 1253 } 1254 1255 _this.progress( image ); 1256 checkedCount++; 1257 if ( checkedCount === length ) { 1258 _this.complete(); 1259 } 1260 return true; // bind once 1261 } 1262 1263 for ( var i=0; i < length; i++ ) { 1264 var loadingImage = this.images[i]; 1265 loadingImage.on( 'confirm', onConfirm ); 1266 loadingImage.check(); 1267 } 1268 }; 1269 1270 ImagesLoaded.prototype.progress = function( image ) { 1271 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 1272 // HACK - Chrome triggers event before object properties have changed. #83 1273 var _this = this; 1274 setTimeout( function() { 1275 _this.emit( 'progress', _this, image ); 1276 if ( _this.jqDeferred && _this.jqDeferred.notify ) { 1277 _this.jqDeferred.notify( _this, image ); 1278 } 1279 }); 1280 }; 1281 1282 ImagesLoaded.prototype.complete = function() { 1283 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 1284 this.isComplete = true; 1285 var _this = this; 1286 // HACK - another setTimeout so that confirm happens after progress 1287 setTimeout( function() { 1288 _this.emit( eventName, _this ); 1289 _this.emit( 'always', _this ); 1290 if ( _this.jqDeferred ) { 1291 var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve'; 1292 _this.jqDeferred[ jqMethod ]( _this ); 1293 } 1294 }); 1295 }; 1296 1297 // -------------------------- jquery -------------------------- // 1298 1299 if ( $ ) { 1300 $.fn.imagesLoaded = function( options, callback ) { 1301 var instance = new ImagesLoaded( this, options, callback ); 1302 return instance.jqDeferred.promise( $(this) ); 1303 }; 1304 } 1305 1306 1307 // -------------------------- -------------------------- // 1308 1309 function LoadingImage( img ) { 1310 this.img = img; 1311 } 1312 1313 LoadingImage.prototype = new EventEmitter(); 1314 1315 LoadingImage.prototype.check = function() { 1316 // first check cached any previous images that have same src 1317 var resource = cache[ this.img.src ] || new Resource( this.img.src ); 1318 if ( resource.isConfirmed ) { 1319 this.confirm( resource.isLoaded, 'cached was confirmed' ); 1320 return; 1321 } 1322 1323 // If complete is true and browser supports natural sizes, 1324 // try to check for image status manually. 1325 if ( this.img.complete && this.img.naturalWidth !== undefined ) { 1326 // report based on naturalWidth 1327 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 1328 return; 1329 } 1330 1331 // If none of the checks above matched, simulate loading on detached element. 1332 var _this = this; 1333 resource.on( 'confirm', function( resrc, message ) { 1334 _this.confirm( resrc.isLoaded, message ); 1335 return true; 1336 }); 1337 1338 resource.check(); 1339 }; 1340 1341 LoadingImage.prototype.confirm = function( isLoaded, message ) { 1342 this.isLoaded = isLoaded; 1343 this.emit( 'confirm', this, message ); 1344 }; 1345 1346 // -------------------------- Resource -------------------------- // 1347 1348 // Resource checks each src, only once 1349 // separate class from LoadingImage to prevent memory leaks. See #115 1350 1351 var cache = {}; 1352 1353 function Resource( src ) { 1354 this.src = src; 1355 // add to cache 1356 cache[ src ] = this; 1357 } 1358 1359 Resource.prototype = new EventEmitter(); 1360 1361 Resource.prototype.check = function() { 1362 // only trigger checking once 1363 if ( this.isChecked ) { 1364 return; 1365 } 1366 // simulate loading on detached element 1367 var proxyImage = new Image(); 1368 eventie.bind( proxyImage, 'load', this ); 1369 eventie.bind( proxyImage, 'error', this ); 1370 proxyImage.src = this.src; 1371 // set flag 1372 this.isChecked = true; 1373 }; 1374 1375 // ----- events ----- // 1376 1377 // trigger specified handler for event type 1378 Resource.prototype.handleEvent = function( event ) { 1379 var method = 'on' + event.type; 1380 if ( this[ method ] ) { 1381 this[ method ]( event ); 1382 } 1383 }; 1384 1385 Resource.prototype.onload = function( event ) { 1386 this.confirm( true, 'onload' ); 1387 this.unbindProxyEvents( event ); 1388 }; 1389 1390 Resource.prototype.onerror = function( event ) { 1391 this.confirm( false, 'onerror' ); 1392 this.unbindProxyEvents( event ); 1393 }; 1394 1395 // ----- confirm ----- // 1396 1397 Resource.prototype.confirm = function( isLoaded, message ) { 1398 this.isConfirmed = true; 1399 this.isLoaded = isLoaded;
1400 this.emit( 'confirm', this, message ); 1401 }; 1402 1403 Resource.prototype.unbindProxyEvents = function( event ) { 1404 eventie.unbind( event.target, 'load', this ); 1405 eventie.unbind( event.target, 'error', this ); 1406 }; 1407 1408 // ----- ----- // 1409 1410 return ImagesLoaded; 1411 1412});; 1413/*! 1414 * hoverIntent v1.8.0 // 2014.06.29 // jQuery v1.9.1+ 1415 * http://cherne.net/brian/resources/jquery.hoverIntent.html 1416 * 1417 * You may use hoverIntent under the terms of the MIT license. Basically that 1418 * means you are free to use hoverIntent as long as this header is left intact. 1419 * Copyright 2007, 2014 Brian Cherne 1420 */ 1421 1422/* hoverIntent is similar to jQuery's built-in "hover" method except that 1423 * instead of firing the handlerIn function immediately, hoverIntent checks 1424 * to see if the user's mouse has slowed down (beneath the sensitivity 1425 * threshold) before firing the event. The handlerOut function is only 1426 * called after a matching handlerIn. 1427 * 1428 * // basic usage ... just like .hover() 1429 * .hoverIntent( handlerIn, handlerOut ) 1430 * .hoverIntent( handlerInOut ) 1431 * 1432 * // basic usage ... with event delegation! 1433 * .hoverIntent( handlerIn, handlerOut, selector ) 1434 * .hoverIntent( handlerInOut, selector ) 1435 * 1436 * // using a basic configuration object 1437 * .hoverIntent( config ) 1438 * 1439 * @param handlerIn function OR configuration object 1440 * @param handlerOut function OR selector for delegation OR undefined 1441 * @param selector selector OR undefined 1442 * @author Brian Cherne <brian(at)cherne(dot)net> 1443 */ 1444(function($) { 1445 $.fn.hoverIntent = function(handlerIn,handlerOut,selector) { 1446 1447 // default configuration values 1448 var cfg = { 1449 interval: 100, 1450 sensitivity: 6, 1451 timeout: 0 1452 }; 1453 1454 if ( typeof handlerIn === "object" ) { 1455 cfg = $.extend(cfg, handlerIn ); 1456 } else if ($.isFunction(handlerOut)) { 1457 cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } ); 1458 } else { 1459 cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } ); 1460 } 1461 1462 // instantiate variables 1463 // cX, cY = current X and Y position of mouse, updated by mousemove event 1464 // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval 1465 var cX, cY, pX, pY; 1466 1467 // A private function for getting mouse position 1468 var track = function(ev) { 1469 cX = ev.pageX; 1470 cY = ev.pageY; 1471 }; 1472 1473 // A private function for comparing current and previous mouse position 1474 var compare = function(ev,ob) { 1475 ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); 1476 // compare mouse positions to see if they've crossed the threshold 1477 if ( Math.sqrt( (pX-cX)*(pX-cX) + (pY-cY)*(pY-cY) ) < cfg.sensitivity ) { 1478 $(ob).off("mousemove.hoverIntent",track); 1479 // set hoverIntent state to true (so mouseOut can be called) 1480 ob.hoverIntent_s = true; 1481 return cfg.over.apply(ob,[ev]); 1482 } else { 1483 // set previous coordinates for next time 1484 pX = cX; pY = cY; 1485 // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs) 1486 ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval ); 1487 } 1488 }; 1489 1490 // A private function for delaying the mouseOut function 1491 var delay = function(ev,ob) { 1492 ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); 1493 ob.hoverIntent_s = false; 1494 return cfg.out.apply(ob,[ev]); 1495 }; 1496 1497 // A private function for handling mouse 'hovering' 1498 var handleHover = function(e) { 1499 // copy objects to be passed into t (required for event object to be passed in IE) 1500 var ev = $.extend({},e); 1501 var ob = this; 1502 1503 // cancel hoverIntent timer if it exists 1504 if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); } 1505 1506 // if e.type === "mouseenter" 1507 if (e.type === "mouseenter") { 1508 // set "previous" X and Y position based on initial entry point 1509 pX = ev.pageX; pY = ev.pageY; 1510 // update "current" X and Y position based on mousemove 1511 $(ob).on("mousemove.hoverIntent",track); 1512 // start polling interval (self-calling timeout) to compare mouse coordinates over time 1513 if (!ob.hoverIntent_s) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );} 1514 1515 // else e.type == "mouseleave" 1516 } else { 1517 // unbind expensive mousemove event 1518 $(ob).off("mousemove.hoverIntent",track); 1519 // if hoverIntent state is true, then call the mouseOut function after the specified delay 1520 if (ob.hoverIntent_s) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );} 1521 } 1522 }; 1523 1524 // listen for mouseenter and mouseleave 1525 return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector); 1526 }; 1527})(jQuery);; 1528/*! VelocityJS.org (1.1.0). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */ 1529 1530/************************* 1531 Velocity jQuery Shim 1532*************************/ 1533
vendor: 9,456 bytes, lines 1534-1877
1534/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */ 1535 1536/* This file contains the jQuery functions that Velocity relies on, thereby removing Velocity's dependency on a full copy of jQuery, and allowing it to work in any environment. */ 1537/* These shimmed functions are only used if jQuery isn't present. If both this shim and jQuery are loaded, Velocity defaults to jQuery proper. */ 1538/* Browser support: Using this shim instead of jQuery proper removes support for IE8. */ 1539 1540;(function (window) { 1541 /*************** 1542 Setup 1543 ***************/ 1544 1545 /* If jQuery is already loaded, there's no point in loading this shim. */ 1546 if (window.jQuery) { 1547 return; 1548 } 1549 1550 /* jQuery base. */ 1551 var $ = function (selector, context) { 1552 return new $.fn.init(selector, context); 1553 }; 1554 1555 /******************** 1556 Private Methods 1557 ********************/ 1558 1559 /* jQuery */ 1560 $.isWindow = function (obj) { 1561 /* jshint eqeqeq: false */ 1562 return obj != null && obj == obj.window; 1563 }; 1564 1565 /* jQuery */ 1566 $.type = function (obj) { 1567 if (obj == null) { 1568 return obj + ""; 1569 } 1570 1571 return typeof obj === "object" || typeof obj === "function" ? 1572 class2type[toString.call(obj)] || "object" : 1573 typeof obj; 1574 }; 1575 1576 /* jQuery */ 1577 $.isArray = Array.isArray || function (obj) { 1578 return $.type(obj) === "array"; 1579 }; 1580 1581 /* jQuery */ 1582 function isArraylike (obj) { 1583 var length = obj.length, 1584 type = $.type(obj); 1585 1586 if (type === "function" || $.isWindow(obj)) { 1587 return false; 1588 } 1589 1590 if (obj.nodeType === 1 && length) { 1591 return true; 1592 } 1593 1594 return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj; 1595 } 1596 1597 /*************** 1598 $ Methods 1599 ***************/ 1600 1601 /* jQuery: Support removed for IE<9. */ 1602 $.isPlainObject = function (obj) { 1603 var key; 1604 1605 if (!obj || $.type(obj) !== "object" || obj.nodeType || $.isWindow(obj)) { 1606 return false; 1607 } 1608 1609 try { 1610 if (obj.constructor && 1611 !hasOwn.call(obj, "constructor") && 1612 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { 1613 return false; 1614 } 1615 } catch (e) { 1616 return false; 1617 } 1618 1619 for (key in obj) {} 1620 1621 return key === undefined || hasOwn.call(obj, key); 1622 }; 1623 1624 /* jQuery */ 1625 $.each = function(obj, callback, args) { 1626 var value, 1627 i = 0, 1628 length = obj.length, 1629 isArray = isArraylike(obj); 1630 1631 if (args) { 1632 if (isArray) { 1633 for (; i < length; i++) { 1634 value = callback.apply(obj[i], args); 1635 1636 if (value === false) { 1637 break; 1638 } 1639 } 1640 } else { 1641 for (i in obj) { 1642 value = callback.apply(obj[i], args); 1643 1644 if (value === false) { 1645 break; 1646 } 1647 } 1648 } 1649 1650 } else { 1651 if (isArray) { 1652 for (; i < length; i++) { 1653 value = callback.call(obj[i], i, obj[i]); 1654 1655 if (value === false) { 1656 break; 1657 } 1658 } 1659 } else { 1660 for (i in obj) { 1661 value = callback.call(obj[i], i, obj[i]); 1662 1663 if (value === false) { 1664 break; 1665 } 1666 } 1667 } 1668 } 1669 1670 return obj; 1671 }; 1672 1673 /* Custom */ 1674 $.data = function (node, key, value) { 1675 /* $.getData() */ 1676 if (value === undefined) { 1677 var id = node[$.expando], 1678 store = id && cache[id]; 1679 1680 if (key === undefined) { 1681 return store; 1682 } else if (store) { 1683 if (key in store) { 1684 return store[key]; 1685 } 1686 } 1687 /* $.setData() */ 1688 } else if (key !== undefined) { 1689 var id = node[$.expando] || (node[$.expando] = ++$.uuid); 1690 1691 cache[id] = cache[id] || {}; 1692 cache[id][key] = value; 1693 1694 return value; 1695 } 1696 }; 1697 1698 /* Custom */ 1699 $.removeData = function (node, keys) { 1700 var id = node[$.expando], 1701 store = id && cache[id]; 1702 1703 if (store) { 1704 $.each(keys, function(_, key) { 1705 delete store[key]; 1706 }); 1707 } 1708 }; 1709 1710 /* jQuery */ 1711 $.extend = function () { 1712 var src, copyIsArray, copy, name, options, clone, 1713 target = arguments[0] || {}, 1714 i = 1, 1715 length = arguments.length, 1716 deep = false; 1717 1718 if (typeof target === "boolean") { 1719 deep = target; 1720 1721 target = arguments[i] || {}; 1722 i++; 1723 } 1724 1725 if (typeof target !== "object" && $.type(target) !== "function") { 1726 target = {}; 1727 } 1728 1729 if (i === length) { 1730 target = this; 1731 i--; 1732 } 1733 1734 for (; i < length; i++) { 1735 if ((options = arguments[i]) != null) { 1736 for (name in options) { 1737 src = target[name]; 1738 copy = options[name]; 1739 1740 if (target === copy) { 1741 continue; 1742 } 1743 1744 if (deep && copy && ($.isPlainObject(copy) || (copyIsArray = $.isArray(copy)))) { 1745 if (copyIsArray) { 1746 copyIsArray = false; 1747 clone = src && $.isArray(src) ? src : []; 1748 1749 } else { 1750 clone = src && $.isPlainObject(src) ? src : {}; 1751 } 1752 1753 target[name] = $.extend(deep, clone, copy); 1754 1755 } else if (copy !== undefined) { 1756 target[name] = copy; 1757 } 1758 } 1759 } 1760 } 1761 1762 return target; 1763 }; 1764 1765 /* jQuery 1.4.3 */ 1766 $.queue = function (elem, type, data) { 1767 function $makeArray (arr, results) { 1768 var ret = results || []; 1769 1770 if (arr != null) { 1771 if (isArraylike(Object(arr))) { 1772 /* $.merge */ 1773 (function(first, second) { 1774 var len = +second.length, 1775 j = 0, 1776 i = first.length; 1777 1778 while (j < len) { 1779 first[i++] = second[j++]; 1780 } 1781 1782 if (len !== len) { 1783 while (second[j] !== undefined) { 1784 first[i++] = second[j++]; 1785 } 1786 } 1787 1788 first.length = i; 1789 1790 return first; 1791 })(ret, typeof arr === "string" ? [arr] : arr); 1792 } else { 1793 [].push.call(ret, arr); 1794 } 1795 } 1796 1797 return ret; 1798 } 1799 1800 if (!elem) { 1801 return; 1802 } 1803 1804 type = (type || "fx") + "queue"; 1805 1806 var q = $.data(elem, type); 1807 1808 if (!data) { 1809 return q || []; 1810 } 1811 1812 if (!q || $.isArray(data)) { 1813 q = $.data(elem, type, $makeArray(data)); 1814 } else { 1815 q.push(data); 1816 } 1817 1818 return q; 1819 }; 1820 1821 /* jQuery 1.4.3 */ 1822 $.dequeue = function (elems, type) { 1823 /* Custom: Embed element iteration. */ 1824 $.each(elems.nodeType ? [ elems ] : elems, function(i, elem) { 1825 type = type || "fx"; 1826 1827 var queue = $.queue(elem, type), 1828 fn = queue.shift(); 1829 1830 if (fn === "inprogress") { 1831 fn = queue.shift(); 1832 } 1833 1834 if (fn) { 1835 if (type === "fx") { 1836 queue.unshift("inprogress"); 1837 } 1838 1839 fn.call(elem, function() { 1840 $.dequeue(elem, type); 1841 }); 1842 } 1843 }); 1844 }; 1845 1846 /****************** 1847 $.fn Methods 1848 ******************/ 1849 1850 /* jQuery */ 1851 $.fn = $.prototype = { 1852 init: function (selector) { 1853 /* Just return the element wrapped inside an array; don't proceed with the actual jQuery node wrapping process. */ 1854 if (selector.nodeType) { 1855 this[0] = selector; 1856 1857 return this; 1858 } else { 1859 throw new Error("Not a DOM node."); 1860 } 1861 }, 1862 1863 offset: function () { 1864 /* jQuery altered code: Dropped disconnected DOM node checking. */ 1865 var box = this[0].getBoundingClientRect ? this[0].getBoundingClientRect() : { top: 0, left: 0 }; 1866 1867 return { 1868 top: box.top + (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || 0), 1869 left: box.left + (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || 0) 1870 }; 1871 }, 1872 1873 position: function () { 1874 /* jQuery */ 1875 function offsetParent() { 1876 var offsetParent = this.offsetParent || document; 1877
1878 while (offsetParent && (!offsetParent.nodeType.toLowerCase === "html" && offsetParent.style.position === "static")) { 1879 offsetParent = offsetParent.offsetParent; 1880 } 1881 1882 return offsetParent || document; 1883 } 1884 1885 /* Zepto */ 1886 var elem = this[0], 1887 offsetParent = offsetParent.apply(elem), 1888 offset = this.offset(), 1889 parentOffset = /^(?:body|html)$/i.test(offsetParent.nodeName) ? { top: 0, left: 0 } : $(offsetParent).offset() 1890 1891 offset.top -= parseFloat(elem.style.marginTop) || 0; 1892 offset.left -= parseFloat(elem.style.marginLeft) || 0; 1893 1894 if (offsetParent.style) { 1895 parentOffset.top += parseFloat(offsetParent.style.borderTopWidth) || 0 1896 parentOffset.left += parseFloat(offsetParent.style.borderLeftWidth) || 0 1897 } 1898 1899 return { 1900 top: offset.top - parentOffset.top, 1901 left: offset.left - parentOffset.left 1902 }; 1903 } 1904 }; 1905 1906 /********************** 1907 Private Variables 1908 **********************/ 1909 1910 /* For $.data() */ 1911 var cache = {}; 1912 $.expando = "velocity" + (new Date().getTime()); 1913 $.uuid = 0; 1914 1915 /* For $.queue() */ 1916 var class2type = {}, 1917 hasOwn = class2type.hasOwnProperty, 1918 toString = class2type.toString; 1919 1920 var types = "Boolean Number String Function Array Date RegExp Object Error".split(" "); 1921 for (var i = 0; i < types.length; i++) { 1922 class2type["[object " + types[i] + "]"] = types[i].toLowerCase(); 1923 } 1924 1925 /* Makes $(node) possible, without having to call init. */ 1926 $.fn.init.prototype = $.fn; 1927 1928 /* Globalize Velocity onto the window, and assign its Utilities property. */ 1929 window.Velocity = { Utilities: $ }; 1930})(window); 1931 1932/****************** 1933 Velocity.js 1934******************/ 1935 1936;(function (factory) { 1937 /* CommonJS module. */ 1938 if (typeof module === "object" && typeof module.exports === "object") { 1939 module.exports = factory(); 1940 /* AMD module. */ 1941 } else if (typeof define === "function" && define.amd) { 1942 define(factory); 1943 /* Browser globals. */ 1944 } else { 1945 factory(); 1946 } 1947}(function() { 1948return function (global, window, document, undefined) { 1949 1950 /*************** 1951 Summary 1952 ***************/ 1953 1954 /* 1955 - CSS: CSS stack that works independently from the rest of Velocity. 1956 - animate(): Core animation method that iterates over the targeted elements and queues the incoming call onto each element individually. 1957 - Pre-Queueing: Prepare the element for animation by instantiating its data cache and processing the call's options. 1958 - Queueing: The logic that runs once the call has reached its point of execution in the element's $.queue() stack. 1959 Most logic is placed here to avoid risking it becoming stale (if the element's properties have changed). 1960 - Pushing: Consolidation of the tween data followed by its push onto the global in-progress calls container. 1961 - tick(): The single requestAnimationFrame loop responsible for tweening all in-progress calls. 1962 - completeCall(): Handles the cleanup process for each Velocity call. 1963 */ 1964 1965 /********************* 1966 Helper Functions 1967 *********************/ 1968 1969 /* IE detection. Gist: https://gist.github.com/julianshapiro/9098609 */ 1970 var IE = (function() { 1971 if (document.documentMode) { 1972 return document.documentMode; 1973 } else { 1974 for (var i = 7; i > 4; i--) { 1975 var div = document.createElement("div"); 1976 1977 div.innerHTML = "<!--[if IE " + i + "]><span></span><![endif]-->"; 1978 1979 if (div.getElementsByTagName("span").length) { 1980 div = null; 1981 1982 return i; 1983 } 1984 } 1985 } 1986 1987 return undefined; 1988 })(); 1989 1990 /* rAF shim. Gist: https://gist.github.com/julianshapiro/9497513 */ 1991 var rAFShim = (function() { 1992 var timeLast = 0; 1993 1994 return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { 1995 var timeCurrent = (new Date()).getTime(), 1996 timeDelta; 1997 1998 /* Dynamically set delay on a per-tick basis to match 60fps. */ 1999 /* Technique by Erik Moller. MIT license: https://gist.github.com/paulirish/1579671 */ 2000 timeDelta = Math.max(0, 16 - (timeCurrent - timeLast)); 2001 timeLast = timeCurrent + timeDelta; 2002 2003 return setTimeout(function() { callback(timeCurrent + timeDelta); }, timeDelta); 2004 }; 2005 })(); 2006 2007 /* Array compacting. Copyright Lo-Dash. MIT License: https://github.com/lodash/lodash/blob/master/LICENSE.txt */ 2008 function compactSparseArray (array) { 2009 var index = -1, 2010 length = array ? array.length : 0, 2011 result = []; 2012 2013 while (++index < length) { 2014 var value = array[index]; 2015 2016 if (value) { 2017 result.push(value); 2018 } 2019 } 2020 2021 return result; 2022 } 2023 2024 function sanitizeElements (elements) { 2025 /* Unwrap jQuery/Zepto objects. */ 2026 if (Type.isWrapped(elements)) { 2027 elements = [].slice.call(elements); 2028 /* Wrap a single element in an array so that $.each() can iterate with the element instead of its node's children. */ 2029 } else if (Type.isNode(elements)) { 2030 elements = [ elements ]; 2031 } 2032 2033 return elements; 2034 } 2035 2036 var Type = { 2037 isString: function (variable) { 2038 return (typeof variable === "string"); 2039 }, 2040 isArray: Array.isArray || function (variable) { 2041 return Object.prototype.toString.call(variable) === "[object Array]"; 2042 }, 2043 isFunction: function (variable) { 2044 return Object.prototype.toString.call(variable) === "[object Function]"; 2045 }, 2046 isNode: function (variable) { 2047 return variable && variable.nodeType; 2048 }, 2049 /* Copyright Martin Bohm. MIT License: https://gist.github.com/Tomalak/818a78a226a0738eaade */ 2050 isNodeList: function (variable) { 2051 return typeof variable === "object" && 2052 /^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(variable)) && 2053 variable.length !== undefined && 2054 (variable.length === 0 || (typeof variable[0] === "object" && variable[0].nodeType > 0)); 2055 }, 2056 /* Determine if variable is a wrapped jQuery or Zepto element. */ 2057 isWrapped: function (variable) { 2058 return variable && (variable.jquery || (window.Zepto && window.Zepto.zepto.isZ(variable))); 2059 }, 2060 isSVG: function (variable) { 2061 return window.SVGElement && (variable instanceof window.SVGElement); 2062 }, 2063 isEmptyObject: function (variable) { 2064 for (var name in variable) { 2065 return false;
vendor: 7,701 bytes, lines 2066-2232
2066 } 2067 2068 return true; 2069 } 2070 }; 2071 2072 /***************** 2073 Dependencies 2074 *****************/ 2075 2076 var $, 2077 isJQuery = false; 2078 2079 if (global.fn && global.fn.jquery) { 2080 $ = global; 2081 isJQuery = true; 2082 } else { 2083 $ = window.Velocity.Utilities; 2084 } 2085 2086 if (IE <= 8 && !isJQuery) { 2087 throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity."); 2088 } else if (IE <= 7) { 2089 /* Revert to jQuery's $.animate(), and lose Velocity's extra features. */ 2090 jQuery.fn.velocity = jQuery.fn.animate; 2091 2092 /* Now that $.fn.velocity is aliased, abort this Velocity declaration. */ 2093 return; 2094 } 2095 2096 /***************** 2097 Constants 2098 *****************/ 2099 2100 var DURATION_DEFAULT = 400, 2101 EASING_DEFAULT = "swing"; 2102 2103 /************* 2104 State 2105 *************/ 2106 2107 /* Note: The global object also doubles as a publicly-accessible data store for the purposes of unit testing. */ 2108 /* Note: Alias the lowercase and uppercase variants of "velocity" to minimize user confusion due to the lowercase nature of the $.fn extension. */ 2109 var Velocity = { 2110 /* Container for page-wide Velocity state data. */ 2111 State: { 2112 /* Detect mobile devices to determine if mobileHA should be turned on. */ 2113 isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), 2114 /* The mobileHA option's behavior changes on older Android devices (Gingerbread, versions 2.3.3-2.3.7). */ 2115 isAndroid: /Android/i.test(navigator.userAgent), 2116 isGingerbread: /Android 2\.3\.[3-7]/i.test(navigator.userAgent), 2117 isChrome: window.chrome, 2118 isFirefox: /Firefox/i.test(navigator.userAgent), 2119 /* Create a cached element for re-use when checking for CSS property prefixes. */ 2120 prefixElement: document.createElement("div"), 2121 /* Cache every prefix match to avoid repeating lookups. */ 2122 prefixMatches: {}, 2123 /* Cache the anchor used for animating window scrolling. */ 2124 scrollAnchor: null, 2125 /* Cache the property names associated with the scroll anchor. */ 2126 scrollPropertyLeft: null, 2127 scrollPropertyTop: null, 2128 /* Keep track of whether our RAF tick is running. */ 2129 isTicking: false, 2130 /* Container for every in-progress call to Velocity. */ 2131 calls: [] 2132 }, 2133 /* Velocity's custom CSS stack. Made global for unit testing. */ 2134 CSS: { /* Defined below. */ }, 2135 /* Defined by Velocity's optional jQuery shim. */ 2136 Utilities: $, 2137 /* Container for the user's custom animation redirects that are referenced by name in place of a properties map object. */ 2138 Redirects: { /* Manually registered by the user. */ }, 2139 Easings: { /* Defined below. */ }, 2140 /* Attempt to use ES6 Promises by default. Users can override this with a third-party promises library. */ 2141 Promise: window.Promise, 2142 /* Page-wide option defaults, which can be overriden by the user. */ 2143 defaults: { 2144 queue: "", 2145 duration: DURATION_DEFAULT, 2146 easing: EASING_DEFAULT, 2147 begin: undefined, 2148 complete: undefined, 2149 progress: undefined, 2150 display: undefined, 2151 visibility: undefined, 2152 loop: false, 2153 delay: false, 2154 mobileHA: true, 2155 /* Set to false to prevent property values from being cached between consecutive Velocity-initiated chain calls. */ 2156 _cacheValues: true 2157 }, 2158 /* A design goal of Velocity is to cache data wherever possible in order to avoid DOM requerying. 2159 Accordingly, each element has a data cache instantiated on it. */ 2160 init: function (element) { 2161 $.data(element, "velocity", { 2162 /* Store whether this is an SVG element, since its properties are retrieved and updated differently than standard HTML elements. */ 2163 isSVG: Type.isSVG(element), 2164 /* Keep track of whether the element is currently being animated by Velocity. 2165 This is used to ensure that property values are not transferred between non-consecutive (stale) calls. */ 2166 isAnimating: false, 2167 /* A reference to the element's live computedStyle object. Learn more here: https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle */ 2168 computedStyle: null, 2169 /* Tween data is cached for each animation on the element so that data can be passed across calls -- 2170 in particular, end values are used as subsequent start values in consecutive Velocity calls. */ 2171 tweensContainer: null, 2172 /* The full root property values of each CSS hook being animated on this element are cached so that: 2173 1) Concurrently-animating hooks sharing the same root can have their root values' merged into one while tweening. 2174 2) Post-hook-injection root values can be transferred over to consecutively chained Velocity calls as starting root values. */ 2175 rootPropertyValueCache: {}, 2176 /* A cache for transform updates, which must be manually flushed via CSS.flushTransformCache(). */ 2177 transformCache: {} 2178 }); 2179 }, 2180 /* A parallel to jQuery's $.css(), used for getting/setting Velocity's hooked CSS properties. */ 2181 hook: null, /* Defined below. */ 2182 /* Velocity-wide animation time remapping for testing purposes. */ 2183 mock: false, 2184 version: { major: 1, minor: 1, patch: 0 }, 2185 /* Set to 1 or 2 (most verbose) to output debug info to console. */ 2186 debug: false 2187 }; 2188 2189 /* Retrieve the appropriate scroll anchor and property name for the browser: https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY */ 2190 if (window.pageYOffset !== undefined) { 2191 Velocity.State.scrollAnchor = window; 2192 Velocity.State.scrollPropertyLeft = "pageXOffset"; 2193 Velocity.State.scrollPropertyTop = "pageYOffset"; 2194 } else { 2195 Velocity.State.scrollAnchor = document.documentElement || document.body.parentNode || document.body; 2196 Velocity.State.scrollPropertyLeft = "scrollLeft"; 2197 Velocity.State.scrollPropertyTop = "scrollTop"; 2198 } 2199 2200 /* Shorthand alias for jQuery's $.data() utility. */ 2201 function Data (element) { 2202 /* Hardcode a reference to the plugin name. */ 2203 var response = $.data(element, "velocity"); 2204 2205 /* jQuery <=1.4.2 returns null instead of undefined when no match is found. We normalize this behavior. */ 2206 return response === null ? undefined : response; 2207 }; 2208 2209 /************** 2210 Easing 2211 **************/ 2212 2213 /* Step easing generator. */ 2214 function generateStep (steps) { 2215 return function (p) { 2216 return Math.round(p * steps) * (1 / steps); 2217 }; 2218 } 2219 2220 /* Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */ 2221 function generateBezier (mX1, mY1, mX2, mY2) { 2222 var NEWTON_ITERATIONS = 4, 2223 NEWTON_MIN_SLOPE = 0.001, 2224 SUBDIVISION_PRECISION = 0.0000001, 2225 SUBDIVISION_MAX_ITERATIONS = 10, 2226 kSplineTableSize = 11, 2227 kSampleStepSize = 1.0 / (kSplineTableSize - 1.0), 2228 float32ArraySupported = "Float32Array" in window; 2229 2230 /* Must contain four arguments. */ 2231 if (arguments.length !== 4) { 2232 return false;
2233 } 2234 2235 /* Arguments must be numbers. */ 2236 for (var i = 0; i < 4; ++i) { 2237 if (typeof arguments[i] !== "number" || isNaN(arguments[i]) || !isFinite(arguments[i])) { 2238 return false; 2239 } 2240 } 2241 2242 /* X values must be in the [0, 1] range. */ 2243 mX1 = Math.min(mX1, 1); 2244 mX2 = Math.min(mX2, 1); 2245 mX1 = Math.max(mX1, 0); 2246 mX2 = Math.max(mX2, 0); 2247 2248 var mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); 2249 2250 function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } 2251 function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } 2252 function C (aA1) { return 3.0 * aA1; } 2253 2254 function calcBezier (aT, aA1, aA2) { 2255 return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT; 2256 } 2257 2258 function getSlope (aT, aA1, aA2) { 2259 return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1); 2260 } 2261 2262 function newtonRaphsonIterate (aX, aGuessT) { 2263 for (var i = 0; i < NEWTON_ITERATIONS; ++i) { 2264 var currentSlope = getSlope(aGuessT, mX1, mX2); 2265 2266 if (currentSlope === 0.0) return aGuessT; 2267 2268 var currentX = calcBezier(aGuessT, mX1, mX2) - aX; 2269 aGuessT -= currentX / currentSlope; 2270 } 2271 2272 return aGuessT; 2273 } 2274 2275 function calcSampleValues () { 2276 for (var i = 0; i < kSplineTableSize; ++i) { 2277 mSampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); 2278 } 2279 } 2280 2281 function binarySubdivide (aX, aA, aB) { 2282 var currentX, currentT, i = 0; 2283 2284 do { 2285 currentT = aA + (aB - aA) / 2.0; 2286 currentX = calcBezier(currentT, mX1, mX2) - aX; 2287 if (currentX > 0.0) { 2288 aB = currentT; 2289 } else { 2290 aA = currentT; 2291 } 2292 } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); 2293 2294 return currentT; 2295 } 2296 2297 function getTForX (aX) { 2298 var intervalStart = 0.0, 2299 currentSample = 1, 2300 lastSample = kSplineTableSize - 1; 2301 2302 for (; currentSample != lastSample && mSampleValues[currentSample] <= aX; ++currentSample) { 2303 intervalStart += kSampleStepSize; 2304 } 2305 2306 --currentSample; 2307 2308 var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample+1] - mSampleValues[currentSample]), 2309 guessForT = intervalStart + dist * kSampleStepSize, 2310 initialSlope = getSlope(guessForT, mX1, mX2); 2311 2312 if (initialSlope >= NEWTON_MIN_SLOPE) { 2313 return newtonRaphsonIterate(aX, guessForT); 2314 } else if (initialSlope == 0.0) { 2315 return guessForT; 2316 } else { 2317 return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize); 2318 } 2319 } 2320 2321 var _precomputed = false; 2322 2323 function precompute() { 2324 _precomputed = true; 2325 if (mX1 != mY1 || mX2 != mY2) calcSampleValues(); 2326 } 2327 2328 var f = function (aX) { 2329 if (!_precomputed) precompute(); 2330 if (mX1 === mY1 && mX2 === mY2) return aX; 2331 if (aX === 0) return 0; 2332 if (aX === 1) return 1; 2333 2334 return calcBezier(getTForX(aX), mY1, mY2); 2335 }; 2336 2337 f.getControlPoints = function() { return [{ x: mX1, y: mY1 }, { x: mX2, y: mY2 }]; }; 2338 2339 var str = "generateBezier(" + [mX1, mY1, mX2, mY2] + ")"; 2340 f.toString = function () { return str; }; 2341 2342 return f; 2343 } 2344 2345 /* Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */ 2346 /* Given a tension, friction, and duration, a simulation at 60FPS will first run without a defined duration in order to calculate the full path. A second pass 2347 then adjusts the time delta -- using the relation between actual time and duration -- to calculate the path for the duration-constrained animation. */ 2348 var generateSpringRK4 = (function () { 2349 function springAccelerationForState (state) { 2350 return (-state.tension * state.x) - (state.friction * state.v); 2351 } 2352 2353 function springEvaluateStateWithDerivative (initialState, dt, derivative) { 2354 var state = { 2355 x: initialState.x + derivative.dx * dt, 2356 v: initialState.v + derivative.dv * dt, 2357 tension: initialState.tension, 2358 friction: initialState.friction 2359 }; 2360 2361 return { dx: state.v, dv: springAccelerationForState(state) }; 2362 } 2363 2364 function springIntegrateState (state, dt) { 2365 var a = { 2366 dx: state.v, 2367 dv: springAccelerationForState(state) 2368 }, 2369 b = springEvaluateStateWithDerivative(state, dt * 0.5, a), 2370 c = springEvaluateStateWithDerivative(state, dt * 0.5, b), 2371 d = springEvaluateStateWithDerivative(state, dt, c), 2372 dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx), 2373 dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv); 2374 2375 state.x = state.x + dxdt * dt; 2376 state.v = state.v + dvdt * dt; 2377 2378 return state; 2379 } 2380 2381 return function springRK4Factory (tension, friction, duration) { 2382 2383 var initState = { 2384 x: -1, 2385 v: 0, 2386 tension: null, 2387 friction: null 2388 }, 2389 path = [0],
vendor: 9,606 bytes, lines 2390-2578
2390 time_lapsed = 0, 2391 tolerance = 1 / 10000, 2392 DT = 16 / 1000, 2393 have_duration, dt, last_state; 2394 2395 tension = parseFloat(tension) || 500; 2396 friction = parseFloat(friction) || 20; 2397 duration = duration || null; 2398 2399 initState.tension = tension; 2400 initState.friction = friction; 2401 2402 have_duration = duration !== null; 2403 2404 /* Calculate the actual time it takes for this animation to complete with the provided conditions. */ 2405 if (have_duration) { 2406 /* Run the simulation without a duration. */ 2407 time_lapsed = springRK4Factory(tension, friction); 2408 /* Compute the adjusted time delta. */ 2409 dt = time_lapsed / duration * DT; 2410 } else { 2411 dt = DT; 2412 } 2413 2414 while (true) { 2415 /* Next/step function .*/ 2416 last_state = springIntegrateState(last_state || initState, dt); 2417 /* Store the position. */ 2418 path.push(1 + last_state.x); 2419 time_lapsed += 16; 2420 /* If the change threshold is reached, break. */ 2421 if (!(Math.abs(last_state.x) > tolerance && Math.abs(last_state.v) > tolerance)) { 2422 break; 2423 } 2424 } 2425 2426 /* If duration is not defined, return the actual time required for completing this animation. Otherwise, return a closure that holds the 2427 computed path and returns a snapshot of the position according to a given percentComplete. */ 2428 return !have_duration ? time_lapsed : function(percentComplete) { return path[ (percentComplete * (path.length - 1)) | 0 ]; }; 2429 }; 2430 }()); 2431 2432 /* jQuery easings. */ 2433 Velocity.Easings = { 2434 linear: function(p) { return p; }, 2435 swing: function(p) { return 0.5 - Math.cos( p * Math.PI ) / 2 }, 2436 /* Bonus "spring" easing, which is a less exaggerated version of easeInOutElastic. */ 2437 spring: function(p) { return 1 - (Math.cos(p * 4.5 * Math.PI) * Math.exp(-p * 6)); } 2438 }; 2439 2440 /* CSS3 and Robert Penner easings. */ 2441 $.each( 2442 [ 2443 [ "ease", [ 0.25, 0.1, 0.25, 1.0 ] ], 2444 [ "ease-in", [ 0.42, 0.0, 1.00, 1.0 ] ], 2445 [ "ease-out", [ 0.00, 0.0, 0.58, 1.0 ] ], 2446 [ "ease-in-out", [ 0.42, 0.0, 0.58, 1.0 ] ], 2447 [ "easeInSine", [ 0.47, 0, 0.745, 0.715 ] ], 2448 [ "easeOutSine", [ 0.39, 0.575, 0.565, 1 ] ], 2449 [ "easeInOutSine", [ 0.445, 0.05, 0.55, 0.95 ] ], 2450 [ "easeInQuad", [ 0.55, 0.085, 0.68, 0.53 ] ], 2451 [ "easeOutQuad", [ 0.25, 0.46, 0.45, 0.94 ] ], 2452 [ "easeInOutQuad", [ 0.455, 0.03, 0.515, 0.955 ] ], 2453 [ "easeInCubic", [ 0.55, 0.055, 0.675, 0.19 ] ], 2454 [ "easeOutCubic", [ 0.215, 0.61, 0.355, 1 ] ], 2455 [ "easeInOutCubic", [ 0.645, 0.045, 0.355, 1 ] ], 2456 [ "easeInQuart", [ 0.895, 0.03, 0.685, 0.22 ] ], 2457 [ "easeOutQuart", [ 0.165, 0.84, 0.44, 1 ] ], 2458 [ "easeInOutQuart", [ 0.77, 0, 0.175, 1 ] ], 2459 [ "easeInQuint", [ 0.755, 0.05, 0.855, 0.06 ] ], 2460 [ "easeOutQuint", [ 0.23, 1, 0.32, 1 ] ], 2461 [ "easeInOutQuint", [ 0.86, 0, 0.07, 1 ] ], 2462 [ "easeInExpo", [ 0.95, 0.05, 0.795, 0.035 ] ], 2463 [ "easeOutExpo", [ 0.19, 1, 0.22, 1 ] ], 2464 [ "easeInOutExpo", [ 1, 0, 0, 1 ] ], 2465 [ "easeInCirc", [ 0.6, 0.04, 0.98, 0.335 ] ], 2466 [ "easeOutCirc", [ 0.075, 0.82, 0.165, 1 ] ], 2467 [ "easeInOutCirc", [ 0.785, 0.135, 0.15, 0.86 ] ] 2468 ], function(i, easingArray) { 2469 Velocity.Easings[easingArray[0]] = generateBezier.apply(null, easingArray[1]); 2470 }); 2471 2472 /* Determine the appropriate easing type given an easing input. */ 2473 function getEasing(value, duration) { 2474 var easing = value; 2475 2476 /* The easing option can either be a string that references a pre-registered easing, 2477 or it can be a two-/four-item array of integers to be converted into a bezier/spring function. */ 2478 if (Type.isString(value)) { 2479 /* Ensure that the easing has been assigned to jQuery's Velocity.Easings object. */ 2480 if (!Velocity.Easings[value]) { 2481 easing = false; 2482 } 2483 } else if (Type.isArray(value) && value.length === 1) { 2484 easing = generateStep.apply(null, value); 2485 } else if (Type.isArray(value) && value.length === 2) { 2486 /* springRK4 must be passed the animation's duration. */ 2487 /* Note: If the springRK4 array contains non-numbers, generateSpringRK4() returns an easing 2488 function generated with default tension and friction values. */ 2489 easing = generateSpringRK4.apply(null, value.concat([ duration ])); 2490 } else if (Type.isArray(value) && value.length === 4) { 2491 /* Note: If the bezier array contains non-numbers, generateBezier() returns false. */ 2492 easing = generateBezier.apply(null, value); 2493 } else { 2494 easing = false; 2495 } 2496 2497 /* Revert to the Velocity-wide default easing type, or fall back to "swing" (which is also jQuery's default) 2498 if the Velocity-wide default has been incorrectly modified. */ 2499 if (easing === false) { 2500 if (Velocity.Easings[Velocity.defaults.easing]) { 2501 easing = Velocity.defaults.easing; 2502 } else { 2503 easing = EASING_DEFAULT; 2504 } 2505 } 2506 2507 return easing; 2508 } 2509 2510 /***************** 2511 CSS Stack 2512 *****************/ 2513 2514 /* The CSS object is a highly condensed and performant CSS stack that fully replaces jQuery's. 2515 It handles the validation, getting, and setting of both standard CSS properties and CSS property hooks. */ 2516 /* Note: A "CSS" shorthand is aliased so that our code is easier to read. */ 2517 var CSS = Velocity.CSS = { 2518 2519 /************* 2520 RegEx 2521 *************/ 2522 2523 RegEx: { 2524 isHex: /^#([A-f\d]{3}){1,2}$/i, 2525 /* Unwrap a property value's surrounding text, e.g. "rgba(4, 3, 2, 1)" ==> "4, 3, 2, 1" and "rect(4px 3px 2px 1px)" ==> "4px 3px 2px 1px". */ 2526 valueUnwrap: /^[A-z]+\((.*)\)$/i, 2527 wrappedValueAlreadyExtracted: /[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/, 2528 /* Split a multi-value property into an array of subvalues, e.g. "rgba(4, 3, 2, 1) 4px 3px 2px 1px" ==> [ "rgba(4, 3, 2, 1)", "4px", "3px", "2px", "1px" ]. */ 2529 valueSplit: /([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/ig 2530 }, 2531 2532 /************ 2533 Lists 2534 ************/ 2535 2536 Lists: { 2537 colors: [ "fill", "stroke", "stopColor", "color", "backgroundColor", "borderColor", "borderTopColor", "borderRightColor", "borderBottomColor", "borderLeftColor", "outlineColor" ], 2538 transformsBase: [ "translateX", "translateY", "scale", "scaleX", "scaleY", "skewX", "skewY", "rotateZ" ], 2539 transforms3D: [ "transformPerspective", "translateZ", "scaleZ", "rotateX", "rotateY" ] 2540 }, 2541 2542 /************ 2543 Hooks 2544 ************/ 2545 2546 /* Hooks allow a subproperty (e.g. "boxShadowBlur") of a compound-value CSS property 2547 (e.g. "boxShadow: X Y Blur Spread Color") to be animated as if it were a discrete property. */ 2548 /* Note: Beyond enabling fine-grained property animation, hooking is necessary since Velocity only 2549 tweens properties with single numeric values; unlike CSS transitions, Velocity does not interpolate compound-values. */ 2550 Hooks: { 2551 /******************** 2552 Registration 2553 ********************/ 2554 2555 /* Templates are a concise way of indicating which subproperties must be individually registered for each compound-value CSS property. */ 2556 /* Each template consists of the compound-value's base name, its constituent subproperty names, and those subproperties' default values. */ 2557 templates: { 2558 "textShadow": [ "Color X Y Blur", "black 0px 0px 0px" ], 2559 /* Todo: Add support for inset boxShadows. (webkit places it last whereas IE places it first.) */ 2560 "boxShadow": [ "Color X Y Blur Spread", "black 0px 0px 0px 0px" ], 2561 "clip": [ "Top Right Bottom Left", "0px 0px 0px 0px" ], 2562 "backgroundPosition": [ "X Y", "0% 0%" ], 2563 "transformOrigin": [ "X Y Z", "50% 50% 0px" ], 2564 "perspectiveOrigin": [ "X Y", "50% 50%" ] 2565 }, 2566 2567 /* A "registered" hook is one that has been converted from its template form into a live, 2568 tweenable property. It contains data to associate it with its root property. */ 2569 registered: { 2570 /* Note: A registered hook looks like this ==> textShadowBlur: [ "textShadow", 3 ], 2571 which consists of the subproperty's name, the associated root property's name, 2572 and the subproperty's position in the root's value. */ 2573 }, 2574 /* Convert the templates into individual hooks then append them to the registered object above. */ 2575 register: function () { 2576 /* Color hooks registration: Colors are defaulted to white -- as opposed to black -- since colors that are 2577 currently set to "transparent" default to their respective template below when color-animated, 2578 and white is typically a closer match to transparent than black
2578is. An exception is made for text ("color"), 2579 which is almost always set closer to black than white. */ 2580 for (var i = 0; i < CSS.Lists.colors.length; i++) { 2581 var rgbComponents = (CSS.Lists.colors[i] === "color") ? "0 0 0 1" : "255 255 255 1"; 2582 CSS.Hooks.templates[CSS.Lists.colors[i]] = [ "Red Green Blue Alpha", rgbComponents ]; 2583 } 2584 2585 var rootProperty, 2586 hookTemplate, 2587 hookNames; 2588 2589 /* In IE, color values inside compound-value properties are positioned at the end the value instead of at the beginning. 2590 Thus, we re-arrange the templates accordingly. */ 2591 if (IE) { 2592 for (rootProperty in CSS.Hooks.templates) { 2593 hookTemplate = CSS.Hooks.templates[rootProperty]; 2594 hookNames = hookTemplate[0].split(" "); 2595 2596 var defaultValues = hookTemplate[1].match(CSS.RegEx.valueSplit); 2597 2598 if (hookNames[0] === "Color") { 2599 /* Reposition both the hook's name and its default value to the end of their respective strings. */ 2600 hookNames.push(hookNames.shift()); 2601 defaultValues.push(defaultValues.shift()); 2602 2603 /* Replace the existing template for the hook's root property. */ 2604 CSS.Hooks.templates[rootProperty] = [ hookNames.join(" "), defaultValues.join(" ") ]; 2605 } 2606 } 2607 } 2608 2609 /* Hook registration. */ 2610 for (rootProperty in CSS.Hooks.templates) { 2611 hookTemplate = CSS.Hooks.templates[rootProperty]; 2612 hookNames = hookTemplate[0].split(" "); 2613 2614 for (var i in hookNames) { 2615 var fullHookName = rootProperty + hookNames[i], 2616 hookPosition = i; 2617 2618 /* For each hook, register its full name (e.g. textShadowBlur) with its root property (e.g. textShadow) 2619 and the hook's position in its template's default value string. */ 2620 CSS.Hooks.registered[fullHookName] = [ rootProperty, hookPosition ]; 2621 } 2622 } 2623 }, 2624 2625 /***************************** 2626 Injection and Extraction 2627 *****************************/ 2628 2629 /* Look up the root property associated with the hook (e.g. return "textShadow" for "textShadowBlur"). */ 2630 /* Since a hook cannot be set directly (the browser won't recognize it), style updating for hooks is routed through the hook's root property. */ 2631 getRoot: function (property) { 2632 var hookData = CSS.Hooks.registered[property]; 2633 2634 if (hookData) { 2635 return hookData[0]; 2636 } else { 2637 /* If there was no hook match, return the property name untouched. */ 2638 return property; 2639 } 2640 }, 2641 /* Convert any rootPropertyValue, null or otherwise, into a space-delimited list of hook values so that 2642 the targeted hook can be injected or extracted at its standard position. */ 2643 cleanRootPropertyValue: function(rootProperty, rootPropertyValue) { 2644 /* If the rootPropertyValue is wrapped with "rgb()", "clip()", etc., remove the wrapping to normalize the value before manipulation. */ 2645 if (CSS.RegEx.valueUnwrap.test(rootPropertyValue)) { 2646 rootPropertyValue = rootPropertyValue.match(CSS.RegEx.valueUnwrap)[1]; 2647 } 2648 2649 /* If rootPropertyValue is a CSS null-value (from which there's inherently no hook value to extract), 2650 default to the root's default value as defined in CSS.Hooks.templates. */ 2651 /* Note: CSS null-values include "none", "auto", and "transparent". They must be converted into their
2652 zero-values (e.g. textShadow: "none" ==> textShadow: "0px 0px 0px black") for hook manipulation to proceed. */ 2653 if (CSS.Values.isCSSNullValue(rootPropertyValue)) { 2654 rootPropertyValue = CSS.Hooks.templates[rootProperty][1]; 2655 } 2656 2657 return rootPropertyValue; 2658 }, 2659 /* Extracted the hook's value from its root property's value. This is used to get the starting value of an animating hook. */ 2660 extractValue: function (fullHookName, rootPropertyValue) { 2661 var hookData = CSS.Hooks.registered[fullHookName]; 2662 2663 if (hookData) { 2664 var hookRoot = hookData[0], 2665 hookPosition = hookData[1]; 2666 2667 rootPropertyValue = CSS.Hooks.cleanRootPropertyValue(hookRoot, rootPropertyValue); 2668 2669 /* Split rootPropertyValue into its constituent hook values then grab the desired hook at its standard position. */ 2670 return rootPropertyValue.toString().match(CSS.RegEx.valueSplit)[hookPosition]; 2671 } else { 2672 /* If the provided fullHookName isn't a registered hook, return the rootPropertyValue that was passed in. */ 2673 return rootPropertyValue; 2674 } 2675 }, 2676 /* Inject the hook's value into its root property's value. This is used to piece back together the root property 2677 once Velocity has updated one of its individually hooked values through tweening. */ 2678 injectValue: function (fullHookName, hookValue, rootPropertyValue) { 2679 var hookData = CSS.Hooks.registered[fullHookName]; 2680 2681 if (hookData) { 2682 var hookRoot = hookData[0], 2683 hookPosition = hookData[1], 2684 rootPropertyValueParts, 2685 rootPropertyValueUpdated; 2686 2687 rootPropertyValue = CSS.Hooks.cleanRootPropertyValue(hookRoot, rootPropertyValue); 2688 2689 /* Split rootPropertyValue into its individual hook values, replace the targeted value with hookValue, 2690 then reconstruct the rootPropertyValue string. */ 2691 rootPropertyValueParts = rootPropertyValue.toString().match(CSS.RegEx.valueSplit); 2692 rootPropertyValueParts[hookPosition] = hookValue; 2693 rootPropertyValueUpdated = rootPropertyValueParts.join(" "); 2694 2695 return rootPropertyValueUpdated; 2696 } else { 2697 /* If the provided fullHookName isn't a registered hook, return the rootPropertyValue that was passed in. */ 2698 return rootPropertyValue; 2699 } 2700 } 2701 }, 2702 2703 /******************* 2704 Normalizations 2705 *******************/ 2706 2707 /* Normalizations standardize CSS property manipulation by pollyfilling browser-specific implementations (e.g. opacity) 2708 and reformatting special properties (e.g. clip, rgba) to look like standard ones. */ 2709 Normalizations: { 2710 /* Normalizations are passed a normalization target (either the property's name, its extracted value, or its injected value), 2711 the targeted element (which may need to be queried), and the targeted property value. */ 2712 registered: { 2713 clip: function (type, element, propertyValue) { 2714 switch (type) { 2715 case "name": 2716 return "clip"; 2717 /* Clip needs to be unwrapped and stripped of its commas during extraction. */ 2718 case "extract": 2719 var extracted; 2720 2721 /* If Velocity also extracted this value, skip extraction. */ 2722 if (CSS.RegEx.wrappedValueAlreadyExtracted.test(propertyValue)) { 2723 extracted = propertyValue; 2724 } else { 2725 /* Remove the "rect()" wrapper. */ 2726 extracted = propertyValue.toString().match(CSS.RegEx.valueUnwrap
vendor: 8,245 bytes, lines 2726-2860
2726); 2727 2728 /* Strip off commas. */ 2729 extracted = extracted ? extracted[1].replace(/,(\s+)?/g, " ") : propertyValue; 2730 } 2731 2732 return extracted; 2733 /* Clip needs to be re-wrapped during injection. */ 2734 case "inject": 2735 return "rect(" + propertyValue + ")"; 2736 } 2737 }, 2738 2739 blur: function(type, element, propertyValue) { 2740 switch (type) { 2741 case "name": 2742 return "-webkit-filter"; 2743 case "extract": 2744 var extracted = parseFloat(propertyValue); 2745 2746 /* If extracted is NaN, meaning the value isn't already extracted. */ 2747 if (!(extracted || extracted === 0)) { 2748 var blurComponent = propertyValue.toString().match(/blur\(([0-9]+[A-z]+)\)/i); 2749 2750 /* If the filter string had a blur component, return just the blur value and unit type. */ 2751 if (blurComponent) { 2752 extracted = blurComponent[1]; 2753 /* If the component doesn't exist, default blur to 0. */ 2754 } else { 2755 extracted = 0; 2756 } 2757 } 2758 2759 return extracted; 2760 /* Blur needs to be re-wrapped during injection. */ 2761 case "inject": 2762 /* For the blur effect to be fully de-applied, it needs to be set to "none" instead of 0. */ 2763 if (!parseFloat(propertyValue)) { 2764 return "none"; 2765 } else { 2766 return "blur(" + propertyValue + ")"; 2767 } 2768 } 2769 }, 2770 2771 /* <=IE8 do not support the standard opacity property. They use filter:alpha(opacity=INT) instead. */ 2772 opacity: function (type, element, propertyValue) { 2773 if (IE <= 8) { 2774 switch (type) { 2775 case "name": 2776 return "filter"; 2777 case "extract": 2778 /* <=IE8 return a "filter" value of "alpha(opacity=\d{1,3})". 2779 Extract the value and convert it to a decimal value to match the standard CSS opacity property's formatting. */ 2780 var extracted = propertyValue.toString().match(/alpha\(opacity=(.*)\)/i); 2781 2782 if (extracted) { 2783 /* Convert to decimal value. */ 2784 propertyValue = extracted[1] / 100; 2785 } else { 2786 /* When extracting opacity, default to 1 since a null value means opacity hasn't been set. */ 2787 propertyValue = 1; 2788 } 2789 2790 return propertyValue; 2791 case "inject": 2792 /* Opacified elements are required to have their zoom property set to a non-zero value. */ 2793 element.style.zoom = 1; 2794 2795 /* Setting the filter property on elements with certain font property combinations can result in a 2796 highly unappealing ultra-bolding effect. There's no way to remedy this throughout a tween, but dropping the 2797 value altogether (when opacity hits 1) at leasts ensures that the glitch is gone post-tweening. */ 2798 if (parseFloat(propertyValue) >= 1) { 2799 return ""; 2800 } else { 2801 /* As per the filter property's spec, convert the decimal value to a whole number and wrap the value. */ 2802 return "alpha(opacity=" + parseInt(parseFloat(propertyValue) * 100, 10) + ")"; 2803 } 2804 } 2805 /* With all other browsers, normalization is not required; return the same values that were passed in. */ 2806 } else { 2807 switch (type) { 2808 case "name": 2809 return "opacity"; 2810 case "extract": 2811 return propertyValue; 2812 case "inject": 2813 return propertyValue; 2814 } 2815 } 2816 } 2817 }, 2818 2819 /***************************** 2820 Batched Registrations 2821 *****************************/ 2822 2823 /* Note: Batched normalizations extend the CSS.Normalizations.registered object. */ 2824 register: function () { 2825 2826 /***************** 2827 Transforms 2828 *****************/ 2829 2830 /* Transforms are the subproperties contained by the CSS "transform" property. Transforms must undergo normalization 2831 so that they can be referenced in a properties map by their individual names. */ 2832 /* Note: When transforms are "set", they are actually assigned to a per-element transformCache. When all transform 2833 setting is complete complete, CSS.flushTransformCache() must be manually called to flush the values to the DOM. 2834 Transform setting is batched in this way to improve performance: the transform style only needs to be updated 2835 once when multiple transform subproperties are being animated simultaneously. */ 2836 /* Note: IE9 and Android Gingerbread have support for 2D -- but not 3D -- transforms. Since animating unsupported 2837 transform properties results in the browser ignoring the *entire* transform string, we prevent these 3D values 2838 from being normalized for these browsers so that tweening skips these properties altogether 2839 (since it will ignore them as being unsupported by the browser.) */ 2840 if (!(IE <= 9) && !Velocity.State.isGingerbread) { 2841 /* Note: Since the standalone CSS "perspective" property and the CSS transform "perspective" subproperty 2842 share the same name, the latter is given a unique token within Velocity: "transformPerspective". */ 2843 CSS.Lists.transformsBase = CSS.Lists.transformsBase.concat(CSS.Lists.transforms3D); 2844 } 2845 2846 for (var i = 0; i < CSS.Lists.transformsBase.length; i++) { 2847 /* Wrap the dynamically generated normalization function in a new scope so that transformName's value is 2848 paired with its respective function. (Otherwise, all functions would take the final for loop's transformName.) */ 2849 (function() { 2850 var transformName = CSS.Lists.transformsBase[i]; 2851 2852 CSS.Normalizations.registered[transformName] = function (type, element, propertyValue) { 2853 switch (type) { 2854 /* The normalized property name is the parent "transform" property -- the property that is actually set in CSS. */ 2855 case "name": 2856 return "transform"; 2857 /* Transform values are cached onto a per-element transformCache object. */ 2858 case "extract": 2859 /* If this transform has yet to be assigned a value, return its null value. */ 2860 if (Data(element) === undefined || Data(element).transformCache[transformName] === undefined) {
2861 /* Scale CSS.Lists.transformsBase default to 1 whereas all other transform properties default to 0. */ 2862 return /^scale/i.test(transformName) ? 1 : 0; 2863 /* When transform values are set, they are wrapped in parentheses as per the CSS spec. 2864 Thus, when extracting their values (for tween calculations), we strip off the parentheses. */ 2865 } else { 2866 return Data(element).transformCache[transformName].replace(/[()]/g, ""); 2867 } 2868 case "inject": 2869 var invalid = false; 2870 2871 /* If an individual transform property contains an unsupported unit type, the browser ignores the *entire* transform property. 2872 Thus, protect users from themselves by skipping setting for transform values supplied with invalid unit types. */ 2873 /* Switch on the base transform type; ignore the axis by removing the last letter from the transform's name. */ 2874 switch (transformName.substr(0, transformName.length - 1)) { 2875 /* Whitelist unit types for each transform. */ 2876 case "translate": 2877 invalid = !/(%|px|em|rem|vw|vh|\d)$/i.test(propertyValue); 2878 break; 2879 /* Since an axis-free "scale" property is supported as well, a little hack is used here to detect it by chopping off its last letter. */ 2880 case "scal": 2881 case "scale": 2882 /* Chrome on Android has a bug in which scaled elements blur if their initial scale 2883 value is below 1 (which can happen with forcefeeding). Thus, we detect a yet-unset scale property 2884 and ensure that its first value is always 1. More info: http://stackoverflow.com/questions/10417890/css3-animations-with-transform-causes-blurred-elements-on-webkit/10417962#10417962 */ 2885 if (Velocity.State.isAndroid && Data(element).transformCache[transformName] === undefined && propertyValue < 1) { 2886 propertyValue = 1; 2887 } 2888 2889 invalid = !/(\d)$/i.test(propertyValue); 2890 break; 2891 case "skew": 2892 invalid = !/(deg|\d)$/i.test(propertyValue); 2893 break; 2894 case "rotate": 2895 invalid = !/(deg|\d)$/i.test(propertyValue); 2896 break; 2897 } 2898 2899 if (!invalid) { 2900 /* As per the CSS spec, wrap the value in parentheses. */ 2901 Data(element).transformCache[transformName] = "(" + propertyValue + ")"; 2902 } 2903 2904 /* Although the value is set on the transformCache object, return the newly-updated value for the calling code to process as normal. */ 2905 return Data(element).transformCache[transformName]; 2906 } 2907 }; 2908 })(); 2909 } 2910 2911 /************* 2912 Colors 2913 *************/ 2914 2915 /* Since Velocity only animates a single numeric value per property, color animation is achieved by hooking the individual RGBA components of CSS color properties. 2916 Accordingly, color values must be normalized (e.g. "#ff0000", "red", and "rgb(255, 0, 0)" ==> "255 0 0 1") so that their components can be injected/extracted by CSS.Hooks logic. */ 2917 for (var i = 0; i < CSS.Lists.colors.length; i++) { 2918 /* Wrap the dynamically generated normalization function in a new scope so that colorName's value is paired with its respective function. 2919 (Otherwise, all functions would take the final for loop's colorName.) */ 2920 (function () { 2921 var colorName = CSS.Lists.colors[i]; 2922 2923 /* Note: In IE<=8, which support rgb but not rgba, c
2923olor properties are reverted to rgb by stripping off the alpha component. */ 2924 CSS.Normalizations.registered[colorName] = function(type, element, propertyValue) { 2925 switch (type) { 2926 case "name": 2927 return colorName; 2928 /* Convert all color values into the rgb format. (Old IE can return hex values and color names instead of rgb/rgba.) */ 2929 case "extract": 2930 var extracted; 2931 2932 /* If the color is already in its hookable form (e.g. "255 255 255 1") due to having been previously extracted, skip extraction. */ 2933 if (CSS.RegEx.wrappedValueAlreadyExtracted.test(propertyValue)) { 2934 extracted = propertyValue; 2935 } else { 2936 var converted, 2937 colorNames = { 2938 black: "rgb(0, 0, 0)", 2939 blue: "rgb(0, 0, 255)", 2940 gray: "rgb(128, 128, 128)", 2941 green: "rgb(0, 128, 0)", 2942 red: "rgb(255, 0, 0)", 2943 white: "rgb(255, 255, 255)" 2944 }; 2945 2946 /* Convert color names to rgb. */ 2947 if (/^[A-z]+$/i.test(propertyValue)) { 2948 if (colorNames[propertyValue] !== undefined) { 2949 converted = colorNames[propertyValue] 2950 } else { 2951 /* If an unmatched color name is provided, default to black. */ 2952 converted = colorNames.black; 2953 } 2954 /* Convert hex values to rgb. */ 2955 } else if (CSS.RegEx.isHex.test(propertyValue)) { 2956 converted = "rgb(" + CSS.Values.hexToRgb(propertyValue).join(" ") + ")"; 2957 /* If the provided color doesn't match any of the accepted color formats, default to black. */ 2958 } else if (!(/^rgba?\(/i.test(propertyValue))) { 2959 converted = colorNames.black; 2960 } 2961 2962 /* Remove the surrounding "rgb/rgba()" string then replace commas with spaces and strip 2963 repeated spaces (in case the value included spaces to begin with). */ 2964 extracted = (converted || propertyValue).toString().match(CSS.RegEx.valueUnwrap)[1].replace(/,(\s+)?/g, " "); 2965 } 2966 2967 /* So long as this isn't <=IE8, add a fourth (alpha) component if it's missing and default it to 1 (visible). */ 2968 if (!(IE <= 8) && extracted.split(" ").length === 3) { 2969 extracted += " 1"; 2970 } 2971 2972 return extracted; 2973 case "inject": 2974 /* If this is IE<=8 and an alpha component exists, strip it off. */ 2975 if (IE <= 8) { 2976 if (propertyValue.split(" ").length === 4) { 2977 propertyValue = propertyValue.split(/\s+/).slice(0, 3).join(" "); 2978 } 2979 /* Otherwise, add a fourth (alpha) component if it's missing and default it to 1 (visible). */ 2980 } else if (propertyValue.split(" ").length === 3) { 2981 propertyValue += " 1"; 2982 } 2983 2984 /* Re-insert the browser-appropriate wrapper("rgb/rgba()"), insert commas, and strip off decimal units 2985 on all values but the fourth (R, G, and B only accept whole numbers). */ 2986 return (IE <= 8 ? "rgb" : "rgba") + "(" + propertyValue.replace(/\s+/g, ",").replace(/\.(\d)+(?=,)/g, "") + ")"; 2987 } 2988 }; 2989 })(); 2990 } 2991 } 2992 }, 2993 2994 /************************ 2995 CSS Property Names 2996 ************************/ 2997 2998 Names: {
vendor: 5,382 bytes, lines 2999-3096
2999 /* Camelcase a property name into its JavaScript notation (e.g. "background-color" ==> "backgroundColor"). 3000 Camelcasing is used to normalize property names between and across calls. */ 3001 camelCase: function (property) { 3002 return property.replace(/-(\w)/g, function (match, subMatch) { 3003 return subMatch.toUpperCase(); 3004 }); 3005 }, 3006 3007 /* For SVG elements, some properties (namely, dimensional ones) are GET/SET via the element's HTML attributes (instead of via CSS styles). */ 3008 SVGAttribute: function (property) { 3009 var SVGAttributes = "width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2"; 3010 3011 /* Certain browsers require an SVG transform to be applied as an attribute. (Otherwise, application via CSS is preferable due to 3D support.) */ 3012 if (IE || (Velocity.State.isAndroid && !Velocity.State.isChrome)) { 3013 SVGAttributes += "|transform"; 3014 } 3015 3016 return new RegExp("^(" + SVGAttributes + ")$", "i").test(property); 3017 }, 3018 3019 /* Determine whether a property should be set with a vendor prefix. */ 3020 /* If a prefixed version of the property exists, return it. Otherwise, return the original property name. 3021 If the property is not at all supported by the browser, return a false flag. */ 3022 prefixCheck: function (property) { 3023 /* If this property has already been checked, return the cached value. */ 3024 if (Velocity.State.prefixMatches[property]) { 3025 return [ Velocity.State.prefixMatches[property], true ]; 3026 } else { 3027 var vendors = [ "", "Webkit", "Moz", "ms", "O" ]; 3028 3029 for (var i = 0, vendorsLength = vendors.length; i < vendorsLength; i++) { 3030 var propertyPrefixed; 3031 3032 if (i === 0) { 3033 propertyPrefixed = property; 3034 } else { 3035 /* Capitalize the first letter of the property to conform to JavaScript vendor prefix notation (e.g. webkitFilter). */ 3036 propertyPrefixed = vendors[i] + property.replace(/^\w/, function(match) { return match.toUpperCase(); }); 3037 } 3038 3039 /* Check if the browser supports this property as prefixed. */ 3040 if (Type.isString(Velocity.State.prefixElement.style[propertyPrefixed])) { 3041 /* Cache the match. */ 3042 Velocity.State.prefixMatches[property] = propertyPrefixed; 3043 3044 return [ propertyPrefixed, true ]; 3045 } 3046 } 3047 3048 /* If the browser doesn't support this property in any form, include a false flag so that the caller can decide how to proceed. */ 3049 return [ property, false ]; 3050 } 3051 } 3052 }, 3053 3054 /************************ 3055 CSS Property Values 3056 ************************/ 3057 3058 Values: { 3059 /* Hex to RGB conversion. Copyright Tim Down: http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb */ 3060 hexToRgb: function (hex) { 3061 var shortformRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i, 3062 longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i, 3063 rgbParts; 3064 3065 hex = hex.replace(shortformRegex, function (m, r, g, b) { 3066 return r + r + g + g + b + b; 3067 }); 3068 3069 rgbParts = longformRegex.exec(hex); 3070 3071 return rgbParts ? [ parseInt(rgbParts[1], 16), parseInt(rgbParts[2], 16), parseInt(rgbParts[3], 16) ] : [ 0, 0, 0 ]; 3072 }, 3073 3074 isCSSNullValue: function (value) { 3075 /* The browser defaults CSS values that have not been set to either 0 or one of several possible null-value strings. 3076 Thus, we check for both falsiness and these special strings. */ 3077 /* Null-value checking is performed to default the special strings to 0 (for the sake of tweening) or their hook 3078 templates as defined as CSS.Hooks (for the sake of hook injection/extraction). */ 3079 /* Note: Chrome returns "rgba(0, 0, 0, 0)" for an undefined color whereas IE returns "transparent". */ 3080 return (value == 0 || /^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(value)); 3081 }, 3082 3083 /* Retrieve a property's default unit type. Used for assigning a unit type when one is not supplied by the user. */ 3084 getUnitType: function (property) { 3085 if (/^(rotate|skew)/i.test(property)) { 3086 return "deg"; 3087 } else if (/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(property)) { 3088 /* The above properties are unitless. */ 3089 return ""; 3090 } else { 3091 /* Default to px for all other properties. */ 3092 return "px"; 3093 } 3094 }, 3095 3096 /* HTML elements default to an associated display type when they're not set to display:none. */
3097 /* Note: This function is used for correctly setting the non-"none" display value in certain Velocity redirects, such as fadeIn/Out. */ 3098 getDisplayType: function (element) { 3099 var tagName = element && element.tagName.toString().toLowerCase(); 3100 3101 if (/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(tagName)) { 3102 return "inline"; 3103 } else if (/^(li)$/i.test(tagName)) { 3104 return "list-item"; 3105 } else if (/^(tr)$/i.test(tagName)) { 3106 return "table-row"; 3107 /* Default to "block" when no match is found. */ 3108 } else { 3109 return "block"; 3110 } 3111 }, 3112 3113 /* The class add/remove functions are used to temporarily apply a "velocity-animating" class to elements while they're animating. */ 3114 addClass: function (element, className) { 3115 if (element.classList) { 3116 element.classList.add(className); 3117 } else { 3118 element.className += (element.className.length ? " " : "") + className; 3119 } 3120 }, 3121 3122 removeClass: function (element, className) { 3123 if (element.classList) { 3124 element.classList.remove(className); 3125 } else { 3126 element.className = element.className.toString().replace(new RegExp("(^|\\s)" + className.split(" ").join("|") + "(\\s|$)", "gi"), " "); 3127 } 3128 } 3129 }, 3130 3131 /**************************** 3132 Style Getting & Setting 3133 ****************************/ 3134 3135 /* The singular getPropertyValue, which routes the logic for all normalizations, hooks, and standard CSS properties. */ 3136 getPropertyValue: function (element, property, rootPropertyValue, forceStyleLookup) { 3137 /* Get an element's computed property value. */ 3138 /* Note: Retrieving the value of a CSS property cannot simply be performed by checking an element's 3139 style attribute (which only reflects user-defined values). Instead, the browser must be queried for a property's 3140 *computed* value. You can read more about getComputedStyle here: https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle */ 3141 function computePropertyValue (element, property) { 3142 /* When box-sizing isn't set to border-box, height and width style values are incorrectly computed when an 3143 element's scrollbars are visible (which expands the element's dimensions). Thus, we defer to the more accurate 3144 offsetHeight/Width property, which includes the total dimensions for interior, border, padding, and scrollbar. 3145 We subtract border and padding to get the sum of interior + scrollbar. */ 3146 var computedValue = 0; 3147 3148 /* IE<=8 doesn't support window.getComputedStyle, thus we defer to jQuery, which has an extensive array 3149 of hacks to accurately retrieve IE8 property values. Re-implementing that logic here is not worth bloating the 3150 codebase for a dying browser. The performance repercussions of using jQuery here are minimal since 3151 Velocity is optimized to rarely (and sometimes never) query the DOM. Further, the $.css() codepath isn't that slow. */ 3152 if (IE <= 8) { 3153 computedValue = $.css(element, property); /* GET */ 3154 /* All other browsers support getComputedStyle. The returned live object reference is cached onto its 3155 associated element so that it does not need to be refetched upon every GET. */ 3156 } else { 3157 /* Browsers do not return height and width values for elements that are set to display:"none". Thus, we temporarily 3158 toggle display to the element type's default value. */ 3159 var toggleDisplay = false;
vendor: 7,262 bytes, lines 3160-3265
3160 3161 if (/^(width|height)$/.test(property) && CSS.getPropertyValue(element, "display") === 0) { 3162 toggleDisplay = true; 3163 CSS.setPropertyValue(element, "display", CSS.Values.getDisplayType(element)); 3164 } 3165 3166 function revertDisplay () { 3167 if (toggleDisplay) { 3168 CSS.setPropertyValue(element, "display", "none"); 3169 } 3170 } 3171 3172 if (!forceStyleLookup) { 3173 if (property === "height" && CSS.getPropertyValue(element, "boxSizing").toString().toLowerCase() !== "border-box") { 3174 var contentBoxHeight = element.offsetHeight - (parseFloat(CSS.getPropertyValue(element, "borderTopWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "borderBottomWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingTop")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingBottom")) || 0); 3175 revertDisplay(); 3176 3177 return contentBoxHeight; 3178 } else if (property === "width" && CSS.getPropertyValue(element, "boxSizing").toString().toLowerCase() !== "border-box") { 3179 var contentBoxWidth = element.offsetWidth - (parseFloat(CSS.getPropertyValue(element, "borderLeftWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "borderRightWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingLeft")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingRight")) || 0); 3180 revertDisplay(); 3181 3182 return contentBoxWidth; 3183 } 3184 } 3185 3186 var computedStyle; 3187 3188 /* For elements that Velocity hasn't been called on directly (e.g. when Velocity queries the DOM on behalf 3189 of a parent of an element its animating), perform a direct getComputedStyle lookup since the object isn't cached. */ 3190 if (Data(element) === undefined) { 3191 computedStyle = window.getComputedStyle(element, null); /* GET */ 3192 /* If the computedStyle object has yet to be cached, do so now. */ 3193 } else if (!Data(element).computedStyle) { 3194 computedStyle = Data(element).computedStyle = window.getComputedStyle(element, null); /* GET */ 3195 /* If computedStyle is cached, use it. */ 3196 } else { 3197 computedStyle = Data(element).computedStyle; 3198 } 3199 3200 /* IE and Firefox do not return a value for the generic borderColor -- they only return individual values for each border side's color. 3201 As a polyfill for querying individual border side colors, just return the top border's color. */ 3202 if ((IE || Velocity.State.isFirefox) && property === "borderColor") { 3203 property = "borderTopColor"; 3204 } 3205 3206 /* IE9 has a bug in which the "filter" property must be accessed from computedStyle using the getPropertyValue method 3207 instead of a direct property lookup. The getPropertyValue method is slower than a direct lookup, which is why we avoid it by default. */ 3208 if (IE === 9 && property === "filter") { 3209 computedValue = computedStyle.getPropertyValue(property); /* GET */ 3210 } else { 3211 computedValue = computedStyle[property]; 3212 } 3213 3214 /* Fall back to the property's style value (if defined) when computedValue returns nothing, 3215 which can happen when the element hasn't been painted. */ 3216 if (computedValue === "" || computedValue === null) { 3217 computedValue = element.style[property]; 3218 } 3219 3220 revertDisplay(); 3221 } 3222 3223 /* For top, right, bottom, and left (TRBL) values that are set to "auto" on elements of "fixed" or "absolute" position, 3224 defer to jQuery for converting "auto" to a numeric value. (For elements with a "static" or "relative" position, "auto" has the same 3225 effect as being set to 0, so no conversion is necessary.) */ 3226 /* An example of why numeric conversion is necessary: When an element with "position:absolute" has an untouched "left" 3227 property, which reverts to "auto", left's value is 0 relative to its parent element, but is often non-zero relative 3228 to its *containing* (not parent) element, which is the nearest "position:relative" ancestor or the viewport (and always the viewport in the case of "position:fixed"). */ 3229 if (computedValue === "auto" && /^(top|right|bottom|left)$/i.test(property)) { 3230 var position = computePropertyValue(element, "position"); /* GET */ 3231 3232 /* For absolute positioning, jQuery's $.position() only returns values for top and left; 3233 right and bottom will have their "auto" value reverted to 0. */ 3234 /* Note: A jQuery object must be created here since jQuery doesn't have a low-level alias for $.position(). 3235 Not a big deal since we're currently in a GET batch anyway. */ 3236 if (position === "fixed" || (position === "absolute" && /top|left/i.test(property))) { 3237 /* Note: jQuery strips the pixel unit from its returned values; we re-add it here to conform with computePropertyValue's behavior. */ 3238 computedValue = $(element).position()[property] + "px"; /* GET */ 3239 } 3240 } 3241 3242 return computedValue; 3243 } 3244 3245 var propertyValue; 3246 3247 /* If this is a hooked property (e.g. "clipLeft" instead of the root property of "clip"), 3248 extract the hook's value from a normalized rootPropertyValue using CSS.Hooks.extractValue(). */ 3249 if (CSS.Hooks.registered[property]) { 3250 var hook = property, 3251 hookRoot = CSS.Hooks.getRoot(hook); 3252 3253 /* If a cached rootPropertyValue wasn't passed in (which Velocity always attempts to do in order to avoid requerying the DOM), 3254 query the DOM for the root property's value. */ 3255 if (rootPropertyValue === undefined) { 3256 /* Since the browser is now being directly queried, use the official post-prefixing property name for this lookup. */ 3257 rootPropertyValue = CSS.getPropertyValue(element, CSS.Names.prefixCheck(hookRoot)[0]); /* GET */ 3258 } 3259 3260 /* If this root has a normalization registered, peform the associated normalization extraction. */ 3261 if (CSS.Normalizations.registered[hookRoot]) { 3262 rootPropertyValue = CSS.Normalizations.registered[hookRoot]("extract", element, rootPropertyValue); 3263 } 3264 3265 /* Extract the hook's value. */
3266 propertyValue = CSS.Hooks.extractValue(hook, rootPropertyValue); 3267 3268 /* If this is a normalized property (e.g. "opacity" becomes "filter" in <=IE8) or "translateX" becomes "transform"), 3269 normalize the property's name and value, and handle the special case of transforms. */ 3270 /* Note: Normalizing a property is mutually exclusive from hooking a property since hook-extracted values are strictly 3271 numerical and therefore do not require normalization extraction. */ 3272 } else if (CSS.Normalizations.registered[property]) { 3273 var normalizedPropertyName, 3274 normalizedPropertyValue; 3275 3276 normalizedPropertyName = CSS.Normalizations.registered[property]("name", element); 3277 3278 /* Transform values are calculated via normalization extraction (see below), which checks against the element's transformCache. 3279 At no point do transform GETs ever actually query the DOM; initial stylesheet values are never processed. 3280 This is because parsing 3D transform matrices is not always accurate and would bloat our codebase; 3281 thus, normalization extraction defaults initial transform values to their zero-values (e.g. 1 for scaleX and 0 for translateX). */ 3282 if (normalizedPropertyName !== "transform") { 3283 normalizedPropertyValue = computePropertyValue(element, CSS.Names.prefixCheck(normalizedPropertyName)[0]); /* GET */ 3284 3285 /* If the value is a CSS null-value and this property has a hook template, use that zero-value template so that hooks can be extracted from it. */ 3286 if (CSS.Values.isCSSNullValue(normalizedPropertyValue) && CSS.Hooks.templates[property]) { 3287 normalizedPropertyValue = CSS.Hooks.templates[property][1]; 3288 } 3289 } 3290 3291 propertyValue = CSS.Normalizations.registered[property]("extract", element, normalizedPropertyValue); 3292 } 3293 3294 /* If a (numeric) value wasn't produced via hook extraction or normalization, query the DOM. */ 3295 if (!/^[\d-]/.test(propertyValue)) { 3296 /* For SVG elements, dimensional properties (which SVGAttribute() detects) are tweened via 3297 their HTML attribute values instead of their CSS style values. */ 3298 if (Data(element) && Data(element).isSVG && CSS.Names.SVGAttribute(property)) { 3299 /* Since the height/width attribute values must be set manually, they don't reflect computed values. 3300 Thus, we use use getBBox() to ensure we always get values for elements with undefined height/width attributes. */ 3301 if (/^(height|width)$/i.test(property)) { 3302 propertyValue = element.getBBox()[property]; 3303 /* Otherwise, access the attribute value directly. */ 3304 } else { 3305 propertyValue = element.getAttribute(property); 3306 } 3307 } else { 3308 propertyValue = computePropertyValue(element, CSS.Names.prefixCheck(property)[0]); /* GET */ 3309 } 3310 } 3311 3312 /* Since property lookups are for animation purposes (which entails computing the numeric delta between start and end values), 3313 convert CSS null-values to an integer of value 0. */ 3314 if (CSS.Values.isCSSNullValue(propertyValue)) { 3315 propertyValue = 0; 3316 } 3317 3318 if (Velocity.debug >= 2) console.log("Get " + property + ": " + propertyValue); 3319 3320 return propertyValue; 3321 }, 3322 3323 /* The singular setPropertyValue, which routes the logic for all normalizations, hooks, and standard CSS properties. */ 3324 setPropertyValue: function(element, property, propertyValue, rootPropertyValue, scrollData) { 3325 var propertyName = property; 3326 3327 /* In order to be subjected to call options and element queueing, scroll animation is routed through Velocity as if it were a standard CSS property. */ 3328 if (property === "scroll") { 3329 /* If a container option is present, scroll the container instead of the browser window. */ 3330 if (scrollData.container) { 3331 scrollData.container["scroll" + scrollData.direction] = propertyValue; 3332 /* Otherwise, Velocity defaults to scrolling the browser window. */ 3333 } else { 3334 if (scrollData.direction === "Left") { 3335 window.scrollTo(propertyValue, scrollData.alternateValue); 3336 } else { 3337 window.scrollTo(scrollData.alternateValue, propertyValue); 3338 } 3339 } 3340 } else { 3341 /* Transforms (translateX, rotateZ, etc.) are applied to a per-element transformCache object, which is manually flushed via flushTransformCache(). 3342 Thus, for now, we merely cache transforms being SET. */ 3343 if (CSS.Normalizations.registered[property] && CSS.Normalizations.registered[property]("name", element) === "transform") { 3344 /* Perform a normalization injection. */ 3345 /* Note: The normalization logic handles the transformCache updating. */ 3346 CSS.Normalizations.registered[property]("inject", element, propertyValue); 3347 3348 propertyName = "transform"; 3349 propertyValue = Data(element).transformCache[property]; 3350 } else { 3351 /* Inject hooks. */ 3352 if (CSS.Hooks.registered[property]) { 3353 var hookName = property, 3354 hookRoot = CSS.Hooks.getRoot(property); 3355 3356 /* If a cached rootPropertyValue was not provided, query the DOM for the hookRoot's current value. */ 3357 rootPropertyValue = rootPropertyValue || CSS.getPropertyValue(element, hookRoot); /* GET */ 3358 3359 propertyValue = CSS.Hooks.injectValue(ho
3359okName, propertyValue, rootPropertyValue); 3360 property = hookRoot; 3361 } 3362 3363 /* Normalize names and values. */ 3364 if (CSS.Normalizations.registered[property]) { 3365 propertyValue = CSS.Normalizations.registered[property]("inject", element, propertyValue); 3366 property = CSS.Normalizations.registered[property]("name", element); 3367 } 3368 3369 /* Assign the appropriate vendor prefix before performing an official style update. */ 3370 propertyName = CSS.Names.prefixCheck(property)[0]; 3371 3372 /* A try/catch is used for IE<=8, which throws an error when "invalid" CSS values are set, e.g. a negative width. 3373 Try/catch is avoided for other browsers since it incurs a performance overhead. */ 3374 if (IE <= 8) { 3375 try { 3376 element.style[propertyName] = propertyValue; 3377 } catch (error) { if (Velocity.debug) console.log("Browser does not support [" + propertyValue + "] for [" + propertyName + "]"); } 3378 /* SVG elements have their dimensional properties (width, height, x, y, cx, etc.) applied directly as attributes instead of as styles. */ 3379 /* Note: IE8 does not support SVG elements, so it's okay that we skip it for SVG animation. */ 3380 } else if (Data(element) && Data(element).isSVG && CSS.Names.SVGAttribute(property)) { 3381 /* Note: For SVG attributes, vendor-prefixed property names are never used. */ 3382 /* Note: Not all CSS properties can be animated via attributes, but the browser won't throw an error for unsupported properties. */ 3383 element.setAttribute(property, propertyValue); 3384 } else { 3385 element.style[propertyName] = propertyValue; 3386 } 3387 3388 if (Velocity.debug >= 2) console.log("Set " + property + " (" + propertyName + "): " + propertyValue); 3389 } 3390 } 3391 3392 /* Return the normalized property name and value in case the caller wants to know how these values were modified before being applied to the DOM. */ 3393 return [ propertyName, propertyValue ]; 3394 }, 3395 3396 /* To increase performance by batching transform updates into a single SET, transforms are not directly applied to an element until flushTransformCache() is called. */ 3397 /* Note: Velocity applies transform properties in the same order that they are chronogically introduced to the element's CSS styles. */ 3398 flushTransformCache: function(element) { 3399 var transformString = ""; 3400 3401 /* Certain browsers require that SVG transforms be applied as an attribute. However, the SVG transform attribute takes a modified version of CSS's transform string 3402 (units are dropped and, except for skewX/Y, subproperties are merged into their master property -- e.g. scaleX and scaleY are merged into scale(X Y). */ 3403 if ((IE || (Velocity.State.isAndroid && !Velocity.State.isChrome)) && Data(element).isSVG) { 3404 /* Since transform values are stored in their parentheses-wrapped form, we use a helper function to strip out their numeric values. 3405 Further, SVG transform properties only take unitless (representing pixels) values, so it's okay that parseFloat() strips the unit suffixed to the float value. */ 3406 function getTransformFloat (transformProperty) { 3407 return parseFloat(CSS.getPropertyValue(element, transformProperty)); 3408 } 3409 3410 /* Create an object to organize all the transforms that we'll apply to the SVG element. To keep the logic simple, 3411 we process *all* transform properties -- even those that may not be explicitly applied (since they default to their zero-values anyway). */ 3412 var SVGTransforms = { 3413 translate: [ getTransformFloat("translateX"), getTransformFloat("translateY") ], 3414 skewX: [ getTransformFloat("skewX") ], skewY: [ getTransformFloat("skewY") ],
vendor: 6,513 bytes, lines 3415-3544
3415 /* If the scale property is set (non-1), use that value for the scaleX and scaleY values 3416 (this behavior mimics the result of animating all these properties at once on HTML elements). */ 3417 scale: getTransformFloat("scale") !== 1 ? [ getTransformFloat("scale"), getTransformFloat("scale") ] : [ getTransformFloat("scaleX"), getTransformFloat("scaleY") ], 3418 /* Note: SVG's rotate transform takes three values: rotation degrees followed by the X and Y values 3419 defining the rotation's origin point. We ignore the origin values (default them to 0). */ 3420 rotate: [ getTransformFloat("rotateZ"), 0, 0 ] 3421 }; 3422 3423 /* Iterate through the transform properties in the user-defined property map order. 3424 (This mimics the behavior of non-SVG transform animation.) */ 3425 $.each(Data(element).transformCache, function(transformName) { 3426 /* Except for with skewX/Y, revert the axis-specific transform subproperties to their axis-free master 3427 properties so that they match up with SVG's accepted transform properties. */ 3428 if (/^translate/i.test(transformName)) { 3429 transformName = "translate"; 3430 } else if (/^scale/i.test(transformName)) { 3431 transformName = "scale"; 3432 } else if (/^rotate/i.test(transformName)) { 3433 transformName = "rotate"; 3434 } 3435 3436 /* Check that we haven't yet deleted the property from the SVGTransforms container. */ 3437 if (SVGTransforms[transformName]) { 3438 /* Append the transform property in the SVG-supported transform format. As per the spec, surround the space-delimited values in parentheses. */ 3439 transformString += transformName + "(" + SVGTransforms[transformName].join(" ") + ")" + " "; 3440 3441 /* After processing an SVG transform property, delete it from the SVGTransforms container so we don't 3442 re-insert the same master property if we encounter another one of its axis-specific properties. */ 3443 delete SVGTransforms[transformName]; 3444 } 3445 }); 3446 } else { 3447 var transformValue, 3448 perspective; 3449 3450 /* Transform properties are stored as members of the transformCache object. Concatenate all the members into a string. */ 3451 $.each(Data(element).transformCache, function(transformName) { 3452 transformValue = Data(element).transformCache[transformName]; 3453 3454 /* Transform's perspective subproperty must be set first in order to take effect. Store it temporarily. */ 3455 if (transformName === "transformPerspective") { 3456 perspective = transformValue; 3457 return true; 3458 } 3459 3460 /* IE9 only supports one rotation type, rotateZ, which it refers to as "rotate". */ 3461 if (IE === 9 && transformName === "rotateZ") { 3462 transformName = "rotate"; 3463 } 3464 3465 transformString += transformName + transformValue + " "; 3466 }); 3467 3468 /* If present, set the perspective subproperty first. */ 3469 if (perspective) { 3470 transformString = "perspective" + perspective + " " + transformString; 3471 } 3472 } 3473 3474 CSS.setPropertyValue(element, "transform", transformString); 3475 } 3476 }; 3477 3478 /* Register hooks and normalizations. */ 3479 CSS.Hooks.register(); 3480 CSS.Normalizations.register(); 3481 3482 /* Allow hook setting in the same fashion as jQuery's $.css(). */ 3483 Velocity.hook = function (elements, arg2, arg3) { 3484 var value = undefined; 3485 3486 elements = sanitizeElements(elements); 3487 3488 $.each(elements, function(i, element) { 3489 /* Initialize Velocity's per-element data cache if this element hasn't previously been animated. */ 3490 if (Data(element) === undefined) { 3491 Velocity.init(element); 3492 } 3493 3494 /* Get property value. If an element set was passed in, only return the value for the first element. */ 3495 if (arg3 === undefined) { 3496 if (value === undefined) { 3497 value = Velocity.CSS.getPropertyValue(element, arg2); 3498 } 3499 /* Set property value. */ 3500 } else { 3501 /* sPV returns an array of the normalized propertyName/propertyValue pair used to update the DOM. */ 3502 var adjustedSet = Velocity.CSS.setPropertyValue(element, arg2, arg3); 3503 3504 /* Transform properties don't automatically set. They have to be flushed to the DOM. */ 3505 if (adjustedSet[0] === "transform") { 3506 Velocity.CSS.flushTransformCache(element); 3507 } 3508 3509 value = adjustedSet; 3510 } 3511 }); 3512 3513 return value; 3514 }; 3515 3516 /***************** 3517 Animation 3518 *****************/ 3519 3520 var animate = function() { 3521 3522 /****************** 3523 Call Chain 3524 ******************/ 3525 3526 /* Logic for determining what to return to the call stack when exiting out of Velocity. */ 3527 function getChain () { 3528 /* If we are using the utility function, attempt to return this call's promise. If no promise library was detected, 3529 default to null instead of returning the targeted elements so that utility function's return value is standardized. */ 3530 if (isUtility) { 3531 return promiseData.promise || null; 3532 /* Otherwise, if we're using $.fn, return the jQuery-/Zepto-wrapped element set. */ 3533 } else { 3534 return elementsWrapped; 3535 } 3536 } 3537 3538 /************************* 3539 Arguments Assignment 3540 *************************/ 3541 3542 /* To allow for expressive CoffeeScript code, Velocity supports an alternative syntax in which "properties" and "options" 3543 objects are defined on a container object that's passed in as Velocity's sole argument. */ 3544 /* Note: Some browsers automatically populate arguments with a "properties" object. We detect it by checking for its default "n
3544ames" property. */ 3545 var syntacticSugar = (arguments[0] && (($.isPlainObject(arguments[0].properties) && !arguments[0].properties.names) || Type.isString(arguments[0].properties))), 3546 /* Whether Velocity was called via the utility function (as opposed to on a jQuery/Zepto object). */ 3547 isUtility, 3548 /* When Velocity is called via the utility function ($.Velocity()/Velocity()), elements are explicitly 3549 passed in as the first parameter. Thus, argument positioning varies. We normalize them here. */ 3550 elementsWrapped, 3551 argumentIndex; 3552 3553 var elements, 3554 propertiesMap, 3555 options; 3556 3557 /* Detect jQuery/Zepto elements being animated via the $.fn method. */ 3558 if (Type.isWrapped(this)) { 3559 isUtility = false; 3560 3561 argumentIndex = 0; 3562 elements = this; 3563 elementsWrapped = this; 3564 /* Otherwise, raw elements are being animated via the utility function. */ 3565 } else { 3566 isUtility = true; 3567 3568 argumentIndex = 1; 3569 elements = syntacticSugar ? arguments[0].elements : arguments[0]; 3570 } 3571 3572 elements = sanitizeElements(elements); 3573 3574 if (!elements) { 3575 return; 3576 } 3577 3578 if (syntacticSugar) { 3579 propertiesMap = arguments[0].properties; 3580 options = arguments[0].options; 3581 } else { 3582 propertiesMap = arguments[argumentIndex]; 3583 options = arguments[argumentIndex + 1]; 3584 } 3585 3586 /* The length of the element set (in the form of a nodeList or an array of elements) is defaulted to 1 in case a 3587 single raw DOM element is passed in (which doesn't contain a length property). */ 3588 var elementsLength = elements.length, 3589 elementsIndex = 0; 3590 3591 /*************************** 3592 Argument Overloading 3593 ***************************/ 3594 3595 /* Support is included for jQuery's argument overloading: $.animate(propertyMap [, duration] [, easing] [, complete]). 3596 Overloading is detected by checking for the absence of an object being passed into options. */ 3597 /* Note: The stop action does not accept animation options, and is therefore excluded from this check. */ 3598 if (propertiesMap !== "stop" && !$.isPlainObject(options)) { 3599 /* The utility function shifts all arguments one position to the right, so we adjust for that offset. */ 3600 var startingArgumentPosition = argumentIndex + 1; 3601 3602 options = {}; 3603 3604 /* Iterate through all options arguments */ 3605 for (var i = startingArgumentPosition; i < arguments.length; i++) { 3606 /* Treat a number as a duration. Parse it out. */ 3607 /* Note: The following RegEx will return true if passed an array with a number as its first item. 3608 Thus, arrays are skipped from this check. */ 3609 if (!Type.isArray(arguments[i]) && (/^(fast|normal|slow)$/i.test(arguments[i]) || /^\d/.test(arguments[i]))) { 3610 options.duration = arguments[i]; 3611 /* Treat strings and arrays as easings. */ 3612 } else if (Type.isString(arguments[i]) || Type.isArray(arguments[i])) { 3613 options.easing = arguments[i]; 3614 /* Treat a function as a complete callback. */ 3615 } else if (Type.isFunction(arguments[i])) { 3616 options.complete = arguments[i]; 3617 } 3618 } 3619 } 3620 3621 /*************** 3622 Promises 3623 ***************/ 3624 3625 var promiseData = { 3626 promise: null, 3627 resolver: null, 3628 rejecter: null 3629 }; 3630 3631 /* If this call was made via the utility function (which is the default method of invocation when jQuery/Zepto are not being used), and if 3632 promise support was detected, create a promise object for this call and store references to its resolver and rejecter methods. The resolve 3633 method is used when a call completes naturally or is prematurely stopped by the user. In both cases, completeCall() handles the associated 3634 call cleanup and promise resolving logic. The reject method is used when an invali
3634d set of arguments is passed into a Velocity call. */ 3635 /* Note: Velocity employs a call-based queueing architecture, which means that stopping an animating element actually stops the full call that 3636 triggered it -- not that one element exclusively. Similarly, there is one promise per call, and all elements targeted by a Velocity call are 3637 grouped together for the purposes of resolving and rejecting a promise. */ 3638 if (isUtility && Velocity.Promise) { 3639 promiseData.promise = new Velocity.Promise(function (resolve, reject) { 3640 promiseData.resolver = resolve; 3641 promiseData.rejecter = reject; 3642 }); 3643 } 3644 3645 /********************* 3646 Action Detection 3647 *********************/ 3648 3649 /* Velocity's behavior is categorized into "actions": Elements can either be specially scrolled into view, 3650 or they can be started, stopped, or reversed. If a literal or referenced properties map is passed in as Velocity's 3651 first argument, the associated action is "start". Alternatively, "scroll", "reverse", or "stop" can be passed in instead of a properties map. */ 3652 var action; 3653 3654 switch (propertiesMap) { 3655 case "scroll": 3656 action = "scroll"; 3657 break; 3658 3659 case "reverse": 3660 action = "reverse"; 3661 break; 3662 3663 case "stop": 3664 /******************* 3665 Action: Stop 3666 *******************/ 3667 3668 /* Clear the currently-active delay on each targeted element. */ 3669 $.each(elements, function(i, element) { 3670 if (Data(element) && Data(element).delayTimer) { 3671 /* Stop the timer from triggering its cached next() function. */ 3672 clearTimeout(Data(element).delayTimer.setTimeout); 3673 3674 /* Manually call the next() function so that the subsequent queue items can progress. */ 3675 if (Data(element).delayTimer.next) { 3676 Data(element).delayTimer.next(); 3677 } 3678 3679 delete Data(element).delayTimer; 3680 } 3681 }); 3682 3683 var callsToStop = []; 3684 3685 /* When the stop action is triggered, the elements' currently active call is immediately stopped. The active call might have 3686 been applied to multiple elements, in which case all of the call's elements will be subjected to stopping. When an element 3687 is stopped, the next item in its animation queue is immediately triggered. */ 3688 /* An additional argument may be passed in to clear an element's remaining queued calls. Either true (which defaults to the "fx" queue) 3689 or a custom queue string can be passed in. */ 3690 /* Note: The stop command runs prior to Queueing since its behavior is intended to take effect *immediately*, 3691 regardless of the element's current queue state. */ 3692 3693 /* Iterate through every active call. */ 3694 $.each(Velocity.State.calls, function(i, activeCall) { 3695 /* Inactive calls are set to false by the logic inside completeCall(). Skip them. */ 3696 if (activeCall) { 3697 /* Iterate through the active call's targeted elements. */ 3698 $.each(activeCall[1], function(k, activeElement) { 3699 var queueName = Type.isString(options) ? options : ""; 3700 3701 if (options !== undefined && activeCall[2].queue !== queueName) { 3702 return true; 3703 } 3704 3705 /* Iterate through the calls targeted by the stop command. */ 3706 $.each(elements, function(l, element) { 3707 /* Check that this call was applied to the target element. */ 3708 if (element === activeElement) { 3709 /* Optionally clear the remaining queued calls. */ 3710 if (options !== undefined) { 3711 /* Iterate through the items in the element's queue. */ 3712 $.each($.queue(element, queueName), function(_, item) { 3713 /* The queue array can contain an "inprogress" string, which we skip. */ 3714 if (Type.isFunction(item)) { 3715 /* Pass the item's callback a flag indicating that we want to abort from the queue call. 3716 (Specifically, the queue will resolve the call's associated promise then abort.) */ 3717 item(null, true); 3718 } 3719 }); 3720 3721 /* Clearing the $.queue() array is achieved by resetting it to []. */ 3722 $.queue(element, queueName, []); 3723 } 3724 3725 if (Data(element) && queueName === "") { 3726 /* Since "reverse" uses cached start values (the previous call's endValues), 3727 these values must be changed to reflect the final value that the elements were actually tweened to. */ 3728 $.each(Data(element).tweensContainer, function(m, activeTween) { 3729 activeTween.endValue = activeTween.currentValue; 3730 }); 3731 } 3732 3733 callsToStop.push(i); 3734 } 3735 }); 3736 }); 3737 } 3738 }); 3739 3740 /* Prematurely call completeCall() on each matched active call, passing an additional flag to indicate 3741 that the complete callback and display:none setting should be skipped since we're completing prematurely. */ 3742 $.each(callsToStop, function(i, j) { 3743 completeCall(j, true); 3744 }); 3745 3746 if (promiseData.promise) { 3747 /* Immediately resolve the promise associated with this stop call since stop runs synchronously. */ 3748 promiseData.resolver(elements); 3749 } 3750 3751 /* Since we're stopping, and not proceeding with queueing, exit out of Velocity. */ 3752 return getChain(); 3753 3754 default: 3755 /* Treat a non-empty plain object as a literal properties map. */ 3756 if ($.isPlainObject(propertiesMap) && !Type.isEmptyObject(propertiesMap)) { 3757 action = "start"; 3758 3759 /**************** 3760 Redirects 3761 ****************/ 3762 3763 /* Check if a string matches a registered redirect (see Redirects above). */ 3764 } else if (Type.isString(propertiesMap) && Velocity.Redirects[propertiesMap]) { 3765 var opts = $.extend({}, options), 3766 durationOriginal = opts.duration, 3767 delayOriginal = opts.delay || 0; 3768 3769 /* If the backwards option was passed in, reverse the element set so that elements animate from the last to the first. */ 3770 if (opts.backwards === true) { 3771 elements = $.extend(true, [], elements).reverse(); 3772 } 3773 3774 /* Individually trigger the redirect for each element in the set to prevent users from having to handle iteration logic in their redirect. */ 3775 $.each(elements, function(elementIndex, element) { 3776 /* If the stagger option was passed in, successively delay each element by the stagger value (in ms). Retain the original delay value. */ 3777 if (parseFloat(opts.stagger)) {
vendor: 18,569 bytes, lines 3778-4084
3778 opts.delay = delayOriginal + (parseFloat(opts.stagger) * elementIndex); 3779 } else if (Type.isFunction(opts.stagger)) { 3780 opts.delay = delayOriginal + opts.stagger.call(element, elementIndex, elementsLength); 3781 } 3782 3783 /* If the drag option was passed in, successively increase/decrease (depending on the presense of opts.backwards) 3784 the duration of each element's animation, using floors to prevent producing very short durations. */ 3785 if (opts.drag) { 3786 /* Default the duration of UI pack effects (callouts and transitions) to 1000ms instead of the usual default duration of 400ms. */ 3787 opts.duration = parseFloat(durationOriginal) || (/^(callout|transition)/.test(propertiesMap) ? 1000 : DURATION_DEFAULT); 3788 3789 /* For each element, take the greater duration of: A) animation completion percentage relative to the original duration, 3790 B) 75% of the original duration, or C) a 200ms fallback (in case duration is already set to a low value). 3791 The end result is a baseline of 75% of the redirect's duration that increases/decreases as the end of the element set is approached. */ 3792 opts.duration = Math.max(opts.duration * (opts.backwards ? 1 - elementIndex/elementsLength : (elementIndex + 1) / elementsLength), opts.duration * 0.75, 200); 3793 } 3794 3795 /* Pass in the call's opts object so that the redirect can optionally extend it. It defaults to an empty object instead of null to 3796 reduce the opts checking logic required inside the redirect. */ 3797 Velocity.Redirects[propertiesMap].call(element, element, opts || {}, elementIndex, elementsLength, elements, promiseData.promise ? promiseData : undefined); 3798 }); 3799 3800 /* Since the animation logic resides within the redirect's own code, abort the remainder of this call. 3801 (The performance overhead up to this point is virtually non-existant.) */ 3802 /* Note: The jQuery call chain is kept intact by returning the complete element set. */ 3803 return getChain(); 3804 } else { 3805 var abortError = "Velocity: First argument (" + propertiesMap + ") was not a property map, a known action, or a registered redirect. Aborting."; 3806 3807 if (promiseData.promise) { 3808 promiseData.rejecter(new Error(abortError)); 3809 } else { 3810 console.log(abortError); 3811 } 3812 3813 return getChain(); 3814 } 3815 } 3816 3817 /************************** 3818 Call-Wide Variables 3819 **************************/ 3820 3821 /* A container for CSS unit conversion ratios (e.g. %, rem, and em ==> px) that is used to cache ratios across all elements 3822 being animated in a single Velocity call. Calculating unit ratios necessitates DOM querying and updating, and is therefore 3823 avoided (via caching) wherever possible. This container is call-wide instead of page-wide to avoid the risk of using stale 3824 conversion metrics across Velocity animations that are not immediately consecutively chained. */ 3825 var callUnitConversionData = { 3826 lastParent: null, 3827 lastPosition: null, 3828 lastFontSize: null, 3829 lastPercentToPxWidth: null, 3830 lastPercentToPxHeight: null, 3831 lastEmToPx: null, 3832 remToPx: null, 3833 vwToPx: null, 3834 vhToPx: null 3835 }; 3836 3837 /* A container for all the ensuing tween data and metadata associated with this call. This container gets pushed to the page-wide 3838 Velocity.State.calls array that is processed during animation ticking. */ 3839 var call = []; 3840 3841 /************************ 3842 Element Processing 3843 ************************/ 3844 3845 /* Element processing consists of three parts -- data processing that cannot go stale and data processing that *can* go stale (i.e. third-party style modifications): 3846 1) Pre-Queueing: Element-wide variables, including the element's data storage, are instantiated. Call options are prepared. If triggered, the Stop action is executed. 3847 2) Queueing: The logic that runs once this call has reached its point of execution in the element's $.queue() stack. Most logic is placed here to avoid risking it becoming stale. 3848 3) Pushing: Consolidation of the tween data followed by its push onto the global in-progress calls container. 3849 */ 3850 3851 function processElement () { 3852 3853 /************************* 3854 Part I: Pre-Queueing 3855 *************************/ 3856 3857 /*************************** 3858 Element-Wide Variables 3859 ***************************/ 3860 3861 var element = this, 3862 /* The runtime opts object is the extension of the current call's options and Velocity's page-wide option defaults. */ 3863 opts = $.extend({}, Velocity.defaults, options), 3864 /* A container for the processed data associated with each property in the propertyMap. 3865 (Each property in the map produces its own "tween".) */ 3866 tweensContainer = {}, 3867 elementUnitConversionData; 3868 3869 /****************** 3870 Element Init 3871 ******************/ 3872 3873 if (Data(element) === undefined) { 3874 Velocity.init(element); 3875 } 3876 3877 /****************** 3878 Option: Delay 3879 ******************/ 3880 3881 /* Since queue:false doesn't respect the item's existing queue, we avoid injecting its delay here (it's set later on). */ 3882 /* Note: Velocity rolls its own delay function since jQuery doesn't have a utility alias for $.fn.delay() 3883 (and thus requires jQuery element creation, which we avoid since its overhead includes DOM querying). */ 3884 if (parseFloat(opts.delay) && opts.queue !== false) { 3885 $.queue(element, opts.queue, function(next) { 3886 /* This is a flag used to indicate to the upcoming completeCall() function that this queue entry was initiated by Velocity. See completeCall() for further details. */ 3887 Velocity.velocityQueueEntryFlag = true; 3888 3889 /* The ensuing queue item (which is assigned to the "next" argument that $.queue() automatically passes in) will be triggered after a setTimeout delay. 3890 The setTimeout is stored so that it can be subjected to clearTimeout() if this animation is prematurely stopped via Velocity's "stop" command. */ 3891 Data(element).delayTimer = { 3892 setTimeout: setTimeout(next, parseFloat(opts.delay)), 3893 next: next 3894 }; 3895 }); 3896 } 3897 3898 /********************* 3899 Option: Duration 3900 *********************/ 3901 3902 /* Support for jQuery's named durations. */ 3903 switch (opts.duration.toString().toLowerCase()) { 3904 case "fast": 3905 opts.duration = 200; 3906 break; 3907 3908 case "normal": 3909 opts.duration = DURATION_DEFAULT; 3910 break; 3911 3912 case "slow": 3913 opts.duration = 600; 3914 break; 3915 3916 default: 3917 /* Remove the potential "ms" suffix and default to 1 if the user is attempting to set a duration of 0 (in order to produce an immediate style change). */ 3918 opts.duration = parseFloat(opts.duration) || 1; 3919 } 3920 3921 /************************ 3922 Global Option: Mock 3923 ************************/ 3924 3925 if (Velocity.mock !== false) { 3926 /* In mock mode, all animations are forced to 1ms so that they occur immediately upon the next rAF tick. 3927 Alternatively, a multiplier can be passed in to time remap all delays and durations. */ 3928 if (Velocity.mock === true) { 3929 opts.duration = opts.delay = 1; 3930 } else { 3931 opts.duration *= parseFloat(Velocity.mock) || 1; 3932 opts.delay *= parseFloat(Velocity.mock) || 1; 3933 } 3934 } 3935 3936 /******************* 3937 Option: Easing 3938 *******************/ 3939 3940 opts.easing = getEasing(opts.easing, opts.duration); 3941 3942 /********************** 3943 Option: Callbacks 3944 **********************/ 3945 3946 /* Callbacks must functions. Otherwise, default to null. */ 3947 if (opts.begin && !Type.isFunction(opts.begin)) { 3948 opts.begin = null; 3949 } 3950 3951 if (opts.progress && !Type.isFunction(opts.progress)) { 3952 opts.progress = null; 3953 } 3954 3955 if (opts.complete && !Type.isFunction(opts.complete)) { 3956 opts.complete = null; 3957 } 3958 3959 /********************************* 3960 Option: Display & Visibility 3961 *********************************/ 3962 3963 /* Refer to Velocity's documentation (VelocityJS.org/#displayAndVisibility) for a description of the display and visibility options' behavior. */ 3964 /* Note: We strictly check for undefined instead of falsiness because display accepts an empty string value. */ 3965 if (opts.display !== undefined && opts.display !== null) { 3966 opts.display = opts.display.toString().toLowerCase(); 3967 3968 /* Users can pass in a special "auto" value to instruct Velocity to set the element to its default display value. */ 3969 if (opts.display === "auto") { 3970 opts.display = Velocity.CSS.Values.getDisplayType(element); 3971 } 3972 } 3973 3974 if (opts.visibility !== undefined && opts.visibility !== null) { 3975 opts.visibility = opts.visibility.toString().toLowerCase(); 3976 } 3977 3978 /********************** 3979 Option: mobileHA 3980 **********************/ 3981 3982 /* When set to true, and if this is a mobile device, mobileHA automatically enables hardware acceleration (via a null transform hack) 3983 on animating elements. HA is removed from the element at the completion of its animation. */ 3984 /* Note: Android Gingerbread doesn't support HA. If a null transform hack (mobileHA) is in fact set, it will prevent other tranform subproperties from taking effect. */ 3985 /* Note: You can read more about the use of mobileHA in Velocity's documentation: VelocityJS.org/#mobileHA. */ 3986 opts.mobileHA = (opts.mobileHA && Velocity.State.isMobile && !Velocity.State.isGingerbread); 3987 3988 /*********************** 3989 Part II: Queueing 3990 ***********************/ 3991 3992 /* When a set of elements is targeted by a Velocity call, the set is broken up and each element has the current Velocity call individually queued onto it. 3993 In this way, each element's existing queue is respected; some elements may already be animating and accordingly should not have this current Velocity call triggered immediately. */ 3994 /* In each queue, tween data is processed for each animating property then pushed onto the call-wide calls array. When the last element in the set has had its tweens processed, 3995 the call array is pushed to Velocity.State.calls for live processing by the requestAnimationFrame tick. */ 3996 function buildQueue (next) { 3997 3998 /******************* 3999 Option: Begin 4000 *******************/ 4001 4002 /* The begin callback is fired once per call -- not once per elemenet -- and is passed the full raw DOM element set as both its context and its first argument. */ 4003 if (opts.begin && elementsIndex === 0) { 4004 /* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Velocity itself. */ 4005 try { 4006 opts.begin.call(elements, elements); 4007 } catch (error) { 4008 setTimeout(function() { throw error; }, 1); 4009 } 4010 } 4011 4012 /***************************************** 4013 Tween Data Construction (for Scroll) 4014 *****************************************/ 4015 4016 /* Note: In order to be subjected to chaining and animation options, scroll's tweening is routed through Velocity as if it were a standard CSS property animation. */ 4017 if (action === "scroll") { 4018 /* The scroll action uniquely takes an optional "offset" option -- specified in pixels -- that offsets the targeted scroll position. */ 4019 var scrollDirection = (/^x$/i.test(opts.axis) ? "Left" : "Top"), 4020 scrollOffset = parseFloat(opts.offset) || 0, 4021 scrollPositionCurrent, 4022 scrollPositionCurrentAlternate, 4023 scrollPositionEnd; 4024 4025 /* Scroll also uniquely takes an optional "container" option, which indicates the parent element that should be scrolled -- 4026 as opposed to the browser window itself. This is useful for scrolling toward an element that's inside an overflowing parent element. */ 4027 if (opts.container) { 4028 /* Ensure that either a jQuery object or a raw DOM element was passed in. */ 4029 if (Type.isWrapped(opts.container) || Type.isNode(opts.container)) { 4030 /* Extract the raw DOM element from the jQuery wrapper. */ 4031 opts.container = opts.container[0] || opts.container; 4032 /* Note: Unlike other properties in Velocity, the browser's scroll position is never cached since it so frequently changes 4033 (due to the user's natural interaction with the page). */ 4034 scrollPositionCurrent = opts.container["scroll" + scrollDirection]; /* GET */ 4035 4036 /* $.position() values are relative to the container's currently viewable area (without taking into account the container's true dimensions 4037 -- say, for example, if the container was not overflowing). Thus, the scroll end value is the sum of the child element's position *and* 4038 the scroll container's current scroll position. */ 4039 /* Note: jQuery does not offer a utility alias for $.position(), so we have to incur jQuery object conversion here. 4040 This syncs up with an ensuing batch of GETs, so it fortunately does not trigger layout thrashing. */ 4041 scrollPositionEnd = (scrollPositionCurrent + $(element).position()[scrollDirection.toLowerCase()]) + scrollOffset; /* GET */ 4042 /* If a value other than a jQuery object or a raw DOM element was passed in, default to null so that this option is ignored. */ 4043 } else { 4044 opts.container = null; 4045 } 4046 } else { 4047 /* If the window itself is being scrolled -- not a containing element -- perform a live scroll position lookup using 4048 the appropriate cached property names (which differ based on browser type). */ 4049 scrollPositionCurrent = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + scrollDirection]]; /* GET */ 4050 /* When scrolling the browser window, cache the alternate axis's current value since window.scrollTo() doesn't let us change only one value at a time. */ 4051 scrollPositionCurrentAlternate = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + (scrollDirection === "Left" ? "Top" : "Left")]]; /* GET */ 4052 4053 /* Unlike $.position(), $.offset() values are relative to the browser window's true dimensions -- not merely its currently viewable area -- 4054 and therefore end values do not need to be compounded onto current values. */ 4055 scrollPositionEnd = $(element).offset()[scrollDirection.toLowerCase()] + scrollOffset; /* GET */ 4056 } 4057 4058 /* Since there's only one format that scroll's associated tweensContainer can take, we create it manually. */ 4059 tweensContainer = { 4060 scroll: { 4061 rootPropertyValue: false, 4062 startValue: scrollPositionCurrent, 4063 currentValue: scrollPositionCurrent, 4064 endValue: scrollPositionEnd, 4065 unitType: "", 4066 easing: opts.easing, 4067 scrollData: { 4068 container: opts.container, 4069 direction: scrollDirection, 4070 alternateValue: scrollPositionCurrentAlternate 4071 } 4072 }, 4073 element: element 4074 }; 4075 4076 if (Velocity.debug) console.log("tweensContainer (scroll): ", tweensContainer.scroll, element); 4077 4078 /****************************************** 4079 Tween Data Construction (for Reverse) 4080 ******************************************/ 4081 4082 /* Reverse acts like a "start" action in that a property map is animated toward. The only difference is 4083 that the property map used for reverse is the inverse of the map used in the previous call. Thus, we manipulate 4084 the previous call to construct our new map: use the previous map's end values as our new map's start values. Copy over all other data. */
4085 /* Note: Reverse can be directly called via the "reverse" parameter, or it can be indirectly triggered via the loop option. (Loops are composed of multiple reverses.) */ 4086 /* Note: Reverse calls do not need to be consecutively chained onto a currently-animating element in order to operate on cached values; 4087 there is no harm to reverse being called on a potentially stale data cache since reverse's behavior is simply defined 4088 as reverting to the element's values as they were prior to the previous *Velocity* call. */ 4089 } else if (action === "reverse") { 4090 /* Abort if there is no prior animation data to reverse to. */ 4091 if (!Data(element).tweensContainer) { 4092 /* Dequeue the element so that this queue entry releases itself immediately, allowing subsequent queue entries to run. */ 4093 $.dequeue(element, opts.queue); 4094 4095 return; 4096 } else { 4097 /********************* 4098 Options Parsing 4099 *********************/ 4100 4101 /* If the element was hidden via the display option in the previous call, 4102 revert display to "auto" prior to reversal so that the element is visible again. */ 4103 if (Data(element).opts.display === "none") { 4104 Data(element).opts.display = "auto"; 4105 } 4106 4107 if (Data(element).opts.visibility === "hidden") { 4108 Data(element).opts.visibility = "visible"; 4109 } 4110 4111 /* If the loop option was set in the previous call, disable it so that "reverse" calls aren't recursively generated. 4112 Further, remove the previous call's callback options; typically, users do not want these to be refired. */ 4113 Data(element).opts.loop = false; 4114 Data(element).opts.begin = null; 4115 Data(element).opts.complete = null; 4116 4117 /* Since we're extending an opts object that has already been extended with the defaults options object, 4118 we remove non-explicitly-defined properties that are auto-assigned values. */ 4119 if (!options.easing) { 4120 delete opts.easing; 4121 } 4122 4123 if (!options.duration) { 4124 delete opts.duration; 4125 } 4126 4127 /* The opts object used for reversal is an extension of the options object optionally passed into this 4128 reverse call plus the options used in the previous Velocity call. */ 4129 opts = $.extend({}, Data(element).opts, opts); 4130 4131 /************************************* 4132 Tweens Container Reconstruction 4133 *************************************/ 4134 4135 /* Create a deepy copy (indicated via the true flag) of the previous call's tweensContainer. */ 4136 var lastTweensContainer = $.extend(true, {}, Data(element).tweensContainer); 4137 4138 /* Manipulate the previous tweensContainer by replacing its end values and currentValues with its start values. */ 4139 for (var lastTween in lastTweensContainer) { 4140 /* In addition to tween data, tweensContainers contain an element property that we ignore here. */ 4141 if (lastTween !== "element") { 4142 var lastStartValue = lastTweensContainer[lastTween].startValue; 4143 4144 lastTweensContainer[lastTween].startValue = lastTweensContainer[lastTween].currentValue = lastTweensContainer[lastTween].endValue; 4145 lastTweensContainer[lastTween].endValue = lastStartValue; 4146 4147 /* Easing is the only option that embeds into the individual tween data (since it can be defined on a per-property basis). 4148 Accordingly, every property's easing value must be updated when an options object is passed in with a reverse call. 4149 The side effect of this extensibility is that all per-property easing values are forcefully reset to the new value. */ 4150 if (!Type.isEmptyObject(options)) { 4151 lastTweensContainer[lastTween].easing = opts.easing; 4152 } 4153 4154 if (Velocity.debug) console.log("reverse tweensContainer (" + lastTween + "): " + JSON.stringify(lastTweensContainer[lastTween]), element); 4155 } 4156 } 4157 4158 tweensContainer = lastTweensContainer; 4159 } 4160 4161 /***************************************** 4162 Tween Data Construction (for Start) 4163 *****************************************/ 4164 4165 } else if (action === "start") { 4166 4167 /************************* 4168 Value Transferring 4169 *************************/ 4170 4171 /* If this queue entry follows a previous Velocity-initiated queue entry *and* if this entry was created 4172 while the element was in the process of being animated by Velocity, then this current call is safe to use 4173 the end values from the prior call as its start values. Velocity attempts to perform this value transfer 4174 process whenever possible in order to avoid requerying the DOM. */ 4175 /* If values aren't transferred from a prior call and start values were not forcefed by the user (more on this below), 4176 then the DOM is queried for the element's current values as a last resort. */ 4177 /* Note: Conversely, animation reversal (and looping) *always* perform inter-call value transfers; they never requery the DOM. */ 4178 var lastTweensContainer; 4179 4180 /* The per-element isAnimating flag is used to indicate whether it's safe (i.e. the data isn't stale) 4181 to transfer over end values to use as start values. If it's set to true and there is a previous 4182 Velocity call to pull values from, do so. */ 4183 if (Data(element).tweensContainer && Data(element).isAnimating === true) { 4184 lastTweensContainer = Data(element).tweensContainer; 4185 } 4186 4187 /*************************** 4188 Tween Data Calculation 4189 ***************************/ 4190 4191 /* This function parses property data and defaults endValue, easing, and startValue as appropriate. */ 4192 /* Property map values can either take the form of 1) a single value representing the end value, 4193 or 2) an array in the form of [ endValue, [, easing] [, startValue] ]. 4194 The optional third parameter is a forcefed startValue to be used instead of querying the DOM for 4195 the element's current value. Read Velocity's docmentation to learn more about forcefeeding: VelocityJS.org/#forcefeeding */ 4196 function parsePropertyValue (valueData, skipResolvingEasing) { 4197 var endValue = undefined, 4198 easing = undefined, 4199 startValue = undefined; 4200 4201 /* Handle the array format, which can be structured as one of three potential overloads: 4202 A) [ endValue, easing, startValue ], B) [ endValue, easing ], or C) [ endValue, startValue ] */ 4203 if (Type.isArray(valueData)) { 4204 /* endValue is always the first item in the array. Don't bother validating endValue's value now 4205 since the ensuing property cycling logic does that. */ 4206 endValue = valueData[0]; 4207 4208 /* Two-item array format: If the second item is a number, function, or hex string, treat it as a 4209 start value since easings can only be non-hex strings or arrays. */ 4210 if ((!Type.isArray(valueData[1]) && /^[\d-]/.test(valueData[1])) || Type.isFunction(valueData[1]) || CSS.RegEx.isHex.test(valueData[1])) { 4211 startValue = valueData[1]; 4212 /* Two or three-item array: If the second item is a non-hex string or an array, treat it as an easing. */ 4213 } else if ((Type.isString(valueData[1]) && !CSS.RegEx.isHex.test(valueData[1])) || Type.isArray(valueData[1])) { 4214 easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration); 4215 4216 /* Don't bother validating startValue's value now since the ensuing property cycling logic inherently does that. */ 4217 if (valueData[2] !== undefined) { 4218 startValue = valueData[2]; 4219 } 4220 } 4221 /* Handle the single-value format. */ 4222 } else { 4223 endValue = valueData; 4224 } 4225 4226 /* Default to the call's easing if a per-property easing type was not defined. */ 4227 if (!skipResolvingEasing) { 4228 easing = easing || opts.easing; 4229 } 4230 4231 /* If functions were passed in as values, pass the function the current element as its context, 4232 plus the element's index and the element set's size as arguments. Then, assign the returned value. */
4233 if (Type.isFunction(endValue)) { 4234 endValue = endValue.call(element, elementsIndex, elementsLength); 4235 } 4236 4237 if (Type.isFunction(startValue)) { 4238 startValue = startValue.call(element, elementsIndex, elementsLength); 4239 } 4240 4241 /* Allow startValue to be left as undefined to indicate to the ensuing code that its value was not forcefed. */ 4242 return [ endValue || 0, easing, startValue ]; 4243 } 4244 4245 /* Cycle through each property in the map, looking for shorthand color properties (e.g. "color" as opposed to "colorRed"). Inject the corresponding 4246 colorRed, colorGreen, and colorBlue RGB component tweens into the propertiesMap (which Velocity understands) and remove the shorthand property. */ 4247 $.each(propertiesMap, function(property, value) { 4248 /* Find shorthand color properties that have been passed a hex string. */ 4249 if (RegExp("^" + CSS.Lists.colors.join("$|^") + "$").test(property)) { 4250 /* Parse the value data for each shorthand. */ 4251 var valueData = parsePropertyValue(value, true), 4252 endValue = valueData[0], 4253 easing = valueData[1], 4254 startValue = valueData[2]; 4255 4256 if (CSS.RegEx.isHex.test(endValue)) { 4257 /* Convert the hex strings into their RGB component arrays. */ 4258 var colorComponents = [ "Red", "Green", "Blue" ], 4259 endValueRGB = CSS.Values.hexToRgb(endValue), 4260 startValueRGB = startValue ? CSS.Values.hexToRgb(startValue) : undefined; 4261 4262 /* Inject the RGB component tweens into propertiesMap. */ 4263 for (var i = 0; i < colorComponents.length; i++) { 4264 var dataArray = [ endValueRGB[i] ]; 4265 4266 if (easing) { 4267 dataArray.push(easing); 4268 } 4269 4270 if (startValueRGB !== undefined) { 4271 dataArray.push(startValueRGB[i]); 4272 } 4273 4274 propertiesMap[property + colorComponents[i]] = dataArray; 4275 } 4276 4277 /* Remove the intermediary shorthand property entry now that we've processed it. */ 4278 delete propertiesMap[property]; 4279 } 4280 } 4281 }); 4282 4283 /* Create a tween out of each property, and append its associated data to tweensContainer. */ 4284 for (var property in propertiesMap) { 4285 4286 /************************** 4287 Start Value Sourcing 4288 **************************/ 4289 4290 /* Parse out endValue, easing, and startValue from the property's data. */ 4291 var valueData = parsePropertyValue(propertiesMap[property]), 4292 endValue = valueData[0], 4293 easing = valueData[1], 4294 startValue = valueData[2]; 4295 4296 /* Now that the original property name's format has been used for the parsePropertyValue() lookup above, 4297 we force the property to its camelCase styling to normalize it for manipulation. */ 4298 property = CSS.Names.camelCase(property); 4299 4300 /* In case this property is a hook, there are circumstances where we will intend to work on the hook's root property and not the hooked subproperty. */ 4301 var rootProperty = CSS.Hooks.getRoot(property), 4302 rootPropertyValue = false;
4303 4304 /* Properties that are not supported by the browser (and do not have an associated normalization) will 4305 inherently produce no style changes when set, so they are skipped in order to decrease animation tick overhead. 4306 Property support is determined via prefixCheck(), which returns a false flag when no supported is detected. */ 4307 /* Note: Since SVG elements have some of their properties directly applied as HTML attributes, 4308 there is no way to check for their explicit browser support, and so we skip skip this check for them. */ 4309 if (!Data(element).isSVG && CSS.Names.prefixCheck(rootProperty)[1] === false && CSS.Normalizations.registered[rootProperty] === undefined) { 4310 if (Velocity.debug) console.log("Skipping [" + rootProperty + "] due to a lack of browser support."); 4311 4312 continue; 4313 } 4314 4315 /* If the display option is being set to a non-"none" (e.g. "block") and opacity (filter on IE<=8) is being 4316 animated to an endValue of non-zero, the user's intention is to fade in from invisible, thus we forcefeed opacity 4317 a startValue of 0 if its startValue hasn't already been sourced by value transferring or prior forcefeeding. */ 4318 if (((opts.display !== undefined && opts.display !== null && opts.display !== "none") || (opts.visibility !== undefined && opts.visibility !== "hidden")) && /opacity|filter/.test(property) && !startValue && endValue !== 0) { 4319 startValue = 0; 4320 } 4321 4322 /* If values have been transferred from the previous Velocity call, extract the endValue and rootPropertyValue 4323 for all of the current call's properties that were *also* animated in the previous call. */ 4324 /* Note: Value transferring can optionally be disabled by the user via the _cacheValues option. */ 4325 if (opts._cacheValues && lastTweensContainer && lastTweensContainer[property]) { 4326 if (startValue === undefined) { 4327 startValue = lastTweensContainer[property].endValue + lastTweensContainer[property].unitType; 4328 } 4329 4330 /* The previous call's rootPropertyValue is extracted from the element's data cache since that's the 4331 instance of rootPropertyValue that gets freshly updated by the tweening process, whereas the rootPropertyValue 4332 attached to the incoming lastTweensContainer is equal to the root property's value prior to any tweening. */ 4333 rootPropertyValue = Data(element).rootPropertyValueCache[rootProperty]; 4334 /* If values were not transferred from a previous Velocity call, query the DOM as needed. */ 4335 } else { 4336 /* Handle hooked properties. */ 4337 if (CSS.Hooks.registered[property]) { 4338 if (startValue === undefined) { 4339 rootPropertyValue = CSS.getPropertyValue(element, rootProperty); /* GET */ 4340 /* Note: The following getPropertyValue() call does not actually trigger a DOM query; 4341 getPropertyValue() will extract the hook from rootPropertyValue. */ 4342 startValue = CSS.getPropertyValue(element, property, rootPropertyValue); 4343 /* If startValue is already defined via forcefeeding, do not query the DOM for the root property's value; 4344 just grab rootProperty's zero-value template from CSS.Hooks. This overwrites the element's actual 4345 root property value (if one is set), but this is acceptable since the primary reason users forcefeed is 4346 to avoid DOM queries, and thus we likewise avoid querying the DOM for the root property's value. */ 4347 } else { 4348 /* Grab this hook's zero-value template, e.g. "0px 0px 0px black". */ 4349 rootPropertyValue = CSS.Hooks.templates[rootProperty][1]; 4350 } 4351 /* Handle non-hooked properties that haven't already been defined via forcefeeding. */ 4352 } else if (startValue === undefined) { 4353 startValue = CSS.getPropertyValue(element, property); /* GET */ 4354 } 4355 } 4356 4357 /************************** 4358 Value Data Extraction 4359 **************************/ 4360 4361 var separatedValue, 4362 endValueUnitType, 4363 startValueUnitType, 4364 operator = false;
vendor: 4,539 bytes, lines 4365-4440
4365 4366 /* Separates a property value into its numeric value and its unit type. */ 4367 function separateValue (property, value) { 4368 var unitType, 4369 numericValue; 4370 4371 numericValue = (value || "0") 4372 .toString() 4373 .toLowerCase() 4374 /* Match the unit type at the end of the value. */ 4375 .replace(/[%A-z]+$/, function(match) { 4376 /* Grab the unit type. */ 4377 unitType = match; 4378 4379 /* Strip the unit type off of value. */ 4380 return ""; 4381 }); 4382 4383 /* If no unit type was supplied, assign one that is appropriate for this property (e.g. "deg" for rotateZ or "px" for width). */ 4384 if (!unitType) { 4385 unitType = CSS.Values.getUnitType(property); 4386 } 4387 4388 return [ numericValue, unitType ]; 4389 } 4390 4391 /* Separate startValue. */ 4392 separatedValue = separateValue(property, startValue); 4393 startValue = separatedValue[0]; 4394 startValueUnitType = separatedValue[1]; 4395 4396 /* Separate endValue, and extract a value operator (e.g. "+=", "-=") if one exists. */ 4397 separatedValue = separateValue(property, endValue); 4398 endValue = separatedValue[0].replace(/^([+-\/*])=/, function(match, subMatch) { 4399 operator = subMatch; 4400 4401 /* Strip the operator off of the value. */ 4402 return ""; 4403 }); 4404 endValueUnitType = separatedValue[1]; 4405 4406 /* Parse float values from endValue and startValue. Default to 0 if NaN is returned. */ 4407 startValue = parseFloat(startValue) || 0; 4408 endValue = parseFloat(endValue) || 0; 4409 4410 /*************************************** 4411 Property-Specific Value Conversion 4412 ***************************************/ 4413 4414 /* Custom support for properties that don't actually accept the % unit type, but where pollyfilling is trivial and relatively foolproof. */ 4415 if (endValueUnitType === "%") { 4416 /* A %-value fontSize/lineHeight is relative to the parent's fontSize (as opposed to the parent's dimensions), 4417 which is identical to the em unit's behavior, so we piggyback off of that. */ 4418 if (/^(fontSize|lineHeight)$/.test(property)) { 4419 /* Convert % into an em decimal value. */ 4420 endValue = endValue / 100; 4421 endValueUnitType = "em"; 4422 /* For scaleX and scaleY, convert the value into its decimal format and strip off the unit type. */ 4423 } else if (/^scale/.test(property)) { 4424 endValue = endValue / 100; 4425 endValueUnitType = ""; 4426 /* For RGB components, take the defined percentage of 255 and strip off the unit type. */ 4427 } else if (/(Red|Green|Blue)$/i.test(property)) { 4428 endValue = (endValue / 100) * 255; 4429 endValueUnitType = ""; 4430 } 4431 } 4432 4433 /*************************** 4434 Unit Ratio Calculation 4435 ***************************/ 4436 4437 /* When queried, the browser returns (most) CSS property values in pixels. Therefore, if an endValue with a unit type of 4438 %, em, or rem is animated toward, startValue must be converted from pixels into the same unit type as endValue in order 4439 for value manipulation logic (increment/decrement) to proceed. Further, if the startValue was forcefed or transferred 4440 from a previous call, startValue may al
4440so not be in pixels. Unit conversion logic therefore consists of two steps: 4441 1) Calculating the ratio of %/em/rem/vh/vw relative to pixels 4442 2) Converting startValue into the same unit of measurement as endValue based on these ratios. */ 4443 /* Unit conversion ratios are calculated by inserting a sibling node next to the target node, copying over its position property, 4444 setting values with the target unit type then comparing the returned pixel value. */ 4445 /* Note: Even if only one of these unit types is being animated, all unit ratios are calculated at once since the overhead 4446 of batching the SETs and GETs together upfront outweights the potential overhead 4447 of layout thrashing caused by re-querying for uncalculated ratios for subsequently-processed properties. */ 4448 /* Todo: Shift this logic into the calls' first tick instance so that it's synced with RAF. */ 4449 function calculateUnitRatios () { 4450 4451 /************************ 4452 Same Ratio Checks 4453 ************************/ 4454 4455 /* The properties below are used to determine whether the element differs sufficiently from this call's 4456 previously iterated element to also differ in its unit conversion ratios. If the properties match up with those 4457 of the prior element, the prior element's conversion ratios are used. Like most optimizations in Velocity, 4458 this is done to minimize DOM querying. */ 4459 var sameRatioIndicators = { 4460 myParent: element.parentNode || document.body, /* GET */ 4461 position: CSS.getPropertyValue(element, "position"), /* GET */ 4462 fontSize: CSS.getPropertyValue(element, "fontSize") /* GET */ 4463 }, 4464 /* Determine if the same % ratio can be used. % is based on the element's position value and its parent's width and height dimensions. */ 4465 samePercentRatio = ((sameRatioIndicators.position === callUnitConversionData.lastPosition) && (sameRatioIndicators.myParent === callUnitConversionData.lastParent)), 4466 /* Determine if the same em ratio can be used. em is relative to the element's fontSize. */ 4467 sameEmRatio = (sameRatioIndicators.fontSize === callUnitConversionData.lastFontSize); 4468 4469 /* Store these ratio indicators call-wide for the next element to compare against. */ 4470 callUnitConversionData.lastParent = sameRatioIndicators.myParent; 4471 callUnitConversionData.lastPosition = sameRatioIndicators.position; 4472 callUnitConversionData.lastFontSize = sameRatioIndicators.fontSize; 4473 4474 /*************************** 4475 Element-Specific Units 4476 ***************************/ 4477 4478 /* Note: IE8 rounds to the nearest pixel when returning CSS values, thus we perform conversions using a measurement 4479 of 100 (instead of 1) to give our ratios a precision of at least 2 decimal values. */ 4480 var measurement = 100, 4481 unitRatios = {}; 4482 4483 if (!sameEmRatio || !samePercentRatio) { 4484 var dummy = Data(element).isSVG ? document.createElementNS("http://www.w3.org/2000/svg", "rect") : document.createElement("div"); 4485 4486 Velocity.init(dummy); 4487 sameRatioIndicators.myParent.appendChild(dummy); 4488 4489 /* To accurately and consistently calculate conversion ratios, the element's cascaded overflow and box-sizing are stripped. 4490 Similarly, since width/height can be artificially constrained by their min-/max- equivalents, these are controlled for as well. */ 4491 /* Note: Overflow must be also be c
4491ontrolled for per-axis since the overflow property overwrites its per-axis values. */ 4492 $.each([ "overflow", "overflowX", "overflowY" ], function(i, property) { 4493 Velocity.CSS.setPropertyValue(dummy, property, "hidden"); 4494 }); 4495 Velocity.CSS.setPropertyValue(dummy, "position", sameRatioIndicators.position); 4496 Velocity.CSS.setPropertyValue(dummy, "fontSize", sameRatioIndicators.fontSize); 4497 Velocity.CSS.setPropertyValue(dummy, "boxSizing", "content-box"); 4498 4499 /* width and height act as our proxy properties for measuring the horizontal and vertical % ratios. */ 4500 $.each([ "minWidth", "maxWidth", "width", "minHeight", "maxHeight", "height" ], function(i, property) { 4501 Velocity.CSS.setPropertyValue(dummy, property, measurement + "%"); 4502 }); 4503 /* paddingLeft arbitrarily acts as our proxy property for the em ratio. */ 4504 Velocity.CSS.setPropertyValue(dummy, "paddingLeft", measurement + "em"); 4505 4506 /* Divide the returned value by the measurement to get the ratio between 1% and 1px. Default to 1 since working with 0 can produce Infinite. */ 4507 unitRatios.percentToPxWidth = callUnitConversionData.lastPercentToPxWidth = (parseFloat(CSS.getPropertyValue(dummy, "width", null, true)) || 1) / measurement; /* GET */ 4508 unitRatios.percentToPxHeight = callUnitConversionData.lastPercentToPxHeight = (parseFloat(CSS.getPropertyValue(dummy, "height", null, true)) || 1) / measurement; /* GET */ 4509 unitRatios.emToPx = callUnitConversionData.lastEmToPx = (parseFloat(CSS.getPropertyValue(dummy, "paddingLeft")) || 1) / measurement; /* GET */ 4510 4511 sameRatioIndicators.myParent.removeChild(dummy); 4512 } else { 4513 unitRatios.emToPx = callUnitConversionData.lastEmToPx; 4514 unitRatios.percentToPxWidth = callUnitConversionData.lastPercentToPxWidth; 4515 unitRatios.percentToPxHeight = callUnitConversionData.lastPercentToPxHeight; 4516 } 4517 4518 /*************************** 4519 Element-Agnostic Units 4520 ***************************/ 4521 4522 /* Whereas % and em ratios are determined on a per-element basis, the rem unit only needs to be checked 4523 once per call since it's exclusively dependant upon document.body's fontSize. If this is the first time 4524 that calculateUnitRatios() is being run during this call, remToPx will still be set to its default value of null, 4525 so we calculate it now. */ 4526 if (callUnitConversionData.remToPx === null) { 4527 /* Default to browsers' default fontSize of 16px in the case of 0. */ 4528 callUnitConversionData.remToPx = parseFloat(CSS.getPropertyValue(document.body, "fontSize")) || 16; /* GET */ 4529 } 4530 4531 /* Similarly, viewport units are %-relative to the window's inner dimensions. */ 4532 if (callUnitConversionData.vwToPx === null) { 4533 callUnitConversionData.vwToPx = parseFloat(window.innerWidth) / 100; /* GET */ 4534 callUnitConversionData.vhToPx = parseFloat(window.innerHeight) / 100; /* GET */ 4535 } 4536 4537 unitRatios.remToPx = callUnitConversionData.remToPx; 4538 unitRatios.vwToPx = callUnitConversionData.vwToPx; 4539 unitRatios.vhToPx = callUnitConversionData.vhToPx; 4540 4541 if (Velocity.debug >= 1) console.log("Unit ratios: " + JSON.stringify(unitRatios), element); 4542 4543 return unitRatios; 4544 } 4545 4546 /******************** 4547 Unit Conversion 4548 ********************/ 4549 4550 /* The * and / operators, which are not passed in with an associated unit, inherently use startValue's unit. Skip value and unit conversion. */ 4551 if (/[\/*]/.test(operator)) { 4552 endValueUnitType = startValueUnitType; 4553 /* If startValue and endValue differ in unit type, convert startValue into the same unit type as endValue so that if endValueUnitType 4554 is a relative unit (%, em, rem), the values set during tweening will continue to be accurately relative even if the metrics they depen
4554d 4555 on are dynamically changing during the course of the animation. Conversely, if we always normalized into px and used px for setting values, the px ratio 4556 would become stale if the original unit being animated toward was relative and the underlying metrics change during the animation. */ 4557 /* Since 0 is 0 in any unit type, no conversion is necessary when startValue is 0 -- we just start at 0 with endValueUnitType. */ 4558 } else if ((startValueUnitType !== endValueUnitType) && startValue !== 0) { 4559 /* Unit conversion is also skipped when endValue is 0, but *startValueUnitType* must be used for tween values to remain accurate. */ 4560 /* Note: Skipping unit conversion here means that if endValueUnitType was originally a relative unit, the animation won't relatively 4561 match the underlying metrics if they change, but this is acceptable since we're animating toward invisibility instead of toward visibility, 4562 which remains past the point of the animation's completion. */ 4563 if (endValue === 0) { 4564 endValueUnitType = startValueUnitType; 4565 } else { 4566 /* By this point, we cannot avoid unit conversion (it's undesirable since it causes layout thrashing). 4567 If we haven't already, we trigger calculateUnitRatios(), which runs once per element per call. */ 4568 elementUnitConversionData = elementUnitConversionData || calculateUnitRatios(); 4569 4570 /* The following RegEx matches CSS properties that have their % values measured relative to the x-axis. */ 4571 /* Note: W3C spec mandates that all of margin and padding's properties (even top and bottom) are %-relative to the *width* of the parent element. */ 4572 var axis = (/margin|padding|left|right|width|text|word|letter/i.test(property) || /X$/.test(property) || property === "x") ? "x" : "y"; 4573 4574 /* In order to avoid generating n^2 bespoke conversion functions, unit conversion is a two-step process: 4575 1) Convert startValue into pixels. 2) Convert this new pixel value into endValue's unit type. */ 4576 switch (startValueUnitType) { 4577 case "%": 4578 /* Note: translateX and translateY are the only properties that are %-relative to an element's own dimensions -- not its parent's dimensions. 4579 Velocity does not include a special conversion process to account for this behavior. Therefore, animating translateX/Y from a % value 4580 to a non-% value will produce an incorrect start value. Fortunately, this sort of cross-unit conversion is rarely done by users in practice. */ 4581 startValue *= (axis === "x" ? elementUnitConversionData.percentToPxWidth : elementUnitConversionData.percentToPxHeight); 4582 break; 4583 4584 case "px": 4585 /* px acts as our midpoint in the unit conversion process; do nothing. */ 4586 break; 4587 4588 default: 4589 startValue *= elementUnitConversionData[startValueUnitType + "ToPx"]; 4590 } 4591 4592 /* Invert the px ratios to convert into to the target unit. */ 4593 switch (endValueUnitType) { 4594 case "%": 4595 startValue *= 1 / (axis === "x" ? elementUnitConversionData.percentToPxWidth : elementUnitConversionData.percentToPxHeight); 4596 break; 4597 4598 case "px": 4599 /* startValue is already in px, do nothing; we're done. */ 4600 break; 4601 4602 default: 4603 startValue *= 1 / elementUnitConversionData[endValueUnitType + "ToPx"]; 4604 } 4605 } 4606 } 4607 4608 /********************* 4609 Relative Values 4610 *********************/ 4611 4612 /* Operator logic must be performed last since it requires unit-normalized start and end values. */ 4613 /* Note: Relative *percent values* do not behave how most people think; while one would expect "+=50%" 4614 to increase the property 1.5x its current value, it in fact increases the percent units in absolute terms: 4615 50 points is added on top of the current % value. */ 4616 switch (operator) { 4617 case "+": 4618 endValue = startValue + endValue; 4619 break; 4620 4621 case "-": 4622 endValue = startValue - endValue; 4623 break; 4624 4625 case "*": 4626 endValue = startValue * endValue; 4627 break; 4628 4629 case "/": 4630 endValue = startValue / endValue; 4631 break; 4632 } 4633 4634 /************************** 4635 tweensContainer Push 4636 **************************/ 4637 4638 /* Construct the per-property tween object, and push it to the element's tweensContainer. */ 4639 tweensContainer[property] = { 4640 rootPropertyValue: rootPropertyValue, 4641 startValue: startValue, 4642 currentValue: startValue, 4643 endValue: endValue, 4644 unitType: endValueUnitType, 4645 easing: easing 4646 }; 4647 4648 if (Velocity.debug) console.log("tweensContainer (" + property + "): " + JSON.stringify(tweensContainer[property]), element); 4649 } 4650 4651 /* Along with its property data, store a reference to the element itself onto tweensContainer. */ 4652 tweensContainer.element = element; 4653 } 4654 4655 /***************** 4656 Call Push 4657 *****************/ 4658 4659 /* Note: tweensContainer can be empty if all of the properties in this call's property map were skipped due to not 4660 being supported by the browser. The element property is used for checking that the tweensContainer has been appended to. */ 4661 if (tweensContainer.element) { 4662 /* Apply the "velocity-animating" indicator class. */ 4663 CSS.Values.addClass(element, "velocity-animating"); 4664 4665 /* The call array houses the tweensContainers for each element being animated in the current call. */ 4666 call.push(tweensContainer); 4667 4668 /* Store the tweensContainer and options if we're working on the default effects queue, so that they can be used by the reverse command. */ 4669 if (opts.queue === "") { 4670 Data(element).tweensContainer = tweensContainer; 4671 Data(element).opts = opts; 4672 } 4673 4674 /* Switch on the element's animating flag. */ 4675 Data(element).isAnimating = true; 4676 4677 /* Once the final element in this call's element set has been processed, push the call array onto 4678 Velocity.State.calls for the animation tick to immediately begin processing. */ 4679 if (elementsIndex === elementsLength - 1) { 4680 /* To speed up iterating over this array, it is compacted (falsey items -- calls that have completed -- are removed) 4681 when its length has ballooned to a point that can impact tick performance. This only becomes necessary when animation 4682 has been continuous with many elements over a long period of time; whenever all active calls are completed, completeCall() clears Velocity.State.calls. */ 4683 if (Velocity.State.calls.length > 10000) { 4684 Velocity.State.calls = compactSparseArray(Velocity.State.calls); 4685 } 4686 4687 /* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container. 4688 Anything on this call container is subjected to tick() processing. */ 4689 Velocity.State.calls.push([ call, elements, opts, null, promiseData.resolver ]); 4690 4691 /* If the animation tick isn't running, start it. (Velocity shuts it off when there are no active calls to process.) */ 4692 if (Velocity.State.isTicking === false) { 4693 Velocity.State.isTicking = true; 4694 4695 /* Start the tick loop. */ 4696 tick(); 4697 } 4698 } else { 4699 elementsIndex++; 4700 } 4701 } 4702 } 4703 4704 /* When the queue option is set to false, the call skips the element's queue and fires immediately. */ 4705 if (opts.queue === false) { 4706 /* Since this buildQueue call doesn't respect the element's existing queue (which is where a delay option would have been appended), 4707 we manually inject the delay property here with an explicit setTimeout. */ 4708 if (opts.delay) { 4709 setTimeout(buildQueue, opts.delay); 4710 } else { 4711 buildQueue(); 4712 } 4713 /* Otherwise, the call undergoes element queueing as normal. */ 4714 /* Note: To interoperate with jQuery, Velocity uses jQuery's own $.queue() stack for queuing logic. */ 4715 } else { 4716 $.queue(element, opts.queue, function(next, clearQueue) { 4717 /* If the clearQueue flag was passed in by the stop command, resolve this call's promise. (Promises can only be resolved once, 4718 so it's fine if this is repeatedly triggered for each element in the associated call.) */ 4719 if (clearQueue === true) { 4720 if (promiseData.promise) { 4721 promiseData.resolver(elements); 4722 } 4723 4724 /* Do not continue with animation queueing. */ 4725 return true; 4726 } 4727 4728 /* This flag indicates to the upcoming completeCall() function that this queue entry was initiated by Velocity. 4729 See completeCall() for further details. */ 4730 Velocity.velocityQueueEntryFlag = true; 4731 4732 buildQueue(next); 4733 }); 4734 } 4735 4736 /********************* 4737 Auto-Dequeuing 4738 *********************/ 4739 4740 /* As per jQuery's $.queue() behavior, to fire the first non-custom-queue entry on an element, the element 4741 must be dequeued if its queue stack consists *solely* of the current call. (This can be determined by checking 4742 for the "inprogress" item that jQuery prepends to active queue stack arrays.) Regardless, whenever the element's 4743 queue is further appended with additional items -- including $.delay()'s or even $.animate() calls, the queue's 4744 first entry is automatically fired. This behavior contrasts that of custom queues, which never auto-fire. */ 4745 /* Note: When an element set is being subjected to a non-parallel Velocity call, the animation will not begin until 4746 each one of the elements in the set has reached the end of its individually pre-existing queue chain. */ 4747 /* Note: Unfortunately, most people don't fully grasp jQuery's powerful, yet quirky, $.queue() function. 4748 Lean more here: http://stackoverflow.com/questions/1058158/can-somebody-explain-jquery-queue-to-me */ 4749 if ((opts.queue === "" || opts.queue === "fx") && $.queue(element)[0] !== "inprogress") { 4750 $.dequeue(element); 4751 } 4752 } 4753 4754 /************************** 4755 Element Set Iteration 4756 **************************/ 4757 4758 /* If the "nodeType" property exists on the elements variable, we're animating a single element. 4759 Place it in an array so that $.each() can iterate over it. */ 4760 $.each(elements, function(i, element) { 4761 /* Ensure each element in a set has a nodeType (is a real element) to avoid throwing errors. */ 4762 if (Type.isNode(element)) { 4763 processElement.call(element); 4764 } 4765 }); 4766 4767 /****************** 4768 Option: Loop 4769 ******************/ 4770 4771 /* The loop option accepts an integer indicating how many times the element should loop between the values in the 4772 current call's properties map and the element's property values prior to this call. */ 4773 /* Note: The loop option's logic is performed here -- after element processing -- because the current call needs 4774 to undergo its queue insertion prior to the loop option generating its series of constituent "reverse" calls, 4775 which chain after the current call. Two reverse calls (two "alternations") constitute one loop. */ 4776 var opts = $.extend({}, Velocity.defaults, options), 4777 reverseCallsCount; 4778 4779 opts.loop = parseInt(opts.loop); 4780 reverseCallsCount = (opts.loop * 2) - 1; 4781 4782 if (opts.loop) {
4783 /* Double the loop count to convert it into its appropriate number of "reverse" calls. 4784 Subtract 1 from the resulting value since the current call is included in the total alternation count. */ 4785 for (var x = 0; x < reverseCallsCount; x++) { 4786 /* Since the logic for the reverse action occurs inside Queueing and therefore this call's options object 4787 isn't parsed until then as well, the current call's delay option must be explicitly passed into the reverse 4788 call so that the delay logic that occurs inside *Pre-Queueing* can process it. */ 4789 var reverseOptions = { 4790 delay: opts.delay, 4791 progress: opts.progress 4792 }; 4793 4794 /* If a complete callback was passed into this call, transfer it to the loop redirect's final "reverse" call 4795 so that it's triggered when the entire redirect is complete (and not when the very first animation is complete). */ 4796 if (x === reverseCallsCount - 1) { 4797 reverseOptions.display = opts.display; 4798 reverseOptions.visibility = opts.visibility; 4799 reverseOptions.complete = opts.complete; 4800 } 4801 4802 animate(elements, "reverse", reverseOptions); 4803 } 4804 } 4805 4806 /*************** 4807 Chaining 4808 ***************/ 4809 4810 /* Return the elements back to the call chain, with wrapped elements taking precedence in case Velocity was called via the $.fn. extension. */ 4811 return getChain(); 4812 }; 4813 4814 /* Turn Velocity into the animation function, extended with the pre-existing Velocity object. */ 4815 Velocity = $.extend(animate, Velocity); 4816 /* For legacy support, also expose the literal animate method. */ 4817 Velocity.animate = animate; 4818 4819 /************** 4820 Timing 4821 **************/ 4822 4823 /* Ticker function. */ 4824 var ticker = window.requestAnimationFrame || rAFShim; 4825 4826 /* Inactive browser tabs pause rAF, which results in all active animations immediately sprinting to their completion states when the tab refocuses. 4827 To get around this, we dynamically switch rAF to setTimeout (which the browser *doesn't* pause) when the tab loses focus. We skip this for mobile 4828 devices to avoid wasting battery power on inactive tabs. */ 4829 /* Note: Tab focus detection doesn't work on older versions of IE, but that's okay since they don't support rAF to begin with. */ 4830 if (!Velocity.State.isMobile && document.hidden !== undefined) { 4831 document.addEventListener("visibilitychange", function() { 4832 /* Reassign the rAF function (which the global tick() function uses) based on the tab's focus state. */ 4833 if (document.hidden) { 4834 ticker = function(callback) { 4835 /* The tick function needs a truthy first argument in order to pass its internal timestamp check. */ 4836 return setTimeout(function() { callback(true) }, 16); 4837 }; 4838 4839 /* The rAF loop has been paused by the browser, so we manually restart the tick. */ 4840 tick(); 4841 } else { 4842 ticker = window.requestAnimationFrame || rAFShim; 4843 } 4844 }); 4845 } 4846 4847 /************ 4848 Tick 4849 ************/ 4850 4851 /* Note: All calls to Velocity are pushed to the Velocity.State.calls array, which is fully iterated through upon each tick. */ 4852 function tick (timestamp) { 4853 /* An empty timestamp argument indicates that this is the first tick occurence since ticking was turned on. 4854 We leverage this metadata to fully ignore the first tick pass since RAF's initial pass is fired whenever 4855 the browser's next tick sync time occurs, which results in the first elements subjected to Velocity 4856 calls being animated out of sync with any elements animated immediately thereafter. In short, we ignore 4857 the first RAF tick pass so that elements being immediately consecutively animated -- instead of simultaneously animated 4858 by the same Velocity call -- are properly batched into the same initial RAF tick and consequently remain in sync thereafter. */ 4859 if (timestamp) { 4860 /* We ignore RAF's high resolution timestamp since it can be significantly offset when the browser is 4861 under high stress; we opt for choppiness over allowing the browser to drop huge chunks of frames. */ 4862 var timeCurrent = (new Date).getTime(); 4863 4864 /******************** 4865 Call Iteration 4866 ********************/ 4867 4868 /* Iterate through each active call. */ 4869 for (var i = 0, callsLength = Velocity.State.calls.length; i < callsLength; i++) { 4870 /* When a Velocity call is completed, its Velocity.State.calls entry is set to false. Continue on to the next call. */ 4871 if (!Velocity.State.calls[i]) { 4872 continue; 4873 } 4874 4875 /************************ 4876 Call-Wide Variables 4877 ************************/ 4878 4879 var callContainer = Velocity.State.calls[i], 4880 call = callContainer[0], 4881 opts = callContainer[2], 4882 timeStart = callContainer[3], 4883 firstTick = !!timeStart; 4884 4885 /* If timeStart is undefined, then this is the first time that this call has been processed by tick(). 4886 We assign timeStart now so that its value is as close to the real animation start time as possible. 4887 (Conversely, had timeStart been defined when this call was added to Velocity.State.calls, the delay 4888 between that time and now would cause the first few frames of the tween to be skipped since 4889 percentComplete is calculated relative to timeStart.) */ 4890 /* Further, subtract 16ms (the approximate resolution of RAF) from the current time value so that the 4891 first tick iteration isn't wasted by animating at 0% tween completion, which would produce the 4892 same style value as the element's current value. */ 4893 if (!timeStart) { 4894 timeStart = Velocity.State.calls[i][3] = timeCurrent - 16; 4895 } 4896 4897 /* The tween's completion percentage is relative to the tween's start time, not the tween's start value 4898 (which would result in unpredictable tween durations since JavaScript's timers are not particularly accurate). 4899 Accordingly, we ensure that percentComplete does not exceed 1. */ 4900 var percentComplete = Math.min((timeCurrent - timeStart) / opts.duration, 1); 4901 4902 /********************** 4903 Element Iteration 4904 **********************/ 4905 4906 /* For every call, iterate through each of the elements in its set. */ 4907 for (var j = 0, callLength = call.length; j < callLength; j++) { 4908 var tweensContainer = call[j], 4909 element = tweensContainer.element; 4910 4911 /* Check to see if this element has been deleted midway through the animation by checking for the 4912 continued existence of its data cache. If it's gone, skip animating this element. */ 4913 if (!Data(element)) { 4914 continue; 4915 } 4916 4917 var transformPropertyExists = false;
4918 4919 /********************************** 4920 Display & Visibility Toggling 4921 **********************************/ 4922 4923 /* If the display option is set to non-"none", set it upfront so that the element can become visible before tweening begins. 4924 (Otherwise, display's "none" value is set in completeCall() once the animation has completed.) */ 4925 if (opts.display !== undefined && opts.display !== null && opts.display !== "none") { 4926 if (opts.display === "flex") { 4927 var flexValues = [ "-webkit-box", "-moz-box", "-ms-flexbox", "-webkit-flex" ]; 4928 4929 $.each(flexValues, function(i, flexValue) { 4930 CSS.setPropertyValue(element, "display", flexValue); 4931 }); 4932 } 4933 4934 CSS.setPropertyValue(element, "display", opts.display); 4935 } 4936 4937 /* Same goes with the visibility option, but its "none" equivalent is "hidden". */ 4938 if (opts.visibility !== undefined && opts.visibility !== "hidden") { 4939 CSS.setPropertyValue(element, "visibility", opts.visibility); 4940 } 4941 4942 /************************ 4943 Property Iteration 4944 ************************/ 4945 4946 /* For every element, iterate through each property. */ 4947 for (var property in tweensContainer) { 4948 /* Note: In addition to property tween data, tweensContainer contains a reference to its associated element. */ 4949 if (property !== "element") { 4950 var tween = tweensContainer[property], 4951 currentValue, 4952 /* Easing can either be a pre-genereated function or a string that references a pre-registered easing 4953 on the Velocity.Easings object. In either case, return the appropriate easing *function*. */ 4954 easing = Type.isString(tween.easing) ? Velocity.Easings[tween.easing] : tween.easing; 4955 4956 /****************************** 4957 Current Value Calculation 4958 ******************************/ 4959 4960 /* If this is the last tick pass (if we've reached 100% completion for this tween), 4961 ensure that currentValue is explicitly set to its target endValue so that it's not subjected to any rounding. */ 4962 if (percentComplete === 1) { 4963 currentValue = tween.endValue; 4964 /* Otherwise, calculate currentValue based on the current delta from startValue. */ 4965 } else { 4966 currentValue = tween.startValue + ((tween.endValue - tween.startValue) * easing(percentComplete)); 4967 4968 /* If no value change is occurring, don't proceed with DOM updating. */ 4969 if (!firstTick && (currentValue === tween.currentValue)) { 4970 continue; 4971 } 4972 } 4973 4974 tween.currentValue = currentValue; 4975 4976 /****************** 4977 Hooks: Part I 4978 ******************/ 4979 4980 /* For hooked properties, the newly-updated rootPropertyValueCache is cached onto the element so that it can be used 4981 for subsequent hooks in this call that are associated with the same root property. If we didn't cache the updated 4982 rootPropertyValue, each subsequent update to the root property in this tick pass would reset the previous hook's 4983 updates to rootPropertyValue prior to injection. A nice performance byproduct of rootPropertyValue caching is that 4984 subsequently chained animations using the same hookRoot but a different hook can use this cached rootPropertyValue. */ 4985 if (CSS.Hooks.registered[property]) { 4986 var hookRoot = CSS.Hooks.getRoot(property), 4987 rootPropertyValueCache = Data(element).rootPropertyValueCache[hookRoot]; 4988 4989 if (rootPropertyValueCache) { 4990 tween.rootPropertyValue = rootPropertyValueCache; 4991 } 4992 } 4993 4994 /***************** 4995 DOM Update 4996 *****************/ 4997 4998 /* setPropertyValue() returns an array of the property name and property value post any normalization that may have been performed. */ 4999 /* Note: To solve an IE<=8 positioning bug, the unit type is dropped when setting a property value of 0. */ 5000 var adjustedSetData = CSS.setPropertyValue(element, /* SET */ 5001 property, 5002 tween.currentValue + (parseFloat(currentValue) === 0 ? "" : tween.unitType), 5003 tween.rootPropertyValue, 5004 tween.scrollData); 5005 5006 /******************* 5007 Hooks: Part II 5008 *******************/ 5009 5010 /* Now that we have the hook's updated rootPropertyValue (the post-processed value provided by adjustedSetData), cache it onto the element. */ 5011 if (CSS.Hooks.registered[property]) { 5012 /* Since adjustedSetData contains
5012normalized data ready for DOM updating, the rootPropertyValue needs to be re-extracted from its normalized form. ?? */ 5013 if (CSS.Normalizations.registered[hookRoot]) { 5014 Data(element).rootPropertyValueCache[hookRoot] = CSS.Normalizations.registered[hookRoot]("extract", null, adjustedSetData[1]); 5015 } else { 5016 Data(element).rootPropertyValueCache[hookRoot] = adjustedSetData[1]; 5017 } 5018 } 5019 5020 /*************** 5021 Transforms 5022 ***************/ 5023 5024 /* Flag whether a transform property is being animated so that flushTransformCache() can be triggered once this tick pass is complete. */ 5025 if (adjustedSetData[0] === "transform") { 5026 transformPropertyExists = true; 5027 } 5028 } 5029 } 5030 5031 /**************** 5032 mobileHA 5033 ****************/ 5034 5035 /* If mobileHA is enabled, set the translate3d transform to null to force hardware acceleration. 5036 It's safe to override this property since Velocity doesn't actually support its animation (hooks are used in its place). */ 5037 if (opts.mobileHA) { 5038 /* Don't set the null transform hack if we've already done so. */ 5039 if (Data(element).transformCache.translate3d === undefined) { 5040 /* All entries on the transformCache object are later concatenated into a single transform string via flushTransformCache(). */ 5041 Data(element).transformCache.translate3d = "(0px, 0px, 0px)"; 5042 5043 transformPropertyExists = true; 5044 } 5045 } 5046 5047 if (transformPropertyExists) { 5048 CSS.flushTransformCache(element); 5049 } 5050 } 5051 5052 /* The non-"none" display value is only applied to an element once -- when its associated call is first ticked through. 5053 Accordingly, it's set to false so that it isn't re-processed by this call in the next tick. */ 5054 if (opts.display !== undefined && opts.display !== "none") { 5055 Velocity.State.calls[i][2].display = false; 5056 } 5057 if (opts.visibility !== undefined && opts.visibility !== "hidden") { 5058 Velocity.State.calls[i][2].visibility = false; 5059 } 5060 5061 5062 /* Pass the elements and the timing data (percentComplete, msRemaining, and timeStart) into the progress callback. */ 5063 if (opts.progress) { 5064 opts.progress.call(callContainer[1], 5065 callContainer[1], 5066 percentComplete, 5067 Math.max(0, (timeStart + opts.duration) - timeCurrent), 5068 timeStart); 5069 } 5070 5071 /* If this call has finished tweening, pass its index to completeCall() to handle call cleanup. */ 5072 if (percentComplete === 1) { 5073 completeCall(i); 5074 } 5075 } 5076 } 5077 5078 /* Note: completeCall() sets the isTicking flag to false when the last call on Velocity.State.calls has completed. */ 5079 if (Velocity.State.isTicking) { 5080 ticker(tick); 5081 } 5082 } 5083 5084 /********************** 5085 Call Completion 5086 **********************/ 5087 5088 /* Note: Unlike tick(), which processes all active calls at once, call completion is handled on a per-call basis. */ 5089 function completeCall (callIndex, isStopped) { 5090 /* Ensure the call exists. */ 5091 if (!Velocity.State.calls[callIndex]) { 5092 return false; 5093 } 5094 5095 /* Pull the metadata from the call. */ 5096 var call = Velocity.State.calls[callIndex][0], 5097 elements = Velocity.State.calls[callIndex][1], 5098 opts = Velocity.State.calls[callIndex][2], 5099 resolver = Velocity.State.calls[callIndex][4]; 5100 5101 var remainingCallsExist = false;
5102 5103 /************************* 5104 Element Finalization 5105 *************************/ 5106 5107 for (var i = 0, callLength = call.length; i < callLength; i++) { 5108 var element = call[i].element; 5109 5110 /* If the user set display to "none" (intending to hide the element), set it now that the animation has completed. */ 5111 /* Note: display:none isn't set when calls are manually stopped (via Velocity("stop"). */ 5112 /* Note: Display gets ignored with "reverse" calls and infinite loops, since this behavior would be undesirable. */ 5113 if (!isStopped && !opts.loop) { 5114 if (opts.display === "none") { 5115 CSS.setPropertyValue(element, "display", opts.display); 5116 } 5117 5118 if (opts.visibility === "hidden") { 5119 CSS.setPropertyValue(element, "visibility", opts.visibility); 5120 } 5121 } 5122 5123 /* If the element's queue is empty (if only the "inprogress" item is left at position 0) or if its queue is about to run 5124 a non-Velocity-initiated entry, turn off the isAnimating flag. A non-Velocity-initiatied queue entry's logic might alter 5125 an element's CSS values and thereby cause Velocity's cached value data to go stale. To detect if a queue entry was initiated by Velocity, 5126 we check for the existence of our special Velocity.queueEntryFlag declaration, which minifiers won't rename since the flag 5127 is assigned to jQuery's global $ object and thus exists out of Velocity's own scope. */ 5128 if (opts.loop !== true && ($.queue(element)[1] === undefined || !/\.velocityQueueEntryFlag/i.test($.queue(element)[1]))) { 5129 /* The element may have been deleted. Ensure that its data cache still exists before acting on it. */ 5130 if (Data(element)) { 5131 Data(element).isAnimating = false; 5132 /* Clear the element's rootPropertyValueCache, which will become stale. */ 5133 Data(element).rootPropertyValueCache = {}; 5134 5135 var transformHAPropertyExists = false; 5136 /* If any 3D transform subproperty is at its default value (regardless of unit type), remove it. */ 5137 $.each(CSS.Lists.transforms3D, function(i, transformName) { 5138 var defaultValue = /^scale/.test(transformName) ? 1 : 0, 5139 currentValue = Data(element).transformCache[transformName]; 5140 5141 if (Data(element).transformCache[transformName] !== undefined && new RegExp("^\\(" + defaultValue + "[^.]").test(currentValue)) { 5142 transformHAPropertyExists = true; 5143 5144 delete Data(element).transformCache[transformName]; 5145 } 5146 }); 5147 5148 /* Mobile devices have hardware acceleration removed at the end of the animation in order to avoid hogging the GPU's memory. */ 5149 if (opts.mobileHA) { 5150 transformHAPropertyExists = true; 5151 delete Data(element).transformCache.translate3d; 5152 } 5153 5154 /* Flush the subproperty removals to the DOM. */ 5155 if (transformHAPropertyExists) { 5156 CSS.flushTransformCache(element); 5157 } 5158 5159 /* Remove the "velocity-animating" indicator class. */ 5160 CSS.Values.removeClass(element, "velocity-animating"); 5161 } 5162 } 5163 5164 /********************* 5165 Option: Complete 5166 *********************/ 5167 5168 /* Complete is fired once per call (not once per element) and is passed the full raw DOM element set as both its context and its first argument. */ 5169 /* Note: Callbacks aren't fired when calls are manually stopped (via Velocity("stop"). */ 5170 if (!isStopped && opts.complete && !opts.loop && (i === callLength - 1)) { 5171 /* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Velocity itself. */ 5172 try { 5173 opts.complete.call(elements, elements); 5174 } catch (error) { 5175 setTimeout(function() { throw error; }, 1); 5176 } 5177 } 5178 5179 /********************** 5180 Promise Resolving 5181 **********************/ 5182 5183 /* Note: Infinite loops don't return promises. */ 5184 if (resolver && opts.loop !== true) { 5185 resolver(elements); 5186 } 5187 5188 /**************************** 5189 Option: Loop (Infinite) 5190 ****************************/ 5191 5192 if (opts.loop === true && !isStopped) { 5193 /* If a rotateX/Y/Z property is being animated to 360 deg with loop:true, swap tween start/end values to enable 5194 continuous iterative rotation looping. (Otherise, the element would just rotate back and forth.) */ 5195 $.each(Data(element).tweensContainer, function(propertyName, tweenContainer) { 5196 if (/^rotate/.test(propertyName) && parseFloat(tweenContainer.endValue) === 360) { 5197 tweenContainer.endValue = 0; 5198 tweenContainer.startValue = 360; 5199 } 5200 }); 5201 5202 Velocity(element, "reverse", { loop: true, delay: opts.delay }); 5203 } 5204 5205 /*************** 5206 Dequeueing 5207 ***************/ 5208 5209 /* Fire the next call in the queue so long as this call's queue wasn't set to false (to trigger a parallel animation), 5210 which would have already caused the next call to fire. Note: Even if the end of the animation queue has been reached, 5211 $.dequeue() must still be called in order to completely clear jQuery's animation queue. */ 5212 if (opts.queue !== false) { 5213 $.dequeue(element, opts.queue); 5214 } 5215 } 5216 5217 /************************ 5218 Calls Array Cleanup 5219 ************************/ 5220 5221 /* Since this call is complete, set it to false so that the rAF tick skips it. This array is later compacted via compactSparseArray(). 5222 (For performance reasons, the call is set to false instead of being deleted from the array: http://www.html5rocks.com/en/tutorials/speed/v8/) */ 5223 Velocity.State.calls[callIndex] = false;
5224 5225 /* Iterate through the calls array to determine if this was the final in-progress animation. 5226 If so, set a flag to end ticking and clear the calls array. */ 5227 for (var j = 0, callsLength = Velocity.State.calls.length; j < callsLength; j++) { 5228 if (Velocity.State.calls[j] !== false) { 5229 remainingCallsExist = true; 5230 5231 break; 5232 } 5233 } 5234 5235 if (remainingCallsExist === false) { 5236 /* tick() will detect this flag upon its next iteration and subsequently turn itself off. */ 5237 Velocity.State.isTicking = false; 5238 5239 /* Clear the calls array so that its length is reset. */ 5240 delete Velocity.State.calls; 5241 Velocity.State.calls = []; 5242 } 5243 } 5244 5245 /****************** 5246 Frameworks 5247 ******************/ 5248 5249 /* Both jQuery and Zepto allow their $.fn object to be extended to allow wrapped elements to be subjected to plugin calls. 5250 If either framework is loaded, register a "velocity" extension pointing to Velocity's core animate() method. Velocity 5251 also registers itself onto a global container (window.jQuery || window.Zepto || window) so that certain features are 5252 accessible beyond just a per-element scope. This master object contains an .animate() method, which is later assigned to $.fn 5253 (if jQuery or Zepto are present). Accordingly, Velocity can both act on wrapped DOM elements and stand alone for targeting raw DOM elements. */ 5254 global.Velocity = Velocity; 5255 5256 if (global !== window) { 5257 /* Assign the element function to Velocity's core animate() method. */ 5258 global.fn.velocity = animate; 5259 /* Assign the object function's defaults to Velocity's global defaults object. */ 5260 global.fn.velocity.defaults = Velocity.defaults; 5261 } 5262 5263 /*********************** 5264 Packaged Redirects 5265 ***********************/ 5266 5267 /* slideUp, slideDown */ 5268 $.each([ "Down", "Up" ], function(i, direction) { 5269 Velocity.Redirects["slide" + direction] = function (element, options, elementsIndex, elementsSize, elements, promiseData) { 5270 var opts = $.extend({}, options), 5271 begin = opts.begin, 5272 complete = opts.complete, 5273 computedValues = { height: "", marginTop: "", marginBottom: "", paddingTop: "", paddingBottom: "" }, 5274 inlineValues = {}; 5275 5276 if (opts.display === undefined) { 5277 /* Show the element before slideDown begins and hide the element after slideUp completes. */ 5278 /* Note: Inline elements cannot have dimensions animated, so they're reverted to inline-block. */ 5279 opts.display = (direction === "Down" ? (Velocity.CSS.Values.getDisplayType(element) === "inline" ? "inline-block" : "block") : "none"); 5280 } 5281 5282 opts.begin = function() { 5283 /* If the user passed in a begin callback, fire it now. */ 5284 begin && begin.call(elements, elements); 5285 5286 /* Cache the elements' original vertical dimensional property values so that we can animate back to them. */ 5287 for (var property in computedValues) { 5288 /* Cache all inline values, we reset to upon animation completion. */ 5289 inlineValues[property] = element.style[property]; 5290 5291 /* For slideDown, use forcefeeding to animate all vertical properties from 0. For slideUp, 5292 use forcefeeding to start from computed values and animate down to 0. */ 5293 var propertyValue = Velocity.CSS.getPropertyValue(element, property); 5294 computedValues[property] = (direction === "Down") ? [ propertyValue, 0 ] : [ 0, propertyValue ]; 5295 } 5296 5297 /* Force vertical overflow content to clip so that sliding works as expected. */ 5298 inlineValues.overflow = element.style.overflow; 5299 element.style.overflow = "hidden"; 5300 } 5301 5302 opts.complete = function() { 5303 /* Reset element to its pre-slide inline values once its slide animation is complete. */ 5304 for (var property in inlineValues) { 5305 element.style[property] = inlineValues[property]; 5306 } 5307 5308 /* If the user passed in a complete callback, fire it now. */ 5309 complete && complete.call(elements, elements); 5310 promiseData && promiseData.resolver(elements); 5311 }; 5312 5313 Velocity(element, computedValues, opts); 5314 }; 5315 }); 5316 5317 /* fadeIn, fadeOut */ 5318 $.each([ "In", "Out" ], function(i, direction) { 5319 Velocity.Redirects["fade" + direction] = function (element, options, elementsIndex, elementsSize, elements, promiseData) { 5320 var opts = $.extend({}, options), 5321 propertiesMap = { opacity: (direction === "In") ? 1 : 0 },
5322 originalComplete = opts.complete; 5323 5324 /* Since redirects are triggered individually for each element in the animated set, avoid repeatedly triggering 5325 callbacks by firing them only when the final element has been reached. */ 5326 if (elementsIndex !== elementsSize - 1) { 5327 opts.complete = opts.begin = null; 5328 } else { 5329 opts.complete = function() { 5330 if (originalComplete) { 5331 originalComplete.call(elements, elements); 5332 } 5333 5334 promiseData && promiseData.resolver(elements); 5335 } 5336 } 5337 5338 /* If a display was passed in, use it. Otherwise, default to "none" for fadeOut or the element-specific default for fadeIn. */ 5339 /* Note: We allow users to pass in "null" to skip display setting altogether. */ 5340 if (opts.display === undefined) { 5341 opts.display = (direction === "In" ? "auto" : "none"); 5342 } 5343 5344 Velocity(this, propertiesMap, opts); 5345 }; 5346 }); 5347 5348 return Velocity; 5349}((window.jQuery || window.Zepto || window), window, document); 5350})); 5351 5352/****************** 5353 Known Issues 5354******************/ 5355 5356/* The CSS spec mandates that the translateX/Y/Z transforms are %-relative to the element itself -- not its parent. 5357Velocity, however, doesn't make this distinction. Thus, converting to or from the % unit with these subproperties 5358will produce an inaccurate conversion value. The same issue exists with the cx/cy attributes of SVG circles and ellipses. */ 5359; 5360(function ($, window, undefined) { 5361 5362 // /* ====== SHARED VARS - jQuery ====== */ 5363 // These depend on jQuery 5364 var $window = $(window), 5365 windowHeight = $window.height(), 5366 windowWidth = $window.width(); 5367 5368 /** 5369 * Detect browser size and remember it in global variables 5370 */ 5371 5372 function browserSize() { 5373 wh = $window.height(); 5374 ww = $window.width(); 5375 dh = $(document).height(); 5376 ar = ww / wh; 5377 } 5378 5379 5380 /** 5381 * Detect what platform are we on (browser, mobile, etc) 5382 */ 5383 5384 function platformDetect() { 5385 $.support.touch = 'ontouchend' in document; 5386 var navUA = navigator.userAgent.toLowerCase(), 5387 navPlat = navigator.platform.toLowerCase(); 5388 5389 var isiPhone = navPlat.indexOf("iphone"), 5390 isiPod = navPlat.indexOf("ipod"), 5391 isAndroidPhone = navPlat.indexOf("android"), 5392 safari = (navUA.indexOf('safari') != -1 && navUA.indexOf('chrome') == -1) ? true : false, 5393 svgSupport = (window.SVGAngle) ? true : false, 5394 svgSupportAlt = (document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) ? true : false, 5395 ff3x = (/gecko/i.test(navUA) && /rv:1.9/i.test(navUA)) ? true : false; 5396 5397 ieMobile = navigator.userAgent.match(/Windows Phone/i) ? true : false; 5398 phone = (isiPhone > -1 || isiPod > -1 || isAndroidPhone > -1) ? true : false; 5399 touch = $.support.touch ? true : false; 5400 5401 if (touch) $html.addClass('touch'); 5402 5403 if (ieMobile) $html.addClass('is--winmob'); 5404 if (is_android) $html.addClass('is--ancient-android'); 5405 5406 if (safari) $body.addClass('safari'); 5407 if (phone) $body.addClass('phone'); 5408 } 5409 5410 // /* ====== SHARED VARS ====== */ 5411 // These do not depend on jQuery 5412 var phone, touch, wh, ww, dh, ar, fonts; 5413 5414 var ua = navigator.userAgent; 5415 var winLoc = window.location.toString(); 5416 5417 var is_webkit = ua.match(/webkit/i); 5418 var is_firefox = ua.match(/gecko/i); 5419 var is_newer_ie = ua.match(/msie (9|([1-9][0-9]))/i); 5420 var is_older_ie = ua.match(/msie/i) && !is_newer_ie; 5421 var is_ancient_ie = ua.match(/msie 6/i); 5422 var is_mobile = ua.match(/mobile/i);
5423 var is_OSX = (ua.match(/(iPad|iPhone|iPod|Macintosh)/g) ? true : false); 5424 5425 var nua = navigator.userAgent; 5426 var is_android = ((nua.indexOf('Mozilla/5.0') !== -1 && nua.indexOf('Android ') !== -1 && nua.indexOf('AppleWebKit') !== -1) && nua.indexOf('Chrome') === -1); 5427 5428 var useTransform = true; 5429 var use2DTransform = (ua.match(/msie 9/i) || winLoc.match(/transform\=2d/i)); 5430 var transform; 5431 5432 var $html = $('html'); 5433 var $body = $('body'); 5434 5435 // setting up transform prefixes 5436 var prefixes = { 5437 webkit: 'webkitTransform', 5438 firefox: 'MozTransform', 5439 ie: 'msTransform', 5440 w3c: 'transform' 5441 }; 5442 5443 if (useTransform) { 5444 if (is_webkit) { 5445 transform = prefixes.webkit; 5446 } else if (is_firefox) { 5447 transform = prefixes.firefox; 5448 } else if (is_newer_ie) { 5449 transform = prefixes.ie; 5450 } 5451 } 5452 // /* ====== Masonry Logic ====== */ 5453 (function () { 5454 5455 var $container = $('.archive__grid'), 5456 $blocks = $container.children().addClass('post--animated post--loaded'), 5457 slices = $blocks.first().children().length; 5458 5459 var observerConfig = { attributes: false, childList: true, characterData: true }, 5460 observer; 5461 5462 if ( "MutationObserver" in window ) { 5463 observer = new MutationObserver( function( mutations ) { 5464 $container.masonry( 'layout' ); 5465 } ); 5466 } 5467 5468 // initialize masonry after the images have loaded 5469 $container.imagesLoaded(function () { 5470 5471 // prepare hover animations 5472 if (!$html.hasClass('touch')) 5473 $blocks.addHoverAnimation(); 5474 5475 // initialize masonry 5476 $container.masonry({ 5477 isAnimated: false, 5478 itemSelector: '.grid__item', 5479 transitionDuration: 0, 5480 hiddenStyle: { 5481 opacity: 0 5482 } 5483 }); 5484 5485 /** 5486 * function used to display cards with a simple fade in transition 5487 */ 5488 5489 function showBlocks($blocks) { 5490 5491 // use different delays for each card to stagger them 5492 $blocks.each(function (i, obj) { 5493 5494 var $block = $(obj), 5495 duration = 200 + slices * 0.1; 5496 5497 $block.velocity({ 5498 translateY: 40 5499 }, { 5500 duration: 0 5501 }); 5502 setTimeout(function () { 5503 $block.velocity({ 5504 translateY: 0 5505 }, { 5506 easing: "easeOutQuad", 5507 duration: 100 5508 }); 5509 5510 $block.children().each(function (j, child) { 5511 var $child = $(child), 5512 timeout = (j + 1) * 100; 5513 5514 $child.velocity({ 5515 opacity: 0, 5516 translateY: 40 5517 }, { 5518 duration: 0 5519 }); 5520 5521 $child.velocity({ 5522 opacity: 1, 5523 translateY: 0 5524 }, { 5525 duration: 300, 5526 delay: timeout 5527 }); 5528 }); 5529 5530 setTimeout(function () { 5531 $block.toggleClass('sticky--bg', $block.hasClass('sticky')); 5532 $block.addClass('post--visible'); 5533 }, 300); 5534 5535 }, i * 200); 5536 }); 5537 } 5538 5539 // animate cards in 5540 showBlocks($blocks); 5541 5542 $blocks.each( function( i, obj ) { 5543 if ( typeof observer !== "undefined" ) { 5544 observer.observe( obj, observerConfig ); 5545 } 5546 } ); 5547 5548 // update the masonry layout on window.resize 5549 $(window).smartresize(function () { 5550 $container.masonry('layout'); 5551 }); 5552 5553 $(window).load(function () { 5554 $container.masonry('layout'); 5555 }); 5556 5557 // handle behavior for infinite scroll 5558 $(document.body).on('post-load', function () { 5559 5560 // figure out which are the new loaded posts 5561 var $newBlocks = $('.archive__grid').children().not('.post--loaded').addClass('post--loaded'); 5562 5563 // when images have loaded take care of the layout, prepare hover animations, and animate cards in 5564 $newBlocks.imagesLoaded( function() { 5565 $container.masonry( 'appended', $newBlocks, true ).masonry( 'layout' ); 5566 if ( ! $html.hasClass( 'touch' ) ) { 5567 $newBlocks.addHoverAnimation(); 5568 } 5569 showBlocks( $newBlocks ); 5570 } ); 5571 5572 if ( typeof observer !== "undefined" ) { 5573 $newBlocks.each( function(i, obj ) { 5574 observer.observe( obj, observerConfig ); 5575 } ); 5576 } 5577 }); 5578 }); 5579 })(); 5580 5581 // /* ====== Navigation Logic ====== */ 5582 var $nav = $('.nav--main'), 5583 $navTrigger = $('.navigation__trigger'), 5584 $navContainer = $('.main-navigation'), 5585 navTop = (typeof $navContainer.offset() !== 'undefined') ? $navContainer.offset().top : 0, 5586 navLeft = (typeof $navContainer.offset() !== 'undefined') ? $navContainer.offset().left : 0, 5587 navWidth = $nav.outerWidth(), 5588 containerWidth = $navContainer.outerWidth(),
5589 navHeight = $nav.outerHeight(), 5590 $toolbar = $('.toolbar'), 5591 isOpen = false, 5592 pageTop = $('#page').offset().top, 5593 pageWidth = $('#page').width(), 5594 pageLeft = $('#page').offset().left, 5595 sticked = false; 5596 5597 /** 5598 * bind toggling the navigation drawer to click and touchstart 5599 *in order to get rid of the 300ms delay on touch devices we use the touchstart event 5600 */ 5601 var triggerEvents = 'click touchstart'; 5602 if (is_android) triggerEvents = 'click'; 5603 5604 // Set the Navigation Container Height 5605 $navContainer.height(navHeight); 5606 5607 $navTrigger.on(triggerEvents, function (e) { 5608 // but we still have to prevent the default behavior of the touchstart event 5609 // because this way we're making sure the click event won't fire anymore 5610 e.preventDefault(); 5611 e.stopPropagation(); 5612 5613 isOpen = !isOpen; 5614 $('body').toggleClass('nav--is-open'); 5615 5616 var offset; 5617 5618 navWidth = $nav.outerWidth(); 5619 5620 if ($('body').hasClass('rtl')) { 5621 offset = -1 * navWidth; 5622 } else { 5623 offset = navWidth; 5624 } 5625 5626 if (!is_android) { 5627 if (!isOpen) { 5628 5629 $([$nav, $navTrigger]).each(function (i, obj) { 5630 $(obj).velocity({ 5631 translateX: 0, 5632 translateZ: 0.01 5633 }, {
5634 duration: 300, 5635 easing: "easeInQuart", 5636 begin: function () { 5637 $navContainer.removeClass('shadow'); 5638 } 5639 }); 5640 }); 5641 5642 } else { 5643 5644 $([$nav, $navTrigger]).each(function (i, obj) { 5645 $(obj).velocity({ 5646 translateX: offset, 5647 translateZ: 0.01 5648 }, { 5649 easing: "easeOutCubic", 5650 duration: 300, 5651 complete: function () { 5652 $navContainer.addClass('shadow'); 5653 } 5654 }); 5655 }); 5656 } 5657 } 5658 }); 5659 5660 var HandleParentMenuItems = (function() { 5661 // Handle parent menu items on tablet in landscape mode; 5662 // use case: normal, horizontal menu, touch events, 5663 // sub menus are not visible. 5664 function handleParentMenuItems() { 5665 // Make sure there are no open menu items 5666 $('[class*="has-children"]').removeClass('hover'); 5667 5668 $('[class*="has-children"] > a').each( function(){ 5669 // Add a class so we know the items to handle 5670 $(this).addClass('prevent-one').attr('hasbeenclicked', false); 5671 }); 5672 5673 $('a.prevent-one').on('click', function(e) { 5674 if( $( this ).attr( 'hasbeenclicked' ) == "false" ) { 5675 e.preventDefault(); 5676 e.stopPropagation(); 5677 5678 $(this).attr('hasbeenclicked', true); 5679 5680 // Open the sub menu of this parent item 5681 $(this).parent().addClass('hover') 5682 // When a parent menu item is activated, 5683 // close other menu items on the same level 5684 .siblings().removeClass('hover').find('> a.prevent-one').attr('hasbeenclicked', false); 5685 } 5686 }); 5687 } 5688 5689 // Restore the original behaviour when in portrait mode; 5690 // use case: vertical menu, all menu items are visible. 5691 function unHandleParentMenuItems() { 5692 $('a.prevent-one').each(function(){ 5693 // Unbind te click handler 5694 $(this).unbind(); 5695 }); 5696 } 5697 5698 // When a sub menu is open, close it by a touch on 5699 // any other part of the viewport than navigation. 5700 // use case: normal, horizontal menu, touch events, 5701 // sub menus are not visible. 5702 function bindOuterNavClick() { 5703 $('body').on( 'touchstart', function (e) { 5704 var container = $('.nav--main'); 5705 5706 if (!container.is(e.target) // if the target of the click isn't the container... 5707 && container.has(e.target).length === 0) // ... nor a descendant of the container 5708 { 5709 $('[class*="has-children"]').removeClass('hover'); 5710 $('a.prevent-one').attr('hasbeenclicked', false); 5711 } 5712 }); 5713 } 5714 5715 return { 5716 handle: handleParentMenuItems, 5717 unHandle: unHandleParentMenuItems, 5718 bindOuterNavClick: bindOuterNavClick 5719 } 5720 }()); 5721 5722 /** 5723 * function used to make the navigation bar on big screens 5724 * sticky or static depending on the scroll position 5725 */ 5726 5727 function updateStickyMenu() { 5728 5729 // pin 5730 if (latestKnownScrollY + pageTop > navTop && !sticked) { 5731 $nav.css({ 5732 position: 'fixed', 5733 top: pageTop, 5734 left: pageLeft, 5735 width: pageWidth 5736 }); 5737 5738 sticked = true; 5739 return; 5740 } 5741 5742 // unpin 5743 if (latestKnownScrollY + pageTop <= navTop && sticked) { 5744 5745 $nav.css({ 5746 position: '', 5747 left: '', 5748 top: '', 5749 width: '' 5750 }); 5751 5752 sticked = false; 5753 } 5754 5755 } 5756 5757 /** 5758 * because we hard-code properties on the navigation bar when we stick it at the top of the window 5759 * we need to update some properties on window resize 5760 */ 5761 5762 function refreshNavigation() { 5763 navTop = (typeof $navContainer.offset() !== 'undefined') ? $navContainer.offset().top : 0; 5764 navLeft = (typeof $navContainer.offset() !== 'undefined') ? $navContainer.offset().left : 0; 5765 containerWidth = $navContainer.outerWidth(); 5766 navWidth = $nav.outerWidth(); 5767 navHeight = $nav.outerHeight(); 5768 pageTop = $('#page').offset().top; 5769 pageWidth = $('#page').width(); 5770 5771 $navContainer.height(navHeight); 5772 5773 if (sticked) { 5774 $nav.velocity({ 5775 width: pageWidth 5776 }, { 5777 easing: "easeOutCubic", 5778 duration: 200 5779 }); 5780 } 5781 5782 if (isOpen) { 5783 $([$nav, $navTrigger]).each(function (i, obj) { 5784 $(obj).velocity({ 5785 translateX: navWidth 5786 }, { 5787 easing: "easeOutQuint", 5788 duration: 200 5789 }); 5790 }); 5791 } 5792 5793 navWidth = containerWidth; 5794 } 5795 5796 /** 5797 * cardHover jQuery plugin 5798 * 5799 * we need to create a jQuery plugin so we can easily create the hover animations on the archive 5800 * both an window.load and on jetpack's infinite scroll 'post-load' 5801 */ 5802 $.fn.addHoverAnimation = function () { 5803 5804 return this.each(function (i, obj) { 5805 5806 var $obj = $(obj), 5807 $handler = $obj.find('.hover__handler'), 5808 $hover = $obj.find('.hover'); 5809 5810 // if we don't have have elements that need to be animated return 5811 if (!$hover.length) { 5812 return; 5813 } 5814 5815 var $letter = $hover.find('.hover__letter'), 5816 letterWidth = $letter.outerWidth, 5817 letterHeight = $letter.outerHeight; 5818 5819 $hover.find('.hover__bg').velocity({ 5820 opacity: 0 5821 }, { 5822 duration: 0 5823 }); 5824 $hover.find('.hover__line').velocity({ 5825 height: 0 5826 }, { 5827 duration: 0 5828 }); 5829 $hover.find('.hover__more').velocity({ 5830 opacity: 0 5831 }, { 5832 duration: 0 5833 }); 5834 $hover.find('.hover__letter').velocity({ 5835 opacity: 0, 5836 translateX: '-50%', 5837 translateY: '-50%', 5838 scaleX: 1.25, 5839 scaleY: 1.25 5840 }, { 5841 duration: 0 5842 }); 5843 5844 // bind the tweens we created above to mouse events accordingly, through hoverIntent to avoid flickering 5845 if ($handler.length) { 5846 $handler.hoverIntent({ 5847 over: animateHoverIn, 5848 out: animateHoverOut, 5849 timeout: 100, 5850 interval: 50 5851 }); 5852 } 5853 5854 function animateHoverIn() { 5855 5856 $hover.find('.hover__bg').velocity("reverse", { 5857 easing: "easeOutQuart", 5858 duration: 500 5859 }); 5860 $hover.find('.hover__line').velocity("reverse", { 5861 easing: "easeOutQuart", 5862 duration: 350, 5863 delay: 150 5864 }); 5865 $hover.find('.hover__more').velocity("reverse", { 5866 easing: "easeOutQuart", 5867 duration: 350, 5868 delay: 150 5869 }); 5870 $hover.find('.hover__letter').velocity({ 5871 scaleX: 1, 5872 scaleY: 1, 5873 opacity: 0.2, 5874 translateX: '-50%', 5875 translateY: '-50%' 5876 }, { 5877 easing: "easeOutQuart", 5878 duration: 350, 5879 delay: 150 5880 }); 5881 5882 } 5883 5884 function animateHoverOut() { 5885 5886 var letterHeight = $hover.find('.hover__letter-mask').outerHeight(); 5887 5888 $hover.find('.hover__letter').velocity({ 5889 opacity: 0, 5890 translateX: '-50%', 5891 translateY: '-50%', 5892 scaleX: 1.25, 5893 scaleY: 1.25 5894 }, { 5895 easing: "easeOutQuart", 5896 duration: 350, 5897 delay: 0 5898 }); 5899 $hover.find('.hover__more').velocity("reverse", { 5900 duration: 350, 5901 delay: 0 5902 }); 5903 $hover.find('.hover__line').velocity("reverse", { 5904 duration: 350, 5905 delay: 0 5906 }); 5907 $hover.find('.hover__bg').velocity("reverse", { 5908 duration: 350, 5909 delay: 0 5910 }); 5911 5912 } 5913 5914 }); 5915 }; 5916 5917 // /* ====== Search Overlay Logic ====== */ 5918 (function () { 5919 5920 var isOpen = false,
5921 $overlay = $('.overlay--search'); 5922 5923 // update overlay position (if it's open) on window.resize 5924 $(window).on('smartresize', function () { 5925 5926 windowWidth = $(window).outerWidth(); 5927 5928 if (isOpen) { 5929 $overlay.velocity({ 5930 translateX: -1 * windowWidth 5931 }, { 5932 duration: 200, 5933 easing: "easeInCubic" 5934 }); 5935 } 5936 5937 }); 5938 5939 /** 5940 * dismiss overlay 5941 */ 5942 5943 function closeOverlay() { 5944 5945 if (!isOpen) { 5946 return; 5947 } 5948 5949 var offset; 5950 5951 if ($('body').hasClass('rtl')) { 5952 offset = windowWidth 5953 } else { 5954 offset = -1 * windowWidth 5955 } 5956 5957 // we don't need a timeline for this animations so we'll use a simple tween between two states 5958 $overlay.velocity({ 5959 translateX: offset 5960 }, { 5961 duration: 0 5962 }); 5963 $overlay.velocity({ 5964 translateX: 0 5965 }, { 5966 duration: 300, 5967 easing: "easeInCubic" 5968 }); 5969 5970 // remove focus from the search field 5971 $overlay.find('input').blur(); 5972 5973 isOpen = false; 5974 } 5975 5976 function escOverlay(e) { 5977 if (e.keyCode == 27) { 5978 closeOverlay(); 5979 } 5980 } 5981 5982 // create animation and run it on 5983 $('.nav__item--search').on('click touchstart', function (e) { 5984 // prevent default behavior and stop propagation 5985 e.preventDefault(); 5986 e.stopPropagation(); 5987 5988 // if through some kind of sorcery the navigation drawer is already open return 5989 if (isOpen) { 5990 return; 5991 } 5992 5993 var offset; 5994 5995 if ($('body').hasClass('rtl')) { 5996 offset = windowWidth 5997 } else { 5998 offset = -1 * windowWidth 5999 } 6000 6001 // automatically focus the search field so the user can type right away 6002 $overlay.find('input').focus(); 6003 6004 $overlay.velocity({ 6005 translateX: 0 6006 }, { 6007 duration: 0 6008 }).velocity({ 6009 translateX: offset 6010 }, { 6011 duration: 300, 6012 easing: "easeOut", 6013 queue: false 6014 }); 6015 6016 $('.search-form').velocity({ 6017 translateX: 300, 6018 opacity: 0 6019 }, { 6020 duration: 0 6021 }).velocity({ 6022 opacity: 1 6023 }, { 6024 duration: 200, 6025 easing: "easeOutQuad", 6026 delay: 200, 6027 queue: false 6028 }).velocity({ 6029 translateX: 0 6030 }, { 6031 duration: 400, 6032 easeing: [0.175, 0.885, 0.320, 1.275], 6033 delay: 50, 6034 queue: false 6035 }); 6036 6037 $('.overlay__wrapper > p').velocity({ 6038 translateX: 200, 6039 opacity: 0 6040 }, { 6041 duration: 0 6042 }).velocity({ 6043 opacity: 1 6044 }, { 6045 duration: 400, 6046 easing: "easeOutQuad", 6047 delay: 350, 6048 queue: false 6049 }).velocity({ 6050 translateX: 0 6051 }, { 6052 duration: 400, 6053 easing: [0.175, 0.885, 0.320, 1.275], 6054 delay: 250, 6055 queue: false 6056 }); 6057 6058 // bind overlay dismissal to escape key 6059 $(document).on('keyup', escOverlay); 6060 6061 isOpen = true; 6062 }); 6063 6064 // create function to hide the search overlay and bind it to the click event 6065 $('.overlay__close').on('click touchstart', function (e) { 6066 6067 e.preventDefault(); 6068 e.stopPropagation(); 6069 6070 closeOverlay(); 6071 6072 // unbind overlay dismissal from escape key 6073 $(document).off('keyup', escOverlay); 6074 6075 }); 6076 6077 })(); 6078 6079 // /* ====== Smart Resize Logic ====== */ 6080 // It's best to debounce the resize event to a void performance hiccups 6081 (function ($, sr) { 6082 6083 /** 6084 * debouncing function from John Hann 6085 * http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 6086 */ 6087 var debounce = function (func, threshold, execAsap) { 6088 var timeout; 6089 6090 return function debounced() { 6091 var obj = this, 6092 args = arguments; 6093 6094 function delayed() { 6095 if (!execAsap) func.apply(obj, args); 6096 timeout = null; 6097 } 6098 6099 if (timeout) clearTimeout(timeout); 6100 else if (execAsap) func.apply(obj, args); 6101 6102 timeout = setTimeout(delayed, threshold || 200); 6103 }; 6104 } 6105 // smartresize 6106 jQuery.fn[sr] = function (fn) { 6107 return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); 6108 }; 6109 6110 })(jQuery, 'smartresize'); 6111 var latestKnownScrollY = window.scrollY, 6112 ticking = false; 6113 6114 function requestTick() { 6115 "use strict"; 6116 6117 if (!ticking) { 6118 requestAnimationFrame(update); 6119 } 6120 ticking = true; 6121 } 6122 6123 function update() { 6124 "use strict"; 6125 6126 ticking = false; 6127 6128 if (!is_android) { 6129 updateStickyMenu(); 6130 } 6131 } 6132 6133 /* ====== INTERNAL FUNCTIONS END ====== */ 6134 6135 6136 /* ====== ONE TIME INIT ====== */ 6137
6138 function init() { 6139 6140 // /* GLOBAL VARS */ 6141 touch = false; 6142 6143 // GET BROWSER DIMENSIONS 6144 browserSize(); 6145 6146 // /* DETECT PLATFORM */ 6147 platformDetect(); 6148 } 6149 6150 6151 /* --- GLOBAL EVENT HANDLERS --- */ 6152 6153 6154 /* ====== ON DOCUMENT READY ====== */ 6155 6156 $(document).ready(function () { 6157 init(); 6158 }); 6159 6160 6161 /* ====== ON WINDOW LOAD ====== */ 6162 6163 $window.load(function () { 6164 6165 if ( !$html.hasClass( 'touch' ) ) { 6166 var $nav = $( '.nav--main' ).addClass( 'hover-intent' ); 6167 6168 $( '.nav--main li' ).hoverIntent({ 6169 over: showSubMenu, 6170 out: hideSubMenu, 6171 timeout: 300 6172 }); 6173 } else if ( $html.hasClass( 'touch') && windowWidth > 1000 ) { 6174 HandleParentMenuItems.handle(); 6175 HandleParentMenuItems.bindOuterNavClick(); 6176 } 6177 6178 function showSubMenu() { 6179 $(this).addClass('hover'); 6180 } 6181 6182 function hideSubMenu() { 6183 $(this).removeClass('hover'); 6184 } 6185 6186 }); 6187 6188 /* ====== ON RESIZE ====== */ 6189 6190 $(window).smartresize(function () { 6191 if (!is_android) { 6192 refreshNavigation(); 6193 } 6194 windowWidth = $(window).outerWidth(); 6195 windowHeight = $(window).outerHeight(); 6196 6197 if( $html.hasClass( 'touch' ) ) { 6198 if( windowWidth >= 1000 ) { 6199 // Handle parent menu items 6200 HandleParentMenuItems.handle(); 6201 } else if ( windowWidth < 1000 ) { 6202 // Remove handlers 6203 HandleParentMenuItems.unHandle(); 6204 } 6205 } 6206 }); 6207 6208 /* ====== ON SCROLL ====== */ 6209 6210 $window.on('scroll', function (e) { 6211 "use strict"; 6212 6213 latestKnownScrollY = window.scrollY; 6214 requestTick(); 6215 }); 6216 // /* ====== HELPER FUNCTIONS ====== */ 6217 /** 6218 * function similar to PHP's empty function 6219 */ 6220 6221 function empty(data) { 6222 if (typeof(data) == 'number' || typeof(data) == 'boolean') { 6223 return false; 6224 } 6225 if (typeof(data) == 'undefined' || data === null) { 6226 return true; 6227 } 6228 if (typeof(data.length) != 'undefined') { 6229 return data.length === 0; 6230 } 6231 var count = 0; 6232 for (var i in data) { 6233 // if(data.hasOwnProperty(i)) 6234 // 6235 // This doesn't work in ie8/ie9 due the fact that hasOwnProperty works only on native objects. 6236 // http://stackoverflow.com/questions/8157700/object-has-no-hasownproperty-method-i-e-its-undefined-ie8 6237 // 6238 // for hosts objects we do this 6239 if (Object.prototype.hasOwnProperty.call(data, i)) { 6240 count++; 6241 } 6242 } 6243 return count === 0; 6244 } 6245 6246 /** 6247 * function to add/modify a GET parameter 6248 */ 6249 6250 function setQueryParameter(uri, key, value) { 6251 var re = new RegExp("([?|&])" + key + "=.*?(&|$)", "i"); 6252 separator = uri.indexOf('?') !== -1 ? "&" : "?"; 6253 if (uri.match(re)) { 6254 return uri.replace(re, '$1' + key + "=" + value + '$2'); 6255 } 6256 else { 6257 return uri + separator + key + "=" + value; 6258 } 6259 } 6260 6261 /** 6262 * requestAnimationFrame polyfill by Erik Möller. 6263 * Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen SlaviÄ, Darius Bacon 6264 * 6265 * MIT license 6266 */ 6267 6268 if (!Date.now) 6269 Date.now = function () { 6270 return new Date().getTime(); 6271 }; 6272 6273 (function () { 6274 'use strict'; 6275 6276 var vendors = ['webkit', 'moz']; 6277 for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 6278 var vp = vendors[i]; 6279 window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; 6280 window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] 6281 || window[vp + 'CancelRequestAnimationFrame']); 6282 } 6283 if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy 6284 || !window.requestAnimationFrame || !window.cancelAnimationFrame) { 6285 var lastTime = 0; 6286 window.requestAnimationFrame = function (callback) { 6287 var now = Date.now(); 6288 var nextTime = Math.max(lastTime + 16, now); 6289 return setTimeout(function () { 6290 callback(lastTime = nextTime); 6291 }, 6292 nextTime - now); 6293 }; 6294 window.cancelAnimationFrame = clearTimeout; 6295 } 6296 }()); 6297 6298})(jQuery, window);;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.