1/** 2 * jQuery Masonry v2.0.111015 3 * A dynamic layout plugin for jQuery 4 * The flip-side of CSS Floats 5 * http://masonry.desandro.com 6 * 7 * Licensed under the MIT license. 8 * Copyright 2011 David DeSandro 9 */ 10 11(function(window, $, undefined){ 12 13 /* 14 * smartresize: debounced resize event for jQuery 15 * 16 * latest version and complete README available on Github: 17 * https://github.com/louisremi/jquery.smartresize.js 18 * 19 * Copyright 2011 @louis_remi 20 * Licensed under the MIT license. 21 */ 22 23 var $event = $.event, 24 resizeTimeout; 25 26 $event.special.smartresize = { 27 setup: function() { 28 $(this).bind("resize", $event.special.smartresize.handler); 29 }, 30 teardown: function() { 31 $(this).unbind("resize", $event.special.smartresize.handler); 32 }, 33 handler: function(event, execAsap) { 34 // Save the context 35 var context = this, 36 args = arguments; 37 38 // set correct event type 39 event.type = "smartresize"; 40 41 if (resizeTimeout) { clearTimeout(resizeTimeout); } 42 resizeTimeout = setTimeout(function() { 43 jQuery.event.handle.apply(context, args); 44 }, execAsap === "execAsap"? 0 : 100); 45 } 46 }; 47 48 $.fn.smartresize = function(fn) { 49 return fn ? this.bind("smartresize", fn) : this.trigger("smartresize", ["execAsap"]); 50 }; 51 52 53 54// ========================= Masonry =============================== 55 56 57 // our "Widget" object constructor 58 $.Mason = function(options, element){ 59 this.element = $(element); 60 61 this._create(options); 62 this._init(); 63 }; 64 65 // styles of container element we want to keep track of 66 var masonryContainerStyles = [ 'position', 'height' ]; 67 68 $.Mason.settings = { 69 isResizable: true, 70 isAnimated: false, 71 animationOptions: { 72 queue: false, 73 duration: 500 74 }, 75 gutterWidth: 0, 76 isRTL: false, 77 isFitWidth: false 78 }; 79 80 $.Mason.prototype = { 81 82 _filterFindBricks: function($elems) { 83 var selector = this.options.itemSelector; 84 // if there is a selector 85 // filter/find appropriate item elements 86 return !selector ? $elems : $elems.filter(selector).add($elems.find(selector)); 87 }, 88 89 _getBricks: function($elems) { 90 var $bricks = this._filterFindBricks($elems) 91 .css({ position: 'absolute' }) 92 .addClass('masonry-brick'); 93 return $bricks; 94 }, 95 96 // sets up widget 97 _create : function(options) { 98 99 this.options = $.extend(true, {}, $.Mason.settings, options); 100 101 this.styleQueue = []; 102 // need to get bricks 103 this.reloadItems(); 104 105 106 // get original styles in case we re-apply them in .destroy() 107 var elemStyle = this.element[0].style; 108 this.originalStyle = {}; 109 for (var i=0, len = masonryContainerStyles.length; i < len; i++) { 110 var prop = masonryContainerStyles[i]; 111 this.originalStyle[ prop ] = elemStyle[ prop ] || ''; 112 } 113 114 this.element.css({ 115 position : 'relative' 116 }); 117 118 this.horizontalDirection = this.options.isRTL ? 'right' : 'left'; 119 this.offset = {}; 120 121 // get top left position of where the bricks should be 122 var $cursor = $(document.createElement('div')); 123 this.element.prepend($cursor); 124 this.offset.y = Math.round($cursor.position().top); 125 // get horizontal offset 126 if (!this.options.isRTL) { 127 this.offset.x = Math.round($cursor.position().left); 128 } else { 129 $cursor.css({ 'float': 'right', display: 'inline-block'}); 130 this.offset.x = Math.round(this.element.outerWidth() - $cursor.position().left); 131 } 132 $cursor.remove(); 133 134 // add masonry class first time around 135 var instance = this; 136 setTimeout(function() { 137 instance.element.addClass('masonry'); 138 }, 0); 139 140 // bind resize method 141 if (this.options.isResizable) { 142 $(window).bind('smartresize.masonry', function() { 143 instance.resize(); 144 }); 145 } 146 147 }, 148 149 // _init fires when instance is first created 150 // and when instance is triggered again -> $el.masonry(); 151 _init : function(callback) { 152 this._getColumns(); 153 this._reLayout(callback); 154 }, 155 156 option: function(key, value){ 157 // set options AFTER initialization: 158 // signature: $('#foo').bar({ cool:false }); 159 if ($.isPlainObject(key)){ 160 this.options = $.extend(true, this.options, key); 161 } 162 }, 163 164 // ====================== General Layout ====================== 165 166 // used on collection of atoms (should be filtered, and sorted before) 167 // accepts atoms-to-be-laid-out to start with 168 layout : function($bricks, callback) { 169 170 // layout logic 171 var $brick, colSpan, groupCount, groupY, groupColY, j; 172 173 for (var i=0, len = $bricks.length; i < len; i++) { 174 $brick = $($bricks[i]); 175 //how many columns does this brick span 176 colSpan = Math.ceil($brick.outerWidth(true) / this.columnWidth); 177 colSpan = Math.min(colSpan, this.cols); 178 179 if (colSpan === 1) { 180 // if brick spans only one column, just like singleMode 181 this._placeBrick($brick, this.colYs); 182 } else { 183 // brick spans more than one column 184 // how many different places could this brick fit horizontally 185 groupCount = this.cols + 1 - colSpan; 186 groupY = []; 187 188 // for each group potential horizontal position 189 for (j=0; j < groupCount; j++) { 190 // make an array of colY values for that one group 191 groupColY = this.colYs.slice(j, j+colSpan); 192 // and get the max value of the array 193 groupY[j] = Math.max.apply(Math, groupColY); 194 } 195 196 this._placeBrick($brick, groupY); 197 } 198 } 199 200 // set the size of the container 201 var containerSize = {}; 202 containerSize.height = Math.max.apply(Math, this.colYs) - this.offset.y; 203 if (this.options.isFitWidth) { 204 var unusedCols = 0, 205 i = this.cols; 206 // count unused columns 207 while (--i) { 208 if (this.colYs[i] !== this.offset.y) { 209 break; 210 } 211 unusedCols++; 212 } 213 // fit container to columns that have been used; 214 containerSize.width = (this.cols - unusedCols) * this.columnWidth - this.options.gutterWidth; 215 } 216 this.styleQueue.push({ $el: this.element, style: containerSize }); 217 218 // are we animating the layout arrangement? 219 // use plugin-ish syntax for css or animate 220 var styleFn = !this.isLaidOut ? 'css' : ( 221 this.options.isAnimated ? 'animate' : 'css' 222 ), 223 animOpts = this.options.animationOptions; 224 225 // process styleQueue 226 var obj; 227 for (i=0, len = this.styleQueue.length; i < len; i++) { 228 obj = this.styleQueue[i]; 229 obj.$el[ styleFn ](obj.style, animOpts); 230 } 231 232 // clear out queue for next time 233 this.styleQueue = []; 234 235 // provide $elems as context for the callback 236 if (callback) { 237 callback.call($bricks); 238 } 239 240 this.isLaidOut = true; 241 }, 242 243 // calculates number of columns 244 // i.e. this.columnWidth = 200 245 _getColumns : function() { 246 var container = this.options.isFitWidth ? this.element.parent() : this.element, 247 containerWidth = container.width(); 248 249 this.columnWidth = this.options.columnWidth || 250 // or use the size of the first item 251 this.$bricks.outerWidth(true) || 252 // if there's no items, use size of container 253 containerWidth; 254 255 this.columnWidth += this.options.gutterWidth; 256 257 this.cols = Math.floor((containerWidth + this.options.gutterWidth) / this.columnWidth); 258 this.cols = Math.max(this.cols, 1); 259 260 }, 261 262 _placeBrick : function($brick, setY) { 263 // get the minimum Y value from the columns 264 var minimumY = Math.min.apply(Math, setY), 265 shortCol = 0; 266 267 // Find index of short column, the first from the left 268 for (var i=0, len = setY.length; i < len; i++) { 269 if (setY[i] === minimumY) { 270 shortCol = i; 271 break; 272 } 273 } 274 275 // position the brick 276 var position = { 277 top : minimumY 278 }; 279 // position.left or position.right 280 position[ this.horizontalDirection ] = this.columnWidth * shortCol + this.offset.x; 281 this.styleQueue.push({ $el: $brick, style: position }); 282 283 // apply setHeight to necessary columns 284 var setHeight = minimumY + $brick.outerHeight(true), 285 setSpan = this.cols + 1 - len; 286 for (i=0; i < setSpan; i++) { 287 this.colYs[ shortCol + i ] = setHeight; 288 } 289 290 }, 291 292 293 resize : function() { 294 var prevColCount = this.cols; 295 // get updated colCount 296 this._getColumns(); 297 if (this.cols !== prevColCount) { 298 // if column count has changed, trigger new layout 299 this._reLayout(); 300 } 301 }, 302 303 304 _reLayout : function(callback) { 305 // reset columns 306 var i = this.cols; 307 this.colYs = []; 308 while (i--) { 309 this.colYs.push(this.offset.y); 310 } 311 // apply layout logic to all bricks 312 this.layout(this.$bricks, callback); 313 }, 314 315 // ====================== Convenience methods ====================== 316 317 // goes through all children again and gets bricks in proper order 318 reloadItems : function() { 319 this.$bricks = this._getBricks(this.element.children()); 320 }, 321 322 323 reload : function(callback) { 324 this.reloadItems(); 325 this._init(callback); 326 }, 327 328 329 // convienence method for working with Infinite Scroll 330 appended : function($content, isAnimatedFromBottom, callback) { 331 if (isAnimatedFromBottom) { 332 // set new stuff to the bottom 333 this._filterFindBricks($content).css({ top: this.element.height() }); 334 var instance = this; 335 setTimeout(function(){ 336 instance._appended($content, callback); 337 }, 1); 338 } else { 339 this._appended($content, callback); 340 } 341 }, 342 343 _appended : function($content, callback) { 344 var $newBricks = this._getBricks($content); 345 // add new bricks to brick pool 346 this.$bricks = this.$bricks.add($newBricks); 347 this.layout($newBricks, callback); 348 }, 349 350 // removes elements from Masonry widget 351 remove : function($content) { 352 this.$bricks = this.$bricks.not($content); 353 $content.remove(); 354 }, 355 356 // destroys widget, returns elements and container back (close) to original style 357 destroy : function() { 358 359 this.$bricks 360 .removeClass('masonry-brick') 361 .each(function(){ 362 this.style.position = ''; 363 this.style.top = ''; 364 this.style.left = ''; 365 }); 366 367 // re-apply saved container styles 368 var elemStyle = this.element[0].style; 369 for (var i=0, len = masonryContainerStyles.length; i < len; i++) { 370 var prop = masonryContainerStyles[i]; 371 elemStyle[ prop ] = this.originalStyle[ prop ]; 372 } 373 374 this.element 375 .unbind('.masonry') 376 .removeClass('masonry') 377 .removeData('masonry'); 378 379 $(window).unbind('.masonry'); 380 381 } 382 383 }; 384 385 386 // ======================= imagesLoaded Plugin =============================== 387 /*! 388 * jQuery imagesLoaded plugin v1.0.3 389 * http://github.com/desandro/imagesloaded 390 * 391 * MIT License. by Paul Irish et al. 392 */ 393 394 395 // $('#my-container').imagesLoaded(myFunction) 396 // or 397 // $('img').imagesLoaded(myFunction) 398 399 // execute a callback when all images have loaded. 400 // needed because .load() doesn't work on cached images 401 402 // callback function gets image collection as argument 403 // `this` is the container 404 405 $.fn.imagesLoaded = function(callback) { 406 var $this = this, 407 $images = $this.find('img').add($this.filter('img')), 408 len = $images.length, 409 blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='; 410 411 function triggerCallback() { 412 callback.call($this, $images); 413 } 414 415 function imgLoaded() { 416 if (--len <= 0 && this.src !== blank){ 417 setTimeout(triggerCallback); 418 $images.unbind('load error', imgLoaded); 419 } 420 } 421 422 if (!len) { 423 triggerCallback(); 424 } 425 426 $images.bind('load error', imgLoaded).each(function() { 427 // cached images don't fire load sometimes, so we reset src. 428 if (this.complete || this.complete === undefined){ 429 var src = this.src; 430 // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f 431 // data uri bypasses webkit log warning (thx doug jones) 432 this.src = blank; 433 this.src = src; 434 } 435 }); 436 437 return $this; 438 }; 439 440 441 // helper function for logging errors 442 // $.error breaks jQuery chaining 443 var logError = function(message) { 444 if (this.console) { 445 console.error(message); 446 } 447 }; 448 449 // ======================= Plugin bridge =============================== 450 // leverages data method to either create or return $.Mason constructor 451 // A bit from jQuery UI 452 // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 453 // A bit from jcarousel 454 // https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarou
454sel.js 455 456 $.fn.masonry = function(options) { 457 if (typeof options === 'string') { 458 // call method 459 var args = Array.prototype.slice.call(arguments, 1); 460 461 this.each(function(){ 462 var instance = $.data(this, 'masonry'); 463 if (!instance) { 464 logError("cannot call methods on masonry prior to initialization; " + 465 "attempted to call method '" + options + "'"); 466 return; 467 } 468 if (!$.isFunction(instance[options]) || options.charAt(0) === "_") { 469 logError("no such method '" + options + "' for masonry instance"); 470 return; 471 } 472 // apply method 473 instance[ options ].apply(instance, args); 474 }); 475 } else { 476 this.each(function() { 477 var instance = $.data(this, 'masonry'); 478 if (instance) { 479 // apply options & init 480 instance.option(options || {}); 481 instance._init(); 482 } else { 483 // initialize new instance 484 $.data(this, 'masonry', new $.Mason(options, this)); 485 } 486 }); 487 } 488 return this; 489 }; 490 491}) (window, jQuery);
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.