PageSourceSearch

https://www.der-roemer-shop.de/templates/NOVA/js/colcade.js?v=5.3.0

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

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.