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 );

联系我们
文章看不懂?联系我们为您免费解答!免费助力个人,小企站点!
电话:020-2206-9892
QQ咨询:1025174874
邮件:info@361sale.com
工作时间:周一至周五,9:30-18:30,节假日休息
发布者:光子波动,转转请注明出处:https://www.361sale.com/12266/

(0)
上一篇 2024年 7月 2日 上午10:00
下一篇 2024年 7月 2日 上午10:19

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

联系我们

020-2206-9892

QQ咨询:1025174874

邮件:info@361sale.com

工作时间:周一至周五,9:30-18:30,节假日休息

客服微信
为方便全球用户注册登录,我们已取消电话登录功能。如遇登录问题,请联系客服协助绑定邮箱。