PageSourceSearch

https://www.topcamping.at/typo3conf/ext/mw_theme/Resources/Public/Isotope/js/isotope.js?1761991637

js topcamping.at collected 2026-10-09 04:09:21 UTC 17,537 bytes, 621 lines download raw bytes

vendor: 17,537 bytes, lines 1-621
1/*!
2 * Isotope v3.0.6
3 *
4 * Licensed GPLv3 for open source use
5 * or Isotope Commercial License for commercial use
6 *
7 * https://isotope.metafizzy.co
8 * Copyright 2010-2018 Metafizzy
9 */
10
11( function( window, factory ) {
12  // universal module definition
13  /* jshint strict: false */ /*globals define, module, require */
14  if ( typeof define == 'function' && define.amd ) {
15    // AMD
16    define( [
17        'outlayer/outlayer',
18        'get-size/get-size',
19        'desandro-matches-selector/matches-selector',
20        'fizzy-ui-utils/utils',
21        './item',
22        './layout-mode',
23        // include default layout modes
24        './layout-modes/masonry',
25        './layout-modes/fit-rows',
26        './layout-modes/vertical'
27      ],
28      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
29        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
30      });
31  } else if ( typeof module == 'object' && module.exports ) {
32    // CommonJS
33    module.exports = factory(
34      window,
35      require('outlayer'),
36      require('get-size'),
37      require('desandro-matches-selector'),
38      require('fizzy-ui-utils'),
39      require('./item'),
40      require('./layout-mode'),
41      // include default layout modes
42      require('./layout-modes/masonry'),
43      require('./layout-modes/fit-rows'),
44      require('./layout-modes/vertical')
45    );
46  } else {
47    // browser global
48    window.Isotope = factory(
49      window,
50      window.Outlayer,
51      window.getSize,
52      window.matchesSelector,
53      window.fizzyUIUtils,
54      window.Isotope.Item,
55      window.Isotope.LayoutMode
56    );
57  }
58
59}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
60  Item, LayoutMode ) {
61
62'use strict';
63
64// -------------------------- vars -------------------------- //
65
66var jQuery = window.jQuery;
67
68// -------------------------- helpers -------------------------- //
69
70var trim = String.prototype.trim ?
71  function( str ) {
72    return str.trim();
73  } :
74  function( str ) {
75    return str.replace( /^\s+|\s+$/g, '' );
76  };
77
78// -------------------------- isotopeDefinition -------------------------- //
79
80  // create an Outlayer layout class
81  var Isotope = Outlayer.create( 'isotope', {
82    layoutMode: 'masonry',
83    isJQueryFiltering: true,
84    sortAscending: true
85  });
86
87  Isotope.Item = Item;
88  Isotope.LayoutMode = LayoutMode;
89
90  var proto = Isotope.prototype;
91
92  proto._create = function() {
93    this.itemGUID = 0;
94    // functions that sort items
95    this._sorters = {};
96    this._getSorters();
97    // call super
98    Outlayer.prototype._create.call( this );
99
100    // create layout modes
101    this.modes = {};
102    // start filteredItems with all items
103    this.filteredItems = this.items;
104    // keep of track of sortBys
105    this.sortHistory = [ 'original-order' ];
106    // create from registered layout modes
107    for ( var name in LayoutMode.modes ) {
108      this._initLayoutMode( name );
109    }
110  };
111
112  proto.reloadItems = function() {
113    // reset item ID counter
114    this.itemGUID = 0;
115    // call super
116    Outlayer.prototype.reloadItems.call( this );
117  };
118
119  proto._itemize = function() {
120    var items = Outlayer.prototype._itemize.apply( this, arguments );
121    // assign ID for original-order
122    for ( var i=0; i < items.length; i++ ) {
123      var item = items[i];
124      item.id = this.itemGUID++;
125    }
126    this._updateItemsSortData( items );
127    return items;
128  };
129
130
131  // -------------------------- layout -------------------------- //
132
133  proto._initLayoutMode = function( name ) {
134    var Mode = LayoutMode.modes[ name ];
135    // set mode options
136    // HACK extend initial options, back-fill in default options
137    var initialOpts = this.options[ name ] || {};
138    this.options[ name ] = Mode.options ?
139      utils.extend( Mode.options, initialOpts ) : initialOpts;
140    // init layout mode instance
141    this.modes[ name ] = new Mode( this );
142  };
143
144
145  proto.layout = function() {
146    // if first time doing layout, do all magic
147    if ( !this._isLayoutInited && this._getOption('initLayout') ) {
148      this.arrange();
149      return;
150    }
151    this._layout();
152  };
153
154  // private method to be used in layout() & magic()
155  proto._layout = function() {
156    // don't animate first layout
157    var isInstant = this._getIsInstant();
158    // layout flow
159    this._resetLayout();
160    this._manageStamps();
161    this.layoutItems( this.filteredItems, isInstant );
162
163    // flag for initalized
164    this._isLayoutInited = true;
165  };
166
167  // filter + sort + layout
168  proto.arrange = function( opts ) {
169    // set any options pass
170    this.option( opts );
171    this._getIsInstant();
172    // filter, sort, and layout
173
174    // filter
175    var filtered = this._filter( this.items );
176    this.filteredItems = filtered.matches;
177
178    this._bindArrangeComplete();
179
180    if ( this._isInstant ) {
181      this._noTransition( this._hideReveal, [ filtered ] );
182    } else {
183      this._hideReveal( filtered );
184    }
185
186    this._sort();
187    this._layout();
188  };
189  // alias to _init for main plugin method
190  proto._init = proto.arrange;
191
192  proto._hideReveal = function( filtered ) {
193    this.reveal( filtered.needReveal );
194    this.hide( filtered.needHide );
195  };
196
197  // HACK
198  // Don't animate/transition first layout
199  // Or don't animate/transition other layouts
200  proto._getIsInstant = function() {
201    var isLayoutInstant = this._getOption('layoutInstant');
202    var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
203      !this._isLayoutInited;
204    this._isInstant = isInstant;
205    return isInstant;
206  };
207
208  // listen for layoutComplete, hideComplete and revealComplete
209  // to trigger arrangeComplete
210  proto._bindArrangeComplete = function() {
211    // listen for 3 events to trigger arrangeComplete
212    var isLayoutComplete, isHideComplete, isRevealComplete;
213    var _this = this;
214    function arrangeParallelCallback() {
215      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
216        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
217      }
218    }
219    this.once( 'layoutComplete', function() {
220      isLayoutComplete = true;
221      arrangeParallelCallback();
222    });
223    this.once( 'hideComplete', function() {
224      isHideComplete = true;
225      arrangeParallelCallback();
226    });
227    this.once( 'revealComplete', function() {
228      isRevealComplete = true;
229      arrangeParallelCallback();
230    });
231  };
232
233  // -------------------------- filter -------------------------- //
234
235  proto._filter = function( items ) {
236    var filter = this.options.filter;
237    filter = filter || '*';
238    var matches = [];
239    var hiddenMatched = [];
240    var visibleUnmatched = [];
241
242    var test = this._getFilterTest( filter );
243
244    // test each item
245    for ( var i=0; i < items.length; i++ ) {
246      var item = items[i];
247      if ( item.isIgnored ) {
248        continue;
249      }
250      // add item to either matched or unmatched group
251      var isMatched = test( item );
252      // item.isFilterMatched = isMatched;
253      // add to matches if its a match
254      if ( isMatched ) {
255        matches.push( item );
256      }
257      // add to additional group if item needs to be hidden or revealed
258      if ( isMatched && item.isHidden ) {
259        hiddenMatched.push( item );
260      } else if ( !isMatched && !item.isHidden ) {
261        visibleUnmatched.push( item );
262      }
263    }
264
265    // return collections of items to be manipulated
266    return {
267      matches: matches,
268      needReveal: hiddenMatched,
269      needHide: visibleUnmatched
270    };
271  };
272
273  // get a jQuery, function, or a matchesSelector test given the filter
274  proto._getFilterTest = function( filter ) {
275    if ( jQuery && this.options.isJQueryFiltering ) {
276      // use jQuery
277      return function( item ) {
278        return jQuery( item.element ).is( filter );
279      };
280    }
281    if ( typeof filter == 'function' ) {
282      // use filter as function
283      return function( item ) {
284        return filter( item.element );
285      };
286    }
287    // default, use filter as selector string
288    return function( item ) {
289      return matchesSelector( item.element, filter );
290    };
291  };
292
293  // -------------------------- sorting -------------------------- //
294
295  /**
296   * @params {Array} elems
297   * @public
298   */
299  proto.updateSortData = function( elems ) {
300    // get items
301    var items;
302    if ( elems ) {
303      elems = utils.makeArray( elems );
304      items = this.getItems( elems );
305    } else {
306      // update all items if no elems provided
307      items = this.items;
308    }
309
310    this._getSorters();
311    this._updateItemsSortData( items );
312  };
313
314  proto._getSorters = function() {
315    var getSortData = this.options.getSortData;
316    for ( var key in getSortData ) {
317      var sorter = getSortData[ key ];
318      this._sorters[ key ] = mungeSorter( sorter );
319    }
320  };
321
322  /**
323   * @params {Array} items - of Isotope.Items
324   * @private
325   */
326  proto._updateItemsSortData = function( items ) {
327    // do not update if no items
328    var len = items && items.length;
329
330    for ( var i=0; len && i < len; i++ ) {
331      var item = items[i];
332      item.updateSortData();
333    }
334  };
335
336  // ----- munge sorter ----- //
337
338  // encapsulate this, as we just need mungeSorter
339  // other functions in here are just for munging
340  var mungeSorter = ( function() {
341    // add a magic layer to sorters for convienent shorthands
342    // `.foo-bar` will use the text of .foo-bar querySelector
343    // `[foo-bar]` will use attribute
344    // you can also add parser
345    // `.foo-bar parseInt` will parse that as a number
346    function mungeSorter( sorter ) {
347      // if not a string, return function or whatever it is
348      if ( typeof sorter != 'string' ) {
349        return sorter;
350      }
351      // parse the sorter string
352      var args = trim( sorter ).split(' ');
353      var query = args[0];
354      // check if query looks like [an-attribute]
355      var attrMatch = query.match( /^\[(.+)\]$/ );
356      var attr = attrMatch && attrMatch[1];
357      var getValue = getValueGetter( attr, query );
358      // use second argument as a parser
359      var parser = Isotope.sortDataParsers[ args[1] ];
360      // parse the value, if there was a parser
361      sorter = parser ? function( elem ) {
362        return elem && parser( getValue( elem ) );
363      } :
364      // otherwise just return value
365      function( elem ) {
366        return elem && getValue( elem );
367      };
368
369      return sorter;
370    }
371
372    // get an attribute getter, or get text of the querySelector
373    function getValueGetter( attr, query ) {
374      // if query looks like [foo-bar], get attribute
375      if ( attr ) {
376        return function getAttribute( elem ) {
377          return elem.getAttribute( attr );
378        };
379      }
380
381      // otherwise, assume its a querySelector, and get its text
382      return function getChildText( elem ) {
383        var child = elem.querySelector( query );
384        return child && child.textContent;
385      };
386    }
387
388    return mungeSorter;
389  })();
390
391  // parsers used in getSortData shortcut strings
392  Isotope.sortDataParsers = {
393    'parseInt': function( val ) {
394      return parseInt( val, 10 );
395    },
396    'parseFloat': function( val ) {
397      return parseFloat( val );
398    }
399  };
400
401  // ----- sort method ----- //
402
403  // sort filteredItem order
404  proto._sort = function() {
405    if ( !this.options.sortBy ) {
406      return;
407    }
408    // keep track of sortBy History
409    var sortBys = utils.makeArray( this.options.sortBy );
410    if ( !this._getIsSameSortBy( sortBys ) ) {
411      // concat all sortBy and sortHistory, add to front, oldest goes in last
412      this.sortHistory = sortBys.concat( this.sortHistory );
413    }
414    // sort magic
415    var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
416    this.filteredItems.sort( itemSorter );
417  };
418
419  // check if sortBys is same as start of sortHistory
420  proto._getIsSameSortBy = function( sortBys ) {
421    for ( var i=0; i < sortBys.length; i++ ) {
422      if ( sortBys[i] != this.sortHistory[i] ) {
423        return false;
424      }
425    }
426    return true;
427  };
428
429  // returns a function used for sorting
430  function getItemSorter( sortBys, sortAsc ) {
431    return function sorter( itemA, itemB ) {
432      // cycle through all sortKeys
433      for ( var i = 0; i < sortBys.length; i++ ) {
434        var sortBy = sortBys[i];
435        var a = itemA.sortData[ sortBy ];
436        var b = itemB.sortData[ sortBy ];
437        if ( a > b || a < b ) {
438          // if sortAsc is an object, use the value given the sortBy key
439          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
440          var direction = isAscending ? 1 : -1;
441          return ( a > b ? 1 : -1 ) * direction;
442        }
443      }
444      return 0;
445    };
446  }
447
448  // -------------------------- methods -------------------------- //
449
450  // get layout mode
451  proto._mode = function() {
452    var layoutMode = this.options.layoutMode;
453    var mode = this.modes[ layoutMode ];
454    if ( !mode ) {
455      // TODO console.error
456      throw new Error( 'No layout mode: ' + layoutMode );
457    }
458    // HACK sync mode's options
459    // any options set after init for layout mode need to be synced
460    mode.options = this.options[ layoutMode ];
461    return mode;
462  };
463
464  proto._resetLayout = function() {
465    // trigger original reset layout
466    Outlayer.prototype._resetLayout.call( this );
467    this._mode()._resetLayout();
468  };
469
470  proto._getItemLayoutPosition = function( item  ) {
471    return this._mode()._getItemLayoutPosition( item );
472  };
473
474  proto._manageStamp = function( stamp ) {
475    this._mode()._manageStamp( stamp );
476  };
477
478  proto._getContainerSize = function() {
479    return this._mode()._getContainerSize();
480  };
481
482  proto.needsResizeLayout = function() {
483    return this._mode().needsResizeLayout();
484  };
485
486  // -------------------------- adding & removing -------------------------- //
487
488  // HEADS UP overwrites default Outlayer appended
489  proto.appended = function( elems ) {
490    var items = this.addItems( elems );
491    if ( !items.length ) {
492      return;
493    }
494    // filter, layout, reveal new items
495    var filteredItems = this._filterRevealAdded( items );
496    // add to filteredItems
497    this.filteredItems = this.filteredItems.concat( filteredItems );
498  };
499
500  // HEADS UP overwrites default Outlayer prepended
501  proto.prepended = function( elems ) {
502    var items = this._itemize( elems );
503    if ( !items.length ) {
504      return;
505    }
506    // start new layout
507    this._resetLayout();
508    this._manageStamps();
509    // filter, layout, reveal new items
510    var filteredItems = this._filterRevealAdded( items );
511    // layout previous items
512    this.layoutItems( this.filteredItems );
513    // add to items and filteredItems
514    this.filteredItems = filteredItems.concat( this.filteredItems );
515    this.items = items.concat( this.items );
516  };
517
518  proto._filterRevealAdded = function( items ) {
519    var filtered = this._filter( items );
520    this.hide( filtered.needHide );
521    // reveal all new items
522    this.reveal( filtered.matches );
523    // layout new items, no transition
524    this.layoutItems( filtered.matches, true );
525    return filtered.matches;
526  };
527
528  /**
529   * Filter, sort, and layout newly-appended item elements
530   * @param {Array or NodeList or Element} elems
531   */
532  proto.insert = function( elems ) {
533    var items = this.addItems( elems );
534    if ( !items.length ) {
535      return;
536    }
537    // append item elements
538    var i, item;
539    var len = items.length;
540    for ( i=0; i < len; i++ ) {
541      item = items[i];
542      this.element.appendChild( item.element );
543    }
544    // filter new stuff
545    var filteredInsertItems = this._filter( items ).matches;
546    // set flag
547    for ( i=0; i < len; i++ ) {
548      items[i].isLayoutInstant = true;
549    }
550    this.arrange();
551    // reset flag
552    for ( i=0; i < len; i++ ) {
553      delete items[i].isLayoutInstant;
554    }
555    this.reveal( filteredInsertItems );
556  };
557
558  var _remove = proto.remove;
559  proto.remove = function( elems ) {
560    elems = utils.makeArray( elems );
561    var removeItems = this.getItems( elems );
562    // do regular thing
563    _remove.call( this, elems );
564    // bail if no items to remove
565    var len = removeItems && removeItems.length;
566    // remove elems from filteredItems
567    for ( var i=0; len && i < len; i++ ) {
568      var item = removeItems[i];
569      // remove item from collection
570      utils.removeFrom( this.filteredItems, item );
571    }
572  };
573
574  proto.shuffle = function() {
575    // update random sortData
576    for ( var i=0; i < this.items.length; i++ ) {
577      var item = this.items[i];
578      item.sortData.random = Math.random();
579    }
580    this.options.sortBy = 'random';
581    this._sort();
582    this._layout();
583  };
584
585  /**
586   * trigger fn without transition
587   * kind of hacky to have this in the first place
588   * @param {Function} fn
589   * @param {Array} args
590   * @returns ret
591   * @private
592   */
593  proto._noTransition = function( fn, args ) {
594    // save transitionDuration before disabling
595    var transitionDuration = this.options.transitionDuration;
596    // disable transition
597    this.options.transitionDuration = 0;
598    // do it
599    var returnValue = fn.apply( this, args );
600    // re-enable transition for reveal
601    this.options.transitionDuration = transitionDuration;
602    return returnValue;
603  };
604
605  // ----- helper methods ----- //
606
607  /**
608   * getter method for getting filtered item elements
609   * @returns {Array} elems - collection of item elements
610   */
611  proto.getFilteredItemElements = function() {
612    return this.filteredItems.map( function( item ) {
613      return item.element;
614    });
615  };
616
617  // -----  ----- //
618
619  return Isotope;
620
621}));

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.