1(function (jQuery, window) { 2 3 function registerNamespace(ns, raw) { 4 var nsParts = ns.split('.'); 5 var root = window; 6 for (var i = 0; i < nsParts.length; i++) { 7 if (typeof root[nsParts[i]] == 'undefined') { 8 root[nsParts[i]] = (raw) ? raw : {}; 9 } 10 root = root[nsParts[i]]; 11 } 12 } 13 14 // verbatim from jQuery Migrate (as of 10/13 never received an official release) 15 jQuery.sub = function() { 16 function jQuerySub( selector, context ) { 17 return new jQuerySub.fn.init( selector, context ); 18 } 19 jQuery.extend( true, jQuerySub, this ); 20 jQuerySub.superclass = this; 21 jQuerySub.fn = jQuerySub.prototype = this(); 22 jQuerySub.fn.constructor = jQuerySub; 23 jQuerySub.sub = this.sub; 24 jQuerySub.fn.init = function init( selector, context ) { 25 var instance = jQuery.fn.init.call( this, selector, context, rootjQuerySub ); 26 return instance instanceof jQuerySub ? 27 instance : 28 jQuerySub( instance ); 29 }; 30 jQuerySub.fn.init.prototype = jQuerySub.fn; 31 var rootjQuerySub = jQuerySub(document); 32 return jQuerySub; 33 }; 34 35 var $sub = jQuery.sub(); 36 37 registerNamespace('JQPM', $sub || {}); 38 registerNamespace('PhotoMosaic'); 39 registerNamespace('PhotoMosaic.$', $sub || {}); 40 registerNamespace('PhotoMosaic.version', '2.15.8'); 41 registerNamespace('PhotoMosaic.Utils'); 42 registerNamespace('PhotoMosaic.Inputs'); 43 registerNamespace('PhotoMosaic.Loader'); 44 registerNamespace('PhotoMosaic.Layouts'); 45 registerNamespace('PhotoMosaic.Plugins'); 46 registerNamespace('PhotoMosaic.ErrorChecks'); 47 registerNamespace('PhotoMosaic.Mosaics', []); 48 registerNamespace('PhotoMosaic.WP', {}); 49 registerNamespace('PhotoMosaic.LightboxBridge', {}); 50 registerNamespace('PhotoMosaic.each', function (callback) { 51 PhotoMosaic.$.each( PhotoMosaic.Mosaics, function (i, mosaic) { 52 // this = the raw target element 53 // arg[0] = the JQPM instance 54 // arg[1] = $( this ) 55 // arg[2] = direct access to $(this).photoMosaic() w/o all the typing 56 // arg[3] = index of mosaic in list of mosaics 57 callback.apply(mosaic.el, [ 58 PhotoMosaic.$, 59 mosaic.$el, 60 function (args) { 61 mosaic.$el.photoMosaic.apply(mosaic.$el, [args]); 62 }, 63 i 64 ]); 65 }); 66 }); 67 registerNamespace('PhotoMosaic.refreshPage', function () { 68 // calls instance.refresh() on existing mosaics 69 // inits any uninitialized mosaics 70 var $ = PhotoMosaic.$; 71 $.each(PhotoMosaic.WP, function (id, config) { 72 var $el = $('#' + config.target); 73 var instance = $el.data('photoMosaic') 74 var params = (instance) ? null : $.extend(true, {}, config.settings, { 75 gallery : config.gallery 76 }); 77 78 $el.photoMosaic( params ); 79 }); 80 }); 81}(jQuery, window)); 82/* 83 Modernizr 2.8.3 (Custom Build) | MIT & BSD 84 Build: http://modernizr.com/download/#-csstransforms-csstransitions-prefixed-testprop-testallprops-prefixes-domprefixes 85 // Extra > Add CSS Classes + prefix "PM_" 86*/ 87(function(window){ 88 window.PhotoMosaic.Plugins.Modernizr = function(a,b,c){function y(a){j.cssText=a}function z(a,b){return y(m.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b){for(var d in a){var e=a[d];if(!B(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function D(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}function E(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+o.join(d+" ")+d).split(" ");return A(b,"string")||A(b,"undefined")?C(e,b):(e=(a+" "+p.join(d+" ")+d).split(" "),D(e,b,c))}var d="2.8.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n="Webkit Moz O ms",o=n.split(" "),p=n.toLowerCase().split(" "),q={},r={},s={},t=[],u=t.slice,v,w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;
88var d=u.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(u.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(u.call(arguments)))};return e}),q.csstransforms=function(){return!!E("transform")},q.csstransitions=function(){return E("transition")};for(var F in q)x(q,F)&&(v=F.toLowerCase(),e[v]=q[F](),t.push((e[v]?"":"no-")+v));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" PM_"+(b?"":"no-")+a),e[a]=b}return e},y(""),i=k=null,e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.testProp=function(a){return C([a])},e.testAllProps=E,e.prefixed=function(a,b,c){return b?E(a,b,c):E(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" PM_js PM_"+t.join(" PM_")+" ":""),e}(this,this.document); 89}(window)); 90/*! 91 * imagesLoaded PACKAGED v3.1.4 92 * JavaScript is all like "You images are done yet or what?" 93 * MIT License 94 */ 95 96 97/*! 98 * EventEmitter v4.2.6 - git.io/ee 99 * Oliver Caldwell 100 * MIT license 101 * @preserve 102 */ 103(function () { 104 /** 105 * Class for managing events. 106 * Can be extended to provide event functionality in other classes. 107 * 108 * @class EventEmitter Manages event registering and emitting. 109 */ 110 function EventEmitter() {} 111 112 // Shortcuts to improve speed and size 113 var proto = EventEmitter.prototype; 114 var exports = this; 115 var originalGlobalValue = exports.EventEmitter; 116 117 /** 118 * Finds the index of the listener for the event in it's storage array. 119 * 120 * @param {Function[]} listeners Array of listeners to search through. 121 * @param {Function} listener Method to look for. 122 * @return {Number} Index of the specified listener, -1 if not found 123 * @api private 124 */ 125 function indexOfListener(listeners, listener) { 126 var i = listeners.length; 127 while (i--) { 128 if (listeners[i].listener === listener) { 129 return i; 130 } 131 } 132 133 return -1; 134 } 135 136 /** 137 * Alias a method while keeping the context correct, to allow for overwriting of target method. 138 * 139 * @param {String} name The name of the target method. 140 * @return {Function} The aliased method 141 * @api private 142 */ 143 function alias(name) { 144 return function aliasClosure() { 145 return this[name].apply(this, arguments); 146 }; 147 } 148 149 /** 150 * Returns the listener array for the specified event. 151 * Will initialise the event object and listener arrays if required. 152 * 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 c
vendor: 16,384 bytes, lines 152-557
152ontaining bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 153 * Each property in the object response is an array of listener functions. 154 * 155 * @param {String|RegExp} evt Name of the event to return the listeners from. 156 * @return {Function[]|Object} All listener functions for the event. 157 */ 158 proto.getListeners = function getListeners(evt) { 159 var events = this._getEvents(); 160 var response; 161 var key; 162 163 // Return a concatenated array of all matching events if 164 // the selector is a regular expression. 165 if (typeof evt === 'object') { 166 response = {}; 167 for (key in events) { 168 if (events.hasOwnProperty(key) && evt.test(key)) { 169 response[key] = events[key]; 170 } 171 } 172 } 173 else { 174 response = events[evt] || (events[evt] = []); 175 } 176 177 return response; 178 }; 179 180 /** 181 * Takes a list of listener objects and flattens it into a list of listener functions. 182 * 183 * @param {Object[]} listeners Raw listener objects. 184 * @return {Function[]} Just the listener functions. 185 */ 186 proto.flattenListeners = function flattenListeners(listeners) { 187 var flatListeners = []; 188 var i; 189 190 for (i = 0; i < listeners.length; i += 1) { 191 flatListeners.push(listeners[i].listener); 192 } 193 194 return flatListeners; 195 }; 196 197 /** 198 * 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. 199 * 200 * @param {String|RegExp} evt Name of the event to return the listeners from. 201 * @return {Object} All listener functions for an event in an object. 202 */ 203 proto.getListenersAsObject = function getListenersAsObject(evt) { 204 var listeners = this.getListeners(evt); 205 var response; 206 207 if (listeners instanceof Array) { 208 response = {}; 209 response[evt] = listeners; 210 } 211 212 return response || listeners; 213 }; 214 215 /** 216 * Adds a listener function to the specified event. 217 * The listener will not be added if it is a duplicate. 218 * If the listener returns true then it will be removed after it is called. 219 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 220 * 221 * @param {String|RegExp} evt Name of the event to attach the listener to. 222 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 223 * @return {Object} Current instance of EventEmitter for chaining. 224 */ 225 proto.addListener = function addListener(evt, listener) { 226 var listeners = this.getListenersAsObject(evt); 227 var listenerIsWrapped = typeof listener === 'object'; 228 var key; 229 230 for (key in listeners) { 231 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 232 listeners[key].push(listenerIsWrapped ? listener : { 233 listener: listener, 234 once: false 235 }); 236 } 237 } 238 239 return this; 240 }; 241 242 /** 243 * Alias of addListener 244 */ 245 proto.on = alias('addListener'); 246 247 /** 248 * Semi-alias of addListener. It will add a listener that will be 249 * automatically removed after it's first execution. 250 * 251 * @param {String|RegExp} evt Name of the event to attach the listener to. 252 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 253 * @return {Object} Current instance of EventEmitter for chaining. 254 */ 255 proto.addOnceListener = function addOnceListener(evt, listener) { 256 return this.addListener(evt, { 257 listener: listener, 258 once: true 259 }); 260 }; 261 262 /** 263 * Alias of addOnceListener. 264 */ 265 proto.once = alias('addOnceListener'); 266 267 /** 268 * 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. 269 * You need to tell it what event names should be matched by a regex. 270 * 271 * @param {String} evt Name of the event to create. 272 * @return {Object} Current instance of EventEmitter for chaining. 273 */ 274 proto.defineEvent = function defineEvent(evt) { 275 this.getListeners(evt); 276 return this; 277 }; 278 279 /** 280 * Uses defineEvent to define multiple events. 281 * 282 * @param {String[]} evts An array of event names to define. 283 * @return {Object} Current instance of EventEmitter for chaining. 284 */ 285 proto.defineEvents = function defineEvents(evts) { 286 for (var i = 0; i < evts.length; i += 1) { 287 this.defineEvent(evts[i]); 288 } 289 return this; 290 }; 291 292 /** 293 * Removes a listener function from the specified event. 294 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 295 * 296 * @param {String|RegExp} evt Name of the event to remove the listener from. 297 * @param {Function} listener Method to remove from the event. 298 * @return {Object} Current instance of EventEmitter for chaining. 299 */ 300 proto.removeListener = function removeListener(evt, listener) { 301 var listeners = this.getListenersAsObject(evt); 302 var index; 303 var key; 304 305 for (key in listeners) { 306 if (listeners.hasOwnProperty(key)) { 307 index = indexOfListener(listeners[key], listener); 308 309 if (index !== -1) { 310 listeners[key].splice(index, 1); 311 } 312 } 313 } 314 315 return this; 316 }; 317 318 /** 319 * Alias of removeListener 320 */ 321 proto.off = alias('removeListener'); 322 323 /** 324 * Adds listeners in bulk using the manipulateListeners method. 325 * 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. 326 * You can also pass it a regular expression to add the array of listeners to all events that match it. 327 * Yeah, this function does quite a bit. That's probably a bad thing. 328 * 329 * @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. 330 * @param {Function[]} [listeners] An optional array of listener functions to add. 331 * @return {Object} Current instance of EventEmitter for chaining. 332 */ 333 proto.addListeners = function addListeners(evt, listeners) { 334 // Pass through to manipulateListeners 335 return this.manipulateListeners(false, evt, listeners); 336 }; 337 338 /** 339 * Removes listeners in bulk using the manipulateListeners method. 340 * 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. 341 * You can also pass it an event name and an array of listeners to be removed. 342 * You can also pass it a regular expression to remove the listeners from all events that match it. 343 * 344 * @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. 345 * @param {Function[]} [listeners] An optional array of listener functions to remove. 346 * @return {Object} Current instance of EventEmitter for chaining. 347 */ 348 proto.removeListeners = function removeListeners(evt, listeners) { 349 // Pass through to manipulateListeners 350 return this.manipulateListeners(true, evt, listeners); 351 }; 352 353 /** 354 * 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. 355 * The first argument will determine if the listeners are removed (true) or added (false). 356 * 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. 357 * You can also pass it an event name and an array of listeners to be added/removed. 358 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 359 * 360 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 361 * @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. 362 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 363 * @return {Object} Current instance of EventEmitter for chaining. 364 */ 365 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 366 var i; 367 var value; 368 var single = remove ? this.removeListener : this.addListener; 369 var multiple = remove ? this.removeListeners : this.addListeners; 370 371 // If evt is an object then pass each of it's properties to this method 372 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 373 for (i in evt) { 374 if (evt.hasOwnProperty(i) && (value = evt[i])) { 375 // Pass the single listener straight through to the singular method 376 if (typeof value === 'function') { 377 single.call(this, i, value); 378 } 379 else { 380 // Otherwise pass back to the multiple function 381 multiple.call(this, i, value); 382 } 383 } 384 } 385 } 386 else { 387 // So evt must be a string 388 // And listeners must be an array of listeners 389 // Loop over it and pass each one to the multiple method 390 i = listeners.length; 391 while (i--) { 392 single.call(this, evt, listeners[i]); 393 } 394 } 395 396 return this; 397 }; 398 399 /** 400 * Removes all listeners from a specified event. 401 * If you do not specify an event then all listeners will be removed. 402 * That means every event will be emptied. 403 * You can also pass a regex to remove all events that match it. 404 * 405 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 406 * @return {Object} Current instance of EventEmitter for chaining. 407 */ 408 proto.removeEvent = function removeEvent(evt) { 409 var type = typeof evt; 410 var events = this._getEvents(); 411 var key; 412 413 // Remove different things depending on the state of evt 414 if (type === 'string') { 415 // Remove all listeners for the specified event 416 delete events[evt]; 417 } 418 else if (type === 'object') { 419 // Remove all events matching the regex. 420 for (key in events) { 421 if (events.hasOwnProperty(key) && evt.test(key)) { 422 delete events[key]; 423 } 424 } 425 } 426 else { 427 // Remove all listeners in all events 428 delete this._events; 429 } 430 431 return this; 432 }; 433 434 /** 435 * Alias of removeEvent. 436 * 437 * Added to mirror the node API. 438 */ 439 proto.removeAllListeners = alias('removeEvent'); 440 441 /** 442 * Emits an event of your choice. 443 * When emitted, every listener attached to that event will be executed. 444 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 445 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 446 * So they will not arrive within the array on the other side, they will be separate. 447 * You can also pass a regular expression to emit to all events that match it. 448 * 449 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 450 * @param {Array} [args] Optional array of arguments to be passed to each listener. 451 * @return {Object} Current instance of EventEmitter for chaining. 452 */ 453 proto.emitEvent = function emitEvent(evt, args) { 454 var listeners = this.getListenersAsObject(evt); 455 var listener; 456 var i; 457 var key; 458 var response; 459 460 for (key in listeners) { 461 if (listeners.hasOwnProperty(key)) { 462 i = listeners[key].length; 463 464 while (i--) { 465 // If the listener returns true then it shall be removed from the event 466 // The function is executed either with a basic call or an apply if there is an args array 467 listener = listeners[key][i]; 468 469 if (listener.once === true) { 470 this.removeListener(evt, listener.listener); 471 } 472 473 response = listener.listener.apply(this, args || []); 474 475 if (response === this._getOnceReturnValue()) { 476 this.removeListener(evt, listener.listener); 477 } 478 } 479 } 480 } 481 482 return this; 483 }; 484 485 /** 486 * Alias of emitEvent 487 */ 488 proto.trigger = alias('emitEvent'); 489 490 /** 491 * 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. 492 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 493 * 494 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 495 * @param {...*} Optional additional arguments to be passed to each listener. 496 * @return {Object} Current instance of EventEmitter for chaining. 497 */ 498 proto.emit = function emit(evt) { 499 var args = Array.prototype.slice.call(arguments, 1); 500 return this.emitEvent(evt, args); 501 }; 502 503 /** 504 * Sets the current value to check against when executing listeners. If a 505 * listeners return value matches the one set here then it will be removed 506 * after execution. This value defaults to true. 507 * 508 * @param {*} value The new value to check for when executing listeners. 509 * @return {Object} Current instance of EventEmitter for chaining. 510 */ 511 proto.setOnceReturnValue = function setOnceReturnValue(value) { 512 this._onceReturnValue = value; 513 return this; 514 }; 515 516 /** 517 * Fetches the current value to check against when executing listeners. If 518 * the listeners return value matches this one then it should be removed 519 * automatically. It will return true by default. 520 * 521 * @return {*|Boolean} The current value to check for or the default, true. 522 * @api private 523 */ 524 proto._getOnceReturnValue = function _getOnceReturnValue() { 525 if (this.hasOwnProperty('_onceReturnValue')) { 526 return this._onceReturnValue; 527 } 528 else { 529 return true; 530 } 531 }; 532 533 /** 534 * Fetches the events object and creates one if required. 535 * 536 * @return {Object} The events storage object. 537 * @api private 538 */ 539 proto._getEvents = function _getEvents() { 540 return this._events || (this._events = {}); 541 }; 542 543 /** 544 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 545 * 546 * @return {Function} Non conflicting EventEmitter class. 547 */ 548 EventEmitter.noConflict = function noConflict() { 549 exports.EventEmitter = originalGlobalValue; 550 return EventEmitter; 551 }; 552 553 // Expose the class either via AMD, CommonJS or the global object 554 if (typeof define === 'function' && define.amd) { 555 define('eventEmitter/EventEmitter',[],function () { 556 return EventEmitter; 557
557 }); 558 } 559 else if (typeof module === 'object' && module.exports){ 560 module.exports = EventEmitter; 561 } 562 else { 563 this.EventEmitter = EventEmitter; 564 } 565}.call(this)); 566 567/*! 568 * eventie v1.0.4 569 * event binding helper 570 * eventie.bind( elem, 'click', myFn ) 571 * eventie.unbind( elem, 'click', myFn ) 572 */ 573/*jshint browser: true, undef: true, unused: true */ 574/*global define: false */ 575(function( window ) { 576 var docElem = document.documentElement; 577 var bind = function() {}; 578 579 function getIEEvent( obj ) { 580 var event = window.event; 581 // add event.target 582 event.target = event.target || event.srcElement || obj; 583 return event; 584 } 585 586 if ( docElem.addEventListener ) { 587 bind = function( obj, type, fn ) { 588 obj.addEventListener( type, fn, false ); 589 }; 590 } else if ( docElem.attachEvent ) { 591 bind = function( obj, type, fn ) { 592 obj[ type + fn ] = fn.handleEvent ? 593 function() { 594 var event = getIEEvent( obj ); 595 fn.handleEvent.call( fn, event ); 596 } : 597 function() { 598 var event = getIEEvent( obj ); 599 fn.call( obj, event ); 600 }; 601 obj.attachEvent( "on" + type, obj[ type + fn ] ); 602 }; 603 } 604 605 var unbind = function() {}; 606 607 if ( docElem.removeEventListener ) { 608 unbind = function( obj, type, fn ) { 609 obj.removeEventListener( type, fn, false ); 610 }; 611 } else if ( docElem.detachEvent ) { 612 unbind = function( obj, type, fn ) { 613 obj.detachEvent( "on" + type, obj[ type + fn ] ); 614 try { 615 delete obj[ type + fn ]; 616 } catch ( err ) { 617 // can't delete window object properties 618 obj[ type + fn ] = undefined; 619 } 620 }; 621 } 622 623 var eventie = { 624 bind: bind, 625 unbind: unbind 626 }; 627 628 // transport 629 if ( typeof define === 'function' && define.amd ) { 630 // AMD 631 define( 'eventie/eventie',eventie ); 632 } else { 633 // browser global 634 window.eventie = eventie; 635 } 636})( this ); 637 638/*! 639 * imagesLoaded v3.1.4 640 * JavaScript is all like "You images are done yet or what?" 641 * MIT License 642 */ 643(function( window, factory ) { 644 // universal module definition 645 /*global define: false, module: false, require: false */ 646 if ( typeof define === 'function' && define.amd ) { 647 // AMD 648 define( [ 649 'eventEmitter/EventEmitter', 650 'eventie/eventie' 651 ], function( EventEmitter, eventie ) { 652 return factory( window, EventEmitter, eventie ); 653 }); 654 } else if ( typeof exports === 'object' ) { 655 // CommonJS 656 module.exports = factory( 657 window, 658 require('eventEmitter'), 659 require('eventie') 660 ); 661 } else { 662 // browser global 663 window.PhotoMosaic.Plugins.imagesLoaded = factory( 664 window, 665 window.EventEmitter, 666 window.eventie 667 ); 668 } 669})( this, 670 671// -------------------------- factory -------------------------- // 672function factory( window, EventEmitter, eventie ) { 673 var $ = window.JQPM; 674 var console = window.console; 675 var hasConsole = typeof console !== 'undefined'; 676 677 // -------------------------- helpers -------------------------- // 678 // extend objects 679 function extend( a, b ) { 680 for ( var prop in b ) { 681 a[ prop ] = b[ prop ]; 682 } 683 return a; 684 } 685 686 var objToString = Object.prototype.toString; 687 function isArray( obj ) { 688 return objToString.call( obj ) === '[object Array]'; 689 } 690 691 // turn element or nodeList into an array 692 function makeArray( obj ) { 693 var ary = []; 694 if ( isArray( obj ) ) { 695 // use object if already an array 696 ary = obj; 697 } else if ( typeof obj.length === 'number' ) { 698 // convert nodeList to array 699 for ( var i=0, len = obj.length; i < len; i++ ) { 700 ary.push( obj[i] ); 701 } 702 } else { 703 // array of single index 704 ary.push( obj ); 705 } 706 return ary; 707 } 708 709 // -------------------------- imagesLoaded -------------------------- // 710 /** 711 * @param {Array, Element, NodeList, String} elem 712 * @param {Object or Function} options - if function, use as callback 713 * @param {Function} onAlways - callback function 714 */ 715 function ImagesLoaded( elem, options, onAlways ) { 716 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 717 if ( !( this instanceof ImagesLoaded ) ) { 718 return new ImagesLoaded( elem, options ); 719 } 720 // use elem as selector string 721 if ( typeof elem === 'string' ) { 722 elem = document.querySelectorAll( elem ); 723 } 724 725 this.elements = makeArray( elem ); 726 this.options = extend( {}, this.options ); 727 728 if ( typeof options === 'function' ) { 729 onAlways = options; 730 } else { 731 extend( this.options, options ); 732 } 733 734 if ( onAlways ) { 735 this.on( 'always', onAlways ); 736 } 737 738 this.getImages(); 739 740 if ( $ ) { 741 // add jQuery Deferred object 742 this.jqDeferred = new $.Deferred(); 743 } 744 745 // HACK check async to allow time to bind listeners 746 var _this = this; 747 setTimeout( function() { 748 _this.check(); 749 }); 750 } 751 752 ImagesLoaded.prototype = new EventEmitter(); 753 754 ImagesLoaded.prototype.options = {}; 755 756 ImagesLoaded.prototype.getImages = function() { 757 this.images = []; 758 759 // filter & find items if we have an item selector 760 for ( var i=0, len = this.elements.length; i < len; i++ ) { 761 var elem = this.elements[i]; 762 // filter siblings 763 if ( elem.nodeName === 'IMG' ) { 764 this.addImage( elem ); 765 } 766 // find children 767 var childElems = elem.querySelectorAll('img'); 768 // concat childElems to filterFound array 769 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 770 var img = childElems[j]; 771 this.addImage( img ); 772 } 773 } 774 }; 775 776 /** 777 * @param {Image} img 778 */ 779 ImagesLoaded.prototype.addImage = function( img ) { 780 var loadingImage = new LoadingImage( img ); 781 this.images.push( loadingImage ); 782 }; 783
784 ImagesLoaded.prototype.check = function() { 785 var _this = this; 786 var checkedCount = 0; 787 var length = this.images.length; 788 this.hasAnyBroken = false; 789 // complete if no images 790 if ( !length ) { 791 this.complete(); 792 return; 793 } 794 795 function onConfirm( image, message ) { 796 if ( _this.options.debug && hasConsole ) { 797 console.log( 'confirm', image, message ); 798 } 799 800 _this.progress( image ); 801 checkedCount++; 802 if ( checkedCount === length ) { 803 _this.complete(); 804 } 805 return true; // bind once 806 } 807 808 for ( var i=0; i < length; i++ ) { 809 var loadingImage = this.images[i]; 810 loadingImage.on( 'confirm', onConfirm ); 811 loadingImage.check(); 812 } 813 }; 814 815 ImagesLoaded.prototype.progress = function( image ) { 816 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 817 // HACK - Chrome triggers event before object properties have changed. #83 818 var _this = this; 819 setTimeout( function() { 820 _this.emit( 'progress', _this, image ); 821 if ( _this.jqDeferred && _this.jqDeferred.notify ) { 822 _this.jqDeferred.notify( _this, image ); 823 } 824 }); 825 }; 826 827 ImagesLoaded.prototype.complete = function() { 828 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 829 this.isComplete = true; 830 var _this = this; 831 // HACK - another setTimeout so that confirm happens after progress 832 setTimeout( function() { 833 _this.emit( eventName, _this ); 834 _this.emit( 'always', _this ); 835 if ( _this.jqDeferred ) { 836 var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve'; 837 _this.jqDeferred[ jqMethod ]( _this ); 838 } 839 }); 840 }; 841 842 // -------------------------- jquery -------------------------- // 843 if ( $ ) { 844 $.fn.imagesLoaded = function( options, callback ) { 845 var instance = new ImagesLoaded( this, options, callback ); 846 return instance.jqDeferred.promise( $(this) ); 847 }; 848 } 849 850 // -------------------------- -------------------------- // 851 function LoadingImage( img ) { 852 this.img = img; 853 } 854 855 LoadingImage.prototype = new EventEmitter(); 856 857 LoadingImage.prototype.check = function() { 858 // first check cached any previous images that have same src 859 var resource = cache[ this.img.src ] || new Resource( this.img.src ); 860 if ( resource.isConfirmed ) { 861 this.confirm( resource.isLoaded, 'cached was confirmed' ); 862 return; 863 } 864 865 // If complete is true and browser supports natural sizes, 866 // try to check for image status manually. 867 if ( this.img.complete && this.img.naturalWidth !== undefined ) { 868 // report based on naturalWidth 869 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 870 return; 871 } 872 873 // If none of the checks above matched, simulate loading on detached element. 874 var _this = this; 875 resource.on( 'confirm', function( resrc, message ) { 876 _this.confirm( resrc.isLoaded, message ); 877 return true; 878 }); 879 880 resource.check(); 881 }; 882 883 LoadingImage.prototype.confirm = function( isLoaded, message ) { 884 this.isLoaded = isLoaded; 885 this.emit( 'confirm', this, message ); 886 }; 887 888 // -------------------------- Resource -------------------------- // 889 // Resource checks each src, only once 890 // separate class from LoadingImage to prevent memory leaks. See #115 891 892 var cache = {}; 893 894 function Resource( src ) { 895 this.src = src; 896 // add to cache 897 cache[ src ] = this; 898 } 899 900 Resource.prototype = new EventEmitter(); 901 902 Resource.prototype.check = function() { 903 // only trigger checking once 904 if ( this.isChecked ) { 905 return; 906 } 907 // simulate loading on detached element 908 var proxyImage = new Image(); 909 eventie.bind( proxyImage, 'load', this ); 910 eventie.bind( proxyImage, 'error', this ); 911 proxyImage.src = this.src; 912 // set flag 913 this.isChecked = true; 914 }; 915 916 // ----- events ----- // 917 918 // trigger specified handler for event type 919 Resource.prototype.handleEvent = function( event ) { 920 var method = 'on' + event.type; 921 if ( this[ method ] ) { 922 this[ method ]( event ); 923 } 924 }; 925 926 Resource.prototype.onload = function( event ) { 927 this.confirm( true, 'onload' ); 928 this.unbindProxyEvents( event ); 929 }; 930 931 Resource.prototype.onerror = function( event ) { 932 this.confirm( false, 'onerror' ); 933 this.unbindProxyEvents( event ); 934 }; 935 936 // ----- confirm ----- // 937 938 Resource.prototype.confirm = function( isLoaded, message ) { 939 this.isConfirmed = true; 940 this.isLoaded = isLoaded;
vendor: 1,742 bytes, lines 941-991
941 this.emit( 'confirm', this, message ); 942 }; 943 944 Resource.prototype.unbindProxyEvents = function( event ) { 945 eventie.unbind( event.target, 'load', this ); 946 eventie.unbind( event.target, 'error', this ); 947 }; 948 949 // ----- ----- // 950 return ImagesLoaded; 951}); 952/* 953 Version: 2.0.5a 954 Modified by Mike Kafka (http://codecanyon.net/user/makfak) to serve my own purposes 955 - #28 - reference custom $ instance (root.jQuery >>> root.JQPM) 956 - #41,42 - custom event namespaces to prevent colisions with other waypoints instances 957*/ 958// Generated by CoffeeScript 1.6.2 959/*! 960jQuery Waypoints - v2.0.5 961Copyright (c) 2011-2014 Caleb Troughton 962Licensed under the MIT license. 963https://github.com/imakewebthings/jquery-waypoints/blob/master/licenses.txt 964*/ 965 966(function() { 967 var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, 968 __slice = [].slice; 969 970 (function(root, factory) { 971 if (typeof define === 'function' && define.amd) { 972 return define('waypoints', ['jquery'], function($) { 973 return factory($, root); 974 }); 975 } else { 976 return factory(root.JQPM, root); 977 } 978 })(window, function($, window) { 979 var $w, Context, Waypoint, allWaypoints, contextCounter, contextKey, contexts, isTouch, jQMethods, methods, resizeEvent, scrollEvent, waypointCounter, waypointKey, wp, wps; 980 981 $w = $(window); 982 isTouch = __indexOf.call(window, 'ontouchstart') >= 0; 983 allWaypoints = { 984 horizontal: {}, 985 vertical: {} 986 }; 987 contextCounter = 1; 988 contexts = {}; 989 contextKey = 'waypoints-context-id'; 990 resizeEvent = 'resize.waypoints_pm'; 991 scrollEvent = 'scroll.waypoints_pm
vendor: 15,618 bytes, lines 991-1473
991'; 992 waypointCounter = 1; 993 waypointKey = 'waypoints-waypoint-ids'; 994 wp = 'waypoint'; 995 wps = 'waypoints'; 996 Context = (function() { 997 function Context($element) { 998 var _this = this; 999 1000 this.$element = $element; 1001 this.element = $element[0]; 1002 this.didResize = false; 1003 this.didScroll = false; 1004 this.id = 'context' + contextCounter++; 1005 this.oldScroll = { 1006 x: $element.scrollLeft(), 1007 y: $element.scrollTop() 1008 }; 1009 this.waypoints = { 1010 horizontal: {}, 1011 vertical: {} 1012 }; 1013 this.element[contextKey] = this.id; 1014 contexts[this.id] = this; 1015 $element.bind(scrollEvent, function() { 1016 var scrollHandler; 1017 1018 if (!(_this.didScroll || isTouch)) { 1019 _this.didScroll = true; 1020 scrollHandler = function() { 1021 _this.doScroll(); 1022 return _this.didScroll = false; 1023 }; 1024 return window.setTimeout(scrollHandler, $[wps].settings.scrollThrottle); 1025 } 1026 }); 1027 $element.bind(resizeEvent, function() { 1028 var resizeHandler; 1029 1030 if (!_this.didResize) { 1031 _this.didResize = true; 1032 resizeHandler = function() { 1033 $[wps]('refresh'); 1034 return _this.didResize = false; 1035 }; 1036 return window.setTimeout(resizeHandler, $[wps].settings.resizeThrottle); 1037 } 1038 }); 1039 } 1040 1041 Context.prototype.doScroll = function() { 1042 var axes, 1043 _this = this; 1044 1045 axes = { 1046 horizontal: { 1047 newScroll: this.$element.scrollLeft(), 1048 oldScroll: this.oldScroll.x, 1049 forward: 'right', 1050 backward: 'left' 1051 }, 1052 vertical: { 1053 newScroll: this.$element.scrollTop(), 1054 oldScroll: this.oldScroll.y, 1055 forward: 'down', 1056 backward: 'up' 1057 } 1058 }; 1059 if (isTouch && (!axes.vertical.oldScroll || !axes.vertical.newScroll)) { 1060 $[wps]('refresh'); 1061 } 1062 $.each(axes, function(aKey, axis) { 1063 var direction, isForward, triggered; 1064 1065 triggered = []; 1066 isForward = axis.newScroll > axis.oldScroll; 1067 direction = isForward ? axis.forward : axis.backward; 1068 $.each(_this.waypoints[aKey], function(wKey, waypoint) { 1069 var _ref, _ref1; 1070 1071 if ((axis.oldScroll < (_ref = waypoint.offset) && _ref <= axis.newScroll)) { 1072 return triggered.push(waypoint); 1073 } else if ((axis.newScroll < (_ref1 = waypoint.offset) && _ref1 <= axis.oldScroll)) { 1074 return triggered.push(waypoint); 1075 } 1076 }); 1077 triggered.sort(function(a, b) { 1078 return a.offset - b.offset; 1079 }); 1080 if (!isForward) { 1081 triggered.reverse(); 1082 } 1083 return $.each(triggered, function(i, waypoint) { 1084 if (waypoint.options.continuous || i === triggered.length - 1) { 1085 return waypoint.trigger([direction]); 1086 } 1087 }); 1088 }); 1089 return this.oldScroll = { 1090 x: axes.horizontal.newScroll, 1091 y: axes.vertical.newScroll 1092 }; 1093 }; 1094 1095 Context.prototype.refresh = function() { 1096 var axes, cOffset, isWin, 1097 _this = this; 1098 1099 isWin = $.isWindow(this.element); 1100 cOffset = this.$element.offset(); 1101 this.doScroll(); 1102 axes = { 1103 horizontal: { 1104 contextOffset: isWin ? 0 : cOffset.left, 1105 contextScroll: isWin ? 0 : this.oldScroll.x, 1106 contextDimension: this.$element.width(), 1107 oldScroll: this.oldScroll.x, 1108 forward: 'right', 1109 backward: 'left', 1110 offsetProp: 'left' 1111 }, 1112 vertical: { 1113 contextOffset: isWin ? 0 : cOffset.top, 1114 contextScroll: isWin ? 0 : this.oldScroll.y, 1115 contextDimension: isWin ? $[wps]('viewportHeight') : this.$element.height(), 1116 oldScroll: this.oldScroll.y, 1117 forward: 'down', 1118 backward: 'up', 1119 offsetProp: 'top' 1120 } 1121 }; 1122 return $.each(axes, function(aKey, axis) { 1123 return $.each(_this.waypoints[aKey], function(i, waypoint) { 1124 var adjustment, elementOffset, oldOffset, _ref, _ref1; 1125 1126 adjustment = waypoint.options.offset; 1127 oldOffset = waypoint.offset; 1128 elementOffset = $.isWindow(waypoint.element) ? 0 : waypoint.$element.offset()[axis.offsetProp]; 1129 if ($.isFunction(adjustment)) { 1130 adjustment = adjustment.apply(waypoint.element); 1131 } else if (typeof adjustment === 'string') { 1132 adjustment = parseFloat(adjustment); 1133 if (waypoint.options.offset.indexOf('%') > -1) { 1134 adjustment = Math.ceil(axis.contextDimension * adjustment / 100); 1135 } 1136 } 1137 waypoint.offset = elementOffset - axis.contextOffset + axis.contextScroll - adjustment; 1138 if ((waypoint.options.onlyOnScroll && (oldOffset != null)) || !waypoint.enabled) { 1139 return; 1140 } 1141 if (oldOffset !== null && (oldOffset < (_ref = axis.oldScroll) && _ref <= waypoint.offset)) { 1142 return waypoint.trigger([axis.backward]); 1143 } else if (oldOffset !== null && (oldOffset > (_ref1 = axis.oldScroll) && _ref1 >= waypoint.offset)) { 1144 return waypoint.trigger([axis.forward]); 1145 } else if (oldOffset === null && axis.oldScroll >= waypoint.offset) { 1146 return waypoint.trigger([axis.forward]); 1147 } 1148 }); 1149 }); 1150 }; 1151 1152 Context.prototype.checkEmpty = function() { 1153 if ($.isEmptyObject(this.waypoints.horizontal) && $.isEmptyObject(this.waypoints.vertical)) { 1154 this.$element.unbind([resizeEvent, scrollEvent].join(' ')); 1155 return delete contexts[this.id]; 1156 } 1157 }; 1158 1159 return Context; 1160 1161 })(); 1162 Waypoint = (function() { 1163 function Waypoint($element, context, options) { 1164 var idList, _ref; 1165 1166 if (options.offset === 'bottom-in-view') { 1167 options.offset = function() { 1168 var contextHeight; 1169 1170 contextHeight = $[wps]('viewportHeight'); 1171 if (!$.isWindow(context.element)) { 1172 contextHeight = context.$element.height(); 1173 } 1174 return contextHeight - $(this).outerHeight(); 1175 }; 1176 } 1177 this.$element = $element; 1178 this.element = $element[0]; 1179 this.axis = options.horizontal ? 'horizontal' : 'vertical'; 1180 this.callback = options.handler; 1181 this.context = context; 1182 this.enabled = options.enabled; 1183 this.id = 'waypoints' + waypointCounter++; 1184 this.offset = null; 1185 this.options = options; 1186 context.waypoints[this.axis][this.id] = this; 1187 allWaypoints[this.axis][this.id] = this; 1188 idList = (_ref = this.element[waypointKey]) != null ? _ref : []; 1189 idList.push(this.id); 1190 this.element[waypointKey] = idList; 1191 } 1192 1193 Waypoint.prototype.trigger = function(args) { 1194 if (!this.enabled) { 1195 return; 1196 } 1197 if (this.callback != null) { 1198 this.callback.apply(this.element, args); 1199 } 1200 if (this.options.triggerOnce) { 1201 return this.destroy(); 1202 } 1203 }; 1204 1205 Waypoint.prototype.disable = function() { 1206 return this.enabled = false; 1207 }; 1208 1209 Waypoint.prototype.enable = function() { 1210 this.context.refresh(); 1211 return this.enabled = true; 1212 }; 1213 1214 Waypoint.prototype.destroy = function() { 1215 delete allWaypoints[this.axis][this.id]; 1216 delete this.context.waypoints[this.axis][this.id]; 1217 return this.context.checkEmpty(); 1218 }; 1219 1220 Waypoint.getWaypointsByElement = function(element) { 1221 var all, ids; 1222 1223 ids = element[waypointKey]; 1224 if (!ids) { 1225 return []; 1226 } 1227 all = $.extend({}, allWaypoints.horizontal, allWaypoints.vertical); 1228 return $.map(ids, function(id) { 1229 return all[id]; 1230 }); 1231 }; 1232 1233 return Waypoint; 1234 1235 })(); 1236 methods = { 1237 init: function(f, options) { 1238 var _ref; 1239 1240 options = $.extend({}, $.fn[wp].defaults, options); 1241 if ((_ref = options.handler) == null) { 1242 options.handler = f; 1243 } 1244 this.each(function() { 1245 var $this, context, contextElement, _ref1; 1246 1247 $this = $(this); 1248 contextElement = (_ref1 = options.context) != null ? _ref1 : $.fn[wp].defaults.context; 1249 if (!$.isWindow(contextElement)) { 1250 contextElement = $this.closest(contextElement); 1251 } 1252 contextElement = $(contextElement); 1253 context = contexts[contextElement[0][contextKey]]; 1254 if (!context) { 1255 context = new Context(contextElement); 1256 } 1257 return new Waypoint($this, context, options); 1258 }); 1259 $[wps]('refresh'); 1260 return this; 1261 }, 1262 disable: function() { 1263 return methods._invoke.call(this, 'disable'); 1264 }, 1265 enable: function() { 1266 return methods._invoke.call(this, 'enable'); 1267 }, 1268 destroy: function() { 1269 return methods._invoke.call(this, 'destroy'); 1270 }, 1271 prev: function(axis, selector) { 1272 return methods._traverse.call(this, axis, selector, function(stack, index, waypoints) { 1273 if (index > 0) { 1274 return stack.push(waypoints[index - 1]); 1275 } 1276 }); 1277 }, 1278 next: function(axis, selector) { 1279 return methods._traverse.call(this, axis, selector, function(stack, index, waypoints) { 1280 if (index < waypoints.length - 1) { 1281 return stack.push(waypoints[index + 1]); 1282 } 1283 }); 1284 }, 1285 _traverse: function(axis, selector, push) { 1286 var stack, waypoints; 1287 1288 if (axis == null) { 1289 axis = 'vertical'; 1290 } 1291 if (selector == null) { 1292 selector = window; 1293 } 1294 waypoints = jQMethods.aggregate(selector); 1295 stack = []; 1296 this.each(function() { 1297 var index; 1298 1299 index = $.inArray(this, waypoints[axis]); 1300 return push(stack, index, waypoints[axis]); 1301 }); 1302 return this.pushStack(stack); 1303 }, 1304 _invoke: function(method) { 1305 this.each(function() { 1306 var waypoints; 1307 1308 waypoints = Waypoint.getWaypointsByElement(this); 1309 return $.each(waypoints, function(i, waypoint) { 1310 waypoint[method](); 1311 return true; 1312 }); 1313 }); 1314 return this; 1315 } 1316 }; 1317 $.fn[wp] = function() { 1318 var args, method; 1319 1320 method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 1321 if (methods[method]) { 1322 return methods[method].apply(this, args); 1323 } else if ($.isFunction(method)) { 1324 return methods.init.apply(this, arguments); 1325 } else if ($.isPlainObject(method)) { 1326 return methods.init.apply(this, [null, method]); 1327 } else if (!method) { 1328 return $.error("jQuery Waypoints needs a callback function or handler option."); 1329 } else { 1330 return $.error("The " + method + " method does not exist in jQuery Waypoints."); 1331 } 1332 }; 1333 $.fn[wp].defaults = { 1334 context: window, 1335 continuous: true, 1336 enabled: true, 1337 horizontal: false, 1338 offset: 0, 1339 triggerOnce: false 1340 }; 1341 jQMethods = { 1342 refresh: function() { 1343 return $.each(contexts, function(i, context) { 1344 return context.refresh(); 1345 }); 1346 }, 1347 viewportHeight: function() { 1348 var _ref; 1349 1350 return (_ref = window.innerHeight) != null ? _ref : $w.height(); 1351 }, 1352 aggregate: function(contextSelector) { 1353 var collection, waypoints, _ref; 1354 1355 collection = allWaypoints; 1356 if (contextSelector) { 1357 collection = (_ref = contexts[$(contextSelector)[0][contextKey]]) != null ? _ref.waypoints : void 0; 1358 } 1359 if (!collection) { 1360 return []; 1361 } 1362 waypoints = { 1363 horizontal: [], 1364 vertical: [] 1365 }; 1366 $.each(waypoints, function(axis, arr) { 1367 $.each(collection[axis], function(key, waypoint) { 1368 return arr.push(waypoint); 1369 }); 1370 arr.sort(function(a, b) { 1371 return a.offset - b.offset; 1372 }); 1373 waypoints[axis] = $.map(arr, function(waypoint) { 1374 return waypoint.element; 1375 }); 1376 return waypoints[axis] = $.unique(waypoints[axis]); 1377 }); 1378 return waypoints; 1379 }, 1380 above: function(contextSelector) { 1381 if (contextSelector == null) { 1382 contextSelector = window; 1383 } 1384 return jQMethods._filter(contextSelector, 'vertical', function(context, waypoint) { 1385 return waypoint.offset <= context.oldScroll.y; 1386 }); 1387 }, 1388 below: function(contextSelector) { 1389 if (contextSelector == null) { 1390 contextSelector = window; 1391 } 1392 return jQMethods._filter(contextSelector, 'vertical', function(context, waypoint) { 1393 return waypoint.offset > context.oldScroll.y; 1394 }); 1395 }, 1396 left: function(contextSelector) { 1397 if (contextSelector == null) { 1398 contextSelector = window; 1399 } 1400 return jQMethods._filter(contextSelector, 'horizontal', function(context, waypoint) { 1401 return waypoint.offset <= context.oldScroll.x; 1402 }); 1403 }, 1404 right: function(contextSelector) { 1405 if (contextSelector == null) { 1406 contextSelector = window; 1407 } 1408 return jQMethods._filter(contextSelector, 'horizontal', function(context, waypoint) { 1409 return waypoint.offset > context.oldScroll.x; 1410 }); 1411 }, 1412 enable: function() { 1413 return jQMethods._invoke('enable'); 1414 }, 1415 disable: function() { 1416 return jQMethods._invoke('disable'); 1417 }, 1418 destroy: function() { 1419 return jQMethods._invoke('destroy'); 1420 }, 1421 extendFn: function(methodName, f) { 1422 return methods[methodName] = f; 1423 }, 1424 _invoke: function(method) { 1425 var waypoints; 1426 1427 waypoints = $.extend({}, allWaypoints.vertical, allWaypoints.horizontal); 1428 return $.each(waypoints, function(key, waypoint) { 1429 waypoint[method](); 1430 return true; 1431 }); 1432 }, 1433 _filter: function(selector, axis, test) { 1434 var context, waypoints; 1435 1436 context = contexts[$(selector)[0][contextKey]]; 1437 if (!context) { 1438 return []; 1439 } 1440 waypoints = []; 1441 $.each(context.waypoints[axis], function(i, waypoint) { 1442 if (test(context, waypoint)) { 1443 return waypoints.push(waypoint); 1444 } 1445 }); 1446 waypoints.sort(function(a, b) { 1447 return a.offset - b.offset; 1448 }); 1449 return $.map(waypoints, function(waypoint) { 1450 return waypoint.element; 1451 }); 1452 } 1453 }; 1454 $[wps] = function() { 1455 var args, method; 1456 1457 method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 1458 if (jQMethods[method]) { 1459 return jQMethods[method].apply(null, args); 1460 } else { 1461 return jQMethods.aggregate.call(null, method); 1462 } 1463 }; 1464 $[wps].settings = { 1465 resizeThrottle: 100, 1466 scrollThrottle: 30 1467 }; 1468 return $w.on('load.waypoints', function() { 1469 return $[wps]('refresh'); 1470 }); 1471 }); 1472 1473}).call(this);
1474/* 1475 Version: 3.1.6f 1476 Modified by Mike Kafka (http://codecanyon.net/user/makfak) to serve my own purposes 1477 # b 1478 - new jQuery namespace (JQPM) 1479 - _getFileType (#662) extended to autodetect image URLs (avoid the need for "iframe=true") 1480 - content type switch (#330) extended to support iframe URLs w/o "iframe=true" 1481 # c 1482 - normalized all jQuery references to '$' 1483 - self-invoke arguments ref the window and test for availability (window.JQPM || jQuery) 1484 # d 1485 - new namespace on events 1486 # e 1487 - changed viewport buffer 200 >>> 100 (~#600) 1488 - locked the overlay to the screen (CSS) 1489 - removed the .ppt bumper (CSS) 1490 #f 1491 - changed default 'horizontal_padding' value to match the default theme (what's with the check ~#164) 1492*/ 1493/* ------------------------------------------------------------------------ 1494 Class: prettyPhoto 1495 Use: Lightbox clone for jQuery 1496 Author: Stephane Caron (http://www.no-margin-for-errors.com) 1497 Version: 3.1.6 1498------------------------------------------------------------------------- */ 1499(function($) { 1500 $.prettyPhoto = {version: '3.1.6'}; 1501 1502 $.fn.prettyPhoto = function(pp_settings) { 1503 pp_settings = $.extend({ 1504 hook: 'rel', /* the attribute tag to use for prettyPhoto hooks. default: 'rel'. For HTML5, use "data-rel" or similar. */ 1505 animation_speed: 'fast', /* fast/slow/normal */ 1506 ajaxcallback: function() {}, 1507 slideshow: 5000, /* false OR interval time in ms */ 1508 autoplay_slideshow: false, /* true/false */ 1509 opacity: 0.80, /* Value between 0 and 1 */ 1510 show_title: true, /* true/false */ 1511 allow_resize: true, /* Resize the photos bigger than viewport. true/false */ 1512 allow_expand: true, /* Allow the user to expand a resized image. true/false */ 1513 default_width: 500, 1514 default_height: 344, 1515 counter_separator_label: '/', /* The separator for the gallery counter 1 "of" 2 */ 1516 theme: 'pp_default', /* light_rounded / dark_rounded / light_square / dark_square / facebook */ 1517 horizontal_padding: 16, /* The padding on each side of the picture */ 1518 hideflash: false, /* Hides all the flash object on a page, set to TRUE if flash appears over prettyPhoto */ 1519 wmode: 'opaque', /* Set the flash wmode attribute */ 1520 autoplay: true, /* Automatically start videos: True/False */ 1521 modal: false, /* If set to true, only the close button will close the window */ 1522 deeplinking: true, /* Allow prettyPhoto to update the url to enable deeplinking. */ 1523 overlay_gallery: true, /* If set to true, a gallery will overlay the fullscreen image on mouse over */ 1524 overlay_gallery_max: 30, /* Maximum number of pictures in the overlay gallery */ 1525 keyboard_shortcuts: true, /* Set to false if you open forms inside prettyPhoto */ 1526 changepicturecallback: function(){}, /* Called everytime an item is shown/changed */ 1527 callback: function(){}, /* Called when prettyPhoto is closed */ 1528 ie6_fallback: true, 1529 markup: '<div class="pp_pic_holder"> \ 1530 <div class="ppt"> </div> \ 1531 <div class="pp_top"> \ 1532 <div class="pp_left"></div> \ 1533 <div class="pp_middle"></div> \ 1534 <div class="pp_right"></div> \ 1535 </div> \ 1536 <div class="pp_content_container"> \ 1537 <div class="pp_left"> \ 1538 <div class="pp_right"> \ 1539 <div class="pp_content"> \ 1540 <div class="pp_loaderIcon"></div> \ 1541 <div class="pp_fade"> \ 1542 <a href="#" class="pp_expand" title="Expand the image">Expand</a> \ 1543 <div class="pp_hoverContainer"> \ 1544 <a class="pp_next" href="#">next</a> \ 1545 <a class="pp_previous" href="#">previous</a> \ 1546 </div> \ 1547 <div id="pp_full_res"></div> \ 1548 <div class="pp_details"> \ 1549 <div class="pp_nav"> \ 1550 <a href="#" class="pp_arrow_previous">Previous</a> \ 1551 <p class="currentTextHolder">0/0</p> \ 1552 <a href="#" class="pp_arrow_next">Next</a> \ 1553 </div> \ 1554 <p class="pp_description"></p> \ 1555 <div class="pp_social">{pp_social}</div> \ 1556 <a class="pp_close" href="#">Close</a> \ 1557 </div> \ 1558 </div> \ 1559 </div> \ 1560 </div> \ 1561 </div> \ 1562 </div> \ 1563 <div class="pp_bottom"> \ 1564 <div class="pp_left"></div> \ 1565 <div class="pp_middle"></div> \ 1566 <div class="pp_right"></div> \ 1567 </div> \ 1568 </div> \ 1569 <div class="pp_overlay"></div>', 1570 gallery_markup: '<div class="pp_gallery"> \ 1571 <a href="#" class="pp_arrow_previous">Previous</a> \ 1572 <div> \ 1573 <ul> \ 1574 {gallery} \ 1575 </ul> \ 1576 </div> \ 1577 <a href="#" class="pp_arrow_next">Next</a> \ 1578 </div>', 1579 image_markup: '<img id="fullResImage" src="{path}" />', 1580 flash_markup: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{width}" height="{height}"><param name="wmode" value="{wmode}" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{path}" /><embed src="{path}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="{width}" height="{height}" wmode="{wmode}"></embed></object>', 1581 quicktime_markup: '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" height="{height}" width="{width}"><param name="src" value="{path}"><param name="autoplay" value="{autoplay}"><param name="type" value="video/quicktime"><embed src="{path}" height="{height}" width="{width}" autoplay="{autoplay}" type="video/quicktime" pluginspage="http://www.apple.com/quicktime/download/"></embed></object>', 1582 iframe_markup: '<iframe src ="{path}" width="{width}" height="{height}" frameborder="no"></iframe>', 1583 inline_markup: '<div class="pp_inline">{content}</div>', 1584 custom_markup: '', 1585 social_tools: '<div class="twitter"><a href="http://twitter.com/share" class="twitter-share-button" data-count="none">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script></div><div class="facebook"><iframe src="//www.facebook.com/plugins/like.php?locale=en_US&href={location_href}&layout=button_count&show_faces=true&width=500&action=like&font&colorscheme=light&height=23" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:23px;" allowTransparency="true"></iframe></div>' /* html or false to disable */ 1586 }, pp_settings); 1587 1588 // Global variables accessible only by prettyPhoto 1589 var matchedObjects = this, percentBased = false, pp_dimensions, pp_open, 1590 1591 // prettyPhoto container specific 1592 pp_contentHeight, pp_contentWidth, pp_containerHeight, pp_containerWidth, 1593
1594 // Window size 1595 windowHeight = $(window).height(), windowWidth = $(window).width(), 1596 1597 // Global elements 1598 pp_slideshow; 1599 1600 doresize = true, scroll_pos = _get_scroll(); 1601 1602 // Window/Keyboard events 1603 $(window).unbind('resize.pm-prettyphoto').bind('resize.pm-prettyphoto',function(){ _center_overlay(); _resize_overlay(); }); 1604 1605 if(pp_settings.keyboard_shortcuts) { 1606 $(document).unbind('keydown.pm-prettyphoto').bind('keydown.pm-prettyphoto',function(e){ 1607 if(typeof $pp_pic_holder != 'undefined'){ 1608 if($pp_pic_holder.is(':visible')){ 1609 switch(e.keyCode){ 1610 case 37: 1611 $.prettyPhoto.changePage('previous'); 1612 e.preventDefault(); 1613 break; 1614 case 39: 1615 $.prettyPhoto.changePage('next'); 1616 e.preventDefault(); 1617 break; 1618 case 27: 1619 if(!settings.modal) 1620 $.prettyPhoto.close(); 1621 e.preventDefault(); 1622 break; 1623 }; 1624 // return false; 1625 }; 1626 }; 1627 }); 1628 }; 1629 1630 /** 1631 * Initialize prettyPhoto. 1632 */ 1633 $.prettyPhoto.initialize = function() { 1634 1635 settings = pp_settings; 1636 1637 if(settings.theme == 'pp_default') settings.horizontal_padding = 16; 1638 1639 // Find out if the picture is part of a set 1640 theRel = $(this).attr(settings.hook); 1641 galleryRegExp = /\[(?:.*)\]/; 1642 isSet = (galleryRegExp.exec(theRel)) ? true : false; 1643 1644 // Put the SRCs, TITLEs, ALTs into an array. 1645 pp_images = (isSet) ? $.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return $(n).attr('href'); }) : $.makeArray($(this).attr('href')); 1646 pp_titles = (isSet) ? $.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).find('img').attr('alt')) ? $(n).find('img').attr('alt') : ""; }) : $.makeArray($(this).find('img').attr('alt')); 1647 pp_descriptions = (isSet) ? $.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).attr('title')) ? $(n).attr('title') : ""; }) : $.makeArray($(this).attr('title')); 1648 1649 if(pp_images.length > settings.overlay_gallery_max) settings.overlay_gallery = false; 1650 1651 set_position = $.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned 1652 rel_index = (isSet) ? set_position : $("a["+settings.hook+"^='"+theRel+"']").index($(this)); 1653 1654 _build_overlay(this); // Build the overlay {this} being the caller 1655 1656 if(settings.allow_resize) 1657 $(window).bind('scroll.pm-prettyphoto',function(){ _center_overlay(); }); 1658 1659 1660 $.prettyPhoto.open(); 1661 1662 return false; 1663 } 1664 1665 1666 /** 1667 * Opens the prettyPhoto modal box. 1668 * @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths. 1669 * @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles. 1670 * @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions. 1671 */ 1672 $.prettyPhoto.open = function(event) { 1673 if(typeof settings == "undefined"){ // Means it's an API call, need to manually get the settings and set the variables 1674 settings = pp_settings; 1675 pp_images = $.makeArray(arguments[0]); 1676 pp_titles = (arguments[1]) ? $.makeArray(arguments[1]) : $.makeArray(""); 1677 pp_descriptions = (arguments[2]) ? $.makeArray(arguments[2]) : $.makeArray(""); 1678 isSet = (pp_images.length > 1) ? true : false;
1679 set_position = (arguments[3])? arguments[3]: 0; 1680 _build_overlay(event.target); // Build the overlay {this} being the caller 1681 } 1682 1683 if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','hidden'); // Hide the flash 1684 1685 _checkPosition($(pp_images).size()); // Hide the next/previous links if on first or last images. 1686 1687 $('.pp_loaderIcon').show(); 1688 1689 if(settings.deeplinking) 1690 setHashtag(); 1691 1692 // Rebuild Facebook Like Button with updated href 1693 if(settings.social_tools){ 1694 facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); 1695 $pp_pic_holder.find('.pp_social').html(facebook_like_link); 1696 } 1697 1698 // Fade the content in 1699 if($ppt.is(':hidden')) $ppt.css('opacity',0).show(); 1700 $pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity); 1701 1702 // Display the current position 1703 $pp_pic_holder.find('.currentTextHolder').text((set_position+1) + settings.counter_separator_label + $(pp_images).size()); 1704 1705 // Set the description 1706 if(typeof pp_descriptions[set_position] != 'undefined' && pp_descriptions[set_position] != ""){ 1707 $pp_pic_holder.find('.pp_description').show().html(unescape(pp_descriptions[set_position])); 1708 }else{ 1709 $pp_pic_holder.find('.pp_description').hide(); 1710 } 1711 1712 // Get the dimensions 1713 movie_width = ( parseFloat(getParam('width',pp_images[set_position])) ) ? getParam('width',pp_images[set_position]) : settings.default_width.toString(); 1714 movie_height = ( parseFloat(getParam('height',pp_images[set_position])) ) ? getParam('height',pp_images[set_position]) : settings.default_height.toString(); 1715 1716 // If the size is % based, calculate according to window dimensions 1717 percentBased=false; 1718 if(movie_height.indexOf('%') != -1) { movie_height = parseFloat(($(window).height() * parseFloat(movie_height) / 100) - 150); percentBased = true; } 1719 if(movie_width.indexOf('%') != -1) { movie_width = parseFloat(($(window).width() * parseFloat(movie_width) / 100) - 150); percentBased = true; } 1720 1721 // Fade the holder 1722 $pp_pic_holder.fadeIn(function(){ 1723 // Set the title 1724 (settings.show_title && pp_titles[set_position] != "" && typeof pp_titles[set_position] != "undefined") ? $ppt.html(unescape(pp_titles[set_position])) : $ppt.html(' '); 1725 1726 imgPreloader = ""; 1727 skipInjection = false; 1728 1729 // Inject the proper content 1730 switch(_getFileType(pp_images[set_position])){ 1731 case 'image': 1732 imgPreloader = new Image(); 1733 1734 // Preload the neighbour images 1735 nextImage = new Image(); 1736 if(isSet && set_position < $(pp_images).size() -1) nextImage.src = pp_images[set_position + 1]; 1737 prevImage = new Image(); 1738 if(isSet && pp_images[set_position - 1]) prevImage.src = pp_images[set_position - 1]; 1739 1740 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = settings.image_markup.replace(/{path}/g,pp_images[set_position]); 1741 1742 imgPreloader.onload = function(){ 1743 // Fit item to viewport 1744 pp_dimensions = _fitToViewport(imgPreloader.width,imgPreloader.height); 1745 1746 _showContent(); 1747 }; 1748 1749 imgPreloader.onerror = function(){ 1750 alert('Image cannot be loaded. Make sure the path is correct and image exist.'); 1751 $.prettyPhoto.close(); 1752 }; 1753 1754 imgPreloader.src = pp_images[set_position]; 1755 break; 1756 1757 case 'youtube': 1758 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 1759 1760 // Regular youtube link 1761 movie_id = getParam('v',pp_images[set_position]); 1762 1763 // youtu.be link 1764 if(movie_id == ""){ 1765 movie_id = pp_images[set_position].split('youtu.be/'); 1766 movie_id = movie_id[1]; 1767 if(movie_id.indexOf('?') > 0) 1768 movie_id = movie_id.substr(0,movie_id.indexOf('?')); // Strip anything after the ? 1769 1770 if(movie_id.indexOf('&') > 0) 1771 movie_id = movie_id.substr(0,movie_id.indexOf('&')); // Strip anything after the & 1772 } 1773 1774 movie = 'http://www.youtube.com/embed/'+movie_id; 1775 (getParam('rel',pp_images[set_position])) ? movie+="?rel="+getParam('rel',pp_images[set_position]) : movie+="?rel=1"; 1776 1777 if(settings.autoplay) movie += "&autoplay=1"; 1778 1779 toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie); 1780 break; 1781 1782 case 'vimeo': 1783 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 1784 1785 movie_id = pp_images[set_position]; 1786 var regExp = /http(s?):\/\/(www\.)?vimeo.com\/(\d+)/; 1787 var match = movie_id.match(regExp); 1788 1789 movie = 'http://player.vimeo.com/video/'+ match[3] +'?title=0&byline=0&portrait=0'; 1790 if(settings.autoplay) movie += "&autoplay=1;"; 1791 1792 vimeo_width = pp_dimensions['width'] + '/embed/?moog_width='+ pp_dimensions['width']; 1793 1794 toInject = settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,movie); 1795 break; 1796 1797 case 'quicktime': 1798 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 1799 pp_dimensions['height']+=15; pp_dimensions['contentHeight']+=15; pp_dimensions['containerHeight']+=15; // Add space for the control bar 1800 1801 toInject = settings.quicktime_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}
1801/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay); 1802 break; 1803 1804 case 'flash': 1805 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 1806 1807 flash_vars = pp_images[set_position]; 1808 flash_vars = flash_vars.substring(pp_images[set_position].indexOf('flashvars') + 10,pp_images[set_position].length); 1809 1810 filename = pp_images[set_position]; 1811 filename = filename.substring(0,filename.indexOf('?')); 1812 1813 toInject = settings.flash_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+'?'+flash_vars); 1814 break; 1815 1816 case 'iframe': 1817 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 1818 1819 frame_url = pp_images[set_position]; 1820 1821 if ( frame_url.indexOf('?') !== 0 && frame_url.indexOf('iframe') !== -1) { 1822 frame_url = frame_url.substr(0,frame_url.indexOf('iframe')-1); 1823 } 1824 1825 toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,frame_url); 1826 break; 1827 1828 case 'ajax': 1829 doresize = false; // Make sure the dimensions are not resized. 1830 pp_dimensions = _fitToViewport(movie_width,movie_height); 1831 doresize = true; // Reset the dimensions 1832 1833 skipInjection = true; 1834 $.get(pp_images[set_position],function(responseHTML){ 1835 toInject = settings.inline_markup.replace(/{content}/g,responseHTML); 1836 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; 1837 _showContent(); 1838 }); 1839 1840 break; 1841 1842 case 'custom': 1843 pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport 1844 1845 toInject = settings.custom_markup; 1846 break; 1847 1848 case 'inline': 1849 // to get the item height clone it, apply default width, wrap it in the prettyPhoto containers , then delete 1850 myClone = $(pp_images[set_position]).clone().append('<br clear="all" />').css({'width':settings.default_width}).wrapInner('<div id="pp_full_res"><div class="pp_inline"></div></div>').appendTo($('body')).show(); 1851 doresize = false; // Make sure the dimensions are not resized. 1852 pp_dimensions = _fitToViewport($(myClone).width(),$(myClone).height()); 1853 doresize = true; // Reset the dimensions 1854 $(myClone).remove(); 1855 toInject = settings.inline_markup.replace(/{content}/g,$(pp_images[set_position]).html()); 1856 break; 1857 }; 1858 1859 if(!imgPreloader && !skipInjection){ 1860 $pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject; 1861 1862 // Show content 1863 _showContent(); 1864 }; 1865 }); 1866 1867 return false; 1868 }; 1869 1870 1871 /** 1872 * Change page in the prettyPhoto modal box 1873 * @param direction {String} Direction of the paging, previous or next. 1874 */ 1875 $.prettyPhoto.changePage = function(direction){ 1876 currentGalleryPage = 0; 1877 1878 if(direction == 'previous') { 1879 set_position--; 1880 if (set_position < 0) set_position = $(pp_images).size()-1; 1881 }else if(direction == 'next'){ 1882 set_position++; 1883 if(set_position > $(pp_images).size()-1) set_position = 0; 1884 }else{ 1885 set_position=direction; 1886 }; 1887 1888 rel_index = set_position; 1889 1890 if(!doresize) doresize = true; // Allow the resizing of the images 1891 if(settings.allow_expand) { 1892 $('.pp_contract').removeClass('pp_contract').addClass('pp_expand'); 1893 } 1894 1895 _hideContent(function(){ $.prettyPhoto.open(); }); 1896 }; 1897 1898 1899 /** 1900 * Change gallery page in the prettyPhoto modal box 1901 * @param direction {String} Direction of the paging, previous or next. 1902 */ 1903 $.prettyPhoto.changeGalleryPage = function(direction){ 1904 if(direction=='next'){ 1905 currentGalleryPage ++; 1906 1907 if(currentGalleryPage > totalPage) currentGalleryPage = 0; 1908 }else if(direction=='previous'){ 1909 currentGalleryPage --; 1910 1911 if(currentGalleryPage < 0) currentGalleryPage = totalPage; 1912 }else{ 1913 currentGalleryPage = direction; 1914 }; 1915 1916 slide_speed = (direction == 'next' || direction == 'previous') ? settings.animation_speed : 0; 1917 1918 slide_to = currentGalleryPage * (itemsPerPage * itemWidth); 1919 1920 $pp_gallery.find('ul').animate({left:-slide_to},slide_speed); 1921 }; 1922 1923 1924 /** 1925 * Start the slideshow... 1926 */ 1927 $.prettyPhoto.startSlideshow = function(){ 1928 if(typeof pp_slideshow == 'undefined'){ 1929 $pp_pic_holder.find('.pp_play').unbind('click').removeClass('pp_play').addClass('pp_pause').click(function(){ 1930 $.prettyPhoto.stopSlideshow(); 1931 return false;
1932 }); 1933 pp_slideshow = setInterval($.prettyPhoto.startSlideshow,settings.slideshow); 1934 }else{ 1935 $.prettyPhoto.changePage('next'); 1936 }; 1937 } 1938 1939 1940 /** 1941 * Stop the slideshow... 1942 */ 1943 $.prettyPhoto.stopSlideshow = function(){ 1944 $pp_pic_holder.find('.pp_pause').unbind('click').removeClass('pp_pause').addClass('pp_play').click(function(){ 1945 $.prettyPhoto.startSlideshow(); 1946 return false; 1947 }); 1948 clearInterval(pp_slideshow); 1949 pp_slideshow=undefined; 1950 } 1951 1952 1953 /** 1954 * Closes prettyPhoto. 1955 */ 1956 $.prettyPhoto.close = function(){ 1957 if($pp_overlay.is(":animated")) return; 1958 1959 $.prettyPhoto.stopSlideshow(); 1960 1961 $pp_pic_holder.stop().find('object,embed').css('visibility','hidden'); 1962 1963 $('div.pp_pic_holder,div.ppt,.pp_fade').fadeOut(settings.animation_speed,function(){ $(this).remove(); }); 1964 1965 $pp_overlay.fadeOut(settings.animation_speed, function(){ 1966 1967 if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','visible'); // Show the flash 1968 1969 $(this).remove(); // No more need for the prettyPhoto markup 1970 1971 $(window).unbind('scroll.pm-prettyphoto'); 1972 1973 clearHashtag(); 1974 1975 settings.callback(); 1976 1977 doresize = true; 1978 1979 pp_open = false; 1980 1981 delete settings; 1982 }); 1983 }; 1984 1985 /** 1986 * Set the proper sizes on the containers and animate the content in. 1987 */ 1988 function _showContent(){ 1989 $('.pp_loaderIcon').hide(); 1990 1991 // Calculate the opened top position of the pic holder 1992 projectedTop = scroll_pos['scrollTop'] + ((windowHeight/2) - (pp_dimensions['containerHeight']/2)); 1993 if(projectedTop < 0) projectedTop = 0; 1994 1995 $ppt.fadeTo(settings.animation_speed,1); 1996 1997 // Resize the content holder 1998 $pp_pic_holder.find('.pp_content') 1999 .animate({ 2000 height:pp_dimensions['contentHeight'], 2001 width:pp_dimensions['contentWidth'] 2002 },settings.animation_speed); 2003 2004 var halfWidth = (windowWidth/2) - (pp_dimensions['containerWidth']/2); 2005 2006 // Resize picture the holder 2007 $pp_pic_holder.animate({ 2008 'top': projectedTop, 2009 'left': (halfWidth < 0) ? 0 : halfWidth, 2010 'width': pp_dimensions['containerWidth'] 2011 },settings.animation_speed,function(){ 2012 $pp_pic_holder.find('.pp_hoverContainer,#fullResImage').height(pp_dimensions['height']).width(pp_dimensions['width']); 2013 2014 $pp_pic_holder.find('.pp_fade').fadeIn(settings.animation_speed); // Fade the new content 2015 2016 // Show the nav 2017 if(isSet && _getFileType(pp_images[set_position])=="image") { $pp_pic_holder.find('.pp_hoverContainer').show(); }else{ $pp_pic_holder.find('.pp_hoverContainer').hide(); } 2018 2019 if(settings.allow_expand) { 2020 if(pp_dimensions['resized']){ // Fade the resizing link if the image is resized 2021 $('a.pp_expand,a.pp_contract').show(); 2022 }else{ 2023 $('a.pp_expand').hide(); 2024 } 2025 } 2026 2027 if(settings.autoplay_slideshow && !pp_slideshow && !pp_open) $.prettyPhoto.startSlideshow(); 2028 2029 settings.changepicturecallback(); // Callback! 2030 2031 pp_open = true; 2032 }); 2033 2034 _insert_gallery(); 2035 pp_settings.ajaxcallback(); 2036 }; 2037 2038 /** 2039 * Hide the content...DUH! 2040 */ 2041 function _hideContent(callback){ 2042 // Fade out the current picture 2043 $pp_pic_holder.find('#pp_full_res object,#pp_full_res embed').css('visibility','hidden'); 2044 $pp_pic_holder.find('.pp_fade').fadeOut(settings.animation_speed,function(){ 2045 $('.pp_loaderIcon').show(); 2046 2047 callback(); 2048 }); 2049 }; 2050 2051 /** 2052 * Check the item position in the gallery array, hide or show the navigation links 2053 * @param setCount {integer} The total number of items in the set 2054 */ 2055 function _checkPosition(setCount){ 2056 (setCount > 1) ? $('.pp_nav').show() : $('.pp_nav').hide(); // Hide the bottom nav if it's not a set. 2057 }; 2058 2059 /** 2060 * Resize the item dimensions if it's bigger than the viewport 2061 * @param width {integer} Width of the item to be opened 2062 * @param height {integer} Height of the item to be opened 2063 * @return An array containin the "fitted" dimensions 2064 */ 2065 function _fitToViewport(width,height){ 2066 resized = false;
2067 2068 _getDimensions(width,height); 2069 2070 // Define them in case there's no resize needed 2071 imageWidth = width, imageHeight = height; 2072 2073 if( ((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)) && doresize && settings.allow_resize && !percentBased) { 2074 resized = true, fitting = false; 2075 2076 while (!fitting){ 2077 if((pp_containerWidth > windowWidth)){ 2078 imageWidth = (windowWidth - 100); 2079 imageHeight = (height/width) * imageWidth; 2080 }else if((pp_containerHeight > windowHeight)){ 2081 imageHeight = (windowHeight - 100); 2082 imageWidth = (width/height) * imageHeight; 2083 }else{ 2084 fitting = true; 2085 }; 2086 2087 pp_containerHeight = imageHeight, pp_containerWidth = imageWidth; 2088 }; 2089 2090 2091 2092 if((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)){ 2093 _fitToViewport(pp_containerWidth,pp_containerHeight) 2094 }; 2095 2096 _getDimensions(imageWidth,imageHeight); 2097 }; 2098 2099 return { 2100 width:Math.floor(imageWidth), 2101 height:Math.floor(imageHeight), 2102 containerHeight:Math.floor(pp_containerHeight), 2103 containerWidth:Math.floor(pp_containerWidth) + (settings.horizontal_padding * 2), 2104 contentHeight:Math.floor(pp_contentHeight), 2105 contentWidth:Math.floor(pp_contentWidth), 2106 resized:resized 2107 }; 2108 }; 2109 2110 /** 2111 * Get the containers dimensions according to the item size 2112 * @param width {integer} Width of the item to be opened 2113 * @param height {integer} Height of the item to be opened 2114 */ 2115 function _getDimensions(width,height){ 2116 width = parseFloat(width); 2117 height = parseFloat(height); 2118 2119 // Get the details height, to do so, I need to clone it since it's invisible 2120 $pp_details = $pp_pic_holder.find('.pp_details'); 2121 $pp_details.width(width); 2122 detailsHeight = parseFloat($pp_details.css('marginTop')) + parseFloat($pp_details.css('marginBottom')); 2123 2124 $pp_details = $pp_details.clone().addClass(settings.theme).width(width).appendTo($('body')).css({ 2125 'position':'absolute', 2126 'top':-10000 2127 }); 2128 detailsHeight += $pp_details.height(); 2129 detailsHeight = (detailsHeight <= 34) ? 36 : detailsHeight; // Min-height for the details 2130 $pp_details.remove(); 2131 2132 // Get the titles height, to do so, I need to clone it since it's invisible 2133 $pp_title = $pp_pic_holder.find('.ppt'); 2134 $pp_title.width(width); 2135 titleHeight = parseFloat($pp_title.css('marginTop')) + parseFloat($pp_title.css('marginBottom')); 2136 $pp_title = $pp_title.clone().appendTo($('body')).css({ 2137 'position':'absolute', 2138 'top':-10000 2139 }); 2140 titleHeight += $pp_title.height(); 2141 $pp_title.remove(); 2142 2143 // Get the container size, to resize the holder to the right dimensions 2144 pp_contentHeight = height + detailsHeight; 2145 pp_contentWidth = width; 2146 pp_containerHeight = pp_contentHeight + titleHeight + $pp_pic_holder.find('.pp_top').height() + $pp_pic_holder.find('.pp_bottom').height(); 2147 pp_containerWidth = width; 2148 } 2149 2150 function _getFileType(itemSrc){ 2151 var noQueryString = itemSrc.split("?")[0]; 2152 2153 if (itemSrc.match(/youtube\.com\/watch/i) || itemSrc.match(/youtu\.be/i)) { 2154 return 'youtube'; 2155 } else if (itemSrc.match(/vimeo\.com/i)) { 2156 return 'vimeo'; 2157 } else if (itemSrc.match(/\b.mov\b/i)) { 2158 return 'quicktime'; 2159 } else if (itemSrc.match(/\b.swf\b/i)) { 2160 return 'flash'; 2161 } else if (itemSrc.match(/\bajax=true\b/i)) { 2162 return 'ajax'; 2163 } else if (itemSrc.match(/\bcustom=true\b/i)) { 2164 return 'custom'; 2165 } else if (itemSrc.substr(0,1) == '#') { 2166 return 'inline'; 2167 } else if ( 2168 itemSrc.match(/\biframe=true\b/i) 2169 || !noQueryString.match(/\.(gif|jpg|jpeg|tiff|png)$/i) 2170 ) { 2171 return 'iframe'; 2172 } else { 2173 return 'image'; 2174 }; 2175 }; 2176 2177 function _center_overlay(){ 2178 if(doresize && typeof $pp_pic_holder != 'undefined') { 2179 scroll_pos = _get_scroll(); 2180 contentHeight = $pp_pic_holder.height(), contentwidth = $pp_pic_holder.width(); 2181 2182 projectedTop = (windowHeight/2) + scroll_pos['scrollTop'] - (contentHeight/2); 2183 if(projectedTop < 0) projectedTop = 0; 2184 2185 if(contentHeight > windowHeight) 2186 return; 2187 2188 $pp_pic_holder.css({ 2189 'top': projectedTop, 2190 'left': (windowWidth/2) + scroll_pos['scrollLeft'] - (contentwidth/2) 2191 }); 2192 }; 2193 }; 2194 2195 function _get_scroll(){ 2196 if (self.pageYOffset) { 2197 return {scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset}; 2198 } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict 2199 return {scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft}; 2200 } else if (document.body) {// all other Explorers 2201 return {scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft}; 2202 }; 2203 }; 2204 2205 function _resize_overlay() { 2206 windowHeight = $(window).height(), windowWidth = $(window).width(); 2207 2208 if(typeof $pp_overlay != "undefined") $pp_overlay.height($(document).height()).width(windowWidth); 2209 }; 2210 2211 function _insert_gallery(){ 2212 if(isSet && settings.overlay_gallery && _getFileType(pp_images[set_position])=="image") { 2213 itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. 2214 navWidth = (settings.theme == "facebook" || settings.theme == "pp_default") ? 50 : 30; // Define the arrow width depending on the theme 2215 2216 itemsPerPage = Math.floor((pp_dimensions['containerWidth'] - 100 - navWidth) / itemWidth); 2217 itemsPerPage = (itemsPerPage < pp_images.length) ? itemsPerPage : pp_images.length;
2218 totalPage = Math.ceil(pp_images.length / itemsPerPage) - 1; 2219 2220 // Hide the nav in the case there's no need for links 2221 if(totalPage == 0){ 2222 navWidth = 0; // No nav means no width! 2223 $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').hide(); 2224 }else{ 2225 $pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').show(); 2226 }; 2227 2228 galleryWidth = itemsPerPage * itemWidth; 2229 fullGalleryWidth = pp_images.length * itemWidth; 2230 2231 // Set the proper width to the gallery items 2232 $pp_gallery 2233 .css('margin-left',-((galleryWidth/2) + (navWidth/2))) 2234 .find('div:first').width(galleryWidth+5) 2235 .find('ul').width(fullGalleryWidth) 2236 .find('li.selected').removeClass('selected'); 2237 2238 goToPage = (Math.floor(set_position/itemsPerPage) < totalPage) ? Math.floor(set_position/itemsPerPage) : totalPage; 2239 2240 $.prettyPhoto.changeGalleryPage(goToPage); 2241 2242 $pp_gallery_li.filter(':eq('+set_position+')').addClass('selected'); 2243 }else{ 2244 $pp_pic_holder.find('.pp_content').unbind('mouseenter mouseleave'); 2245 // $pp_gallery.hide(); 2246 } 2247 } 2248 2249 function _build_overlay(caller){ 2250 // Inject Social Tool markup into General markup 2251 if(settings.social_tools) 2252 facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); 2253 2254 settings.markup = settings.markup.replace('{pp_social}',''); 2255 2256 $('body').append(settings.markup); // Inject the markup 2257 2258 $pp_pic_holder = $('.pp_pic_holder') , $ppt = $('.ppt'), $pp_overlay
2258= $('div.pp_overlay'); // Set my global selectors 2259 2260 // Inject the inline gallery! 2261 if(isSet && settings.overlay_gallery) { 2262 currentGalleryPage = 0; 2263 toInject = ""; 2264 for (var i=0; i < pp_images.length; i++) { 2265 if(!pp_images[i].match(/\b(jpg|jpeg|png|gif)\b/gi)){ 2266 classname = 'default'; 2267 img_src = ''; 2268 }else{ 2269 classname = ''; 2270 img_src = pp_images[i]; 2271 } 2272 toInject += "<li class='"+classname+"'><a href='#'><img src='" + img_src + "' width='50' alt='' /></a></li>"; 2273 }; 2274 2275 toInject = settings.gallery_markup.replace(/{gallery}/g,toInject); 2276 2277 $pp_pic_holder.find('#pp_full_res').after(toInject); 2278 2279 $pp_gallery = $('.pp_pic_holder .pp_gallery'), $pp_gallery_li = $pp_gallery.find('li'); // Set the gallery selectors 2280 2281 $pp_gallery.find('.pp_arrow_next').click(function(){ 2282 $.prettyPhoto.changeGalleryPage('next'); 2283 $.prettyPhoto.stopSlideshow(); 2284 return false; 2285 }); 2286 2287 $pp_gallery.find('.pp_arrow_previous').click(function(){ 2288 $.prettyPhoto.changeGalleryPage('previous'); 2289 $.prettyPhoto.stopSlideshow(); 2290 return false; 2291 }); 2292 2293 $pp_pic_holder.find('.pp_content').hover( 2294 function(){ 2295 $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeIn(); 2296 }, 2297 function(){ 2298 $pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeOut(); 2299 }); 2300 2301 itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin. 2302 $pp_gallery_li.each(function(i){ 2303 $(this) 2304 .find('a') 2305 .click(function(){ 2306 $.prettyPhoto.changePage(i); 2307 $.prettyPhoto.stopSlideshow(); 2308 return false; 2309 }); 2310 }); 2311 }; 2312 2313 2314 // Inject the play/pause if it's a slideshow 2315 if(settings.slideshow){ 2316 $pp_pic_holder.find('.pp_nav').prepend('<a href="#" class="pp_play">Play</a>') 2317 $pp_pic_holder.find('.pp_nav .pp_play').click(function(){ 2318 $.prettyPhoto.startSlideshow(); 2319 return false; 2320 }); 2321 } 2322 2323 $pp_pic_holder.attr('class','pp_pic_holder ' + settings.theme); // Set the proper theme 2324 2325 $pp_overlay 2326 .css({ 2327 'opacity':0, 2328 'height':$(document).height(), 2329 'width':$(window).width() 2330 }) 2331 .bind('click',function(){ 2332 if(!settings.modal) $.prettyPhoto.close(); 2333 }); 2334 2335 $('a.pp_close').bind('click',function(){ $.prettyPhoto.close(); return false; }); 2336 2337 2338 if(settings.allow_expand) { 2339 $('a.pp_expand').bind('click',function(e){ 2340 // Expand the image 2341 if($(this).hasClass('pp_expand')){ 2342 $(this).removeClass('pp_expand').addClass('pp_contract'); 2343 doresize = false; 2344 }else{ 2345 $(this).removeClass('pp_contract').addClass('pp_expand'); 2346 doresize = true; 2347 }; 2348 2349 _hideContent(function(){ $.prettyPhoto.open(); }); 2350 2351 return false; 2352 }); 2353 } 2354 2355 $pp_pic_holder.find('.pp_previous, .pp_nav .pp_arrow_previous').bind('click',function(){ 2356 $.prettyPhoto.changePage('previous'); 2357 $.prettyPhoto.stopSlideshow(); 2358 return false;
2359 }); 2360 2361 $pp_pic_holder.find('.pp_next, .pp_nav .pp_arrow_next').bind('click',function(){ 2362 $.prettyPhoto.changePage('next'); 2363 $.prettyPhoto.stopSlideshow(); 2364 return false; 2365 }); 2366 2367 _center_overlay(); // Center it 2368 }; 2369 2370 if(!pp_alreadyInitialized && getHashtag()){ 2371 pp_alreadyInitialized = true; 2372 2373 // Grab the rel index to trigger the click on the correct element 2374 hashIndex = getHashtag(); 2375 hashRel = hashIndex; 2376 hashIndex = hashIndex.substring(hashIndex.indexOf('/')+1,hashIndex.length-1); 2377 hashRel = hashRel.substring(0,hashRel.indexOf('/')); 2378 2379 // Little timeout to make sure all the prettyPhoto initialize scripts has been run. 2380 // Useful in the event the page contain several init scripts. 2381 setTimeout(function(){ $("a["+pp_settings.hook+"^='"+hashRel+"']:eq("+hashIndex+")").trigger('click'); },50); 2382 } 2383 2384 return this.unbind('click.pm-prettyphoto').bind('click.pm-prettyphoto',$.prettyPhoto.initialize); // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once 2385 }; 2386 2387 function getHashtag(){ 2388 var url = location.href; 2389 hashtag = (url.indexOf('#prettyPhoto') !== -1) ? decodeURI(url.substring(url.indexOf('#prettyPhoto')+1,url.length)) : false; 2390 if (hashtag) { 2391 hashtag = hashtag.replace(/<|>/g,''); 2392 } 2393 return hashtag; 2394 }; 2395 2396 function setHashtag(){ 2397 if(typeof theRel == 'undefined') return; // theRel is set on normal calls, it's impossible to deeplink using the API 2398 location.hash = theRel + '/'+rel_index+'/'; 2399 }; 2400 2401 function clearHashtag(){ 2402 if ( location.href.indexOf('#prettyPhoto') !== -1 ) location.hash = "prettyPhoto"; 2403 } 2404 2405 function getParam(name,url){ 2406 name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); 2407 var regexS = "[\\?&]"+name+"=([^&#]*)"; 2408 var regex = new RegExp( regexS ); 2409 var results = regex.exec( url ); 2410 return ( results == null ) ? "" : results[1]; 2411 } 2412 2413})(window.JQPM||jQuery); 2414 2415var pp_alreadyInitialized = false; // Used for the deep linking to make sure not to call the same function several times. 2416 2417PhotoMosaic.Utils = (function(){ 2418 var S4 = function () { 2419 return ( ( (1 + Math.random()) * 0x10000 ) | 0 ).toString(16).substring(1); 2420 }; 2421 2422 return { 2423 log : { 2424 info: function (msg) { 2425 this.prefix(msg); 2426 }, 2427 2428 error: function (msg) { 2429 this.prefix("ERROR: " + msg); 2430 }, 2431 2432 prefix: function (msg) { 2433 this.print("PhotoMosaic: " + msg); 2434 }, 2435 2436 print: function (msg) { 2437 if (window.console !== undefined) { 2438 window.console.log(msg); 2439 } 2440 } 2441 }, 2442 2443 makeID : function (small, prefix) { 2444 prefix = (prefix) ? prefix + '_' : ''; 2445 if (small) { 2446 return prefix + S4() + S4() + '' + S4() + S4(); 2447 } else { 2448 return prefix + ( S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4() ); 2449 } 2450 }, 2451 2452 deepSearch : function (obj, key, value) { 2453 // recursively traverses an nested arrays, and objects looking for a key/value pair 2454 var response = null; 2455 var i = 0; 2456 var prop; 2457 2458 if (obj instanceof Array) { 2459 for (i = 0; i < obj.length; i++) { 2460 response = this.deepSearch(obj[i], key, value); 2461 if (response) { 2462 return response; 2463 } 2464 } 2465 } else { 2466 if (obj.hasOwnProperty(key) && obj[key] == value) { 2467 return obj 2468 } else { 2469 for (prop in obj) { 2470 if (obj.hasOwnProperty(prop)) { 2471 if (obj[prop] instanceof Object || obj[prop] instanceof Array) { 2472 response = this.deepSearch(obj[prop], key, value); 2473 if (response) { 2474 return response; 2475 } 2476 } 2477 } 2478 } 2479 } 2480 } 2481 2482 return response; 2483 }, 2484 2485 arrayToObj : function (array, key) { 2486 var response = {}; 2487 for (var i = 0; i < array.length; i++) { 2488 response[ array[i][key] ] = array[i]; 2489 }; 2490 return response; 2491 }, 2492 2493 pickImageSize : function (images, sizes, honor_device_pixel_ratio) { 2494 // currently only supported in PM4WP 2495 if (!sizes || !images[0].sizes) { return images; } 2496 2497 for (var i = 0; i < images.length; i++) { 2498 var image = images[i]; 2499 var size = null; 2500 var scaled = { 2501 width : 0, 2502 height : 0 2503 }; 2504 var pixel_ratio = (honor_device_pixel_ratio && window.devicePixelRatio) ? window.devicePixelRatio : 1; 2505 2506 for (var key in sizes) { 2507 if (sizes.hasOwnProperty(key)) { 2508 // are we dealing with a portrait or landscape image? 2509 if (image.width.original >= image.height.original) { 2510 scaled.width = sizes[key]; 2511 scaled.height = Math.floor((scaled.width * image.height.original) / image.width.original); 2512 } else { 2513 scaled.height = sizes[key]; 2514 scaled.width = Math.floor((scaled.height * image.width.original) / image.height.original); 2515 } 2516 2517 // compare the dims of the image to the space to which is has been scaled 2518 // if either of the image's dims are less than the container's dims - we'd be scaling up 2519 // scaling up is bad 2520 // keep looping until we scale the image down 2521
2522 if (scaled.width < (image.width.adjusted * pixel_ratio) || 2523 scaled.height < (image.height.adjusted * pixel_ratio)) { 2524 continue; 2525 } else { 2526 size = key; 2527 break; 2528 } 2529 } 2530 }; 2531 2532 // if none of the known sizes are big enough, go with the biggest we've got 2533 if (!size) { 2534 size = 'full'; 2535 } 2536 2537 image.src = image.sizes[size]; 2538 } 2539 2540 return images; 2541 }, 2542 2543 // setImageConstraint : function (images, layout, sizing) { 2544 // var prefix = "photomosaic-constrain-"; 2545 // var image = null; 2546 // var container_is_larger = null; 2547 // var sizing = sizing || 'cover'; 2548 2549 // function constrainWhichDimension (container_is_larger) { 2550 // var dim = "width"; 2551 // if ((container_is_larger && (sizing === 'contain')) || 2552 // (!container_is_larger && (sizing === 'cover'))) { 2553 // dim = "height"; 2554 // } 2555 // return dim; 2556 // } 2557 2558 // for (var i = 0; i < images.length; i++) { 2559 // image = images[i];
2560 // container_is_larger = (image.width.container / image.height.container) > (image.width.original / image.height.original); 2561 2562 // image.constraint = prefix + constrainWhichDimension(container_is_larger); 2563 // } 2564 2565 // images[i] = image; 2566 2567 // return images; 2568 // }, 2569 2570 decodeHTML : function (str) { 2571 var e = document.createElement('div'); 2572 e.innerHTML = str; 2573 return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue; 2574 }, 2575 2576 // taken from UnderscoreJS _.debounce() 2577 debounce : function(func, wait, immediate) { 2578 var timeout = null; 2579 var args = null; 2580 var context = null; 2581 var timestamp = null; 2582 var result = null; 2583 2584 var now = Date.now || function() { return new Date().getTime(); }; 2585 2586 var later = function() { 2587 var last = now() - timestamp; 2588 if (last < wait) { 2589 timeout = setTimeout(later, wait - last); 2590 } else { 2591 timeout = null; 2592 if (!immediate) { 2593 result = func.apply(context, args); 2594 context = args = null; 2595 } 2596 } 2597 }; 2598 2599 return function() { 2600 context = this; 2601 args = arguments; 2602 timestamp = now(); 2603 var callNow = immediate && !timeout; 2604 if (!timeout) { 2605 timeout = setTimeout(later, wait); 2606 } 2607 if (callNow) { 2608 result = func.apply(context, args); 2609 context = args = null; 2610 } 2611 2612 return result; 2613 }; 2614 }, 2615 2616 logGalleryData : function (gallery) { 2617 var output = []; 2618 for (var i = 0; i < gallery.length; i++) { 2619 output.push({ 2620 src : gallery[i].src, 2621 thumb : gallery[i].thumb, 2622 caption : gallery[i].caption, 2623 width : gallery[i].width.original, 2624 height : gallery[i].height.original 2625 }); 2626 } 2627 PhotoMosaic.Utils.log.info("Generate Gallery Data..."); 2628 PhotoMosaic.Utils.log.print( JSON.stringify(output) ); 2629 } 2630 }; 2631}(window.JQPM)); 2632PhotoMosaic.ErrorChecks = (function($){ 2633 return { 2634 initial: function (opts) { 2635 if (opts.input === 'xml') { 2636 if (typeof opts.gallery !== 'string' || opts.gallery === '') { 2637 PhotoMosaic.Utils.log.error("No XML file path specified."); 2638 return true; 2639 } 2640 } 2641 2642 if (opts.input === 'json') { 2643 if (typeof opts.gallery === 'string') { 2644 if (opts.gallery === '') { 2645 PhotoMosaic.Utils.log.error("No JSON object defined."); 2646 return true; 2647 } 2648 2649 if (typeof window[opts.gallery] !== 'undefined') { 2650 opts.gallery = window[opts.gallery]; 2651 } else { 2652 PhotoMosaic.Utils.log.error("No JSON object found when referencing '" + opts.gallery + "'."); 2653 PhotoMosaic.Utils.log.info("Make sure your variable is avaible to the global scope (window['" + opts.gallery + "']) or simply pass the object literal (gallery:" + opts.gallery + ") instead of a string (gallery:\"" + opts.gallery + "\")."); 2654 return true; 2655 } 2656 } 2657 2658 if (opts.gallery.length === 0) { 2659 PhotoMosaic.Utils.log.error("Specified gallery data is empty."); 2660 return true; 2661 } 2662 } 2663 2664 if (opts.layout == 'columns' && opts.prevent_crop && opts.height !== 'auto') { 2665 PhotoMosaic.Utils.log.info("Height must be set to 'auto' to Prevent Cropping. The value for height (" + opts.height + ") is being ignored so as to prevent cropping."); 2666 opts.height = "auto"; 2667 } 2668 return false;
2669 }, 2670 nonModernBrowser: function () { 2671 // first 2 = can't handle React 2672 // last = can't position mosaic-items 2673 return (!Array.isArray || !Object.freeze || !PhotoMosaic.Plugins.Modernizr.csstransforms); 2674 }, 2675// these got moved into layouts/columns.js 2676 imageDimensions: function (images) { 2677 var to_delete = []; 2678 2679 $.each(images, function (i) { 2680 if (isNaN(this.height.adjusted)) { 2681 to_delete.push(i); 2682 } 2683 }); 2684 2685 for (var i = to_delete.length - 1; i >= 0; i--) { 2686 PhotoMosaic.Utils.log.error("The following image failed to load and was skipped.\n" + images[to_delete[i]].src); 2687 var rest = images.slice( to_delete[i] + 1 ); 2688 images.length = to_delete[i]; 2689 images.push.apply(images, rest); 2690 } 2691 2692 return images; 2693 }, 2694 2695 layout: function (json) { 2696 var i = 0; 2697 var j = 0; 2698 2699 for (i = 0; i < json.columns.length; i++) { 2700 for (j = 0; j < json.columns[i].images.length; j++) { 2701 if (json.columns[i].images[j].height.constraint <= 0) { 2702 PhotoMosaic.Utils.log.error("Your gallery's height is too small for your current settings and won't render correctly."); 2703 return true; 2704 } 2705 }; 2706 }; 2707 2708 return false; 2709 } 2710 }; 2711}(JQPM)); 2712PhotoMosaic.Inputs = (function ($){ 2713 return { 2714 json : function (gallery) { 2715 return gallery; 2716 }, 2717 html : function ($node, opts) { 2718 var gallery = []; 2719 var $images = $node.find('img'); 2720 2721 for (var i = 0; i < $images.length; i++) { 2722 var $image = $images.eq(i); 2723 var image = { 2724 caption : $image.attr('title'), 2725 alt : $image.attr('alt'), 2726 width : parseInt( $image.attr('width') ), 2727 height : parseInt( $image.attr('height') ) 2728 }; 2729 2730 if ($image.parent('a').length > 0 && opts.links) { 2731 image.src = $image.attr('src'); 2732 image.url = $image.parent('a').attr('href'); 2733 } else if ($image.parent('a').length > 0) { 2734 image.src = $image.parent('a').attr('href'); 2735 } else { 2736 image.src = $image.attr('src'); 2737 } 2738 2739 gallery.push(image); 2740 } 2741 2742 return gallery; 2743 }, 2744 xml : function (gallery) { 2745 var response = []; 2746 2747 gallery.find('photo').each(function (i) { 2748 var image = {}; 2749 var data = $(this); 2750 2751 image.caption = data.children('title').text(); 2752 image.alt = data.children('alt').text(); 2753 image.src = data.children('src').text(); 2754 image.thumb = data.children('thumb').text(); 2755 image.url = data.children('url').text(); 2756 image.width = data.children('width').text(); 2757 image.height = data.children('height').text(); 2758 2759 response.push(image); 2760 }); 2761 2762 return response; 2763 } 2764 }; 2765 2766}(window.JQPM)); 2767(function ($) { 2768 var self = null; 2769 var loading_class = "photomosaic-loading"; 2770 var loaded_class = "photomosaic-loaded"; 2771 2772 PhotoMosaic.Loader = function ($container, mosaic) { 2773 self = this; 2774 2775 this.obj = $container; 2776 this.images = $container.find('img'); 2777 this.mosaic = mosaic; 2778 this.opts = mosaic.opts; 2779 2780 if (this.opts.lazyload === false) { 2781 this.skipLazyload(); 2782 } else { 2783 this.trigger_point = $.waypoints('viewportHeight') + this.opts.lazyload; 2784 this.lazyload(); 2785 } 2786 2787 // if you want a loading transition but the browser doesn't support it... fade (old IEs) 2788 if ( this.opts.loading_transition !== 'none' && !PhotoMosaic.Plugins.Modernizr.csstransitions ) { 2789 this.images.css('opacity','0'); 2790 } 2791 2792 return this; 2793 }; 2794 2795 PhotoMosaic.Loader.prototype = { 2796 lazyload : function () { 2797 this.images.parent().waypoint({ 2798 triggerOnce : true, 2799 offset : this.trigger_point, 2800 handler : this.handler 2801 }); 2802 }, 2803 2804 skipLazyload : function () { 2805 this.images.parent().each(function () { 2806 self.handler.apply(this); 2807 }); 2808 }, 2809 2810 handler : function () { 2811 var $this = $(this); 2812 var $image = $this.find('img'); 2813 var image_loaded = null; 2814 2815 $image.attr('src', $image.attr('data-src')); 2816 2817 image_loaded = new PhotoMosaic.Plugins.imagesLoaded($image.get(0)); 2818 image_loaded.on('progress', self.progress); 2819 image_loaded.on('fail', self.fail); 2820 image_loaded.on('always', self.always); 2821 }, 2822 2823 progress : function (instance, image) { 2824 // after each image has loaded 2825 setTimeout(function () { 2826 // if you don't want a loading transition OR it's handled by CSS 2827 if ( self.opts.loading_transition === 'none' || PhotoMosaic.Plugins.Modernizr.csstransitions ) { 2828 var $image = $(image.img); 2829 var $parent = $image.closest('.' + loading_class); 2830 var toggleClasses = function () { 2831 $parent.addClass(loaded_class); 2832 $image.off(self.mosaic._transition_end_event_name); 2833 }; 2834 2835 $image.on( 2836 self.mosaic._transition_end_event_name, 2837 toggleClasses 2838 ); 2839 2840 $parent.removeClass(loading_class); 2841 2842 } else { 2843 // you want a transition but the browser doesn't support CSS Transitions... fade (old IEs) 2844 $(image.img).animate( 2845 { 'opacity' : '1' }, 2846 self.opts.resize_transition_settings.duration * 1000, 2847 function(){ 2848 $(this).parents('.' + loading_class).removeClass(loading_class); 2849 } 2850 ); 2851 } 2852 }, 0); 2853 }, 2854 2855 fail : function (instance) { 2856 // after all images have been loaded with at least one broken image 2857 setTimeout(function () { 2858 var id = ''; 2859 var img = null; 2860 var i = 0; 2861 var j = 0; 2862 for (i = 0; i < instance.images.length; i++) { 2863 if (!instance.images[i].isLoaded) { 2864 $node = $(instance.images[i].img); 2865 id = $node.attr('id'); 2866 img = PhotoMosaic.Utils.deepSearch(self.mosaic.images, 'id', id); 2867 2868 for (j = 0; j < self.mosaic.images.length; j++) { 2869 if (self.mosaic.images[j] === img) { 2870 self.mosaic.images.splice(j,1); 2871 } 2872 }; 2873 2874 $node.parent().remove(); 2875 } 2876 }; 2877 2878 self.mosaic.refresh(); 2879 }, 0); 2880 }, 2881 2882 always : function (instance) { 2883 // after all images have been either loaded or confirmed broken 2884 setTimeout(function () { 2885 var $mosaic = self.mosaic.obj.find('.photoMosaic') 2886 var $images = $mosaic.children('a, span'); 2887 var $loading = $images.filter('.' + loading_class); 2888 2889 // transitionend fires for each proprty being transitioned, we only care about when the last one ends 2890 var toggleClasses = PhotoMosaic.Utils.debounce(function () { 2891 $mosaic.removeClass(loading_class).addClass(loaded_class); 2892 self.mosaic.obj.off(self.mosaic._transition_end_event_name); 2893 }, 1000); 2894 2895 if ($loading.length == 0) { 2896 self.mosaic.obj.on( 2897 self.mosaic._transition_end_event_name, 2898 toggleClasses 2899 ); 2900 } 2901 }, 0); 2902 } 2903 }; 2904}(window.JQPM)); 2905(function ($) { 2906 PhotoMosaic.Layouts.Common = { 2907 getRelativeWidth : function (_options, opts, node) { 2908 // auto = 100% 2909 return this.getRelativeDimenion(_options, opts, node, 'width', node.width()); 2910 }, 2911 2912 getRelativeHeight : function (_options, opts, node) { 2913 // auto != 100% 2914 return this.getRelativeDimenion(_options, opts, node, 'height', false); 2915 }, 2916 2917 getRelativeDimenion : function (_options, opts, node, dim, fallback) { 2918 if (opts[dim] && opts[dim] !== 'auto') { 2919 if (typeof(_options[dim]) == 'number') { 2920 return opts[dim]; 2921 } else if (_options[dim].indexOf('%') > -1) { 2922 return Math.floor((node[dim]() * (parseInt(_options[dim], 10) / 100))); 2923 } else { 2924 // I can't imaging what wouldn't be 'auto', a %, or an int 2925 return fallback; 2926 } 2927 } else { 2928 return fallback; 2929 } 2930 }, 2931 2932 makeColumnBuckets : function (opts) { 2933 var columns = []; 2934 var num_cols = 0; 2935 var max_width = 0; 2936 var num_images = 0 2937 var i = 0; 2938 2939 if (opts.columns && opts.columns !== 'auto') { 2940 num_images = opts.gallery.length;
2941 num_cols = (num_images < opts.columns) ? num_images : opts.columns; 2942 } else { 2943 max_width = opts.width; 2944 num_images = opts.gallery.length; 2945 mobile_cutoff = 425; 2946 num_cols = (max_width < mobile_cutoff) ? 1 : Math.floor(max_width / opts.min_column_width); 2947 2948 if (num_images < num_cols) { 2949 num_cols = num_images; 2950 } 2951 2952 if ((opts.max_columns !== 'auto') && (num_cols > opts.max_columns)) { 2953 num_cols = opts.max_columns; 2954 } 2955 2956 if ((opts.min_columns !== 'auto') && (num_cols < opts.min_columns)) { 2957 num_cols = opts.min_columns; 2958 } 2959 } 2960 2961 for (i = 0; i < num_cols; i++) { 2962 columns.push( [] ); 2963 }; 2964 2965 return columns; 2966 }, 2967 2968 getColumnWidth : function (columns, opts) { 2969 var num_cols = columns.length; 2970 var total_padding = opts.padding * (num_cols - 1); // we only pad between columns 2971 var usable_width = opts.width - total_padding; 2972 var col_width = Math.floor(usable_width / num_cols); 2973 return col_width; 2974 }, 2975 2976 getColumnHeights : function (imagesById, columns, opts) { 2977 var column_heights = []; 2978 var column_height = 0; 2979 var image = null; 2980 2981 for (var i = 0; i < columns.length; i++) { 2982 column_height = 0; 2983 2984 for (var j = 0; j < columns[i].length; j++) { 2985 image = imagesById[ columns[i][j] ]; 2986 column_height += image.height.container; 2987 } 2988 2989 column_height += (columns[i].length - 1) * opts.padding; 2990 column_heights.push( column_height ); 2991 } 2992 2993 return column_heights; 2994 }, 2995 2996 dealIntoColumns : function (images, columns, opts, isRefreshing) { 2997 switch ( opts.order ) { 2998 case 'random' : 2999 columns = this.sortRandomly( images, columns, isRefreshing ); 3000 break; 3001 3002 case 'masonry' : 3003 columns = this.sortIntoMasonry( images, columns ); 3004 break; 3005 3006 case 'columns' : 3007 columns = this.sortIntoColumns( images, columns ); 3008 break; 3009 3010 case 'rows' : 3011 default : 3012 columns = this.sortIntoRows( images, columns ); 3013 break; 3014 } 3015 3016 return columns; 3017 }, 3018 3019 sortRandomly : function (images, columns, isRefreshing) { 3020 // randomize and sort into rows 3021 // don't re-randomize if we're refreshing 3022 if (!isRefreshing) { 3023 images = this.randomizeImages( images ); 3024 } 3025 3026 columns = this.sortIntoMasonry( images, columns ); 3027 3028 return columns; 3029 }, 3030 3031 sortIntoMasonry : function (images, columns) { 3032 var num_columns = columns.length; 3033 var num_images = images.length; 3034 var column_heights = []; 3035 var which = 0; 3036 var i = 0; 3037 3038 for (i = 0; i < num_columns; i++) { 3039 column_heights[i] = 0; 3040 } 3041 3042 // always place the next image into the shortest column 3043 for (i = 0; i < num_images; i++) { 3044 which = $.inArray( 3045 Math.min.apply( Math, column_heights ), 3046 column_heights 3047 ); 3048 columns[which].push( images[i].id ); 3049 column_heights[which] = column_heights[which] + images[i].height.container; 3050 } 3051 3052 return columns; 3053 }, 3054 3055 sortIntoRows : function (images, columns) { 3056 var num_columns = columns.length; 3057 var num_images = images.length; 3058 var which = 0; 3059 var i = 0; 3060 3061 for (i = 0; i < num_images; i++) { 3062 which = i % num_columns; 3063 columns[which].push(images[i].id); 3064 } 3065 3066 return columns; 3067 }, 3068 3069 sortIntoColumns : function (images, columns) { 3070 // columns --> rows => columns 3071 var images = $.extend(true, [], images); // deep copy because we .shift() 3072 var num_images = images.length; 3073 var i = 0; 3074 var j = 0; 3075
3076 columns = this.sortIntoRows( images, columns ); 3077 3078 // Sorting into rows tells us how many images are in each column. 3079 // The specific image in each slot is wrong but the slot-division is good. 3080 // So we replace the image in each slot with the next one from the ordered list. 3081 for (i = 0; i < columns.length; i++) { 3082 for (j = 0; j < columns[i].length; j++) { 3083 columns[i][j] = images[0].id; 3084 images.shift(); 3085 } 3086 } 3087 3088 return columns; 3089 }, 3090 3091 randomizeImages : function (images) { 3092 return images.sort(function (a, b) { 3093 return (0.5 - Math.random()); 3094 }); 3095 }, 3096 3097 positionImagesInContainer : function (images, prevent_crop) { 3098 var image = null; 3099 3100 for (var i = 0; i < images.length; i++) { 3101 image = images[i]; 3102 3103 image.adjustments = {}; 3104 3105 if (!prevent_crop) { 3106 // adjusted is still scaled to the column's width 3107 if (image.height.adjusted > image.height.container) { 3108 image.adjustments.top = Math.floor((image.height.adjusted - image.height.container) / 2); 3109 } else { 3110 image.width.adjusted = Math.floor((image.width.adjusted * image.height.container) / image.height.adjusted); 3111 image.height.adjusted = image.height.container; 3112 3113 image.adjustments.left = Math.floor((image.width.adjusted - image.width.container) / 2); 3114 } 3115 } 3116 3117 image.adjustments = PhotoMosaic.Layouts.Common.normalizeAdjustments( image.adjustments ); 3118 3119 images[i] = image; 3120 }; 3121 3122 return images; 3123 }, 3124 3125 positionImagesInMosaic : function (imagesById, columns, column_width, opts) { 3126 var col_height = 0; 3127 var image = null; 3128 3129 for (var i = 0; i < columns.length; i++) { 3130 col_height = 0; 3131 3132 for (var j = 0; j < columns[i].length; j++) { 3133 image = imagesById[ columns[i][j] ]; 3134 3135 image.position = { 3136 top : col_height, 3137 left : (i * column_width) + (i * opts.padding) 3138 }; 3139 3140 col_height = col_height + image.height.container + opts.padding; 3141 }; 3142 }; 3143 }, 3144 3145 normalizeAdjustments : function (adjustments) { 3146 if (!adjustments.hasOwnProperty('top')) { 3147 adjustments.top = 0; 3148 } 3149 3150 if (!adjustments.hasOwnProperty('left')) { 3151 adjustments.left = 0; 3152 } 3153 3154 return adjustments; 3155 } 3156 }; 3157}(window.JQPM)); 3158(function ($) { 3159 'use strict'; 3160 3161 PhotoMosaic.Layouts.columns = function (mosaic) { 3162 this.node = mosaic.obj; 3163 this.opts = mosaic.opts; 3164 this._options = mosaic._options; 3165 this._options.gallery = mosaic.opts.gallery.slice(); // we want to be able to refer to the original gallery order 3166 this.images = mosaic.opts.gallery; 3167 this.imagesById = PhotoMosaic.Utils.arrayToObj( this.images, 'id' ); 3168 return this; 3169 }; 3170 3171 PhotoMosaic.Layouts.columns.prototype = { 3172 getData : function (isRefreshing) { 3173 var images = this.images; 3174 var columns = null; 3175 var column_width = null; 3176 var mosaic_height = 0; 3177 var force_hidden = false; 3178 3179 this.opts.width = PhotoMosaic.Layouts.Common.getRelativeWidth( this._options, this.opts, this.node ); 3180 3181 // lazyloading requires that there be nodes to attach to (so we need a width) 3182 // but we don't want to render the mosaic so we display:none it 3183 if ( this.errorChecks.width(this.opts.width) ) { 3184 this.opts.width = 300; 3185 force_hidden = true; 3186 } 3187 3188 // determine the number of columns 3189 this.columns = columns = PhotoMosaic.Layouts.Common.makeColumnBuckets( this.opts ); 3190 3191 // determine the column width (all columns have the same width) 3192 this.column_width = column_width = PhotoMosaic.Layouts.Common.getColumnWidth( columns, this.opts ); 3193 3194 // scale each image to the column width 3195 images = this.scaleToWidth( images, column_width ); 3196 3197 // sort the images (based on opts.order) and assign them to columns 3198 columns = PhotoMosaic.Layouts.Common.dealIntoColumns( images, columns, this.opts, isRefreshing ); 3199 3200 // determine the target height for the entire mosaic 3201 mosaic_height = this.getMosaicHeight( columns ); 3202 3203 // adjust the images in each column to the new height (for a flat bottom edge) 3204 columns = this.adjustColumnsToHeight( columns, mosaic_height ); 3205 3206 // do everything possible to make sure we show SOMETHING 3207 if ( this.errorChecks.aspectRatio(images) ) { 3208 columns = this.balanceColumnsToHeight( columns, mosaic_height ); 3209 } 3210 3211 // bail if the user's settings creates a super-broken mosaic 3212 if ( this.errorChecks.height(images) ) { 3213 return false;
3214 } 3215 3216 // create crop position info 3217 images = PhotoMosaic.Layouts.Common.positionImagesInContainer( images, this.opts.prevent_crop ); 3218 3219 // convert all this knowledge into position data 3220 // TODO : stop being a side-effect 3221 PhotoMosaic.Layouts.Common.positionImagesInMosaic( this.imagesById, columns, column_width, this.opts ); 3222 3223 images = PhotoMosaic.Utils.pickImageSize( images, this.opts.sizes, this.opts.honor_device_pixel_ratio ); 3224 3225 return { 3226 width : (column_width * columns.length) + (this.opts.padding * (columns.length - 1)), 3227 height : mosaic_height, 3228 images : images, 3229 force_hidden : force_hidden 3230 }; 3231 }, 3232 3233 scaleToWidth : function (images, width) { 3234 for (var i = 0; i < images.length; i++) { 3235 images[i].width.container = images[i].width.adjusted = width; 3236 images[i].height.container = images[i].height.adjusted = Math.floor((images[i].height.original * width) / images[i].width.original); 3237 } 3238 3239 return images; 3240 }, 3241 3242 getMosaicHeight : function (columns) { 3243 var auto_height = PhotoMosaic.Layouts.Common.getRelativeHeight( this._options, this.opts, this.node ); 3244 3245 if (auto_height) { 3246 return auto_height; 3247 } 3248 3249 var column_heights = PhotoMosaic.Layouts.Common.getColumnHeights( this.imagesById, columns, this.opts ); 3250 3251 if (this.opts.prevent_crop) { 3252 return Math.max.apply( Math, column_heights ); 3253 } 3254 3255 /* 3256 function median (values) { 3257 var half = Math.floor( values.length / 2 ); 3258 values.sort( function (a,b) { 3259 return a - b; 3260 } ); 3261 if (values.length % 2) { 3262 return values[half]; 3263 } else { 3264 return Math.ceil( (values[half-1] + values[half]) / 2 ); 3265 } 3266 } 3267 */ 3268 3269 function mean (values) { 3270 var sum = 0; 3271 var i = 0; 3272 3273 for (i = 0; i < values.length; i++) { 3274 sum += values[i]; 3275 }; 3276 3277 return Math.ceil( sum / values.length ); 3278 } 3279 3280 return mean( column_heights ); 3281 }, 3282 3283 adjustColumnsToHeight : function (columns, target_height) { 3284 if (this.opts.prevent_crop) { 3285 return columns; 3286 } 3287 for (var i = 0; i < columns.length; i++) { 3288 columns[i] = this.adjustColumnToHeight( columns[i], target_height ); 3289 } 3290 return columns; 3291 }, 3292 3293 adjustColumnToHeight: function (ids, target_height) { 3294 var column_height = 0; 3295 var i = 0; 3296 3297 // get the height of each column 3298 for (i = 0; i < ids.length; i++) { 3299 column_height += this.imagesById[ ids[i] ].height.container; 3300 } 3301 3302 column_height += (ids.length - 1) * this.opts.padding; 3303 3304 // how much do we need to grow or shrink the column 3305 var diff = target_height - column_height // (plus = grow, minus = shrink) 3306 var direction = (diff > 0) ? 'grow' : 'shrink'; 3307 diff = Math.abs(diff); 3308 3309 // spread the diff between the image 3310 i = 0; 3311 while (diff > 0) { 3312 i = (i >= ids.length) ? 0 : i; 3313 if (direction === 'grow') { 3314 this.imagesById[ ids[i] ].height.container++; 3315 } else { 3316 this.imagesById[ ids[i] ].height.container--; 3317 } 3318 i++; 3319 diff--; 3320 } 3321 3322 return ids; 3323 }, 3324 3325 balanceColumnsToHeight : function (columns, target_height) { 3326 if (this.opts.prevent_crop) { 3327 return columns; 3328 } 3329 for (var i = 0; i < columns.length; i++) { 3330 columns[i] = this.balanceColumnToHeight( columns[i], target_height ); 3331 } 3332 return columns; 3333 }, 3334 3335 balanceColumnToHeight : function (ids, target_height) { 3336 var column_height = target_height - ((ids.length - 1) * this.opts.padding); 3337 var divy = Math.floor(column_height / ids.length); 3338 var remainder = column_height % ids.length; 3339 3340 for (var i = 0; i < ids.length; i++) { 3341 this.imagesById[ ids[i] ].height.container = divy; 3342 } 3343 3344 for (var i = 0; i < remainder; i++) { 3345 this.imagesById[ ids[i] ].height.container++; 3346 } 3347 3348 return ids; 3349 }, 3350 3351 refresh : function () { 3352 return this.getData( true ); 3353 }, 3354 3355 update : function (props) { 3356 this.opts = $.extend({}, this.opts, props); 3357 3358 // take care of any layout-specific change-logic 3359 if (props.hasOwnProperty('order')) { 3360 this.images = this._options.gallery.slice(); 3361 3362 if (props.order == 'random') { 3363 this.images = PhotoMosaic.Layouts.Common.randomizeImages( this.images ); 3364 } 3365 } 3366 3367 if (props.hasOwnProperty('width')) { 3368 this._options.width = props.width; 3369 3370 if (props.width === 'auto' || props.width == 0) { 3371 this.opts.width = this.node.width(); 3372 } 3373 } 3374 }, 3375 3376 errorChecks : { 3377 aspectRatio: function (images) { 3378 for (var i = 0; i < images.length; i++) { 3379 if (images[i].height.container <= 10) { // 10 is pretty arbitrary 3380 PhotoMosaic.Utils.log.error("Your gallery's he
3380ight doesn't allow your images to proportioned based on their aspect ratios."); 3381 return true; 3382 } 3383 } 3384 return false; 3385 }, 3386 height: function (images) { 3387 for (var i = 0; i < images.length; i++) { 3388 if (images[i].height.container <= 0) { 3389 PhotoMosaic.Utils.log.error("Your gallery has been hidden because its height is too small for your current settings and won't render correctly."); 3390 return true; 3391 } 3392 } 3393 return false; 3394 }, 3395 width: function (width) { 3396 if (width == 0) { 3397 PhotoMosaic.Utils.log.error("Your gallery's target container doesn't have a width (width = 0). Make sure it isn't hidden."); 3398 return true; 3399 } 3400 return false; 3401 } 3402 } 3403 }; 3404}(window.JQPM)); 3405(function ($) { 3406 PhotoMosaic.Layouts.rows = function (mosaic) { 3407 this.node = mosaic.obj; 3408 this.opts = mosaic.opts; 3409 this._options = mosaic._options; 3410 this._options.gallery = mosaic.opts.gallery.slice(); // we want to be able to refer to the original gallery order 3411 this.images = mosaic.opts.gallery; 3412 this.imagesById = PhotoMosaic.Utils.arrayToObj( this.images, 'id' ); 3413 this.ordered_images = $.map( this.images, function (item, i) { 3414 return item.id; 3415 } ); 3416 return this; 3417 }; 3418 PhotoMosaic.Layouts.rows.prototype = { 3419 getData : function (isRefreshing) { 3420 var images = this.images; 3421 var rows = null; 3422 3423 this.opts.width = PhotoMosaic.Layouts.Common.getRelativeWidth( this._options, this.opts, this.node ); 3424 this.opts.height = PhotoMosaic.Layouts.Common.getRelativeDimenion( this._options, this.opts, this.node, 'height', this.node.height()); 3425 3426 // look for conflicting settings 3427 this.opts = this.errorChecks.initial( this._options, this.opts ); 3428 3429 // scale images to the tallest height 3430 images = this.scaleImagesToHeight( images, this.opts.max_row_height ); 3431 3432 // group into rows assuming auto-rows 3433 rows = this.groupIntoRows( images, this.opts.width ); 3434 3435 // adjust the groups to get the desired number of rows 3436 if ( 3437 (this.opts.rows === 'auto' || this.opts.rows === 0) 3438 && (this._options.height !== 'auto' && this._options.height !== 0) 3439 ) { 3440 rows = this.adjustNumberOfRowsByHeight( images, rows, this.opts.height ); 3441 } else {
3442 rows = this.adjustNumberOfRowsByRows( images, rows ); 3443 } 3444 3445 // scale the rows to the correct width 3446 rows = this.adjustRowsToWidth( rows, this.opts.width ); 3447 3448 if (!this.opts.prevent_crop) { 3449 rows = this.plumbRows( rows, this.opts.width ); 3450 } 3451 3452 if (this.opts.allow_orphans && this.hasOrphans(rows)) { 3453 // the orphan row tends to be much taller than the others 3454 rows = this.normalizeOrphanRowHeight( rows, this.opts.width ); 3455 } 3456 3457 if (this._options.height !== 'auto' && this._options.height !== 0) { 3458 rows = this.setMosaicHeight( images, rows, this.opts.height ); 3459 } 3460 3461 // create crop position info 3462 images = PhotoMosaic.Layouts.Common.positionImagesInContainer( images, this.opts.prevent_crop ); 3463 3464 // convert all this knowledge into position data 3465 this.positionImagesInMosaic( rows, this.opts.padding ); 3466 3467 images = PhotoMosaic.Utils.pickImageSize( images, this.opts.sizes, this.opts.honor_device_pixel_ratio ); 3468 3469 return { 3470 width : this.opts.width, 3471 height : this.getMosaicHeight(rows), 3472 images : images 3473 }; 3474 }, 3475 3476 groupIntoRows : function (images, container_width) { 3477 var rows = []; 3478 var row = []; 3479 var row_width = 0; 3480 3481 for (var i = 0; i < images.length; i++) { 3482 if (row_width > container_width) { 3483 rows.push( row ); 3484 row = [ images[i] ]; 3485 row_width = images[i].width.container; 3486 } else { 3487 row.push( images[i] ); 3488 row_width = row_width + images[i].width.container; 3489 } 3490 }; 3491 3492 rows.push( row ); 3493 3494 return rows; 3495 }, 3496 3497 scaleImagesToHeight : function (images, height) { 3498 for (var i = 0; i < images.length; i++) { 3499 images[i] = this.scaleImageToHeight( images[i], height ); 3500 }; 3501 3502 return images; 3503 }, 3504 3505 scaleImageToHeight : function (image, height) { 3506 image.height.container = image.height.adjusted = height; 3507 image.width.container = image.width.adjusted = Math.floor((image.width.original * height) / image.height.original); 3508 3509 return image; 3510 }, 3511 3512 adjustNumberOfRowsByRows : function (images, rows, force) { 3513 var desired = null; 3514 3515 if (force) { 3516 desired = force; 3517 } else if ( 3518 (this.opts.rows === 'auto' || this.opts.rows === 0) 3519 && !this.opts.allow_orphans 3520 && this.hasOrphans 3521 ) { 3522 desired = rows.length - 1; 3523 } else if (this.opts.rows !== 'auto' && this.opts.rows !== 0) { 3524 desired = this.opts.rows; 3525 } else { 3526 // we have what we want 3527 return rows; 3528 } 3529 3530 // binary search 3531 var lower = (rows.length < desired) ? this.opts.max_row_height : 0; 3532 var upper = (rows.length > desired) ? this.opts.max_row_height : 1000; 3533 var middle = 0; 3534 var i = 0; 3535 3536 while((upper - lower) > 1) { 3537 middle = Math.floor((upper - lower) / 2) + lower; 3538 3539 images = this.scaleImagesToHeight( images, middle ); 3540 rows = this.groupIntoRows( images, this.opts.width ); 3541 3542 if (rows.length > desired) { 3543 upper = middle; 3544 } else { 3545 lower = middle; 3546 } 3547 } 3548 3549 if (rows.length > desired) { 3550 images = this.scaleImagesToHeight( images, lower ); 3551 rows = this.groupIntoRows( images, this.opts.width ); 3552 } 3553 3554 return rows; 3555 }, 3556 3557 adjustNumberOfRowsByHeight : function (images, rows, desired) { 3558 // binary search 3559 var current = this.getMosaicHeight(rows); 3560 var lower = (current < desired) ? this.opts.max_row_height : 0; 3561 var upper = (current > desired) ? this.opts.max_row_height : 1000; 3562 var middle = 0; 3563 var i = 0; 3564 3565 while((upper - lower) > 1) { 3566 middle = Math.floor((upper - lower) / 2) + lower; 3567 3568 images = this.scaleImagesToHeight( images, middle );
3569 rows = this.groupIntoRows( images, this.opts.width ); 3570 3571 current = this.getMosaicHeight(rows); 3572 3573 if (current > desired) { 3574 upper = middle; 3575 } else { 3576 lower = middle; 3577 } 3578 } 3579 3580 if (current > desired) { 3581 images = this.scaleImagesToHeight( images, upper ); 3582 rows = this.groupIntoRows( images, this.opts.width ); 3583 } 3584 3585 return rows; 3586 }, 3587 3588 adjustRowsToWidth : function (rows, container_width) { 3589 for (var i = 0; i < rows.length; i++) { 3590 rows[i] = this.adjustRowToWidth( rows[i], container_width ); 3591 } 3592 3593 return rows; 3594 }, 3595 3596 adjustRowToWidth : function (row, container_width) { 3597 var row_width = this.getRowWidth(row); 3598 var row_height = row[0].height.container; 3599 var i = 0; 3600 3601 if (row_width > container_width) { 3602 row = this.adjustRowToHeight( row, (row_height - 1) ); 3603 return this.adjustRowToWidth( row, container_width ); 3604 } else { 3605 if (!this.opts.prevent_crop) { 3606 return this.adjustRowToHeight( row, (row_height + 1) ); 3607 } 3608 } 3609 3610 return row; 3611 }, 3612 3613 adjustRowToHeight : function (row, height) { 3614 for (var i = 0; i < row.length; i++) { 3615 row[i] = this.scaleImageToHeight( row[i], height ); 3616 } 3617 3618 return row; 3619 }, 3620 3621 plumbRows : function (rows, container_width) { 3622 for (var i = 0; i < rows.length; i++) { 3623 rows[i] = this.plumbRow( rows[i], container_width ); 3624 } 3625 return rows; 3626 }, 3627 3628 plumbRow : function (row, container_width) { 3629 var row_width = this.getRowWidth(row); 3630 var diff = row_width - container_width; 3631 var i = 0; 3632 3633 if (diff > 0) { 3634 // trim 3635 while(diff > 0) { 3636 i = (i >= row.length) ? 0 : i; 3637 row[i].width.container = row[i].width.container - 1; 3638 i++; 3639 diff--; 3640 } 3641 } else { 3642 if (Math.abs(diff) < (container_width / 10)) { 3643 // scale up 3644 while(diff < 0) { 3645 i = (i >= row.length) ? 0 : i; 3646 row[i].width.container = row[i].width.container + 1; 3647 i++; 3648 diff++; 3649 } 3650 } 3651 } 3652 3653 return row; 3654 }, 3655 3656 normalizeOrphanRowHeight : function (rows, container_width) { 3657 var last_row = rows[rows.length - 1]; 3658 var row_width = this.getRowWidth(last_row); 3659 var average_height = 0; 3660 3661 if (row_width >= container_width) { 3662 return rows; 3663 } else { 3664 average_height = this.getAverageRowHeight(rows); 3665 last_row = this.adjustRowToHeight(last_row, average_height); 3666 } 3667 3668 rows[rows.length - 1] = last_row; 3669 return rows 3670 }, 3671 3672 hasOrphans : function (rows) { 3673 var row_width = this.getRowWidth( rows[rows.length - 1] ); 3674 return (row_width < this.opts.width); 3675 }, 3676 3677 getRowWidth : function (row) { 3678 var row_width = 0; 3679 3680 for (var i = 0; i < row.length; i++) { 3681 row_width += row[i].width.container; 3682 } 3683 3684 row_width += (row.length - 1) * this.opts.padding; 3685 3686 return row_width; 3687 }, 3688 3689 getAverageRowHeight : function (rows) { 3690 var total_height = 0; 3691 3692 for (var i = 0; i < rows.length; i++) { 3693 total_height += rows[i][0].height.container; 3694 } 3695 3696 return Math.floor(total_height / rows.length); 3697 }, 3698 3699 setMosaicHeight : function (images, rows, desired) { 3700 var current = this.getMosaicHeight(rows); 3701 var diff = current - desired; 3702 var row_heights = []; 3703 var padding = this.opts.padding * (rows.length - 1); 3704 3705 // get each row's height as a percentage of the container_height 3706 for (var i = 0; i < rows.length; i++) { 3707 row_heights.push( 3708 Math.round( 3709 (((desired - padding) * rows[i][0].height.container) / (current - padding)) 3710 ) 3711 ); 3712 } 3713 3714 for (var i = 0; i < rows.length; i++) { 3715 for (var j = 0; j < rows[i].length; j++) { 3716 rows[i][j].height.container = row_heights[i]; 3717 } 3718 } 3719 3720 return rows; 3721 }, 3722 3723 getMosaicHeight : function (rows) { 3724 var total_height = 0; 3725 3726 for (var i = 0; i < rows.length; i++) { 3727 total_height += rows[i][0].height.container; 3728 } 3729 3730 return Math.ceil(total_height + ((rows.length - 1) * this.opts.padding)); 3731 }, 3732 3733 positionImagesInMosaic : function (rows, padding) { 3734 var from_left = 0; 3735 var from_top = 0; 3736 var image = null; 3737 3738 for (var i = 0; i < rows.length; i++) { 3739 from_left = 0; 3740 3741 for (var j = 0; j < rows[i].length; j++) { 3742 image = rows[i][j]; 3743 3744 image.position = { 3745 top : from_top, 3746 left : from_left 3747 }; 3748 3749 from_left = from_left + image.width.container + padding; 3750 }; 3751 3752 from_top = from_top + rows[i][0].height.container + padding; 3753 }; 3754 }, 3755 3756 refresh : function () { 3757 return this.getData( true ); 3758 }, 3759 3760 update : function (props) { 3761 this.opts = $.extend({}, this.opts, props); 3762 3763 // take care of any layout-specific change-logic 3764 if (props.hasOwnProperty('order')) { 3765 this.images = this._options.gallery.slice(); 3766 3767 if (props.order == 'random') { 3768 this.images = PhotoMosaic.Layouts.Common.randomizeImages( this.images ); 3769 } 3770 } 3771 3772 if (props.hasOwnProperty('width')) { 3773 this._options.width = props.width; 3774 3775 if (props.width === 'auto' || props.width == 0) { 3776 this.opts.width = this.node.width(); 3777 } 3778 } 3779 }, 3780 3781 errorChecks : { 3782 initial : function (_options, opts) { 3783 if (this.heightRowMismatch(_options, opts)) { 3784 PhotoMosaic.Utils.log.info("Rows must be set to 'auto' to set a fixed Height"); 3785 opts.rows = 'auto'; 3786 } 3787 if (this.heightOrphanMismatch(_options, opts)) { 3788 PhotoMosaic.Utils.log.info("Allow Orphans must be 'true' to set a fixed Height"); 3789 opts.allow_orphans = true; 3790 } 3791 if (this.heightCropMismatch(_options, opts)) { 3792 PhotoMosaic.Utils.log.info("Prevent Cropping must be 'false' to set a fixed Height"); 3793 opts.prevent_crop = false;
3794 } 3795 return opts; 3796 }, 3797 heightRowMismatch : function (_options, opts) { 3798 return ( 3799 (_options.height !== 'auto' && _options.height !== 0) 3800 && (opts.rows !== 'auto' && opts.rows !== 0) 3801 ); 3802 }, 3803 heightOrphanMismatch : function (_options, opts) { 3804 return ( 3805 (_options.height !== 'auto' && _options.height !== 0) 3806 && !opts.allow_orphans 3807 ); 3808 }, 3809 heightCropMismatch : function (_options, opts) { 3810 return ( 3811 (_options.height !== 'auto' && _options.height !== 0) 3812 && opts.prevent_crop 3813 ); 3814 }, 3815 } 3816 }; 3817}(window.JQPM)); 3818(function ($) { 3819 PhotoMosaic.Layouts.grid = function (mosaic) { 3820 this.node = mosaic.obj; 3821 this.opts = mosaic.opts; 3822 this._options = mosaic._options; 3823 this._options.gallery = mosaic.opts.gallery.slice(); // we want to be able to refer to the original gallery order 3824 this.images = mosaic.opts.gallery; 3825 this.imagesById = PhotoMosaic.Utils.arrayToObj( this.images, 'id' ); 3826 return this; 3827 }; 3828 3829 PhotoMosaic.Layouts.grid.prototype = { 3830 getData : function (isRefreshing) { 3831 var images = this.images; 3832 var columns = null; 3833 var column_width = null; 3834 var mosaic_height = 0; 3835 3836 this.opts.width = PhotoMosaic.Layouts.Common.getRelativeWidth( this._options, this.opts, this.node ); 3837 3838 // look for conflicting settings 3839 this.opts = this.errorChecks.initial( this.opts ); 3840 3841 // determine the number of columns 3842 this.columns = columns = PhotoMosaic.Layouts.Common.makeColumnBuckets( this.opts ); 3843 3844 // determine the column width (all columns have the same width) 3845 this.column_width = column_width = PhotoMosaic.Layouts.Common.getColumnWidth( columns, this.opts ); 3846 3847 // set image container 3848 images = this.setContainers(images, column_width); 3849 3850 // scale the image to the container (based on shape) 3851 images = this.scaleToContainer(images); 3852 3853 // sort the images (based on opts.order) and assign them to columns 3854 columns = PhotoMosaic.Layouts.Common.dealIntoColumns( images, columns, this.opts, isRefreshing ); 3855 3856 // adjust for height 3857 columns = this.scaleColumnsToHeight(columns, this.opts.height); 3858 3859 // determine the target height for the entire mosaic 3860 mosaic_height = this.getMosaicHeight( this.imagesById, columns, this.opts ); 3861 3862 // align 3863 images = this.alignInContainer( images ); 3864 3865 // convert all this knowledge into position data 3866 // TODO : stop being a side-effect 3867 PhotoMosaic.Layouts.Common.positionImagesInMosaic( this.imagesById, columns, column_width, this.opts ); 3868 3869 images = PhotoMosaic.Utils.pickImageSize( images, this.opts.sizes, this.opts.honor_device_pixel_ratio ); 3870 3871 return { 3872 width : (column_width * columns.length) + (this.opts.padding * (columns.length - 1)), 3873 height : mosaic_height, 3874 images : images 3875 }; 3876 }, 3877 3878 setContainers : function (images, width) { 3879 var image = null; 3880 var aspect_ratio = null; 3881 3882 for (var i = 0; i < images.length; i++) { 3883 image = images[i]; 3884 aspect_ratio = this.getAspectRatio( this.opts.shape, image ); 3885 3886 image.width.container = width; 3887 image.height.container = Math.floor( (aspect_ratio[1] * width) / aspect_ratio[0] ); 3888 3889 images[i] = image; 3890 } 3891 3892 return images; 3893 }, 3894 3895 scaleToContainer : function (images) { 3896 var image = null; 3897 var scaled_height = null; 3898 3899 for (var i = 0; i < images.length; i++) { 3900 image = (typeof images[i] == 'string') ? this.imagesById[ images[i] ] : images[i]; 3901 scaled_height = Math.floor( (image.height.original * image.width.container) / image.width.original ); 3902 3903 if ( this.shouldScaleWidth( image ) ) { 3904 image.width.adjusted = image.width.container; 3905 image.height.adjusted = Math.floor( (image.height.original * image.width.adjusted) / image.width.original ); 3906 } else { 3907 image.height.adjusted = image.height.container;
3908 image.width.adjusted = Math.floor( (image.width.original * image.height.adjusted) / image.height.original ); 3909 } 3910 } 3911 3912 return images; 3913 }, 3914 3915 scaleColumnsToHeight : function (columns, height) { 3916 if (height == 'auto' || height == 0) { 3917 return columns; 3918 } else { 3919 if ( (typeof(height) == 'string') && (height.indexOf('%') > -1) ) { 3920 height = (this.node.height() * (parseInt(height, 10) / 100)); 3921 } 3922 3923 for (var i = 0; i < columns.length; i++) { 3924 columns[i] = this.scaleColumnToHeight(columns[i], height); 3925 } 3926 3927 return columns; 3928 } 3929 }, 3930 3931 scaleColumnToHeight : function (ids, target_height) { 3932 var column_height = 0; 3933 var i = 0; 3934 3935 // get the height of each column 3936 for (i = 0; i < ids.length; i++) { 3937 column_height += this.imagesById[ ids[i] ].height.container; 3938 } 3939 3940 column_height += (ids.length - 1) * this.opts.padding; 3941 3942 // how much do we need to grow or shrink the column 3943 var diff = target_height - column_height // (plus = grow, minus = shrink) 3944 var direction = (diff > 0) ? 'grow' : 'shrink'; 3945 diff = Math.abs(diff); 3946 3947 // spread the diff between the image 3948 i = 0; 3949 while (diff > 0) { 3950 i = (i >= ids.length) ? 0 : i; 3951 if (direction === 'grow') { 3952 this.imagesById[ ids[i] ].height.container++; 3953 } else { 3954 this.imagesById[ ids[i] ].height.container--; 3955 } 3956 i++; 3957 diff--; 3958 } 3959 3960 ids = this.scaleToContainer(ids); 3961 3962 return ids; 3963 }, 3964 3965 getMosaicHeight : function (imagesById, columns, opts) { 3966 var column_heights = PhotoMosaic.Layouts.Common.getColumnHeights( imagesById, columns, opts ); 3967 return Math.max.apply( Math, column_heights ); 3968 }, 3969 3970 alignInContainer : function (images) { 3971 var image = null; 3972 3973 for (var i = 0; i < images.length; i++) { 3974 image = images[i]; 3975 image.adjustments = {}; 3976 3977 if ( this.shouldScaleWidth( image ) ) { 3978 image.adjustments.top = Math.floor( (image.height.adjusted - image.height.container) / 2 ); 3979 } else { 3980 image.adjustments.left = Math.floor( (image.width.adjusted - image.width.container) / 2 ); 3981 } 3982 3983 if (this.opts.sizing == 'contain') { 3984 switch (this.opts.align) { 3985 case 'top': 3986 image.adjustments.top = 0; 3987 break; 3988 3989 case 'middle': 3990 image.adjustments.top = Math.floor( (image.height.container - image.height.adjusted) / 2 ) * -1; 3991 break; 3992 3993 case 'bottom': 3994 image.adjustments.top = (image.height.container - image.height.adjusted) * -1; 3995 break; 3996 } 3997 } 3998 3999 image.adjustments = PhotoMosaic.Layouts.Common.normalizeAdjustments( image.adjustments ); 4000 4001 images[i] = image; 4002 }; 4003 4004 return images; 4005 }, 4006 4007 getAspectRatio : function (shape, image) { 4008 var aspect_ratio = null; 4009 4010 if ( shape == 'natural' || this.errorChecks.shape(shape) ) { 4011 aspect_ratio = [1,1]; 4012 } else { 4013 aspect_ratio = shape.split(':'); 4014 } 4015 4016 return aspect_ratio; 4017 }, 4018 4019 shouldScaleWidth : function (image) { 4020 // cover = shortest image side == longest container side 4021 // contain = longest image side == shortest container side 4022 var scaled_height = Math.floor( (image.height.original * image.width.container) / image.width.original ); 4023 return ( 4024 ((this.opts.sizing == 'cover') && (scaled_height > image.height.container)) || 4025 ((this.opts.sizing == 'contain') && (scaled_height < image.height.container)) 4026 ); 4027 }, 4028 4029 refresh : function () { 4030 return this.getData( true ); 4031 }, 4032 4033 update : function (props) { 4034 this.opts = $.extend({}, this.opts, props); 4035 4036 // take care of any layout-specific change-logic 4037 if (props.hasOwnProperty('order')) { 4038 this.images = this._options.gallery.slice(); 4039 4040 if (props.order == 'random') { 4041 this.images = PhotoMosaic.Layouts.Common.randomizeImages( this.images ); 4042 } 4043 } 4044 4045 if (props.hasOwnProperty('width')) { 4046 this._options.width = props.width; 4047 4048 if (props.width === 'auto' || props.width == 0) { 4049 this.opts.width = this.node.width(); 4050 } 4051 } 4052 }, 4053 4054 errorChecks : { 4055 initial : function (opts) { 4056 if (this.coverCropMismatch(opts)) { 4057 PhotoMosaic.Utils.log.error("Setting 'Sizing' to 'Cover' requires that images be cropped. Setting 'Prevent Cropping' to 'false'."); 4058 opts.prevent_crop = false;
4059 } 4060 if (this.heightShapeMismatch(opts)) { 4061 PhotoMosaic.Utils.log.info("A fixed 'Height' requires changing the grid item's 'Shape'. The 'Shape' setting ("+ opts.shape +") will not be honored."); 4062 opts.allow_orphans = true; 4063 } 4064 return opts; 4065 }, 4066 coverCropMismatch : function (opts) { 4067 return (opts.sizing == 'cover' && opts.prevent_crop); 4068 }, 4069 heightShapeMismatch : function (opts) { 4070 return (opts.height !== 'auto' && opts.height !== 0); 4071 }, 4072 shape : function (shape) { 4073 if ( (shape != 'natural') && (shape.indexOf(':') <= 0) ) { 4074 PhotoMosaic.Utils.log.error("'Shape' must be 'natural' or an aspect ratio in the form 'x:y'. ") 4075 return true; 4076 } 4077 return false; 4078 } 4079 } 4080 }; 4081}(window.JQPM)); 4082(function ($) { 4083 'use strict'; 4084 4085 function prefixId (id) { 4086 return 'photoMosaic_' + id; 4087 } 4088 4089 function vendorPrefix(str) { 4090 var prop = PhotoMosaic.Plugins.Modernizr.prefixed(str); 4091 return prop.replace(/([A-Z])/g, function(str,m1){ 4092 return '-' + m1.toLowerCase(); 4093 }).replace(/^ms-/,'-ms-'); 4094 } 4095 4096 PhotoMosaic.Layouts.React = { 4097 //mosaic : React.createClass({ 4098 mosaic : createReactClass({ 4099 componentDidMount : function () { 4100 $(ReactDOM.findDOMNode(this)).addClass('photomosaic-loading'); 4101 }, 4102 render : function () { 4103 var id = prefixId(this.props.id); 4104 var class_name = 'photoMosaic ' + this.props.class_name; 4105 var style = { 4106 width : this.props.width, 4107 height : this.props.height 4108 }; 4109 var images = this.props.images.map(function (image) { 4110 return ( 4111 React.createElement(PhotoMosaic.Layouts.React.item, image) 4112 ); 4113 }); 4114 4115 if (this.props.center) { 4116 style['marginRight'] = 'auto'; 4117 style['marginLeft'] = 'auto'; 4118 } 4119 4120 if (this.props.force_hidden) { 4121 style['display'] = 'none'; 4122 } 4123 4124 return ( 4125 React.createElement( 4126 'div', 4127 { 4128 id : id, 4129 className : class_name, 4130 style : style, 4131 children : images 4132 } 4133 ) 4134 ); 4135 } 4136 }), 4137 4138 item : createReactClass({ 4139 componentDidMount : function () { 4140 $(ReactDOM.findDOMNode(this)).addClass('photomosaic-loading'); 4141 }, 4142 render : function () { 4143 var data = this.props; 4144 var node_type = (data.link) ? 'a' : 'span'; 4145 var params = { 4146 className : 'photomosaic-item', 4147 key : data.id, 4148 style : { 4149 width : data.width.container, 4150 height : data.height.container 4151 }, 4152 children : [ 4153 React.createElement( 4154 PhotoMosaic.Layouts.React.spinner, 4155 $.extend({}, data, {key : data.id + '_spinner'}) 4156 ), 4157 React.createElement( 4158 PhotoMosaic.Layouts.React.animation_wrapper, 4159 data 4160 ) 4161 ] 4162 }; 4163 4164 params.style[vendorPrefix('transform')] = 'translate(' + data.position.left + 'px, ' + data.position.top + 'px)'; 4165 4166 if (data.link) { 4167 if (data.external) { params.target = '_blank'; } 4168 if (data.modal) { params.rel = data.modal; } 4169 if (data.caption) { params.title = data.caption; } 4170 params.href = data.path; 4171 } 4172 4173 return ( 4174 React.createElement(node_type, params) 4175 ); 4176 } 4177 }), 4178 4179 animation_wrapper : createReactClass({ 4180 render : function () { 4181 var data = this.props; 4182 var params = { 4183 className : 'photomosaic-animation-wrap', 4184 children : [ 4185 React.createElement(PhotoMosaic.Layouts.React.image, data) 4186 ] 4187 }; 4188 4189 return ( 4190 React.createElement('div', params) 4191 ); 4192 } 4193 }), 4194 4195 image : createReactClass({ 4196 componentDidUpdate : function (prev_props, prev_state) { 4197 var $image = $(ReactDOM.findDOMNode(this)); 4198 var next_src = $image.attr('data-src'); 4199 4200 if (prev_props.src && (prev_props.src != next_src)) { 4201 $image.attr('src', next_src); 4202 } 4203 }, 4204 render : function () { 4205 var data = this.props; 4206 var style = { 4207 width : data.width.adjusted, 4208 height : data.height.adjusted 4209 }; 4210 4211 style[vendorPrefix('transform')] = 'translate(' + (data.adjustments.left * -1) + 'px, ' + (data.adjustments.top * -1) + 'px)'; 4212 4213 return ( 4214 React.createElement( 4215 'IMG', // uppercase because of a MooTools v1.4.5 conflict 4216 { 4217 id : data.id, 4218 'data-src' : data.src, 4219 title : data.caption, 4220 alt : data.alt, 4221 style : style 4222 } 4223 ) 4224 ); 4225 } 4226 }), 4227 4228 spinner : createReactClass({ 4229 render : function () { 4230 var data = this.props; 4231 var style = { 4232 width : data.width.adjusted, 4233 height : data.height.adjusted, 4234 }; 4235 4236 style[vendorPrefix('transform')] = 'translate(' + (data.adjustments.left * -1) + 'px, ' + (data.adjustments.top * -1) + 'px)'; 4237 4238 return ( 4239 React.createElement( 4240 'div', 4241 { 4242 className : 'photomosaic-spinner-wrap', 4243 children : [ 4244 React.createElement( 4245 'div', 4246 { 4247 className : 'photomosaic-spinner', 4248 style : style 4249 } 4250 ) 4251 ] 4252 } 4253 ) 4254 ); 4255 } 4256 }), 4257 4258 loading : createReactClass({ 4259 render : function () { 4260 return ( 4261 React.createElement( 4262 'div', 4263 { 4264 id : prefixId(this.props.id), 4265 className : 'photoMosaic', 4266 children : React.createElement( 4267 'div', 4268 { 4269 className : 'photoMosaicLoading', 4270 children : 'loading gallery...' 4271 } 4272 ) 4273 } 4274 ) 4275 ); 4276 } 4277 }) 4278 }; 4279 4280}(window.JQPM)); 4281(function ($, window) { 4282 'use strict'; 4283 4284 var pluginName = 'photoMosaic'; 4285 var self; 4286 4287 var photoMosaic = function (el, options, i) { 4288 self = this; 4289 4290 this.$ = $; 4291 this.el = el; 4292 this.obj = $(el); 4293 this._options = options; 4294 4295 this._id = options.id || PhotoMosaic.Utils.makeID(true); 4296 4297 this._transition_end_event_name = (function () { 4298 var event_names = { 4299 'WebkitTransition': 'webkitTransitionEnd', 4300 'MozTransition': 'transitionend', 4301 'OTransition': 'oTransitionEnd', 4302 'msTransition': 'MSTransitionEnd', 4303 'transition': 'transitionend' 4304 }; 4305 return event_names[ PhotoMosaic.Plugins.Modernizr.prefixed( 'transition' ) ]; 4306 })(); 4307 4308 // for onReady Callback / modal_ready_callback 4309 $.data(this.el, pluginName, this); 4310 4311 // for debugging 4312 window.PhotoMosaic.Mosaics.push({ 4313 'el' : this.el, 4314 '$el' : this.obj, 4315 'opts' : this._options, 4316 'instance' : this 4317 }); 4318 4319 this.init(); 4320 }; 4321 4322 photoMosaic.prototype = { 4323 _defaults: { 4324 input : 'json', // json, html, xml 4325 gallery : 'PMalbum', // json object, xml file path 4326 padding : 2, 4327 width : 'auto', // auto (str) or (int) 4328 height : 'auto', // auto (str) or (int) 4329 links : true, 4330 external_links: false, 4331 center : true, 4332 prevent_crop : false, 4333 show_loading : false, 4334 loading_transition : 'fade', // none, fade, scale-up|down, slide-top|right|bottom|left, custom 4335 resize_transition : true, 4336 resize_transition_settings : { 4337 time: 0, 4338 duration: 0.3, 4339 effect: 'easeOut' 4340 }, 4341 modal_name : null, 4342 modal_group : true, 4343 modal_hash : null, 4344 modal_ready_callback : null, 4345 lazyload : 0, // int || false 4346 lightbox_rendition : 'full', 4347 honor_device_pixel_ratio : true, 4348 4349 layout : 'columns', // rows, columns, grid 4350
4351 // columns opts 4352 columns : 'auto', // auto (str) or (int) 4353 order : 'rows', // rows, columns, masonry, random 4354 min_column_width : 300, 4355 4356 // rows opts 4357 rows : 'auto', // auto (str) or (int) 4358 allow_orphans : false, 4359 max_row_height : 325, 4360 4361 // grid opts 4362 shape : '16:9', // aspect-ratio (16:9) 4363 sizing : 'contain', // cover, contain 4364 align : 'middle', // top, middle, bottom 4365 orphans : 'left', // left, center, right 4366 4367 log_gallery_data : false 4368 // random : false (deprecated: v2.2) 4369 // force_order : false (deprecated: v2.2) 4370 // auto_columns : false (deprecated: v2.2) 4371 // responsive_transition --> resize_transition (deprecated: v2.8) 4372 // responsive_transition_settings --> resize_transition_settings (deprecated: v2.8) 4373 }, 4374 4375 init: function () { 4376 var self = this; 4377 4378 this.opts = $.extend({}, this._defaults, this._options); 4379 this.opts = this.adjustDeprecatedOptions(this.opts); 4380 this._options = $.extend(true, {}, this.opts); // jQuery deep copy 4381 4382 this.preload = 'PM_preloadify' + this._id; 4383 4384 // Error Checks 4385 if ( PhotoMosaic.ErrorChecks.initial(this.opts) ) { 4386 return; 4387 } 4388 4389 if ( PhotoMosaic.ErrorChecks.nonModernBrowser() ) { 4390 var fallback_node = this.el.childNodes[0]; 4391 var fallback = fallback_node ? fallback_node.textContent : null; 4392 4393 if ( fallback ) { 4394 this.obj.html( fallback ); 4395 4396 setTimeout(function(){ 4397 self.modalCallback( self.obj.find('.gallery') ); 4398 }, 0); 4399 } else { 4400 setTimeout(function(){ 4401 self.modalCallback( self.obj ); 4402 }, 0); 4403 } 4404 4405 return; 4406 } 4407 4408 $.when( 4409 this.getGalleryData() 4410 ).then(function (data) { 4411 self.opts.gallery = self.setImageIDs(data); 4412 self.configure(); 4413 }); 4414 }, 4415 4416 configure: function () { 4417 var self = this; 4418 4419 if (this.opts.show_loading) { 4420 this.react = ReactDOM.render( 4421 React.createElement( 4422 PhotoMosaic.Layouts.React.loading, 4423 { id : this._id } 4424 ), 4425 this.obj.get(0) 4426 ); 4427 } 4428 4429 // if all items have defined w/h we don't need to 4430 // wait for them to load to do the mosaic math 4431 if (this.hasDims()) { 4432 this.opts.gallery = this.prepData(this.opts.gallery); 4433 this.render(); 4434 } else { 4435 $.when(this.preloadify()).then( 4436 $.proxy(this.preloadDone, this), // all loaded successfully 4437 $.proxy(this.preloadDone, this), // not all loaded successfully 4438 $.proxy(this.preloadProgress, this) // an item has finished, successful or not 4439 ); 4440 } 4441 }, 4442 4443 render: function () { 4444 var self = this; 4445 var layout_data = null; 4446 var view_model = null; 4447 var mosaic_data = { 4448 key : this._id, 4449 id : this._id, 4450 class_name : this.makeSpecialClasses(), 4451 center : this.opts.center 4452 }; 4453 4454 // bail if we don't have any images (e.g. they all failed to load) 4455 if ( PhotoMosaic.ErrorChecks.initial(this.opts) ) { return; } 4456 4457 this.layout = new PhotoMosaic.Layouts[ this.opts.layout ]( this ); 4458 layout_data = this.layout.getData( false ); 4459 4460 view_model = $.extend({}, mosaic_data, layout_data); 4461 4462 if (layout_data == false) { 4463 this.react = null; 4464 4465 // update the mosaic on window.resize 4466 $(window)
4467 .unbind('resize.photoMosaic' + self._id) 4468 .bind('resize.photoMosaic' + self._id, function () { 4469 self.refresh(); 4470 }); 4471 return; 4472 } 4473 4474 this.react = ReactDOM.render( 4475 React.createElement( 4476 PhotoMosaic.Layouts.React.mosaic, 4477 view_model 4478 ), // the component to render 4479 this.obj.get(0), // the dom node container 4480 function () { // the callback 4481 // triggers lazyloading / imagesLoaded 4482 self.loader = new PhotoMosaic.Loader(self.obj, self); 4483 4484 // update the mosaic on window.resize 4485 $(window) 4486 .unbind('resize.photoMosaic' + self._id) 4487 .bind('resize.photoMosaic' + self._id, function () { 4488 self.refresh(); 4489 }); 4490 4491 // run the user's modal_ready_callback 4492 self.modalCallback(); 4493 } 4494 ); 4495 4496 // logging 4497 if (this.opts.log_gallery_data) { 4498 PhotoMosaic.Utils.logGalleryData(this.opts.gallery); 4499 } 4500 }, 4501 4502 preloadify: function () { 4503 var $images = $('<div>').attr({ 4504 'id': this.preload, 4505 'class' : 'PM_preloadify' 4506 }); 4507 var self = this; 4508 4509 $.each(this.opts.gallery, function (i) { 4510 var image_url = (this.thumb && this.thumb !== '') ? this.thumb : this.src; 4511 var $item = $('<img>') 4512 .attr({ src : image_url }) 4513 .addClass(this.id); 4514 4515 $images.append($item); 4516 }); 4517 4518 $('body').append($images); 4519 4520 return $images.imagesLoaded(); 4521 }, 4522 4523 preloadDone : function () { 4524 this.opts.gallery = this.prepData(this.opts.gallery, true); 4525 this.render(); 4526 }, 4527 4528 preloadProgress : function (instance, image) { 4529 var img = null; 4530 if (!image.isLoaded) { 4531 id = image.img.className; 4532 4533 for (i = 0; i < this.opts.gallery.length; i++) { 4534 if (this.opts.gallery[i].id == id) { 4535 this.opts.gallery.splice(i,1); 4536 } 4537 } 4538 4539 PhotoMosaic.Utils.log.error("The following image failed to load and was skipped.\n" + image.img.src); 4540 } 4541 }, 4542 4543 prepData: function (gallery, isPreload) { 4544 var self = this; 4545 var $preload = (isPreload) ? $('#' + this.preload) : null; 4546 var $img = null; 4547 var image = null; 4548 var image_url = ''; 4549 var mem = {}; 4550 var images = []; 4551 4552 $.each(gallery, function (i) { 4553 image = $.extend(true, {}, this); // jQuery deep copy 4554 4555 if (isPreload) { 4556 $img = $img = $preload.find('.' + this.id); 4557 mem = { 4558 w : $img.width(), 4559 h : $img.height() 4560 }; 4561 } else { 4562 mem = { 4563 w : parseInt(this.width), 4564 h : parseInt(this.height) 4565 }; 4566 } 4567 4568 image.width = { 4569 original: mem.w 4570 }; 4571 image.height = { 4572 original: mem.h 4573 }; 4574 4575 image_url = (image.thumb && image.thumb !== '') ? image.thumb : image.src; 4576 4577 // image sizes 4578 image.full = image.src; 4579 image.src = image_url; 4580 image.padding = self.opts.padding; 4581 4582 image.caption = PhotoMosaic.Utils.decodeHTML( image.caption ); 4583 4584 image = self.prepDataModal( image ); 4585 4586 image = self.prepDataLinks( image ); 4587 4588 images.push(image); 4589 }); 4590 4591 return images; 4592 }, 4593 4594 prepDataModal: function (image) { 4595 var modal_text = ''; 4596 4597 if (this.opts.modal_name) { 4598 if (this.opts.modal_group) { 4599 if (this.opts.modal_hash) { 4600 modal_text = this.opts.modal_name + '[' + this.opts.modal_hash + ']'; 4601 } else { 4602 modal_text = this.opts.modal_name + '[' + this._id + ']'; 4603 } 4604 } else { 4605 modal_text = this.opts.modal_name; 4606 } 4607 image.modal = modal_text; 4608 } 4609 4610 return image; 4611 }, 4612 4613 prepDataLinks: function (image) { 4614 if (this.opts.links && image.url) { 4615 image.link = true; 4616 image.path = image.url; 4617 image.external = this.opts.external_links; 4618 // delete image.modal; 4619 } else if (this.opts.links) { 4620 image.link = true; 4621 image.external = this.opts.external_links; 4622 4623 if (image.sizes && image.sizes.hasOwnProperty(this.opts.lightbox_rendition)) { 4624 image.path = image.sizes[this.opts.lightbox_rendition]; 4625 } else { 4626 image.path = image.full; 4627 } 4628 } else { 4629 image.link = false;
4630 } 4631 4632 return image; 4633 }, 4634 4635 getGalleryData: function () { 4636 var self = this; 4637 4638 // construct the gallery 4639 if (this.opts.input === 'json') { 4640 return PhotoMosaic.Inputs.json(this.opts.gallery); 4641 4642 } else if (this.opts.input === 'html') { 4643 return PhotoMosaic.Inputs.html(this.obj, this.opts); 4644 4645 } else if (this.opts.input === 'xml' ) { 4646 return $.when( 4647 $.get(this.opts.gallery) 4648 ).then( 4649 // success 4650 function (data) { 4651 var gallery; 4652 if ($(data).find('photos').length > 0) { 4653 return PhotoMosaic.Inputs.xml( $(data).find('photos') ); 4654 } else { 4655 PhotoMosaic.Utils.log.error("The XML doesn't contain any <photo> nodes."); 4656 return; 4657 } 4658 }, 4659 // fail 4660 function () { 4661 PhotoMosaic.Utils.log.error("The XML either couldn't be found or was malformed."); 4662 return; 4663 } 4664 ); 4665 } 4666 }, 4667 4668 setImageIDs: function (gallery) { 4669 for (var i = 0; i < gallery.length; i++) { 4670 gallery[i].key = gallery[i].id = PhotoMosaic.Utils.makeID(false, 'pm'); 4671 }; 4672 return gallery; 4673 }, 4674 4675 hasDims: function () { 4676 var some = false; // set to true if any dims are found 4677 var all = true; // set to false if any dims aren't found 4678 4679 if (this.hasSpecifiedDims !== undefined) { 4680 return this.hasSpecifiedDims; 4681 } 4682 4683 for (var i = 0; i < this.opts.gallery.length; i++) { 4684 // are w/h properties present? 4685 if (this.opts.gallery[i].hasOwnProperty('width') && this.opts.gallery[i].hasOwnProperty('height')) { 4686 // is there valid data? 4687 // in some cases WP reports 0 for both the height and width 4688 if ( 4689 isNaN(parseInt(this.opts.gallery[i].width)) || 4690 isNaN(parseInt(this.opts.gallery[i].height)) || 4691 this.opts.gallery[i].width == 0 || 4692 this.opts.gallery[i].height == 0 4693 ) { 4694 all = false; 4695 } else { 4696 some = true; 4697 } 4698 } else { 4699 all = false; 4700 } 4701 }; 4702 4703 if (some && !all) { 4704 PhotoMosaic.Utils.log.error("Width / Height data not present for all images."); 4705 } 4706 4707 this.hasSpecifiedDims = all; 4708 4709 return this.hasSpecifiedDims; 4710 }, 4711 4712 getLoadingTransition: function () { 4713 var transition = 'none'; 4714 4715 if (PhotoMosaic.Plugins.Modernizr.csstransitions && PhotoMosaic.Plugins.Modernizr.csstransforms && this.opts.loading_transition !== false) { 4716 transition = this.opts.loading_transition 4717 } 4718 return 'loading-transition-' + transition; 4719 }, 4720 4721 getResizeTransition : function () { 4722 return (this.opts.resize_transition) ? '' : 'resize-transition-none'; 4723 }, 4724 4725 getLayoutClass: function () { 4726 return 'layout-' + this.opts.layout + ((this.opts.layout == 'grid') ? '-' + this.opts.sizing : ''); 4727 }, 4728 4729 getUniqueClass: function () { 4730 return (this.opts.modal_hash) ? 'photomosaic-' + this.opts.modal_hash : ''; 4731 }, 4732 4733 getAvia: function () { 4734 // Kriesi's Avia framework overwrites the 'left' prop on my links 4735 // 'noLightbox' prevents that shit from happening 4736 return (typeof window.avia_framework_globals !== 'undefined') ? 'noLightbox' : ''; 4737 }, 4738 4739 makeSpecialClasses: function () { 4740 var classes = [ 4741 this.getUniqueClass(), 4742 this.getLoadingTransition(), 4743 this.getResizeTransition(), 4744 this.getLayoutClass(), 4745 this.getAvia() 4746 ]; 4747 return classes.join(' '); 4748 }, 4749 4750 refresh: function () { 4751 var self = this; 4752 var mosaic_data = { 4753 key : this._id, 4754 id : this._id, 4755 class_name : this.makeSpecialClasses(), 4756 center : this.opts.center 4757 }; 4758 4759 var layout_data = this.layout.getData( true ); 4760 4761 var view_model = $.extend({}, mosaic_data, layout_data); 4762 4763 // transitionend fires for each proprty being transitioned, we only care about when the last one ends 4764 var checkLazyload = PhotoMosaic.Utils.debounce(function () { 4765 $.waypoints('refresh'); 4766 }, 300); 4767 4768 if (layout_data == false) { 4769 this.react = null; 4770 return; 4771 } 4772 4773 this.react = ReactDOM.render( 4774 React.createElement( 4775 PhotoMosaic.Layouts.React.mosaic, 4776 view_model 4777 ), 4778 this.obj.get(0), 4779 function () { 4780 // if applicable, wait until after the CSS transitions fire to trigger a lazyloading check 4781 if (PhotoMosaic.Plugins.Modernizr.csstransitions && self.opts.lazyload !== false) { 4782 self.obj.on( 4783 self._transition_end_event_name, 4784 checkLazyload 4785 ); 4786 } 4787 } 4788 ); 4789 }, 4790 4791 update: function (props) { 4792 if ('object' != typeof(props)) { 4793 PhotoMosaic.Utils.log.error("The 'update' method accepts an object of parameters to be updated."); 4794 return false;
4795 } 4796 4797 // make sure numbers are numbers 4798 var exclusions = ['width', 'height', 'shape', 'modal_hash']; 4799 for (var k in props) { 4800 if (($.inArray(k, exclusions) == -1) && !isNaN(parseFloat(props[k]))) { 4801 props[k] = parseFloat(props[k]); 4802 } 4803 }; 4804 4805 this.opts = $.extend({}, this.opts, props); 4806 4807 var self = this; 4808 var gallery = []; 4809 $.each(this.opts.gallery, function (idx, image) { 4810 gallery.push( self.prepDataModal(image) ); 4811 }); 4812 4813 this.opts.gallery = gallery; 4814 4815 this.layout = new PhotoMosaic.Layouts[ this.opts.layout ]( this ); 4816 4817 this.refresh(); 4818 }, 4819 4820 modalCallback: function ($node) { 4821 var $ = $ || this.$; 4822 var $node = $node || this.obj.children().eq(0); 4823 var $items = $node.children(); 4824 var lightbox_callback = PhotoMosaic.WP[ this.opts.id ].lightbox_callback; 4825 4826 if ( $.isFunction(this.opts.modal_ready_callback) ) { 4827 this.opts.modal_ready_callback.apply(this, [$, $node, $items]); 4828 } 4829 4830 if ( lightbox_callback && $.isFunction( lightbox_callback ) ) { 4831 lightbox_callback.apply(this, [$, $node, $items]); 4832 } 4833 }, 4834 4835 adjustDeprecatedOptions: function (opts) { 4836 // random : true | false 4837 if (opts.random) { 4838 opts.order = 'random'; 4839 } 4840 4841 // force_order : true | false 4842 if (opts.force_order) { 4843 opts.order = 'columns'; 4844 } 4845 4846 // responsive_transition renamed to resize_transition 4847 if (opts.hasOwnProperty('responsive_transition')) { 4848 opts.resize_transition = opts.responsive_transition; 4849 } 4850 if (opts.hasOwnProperty('responsive_transition_settings')) { 4851 opts.resize_transition_settings = opts.responsive_transition_settings; 4852 } 4853 4854 return opts; 4855 }, 4856 4857 _name : pluginName, 4858 4859 version : PhotoMosaic.version 4860 }; 4861 4862 4863 $.fn[pluginName] = function (options) { 4864 return this.each(function () { 4865 var instance = $.data(this, pluginName); 4866 4867 if ( instance && options ) { 4868 instance.update(options); 4869 } else if ( instance ) { 4870 instance.refresh(); 4871 } else { 4872 options = options || {}; 4873 instance = new photoMosaic(this, options); 4874 } 4875 }); 4876 }; 4877 4878 $(document).on('ready', function () { 4879 PhotoMosaic.refreshPage(); 4880 }); 4881 4882}(window.JQPM, 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.