PageSourceSearch

https://ountravela.com/wp-content/plugins/customer-reviews-woocommerce/js/colcade.js

js ountravela.com collected 2026-09-25 01:29:30 UTC 10,374 bytes, 392 lines download raw bytes

1/*!
2 * Colcade v0.2.0
3 * Lightweight masonry layout
4 * by David DeSandro
5 * MIT license
6 */
7
8/*jshint browser: true, undef: true, unused: true */
9
10( function( window, factory ) {
11  // universal module definition
12  /*jshint strict: false */
13  /*global define: false, module: false */
14  if ( typeof define == 'function' && define.amd ) {
15    // AMD
16    define( factory );
17  } else if ( typeof module == 'object' && module.exports ) {
18    // CommonJS
19    module.exports = factory();
20  } else {
21    // browser global
22    window.Colcade = factory();
23  }
24
25}( window, function factory() {
26
27// -------------------------- Colcade -------------------------- //
28
29function Colcade( element, options ) {
30  element = getQueryElement( element );
31
32  // do not initialize twice on same element
33  if ( element && element.colcadeGUID ) {
34    var instance = instances[ element.colcadeGUID ];
35    instance.option( options );
36    return instance;
37  }
38
39  this.element = element;
40  // options
41  this.options = {};
42  this.option( options );
43	// items from the last append operation and ColumnHeights before the append
44	this.lastAppend = [];
45	this.lastColumnHeights = [];
46  // kick things off
47  this.create();
48	element.classList.add('cr-colcade-loaded');
49}
50
51var proto = Colcade.prototype;
52
53proto.option = function( options ) {
54  this.options = extend( this.options, options );
55};
56
57// globally unique identifiers
58var GUID = 0;
59// internal store of all Colcade intances
60var instances = {};
61
62proto.create = function() {
63  this.errorCheck();
64  // add guid for Colcade.data
65  var guid = this.guid = ++GUID;
66  this.element.colcadeGUID = guid;
67  instances[ guid ] = this; // associate via id
68  // update initial properties & layout
69  this.reload();
70  // events
71  this._windowResizeHandler = this.onWindowResize.bind( this );
72  this._loadHandler = this.onLoad.bind( this );
73  window.addEventListener( 'resize', this._windowResizeHandler );
74  this.element.addEventListener( 'load', this._loadHandler, true );
75};
76
77proto.errorCheck = function() {
78  var errors = [];
79  if ( !this.element ) {
80    errors.push( 'Bad element: ' + this.element );
81  }
82  if ( !this.options.columns ) {
83    errors.push( 'columns option required: ' + this.options.columns );
84  }
85  if ( !this.options.items ) {
86    errors.push( 'items option required: ' + this.options.items );
87  }
88
89  if ( errors.length ) {
90    throw new Error( '[Colcade error] ' + errors.join('. ') );
91  }
92};
93
94// update properties and do layout
95proto.reload = function() {
96  this.updateColumns();
97  this.updateItems();
98  this.layout();
99};
100
101proto.updateColumns = function() {
102  this.columns = querySelect( this.options.columns, this.element );
103};
104
105proto.updateItems = function() {
106  this.items = querySelect( this.options.items, this.element );
107};
108
109proto.getActiveColumns = function() {
110  return this.columns.filter( function( column ) {
111    var style = getComputedStyle( column );
112    return style.display != 'none';
113  });
114};
115
116// ----- layout ----- //
117
118// public, updates activeColumns
119proto.layout = function() {
120  this.activeColumns = this.getActiveColumns();
121  this._layout();
122};
123
124// private, does not update activeColumns
125proto._layout = function() {
126  // reset column heights
127  this.columnHeights = this.activeColumns.map( function() {
128    return 0;
129  });
130  // layout all items
131  this.layoutItems( this.items );
132};
133
134proto.layoutItems = function( items ) {
135  items.forEach( this.layoutItem, this );
136};
137
138proto.layoutItem = function( item ) {
139  // layout item by appending to column
140  var minHeight = Math.min.apply( Math, this.columnHeights );
141  var index = this.columnHeights.indexOf( minHeight );
142  this.activeColumns[ index ].appendChild( item );
143  // at least 1px, if item hasn't loaded
144  // Not exactly accurate, but it's cool
145  this.columnHeights[ index ] += item.offsetHeight || 1;
146};
147
148// ----- adding items ----- //
149
150proto.append = function( elems ) {
151  var items = this.getQueryItems( elems );
152  // add items to collection
153  this.items = this.items.concat( items );
154	// capture the items and columnHeights for future onLoad events triggered by images load
155	this.lastAppend.length = 0;
156	this.lastAppend = items.slice();
157	this.lastColumnHeights.length = 0;
158	this.lastColumnHeights = this.columnHeights.slice();
159  // lay them out
160  this.layoutItems( items );
161};
162
163proto.prepend = function( elems ) {
164  var items = this.getQueryItems( elems );
165  // add items to collection
166  this.items = items.concat( this.items );
167  // lay out everything
168  this._layout();
169};
170
171proto.getQueryItems = function( elems ) {
172  elems = makeArray( elems );
173  var fragment = document.createDocumentFragment();
174  elems.forEach( function( elem ) {
175    fragment.appendChild( elem );
176  });
177  return querySelect( this.options.items, fragment );
178};
179
180proto.empty = function() {
181	this.lastAppend.length = 0;
182	this.lastColumnHeights.length = 0;
183	//
184  this.items.forEach( function( item ) {
185    item.remove();
186  }, this );
187  this.items.length = 0;
188  // lay out everything
189  this._layout();
190};
191
192// ----- measure column height ----- //
193
194proto.measureColumnHeight = function( elem ) {
195  var boundingRect = this.element.getBoundingClientRect();
196  this.activeColumns.forEach( function( column, i ) {
197    // if elem, measure only that column
198    // if no elem, measure all columns
199    if ( !elem || column.contains( elem ) ) {
200      var lastChildRect = column.lastElementChild.getBoundingClientRect();
201      // not an exact calculation as it includes top border, and excludes item bottom margin
202      this.columnHeights[ i ] = lastChildRect.bottom - boundingRect.top;
203    }
204  }, this );
205};
206
207// ----- events ----- //
208
209proto.onWindowResize = function() {
210  clearTimeout( this.resizeTimeout );
211  this.resizeTimeout = setTimeout( function() {
212    this.onDebouncedResize();
213  }.bind( this ), 100 );
214};
215
216proto.onDebouncedResize = function() {
217  var activeColumns = this.getActiveColumns();
218  // check if columns changed
219  var isSameLength = activeColumns.length == this.activeColumns.length;
220  var isSameColumns = true;
221  this.activeColumns.forEach( function( column, i ) {
222    isSameColumns = isSameColumns && column == activeColumns[i];
223  });
224  if ( isSameLength && isSameColumns ) {
225    return;
226  }
227  // activeColumns changed
228  this.activeColumns = activeColumns;
229  this._layout();
230};
231
232proto.onLoad = function( event ) {
233  this.measureColumnHeight( event.target );
234	if( 0 < this.lastColumnHeights.length && 0 < this.lastAppend.length ) {
235		this.columnHeights.length = 0;
236		this.columnHeights = this.lastColumnHeights.slice();
237		this.layoutItems( this.lastAppend );
238	}
239};
240
241// ----- destroy ----- //
242
243proto.destroy = function() {
244  // move items back to container
245  this.items.forEach( function( item ) {
246    this.element.appendChild( item );
247  }, this );
248  // remove events
249  window.removeEventListener( 'resize', this._windowResizeHandler );
250  this.element.removeEventListener( 'load', this._loadHandler, true );
251  // remove data
252  delete this.element.colcadeGUID;
253  delete instances[ this.guid ];
254};
255
256// -------------------------- HTML init -------------------------- //
257
258docReady( function() {
259  var dataElems = querySelect('[data-colcade]');
260  dataElems.forEach( htmlInit );
261});
262
263function htmlInit( elem ) {
264  // convert attribute "foo: bar, qux: baz" into object
265  var attr = elem.getAttribute('data-colcade');
266  var attrParts = attr.split(',');
267  var options = {};
268  attrParts.forEach( function( part ) {
269    var pair = part.split(':');
270    var key = pair[0].trim();
271    var value = pair[1].trim();
272    options[ key ] = value;
273  });
274
275  new Colcade( elem, options );
276}
277
278Colcade.data = function( elem ) {
279  elem = getQueryElement( elem );
280  var id = elem && elem.colcadeGUID;
281  return id && instances[ id ];
282};
283
284// -------------------------- jQuery -------------------------- //
285
286Colcade.makeJQueryPlugin = function( $ ) {
287  $ = $ || window.jQuery;
288  if ( !$ ) {
289    return;
290  }
291
292  $.fn.colcade = function( arg0 /*, arg1 */) {
293    // method call $().colcade( 'method', { options } )
294    if ( typeof arg0 == 'string' ) {
295      // shift arguments by 1
296      var args = Array.prototype.slice.call( arguments, 1 );
297      return methodCall( this, arg0, args );
298    }
299    // just $().colcade({ options })
300    plainCall( this, arg0 );
301    return this;
302  };
303
304  function methodCall( $elems, methodName, args ) {
305    var returnValue;
306    $elems.each( function( i, elem ) {
307      // get instance
308      var colcade = $.data( elem, 'colcade' );
309      if ( !colcade ) {
310        return;
311      }
312      // apply method, get return value
313      var value = colcade[ methodName ].apply( colcade, args );
314      // set return value if value is returned, use only first value
315      returnValue = returnValue === undefined ? value : returnValue;
316    });
317    return returnValue !== undefined ? returnValue : $elems;
318  }
319
320  function plainCall( $elems, options ) {
321    $elems.each( function( i, elem ) {
322      var colcade = $.data( elem, 'colcade' );
323      if ( colcade ) {
324        // set options & init
325        colcade.option( options );
326        colcade.layout();
327      } else {
328        // initialize new instance
329        colcade = new Colcade( elem, options );
330        $.data( elem, 'colcade', colcade );
331      }
332    });
333  }
334};
335
336// try making plugin
337Colcade.makeJQueryPlugin();
338
339// -------------------------- utils -------------------------- //
340
341function extend( a, b ) {
342  for ( var prop in b ) {
343    a[ prop ] = b[ prop ];
344  }
345  return a;
346}
347
348// turn element or nodeList into an array
349function makeArray( obj ) {
350  var ary = [];
351  if ( Array.isArray( obj ) ) {
352    // use object if already an array
353    ary = obj;
354  } else if ( obj && typeof obj.length == 'number' ) {
355    // convert nodeList to array
356    for ( var i=0; i < obj.length; i++ ) {
357      ary.push( obj[i] );
358    }
359  } else {
360    // array of single index
361    ary.push( obj );
362  }
363  return ary;
364}
365
366// get array of elements
367function querySelect( selector, elem ) {
368  elem = elem || document;
369  var elems = elem.querySelectorAll( selector );
370  return makeArray( elems );
371}
372
373function getQueryElement( elem ) {
374  if ( typeof elem == 'string' ) {
375    elem = document.querySelector( elem );
376  }
377  return elem;
378}
379
380function docReady( onReady ) {
381  if ( document.readyState == 'complete' ) {
382    onReady();
383    return;
384  }
385  document.addEventListener( 'DOMContentLoaded', onReady );
386}
387
388// -------------------------- end -------------------------- //
389
390return Colcade;
391
392}));

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.