Código fuente de WordPress - jquery-plugins (jquery.masonry-2.1.05.js)

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

Contacte con nosotros
¿No puede leer el artículo? ¡Póngase en contacto con nosotros para obtener una respuesta gratuita! Ayuda gratuita para sitios personales y de pequeñas empresas
Tel: 020-2206-9892
QQ咨询:1025174874
(iii) Correo electrónico: info@361sale.com
Horario de trabajo: de lunes a viernes, de 9:30 a 18:30, días festivos libres
© Declaración de reproducción
Este artículo fue escrito por Harry
EL FIN
Si le gusta, apóyela.
felicitaciones0 compartir (alegrías, beneficios, privilegios, etc.) con los demás
comentarios compra de sofás

Por favor, inicie sesión para enviar un comentario

    Sin comentarios