PageSourceSearch

https://latgale.travel/wp-content/themes/listify/js/vendor/salvattore/salvattore.min.js?ver=3.2.6

js latgale.travel collected 2026-09-25 00:09:48 UTC 11,117 bytes, 397 lines download raw bytes

1/* jshint laxcomma: true */
2var salvattore = (function (global, document, undefined) {
3"use strict";
4
5var self = {},
6    grids = [],
7    mediaRules = [],
8    mediaQueries = [],
9    add_to_dataset = function(element, key, value) {
10      // uses dataset function or a fallback for <ie10
11      if (element.dataset) {
12        element.dataset[key] = value;
13      } else {
14        element.setAttribute("data-" + key, value);
15      }
16      return;
17    };
18
19self.obtainGridSettings = function obtainGridSettings(element) {
20  // returns the number of columns and the classes a column should have,
21  // from computing the style of the ::before pseudo-element of the grid.
22
23  var computedStyle = global.getComputedStyle(element, ":before")
24    , content = computedStyle.getPropertyValue("content").slice(1, -1)
25    , matchResult = content.match(/^\s*(\d+)(?:\s?\.(.+))?\s*$/)
26    , numberOfColumns = 1
27    , columnClasses = []
28  ;
29
30  if (matchResult) {
31    numberOfColumns = matchResult[1];
32    columnClasses = matchResult[2];
33    columnClasses = columnClasses? columnClasses.split(".") : ["column"];
34  } else {
35    matchResult = content.match(/^\s*\.(.+)\s+(\d+)\s*$/);
36    if (matchResult) {
37      columnClasses = matchResult[1];
38      numberOfColumns = matchResult[2];
39      if (numberOfColumns) {
40            numberOfColumns = numberOfColumns.split(".");
41      }
42    }
43  }
44
45  return {
46    numberOfColumns: numberOfColumns,
47    columnClasses: columnClasses
48  };
49};
50
51
52self.addColumns = function addColumns(grid, items) {
53  // from the settings obtained, it creates columns with
54  // the configured classes and adds to them a list of items.
55
56  var settings = self.obtainGridSettings(grid)
57    , numberOfColumns = settings.numberOfColumns
58    , columnClasses = settings.columnClasses
59    , columnsItems = new Array(+numberOfColumns)
60    , columnsFragment = document.createDocumentFragment()
61    , i = numberOfColumns
62    , selector
63  ;
64
65  while (i-- !== 0) {
66    selector = "[data-columns] > *:nth-child(" + numberOfColumns + "n-" + i + ")";
67    columnsItems.push(items.querySelectorAll(selector));
68  }
69
70  columnsItems.forEach(function append_to_grid_fragment(rows) {
71    var column = document.createElement("div")
72      , rowsFragment = document.createDocumentFragment()
73    ;
74
75    column.className = columnClasses.join(" ");
76
77    Array.prototype.forEach.call(rows, function append_to_column(row) {
78      rowsFragment.appendChild(row);
79    });
80    column.appendChild(rowsFragment);
81    columnsFragment.appendChild(column);
82  });
83
84  grid.appendChild(columnsFragment);
85  add_to_dataset(grid, 'columns', numberOfColumns);
86};
87
88
89self.removeColumns = function removeColumns(grid) {
90  // removes all the columns from a grid, and returns a list
91  // of items sorted by the ordering of columns.
92
93  var range = document.createRange();
94  range.selectNodeContents(grid);
95
96  var columns = Array.prototype.filter.call(range.extractContents().childNodes, function filter_elements(node) {
97    return node instanceof global.HTMLElement;
98  });
99
100  var numberOfColumns = columns.length
101    , numberOfRowsInFirstColumn = columns[0].childNodes.length
102    , sortedRows = new Array(numberOfRowsInFirstColumn * numberOfColumns)
103  ;
104
105  Array.prototype.forEach.call(columns, function iterate_columns(column, columnIndex) {
106    Array.prototype.forEach.call(column.children, function iterate_rows(row, rowIndex) {
107      sortedRows[rowIndex * numberOfColumns + columnIndex] = row;
108    });
109  });
110
111  var container = document.createElement("div");
112  add_to_dataset(container, 'columns', 0);
113
114  sortedRows.filter(function filter_non_null(child) {
115    return !!child;
116  }).forEach(function append_row(child) {
117    container.appendChild(child);
118  });
119
120  return container;
121};
122
123
124self.recreateColumns = function recreateColumns(grid) {
125  // removes all the columns from the grid, and adds them again,
126  // it is used when the number of columns change.
127
128  global.requestAnimationFrame(function render_after_css_mediaQueryChange() {
129    self.addColumns(grid, self.removeColumns(grid));
130    var columnsChange = new CustomEvent("columnsChange");
131    grid.dispatchEvent(columnsChange);
132  });
133};
134
135
136self.mediaQueryChange = function mediaQueryChange(mql) {
137  // recreates the columns when a media query matches the current state
138  // of the browser.
139
140  if (mql.matches) {
141    Array.prototype.forEach.call(grids, self.recreateColumns);
142  }
143};
144
145
146self.getCSSRules = function getCSSRules(stylesheet) {
147  // returns a list of css rules from a stylesheet
148
149  var cssRules;
150  try {
151    cssRules = stylesheet.sheet.cssRules || stylesheet.sheet.rules;
152  } catch (e) {
153    return [];
154  }
155
156  return cssRules || [];
157};
158
159
160self.getStylesheets = function getStylesheets() {
161  // returns a list of all the styles in the document (that are accessible).
162
163  return Array.prototype.concat.call(
164    Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),
165    Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))
166  );
167};
168
169
170self.mediaRuleHasColumnsSelector = function mediaRuleHasColumnsSelector(rules) {
171  // checks if a media query css rule has in its contents a selector that
172  // styles the grid.
173
174  var i, rule;
175
176  try {
177    i = rules.length;
178  }
179  catch (e) {
180    i = 0;
181  }
182
183  while (i--) {
184    rule = rules[i];
185    if (rule.selectorText && rule.selectorText.match(/\[data-columns\](.*)::?before$/)) {
186      return true;
187    }
188  }
189
190  return false;
191};
192
193
194self.scanMediaQueries = function scanMediaQueries() {
195  // scans all the stylesheets for selectors that style grids,
196  // if the matchMedia API is supported.
197
198  var newMediaRules = [];
199
200  if (!global.matchMedia) {
201    return;
202  }
203
204  self.getStylesheets().forEach(function extract_rules(stylesheet) {
205    Array.prototype.forEach.call(self.getCSSRules(stylesheet), function filter_by_column_selector(rule) {
206      if (rule.media && rule.cssRules && self.mediaRuleHasColumnsSelector(rule.cssRules)) {
207        newMediaRules.push(rule);
208      }
209    });
210  });
211
212  // remove matchMedia listeners from the old rules
213  var oldRules = mediaRules.filter(function (el) {
214      return newMediaRules.indexOf(el) === -1;
215  });
216  mediaQueries.filter(function (el) {
217    return oldRules.indexOf(el.rule) !== -1;
218  }).forEach(function (el) {
219      el.mql.removeListener(self.mediaQueryChange);
220  });
221  mediaQueries = mediaQueries.filter(function (el) {
222    return oldRules.indexOf(el.rule) === -1;
223  });
224
225  // add matchMedia listeners to the new rules
226  newMediaRules.filter(function (el) {
227    return mediaRules.indexOf(el) == -1;
228  }).forEach(function (rule) {
229      var mql = global.matchMedia(rule.media.mediaText);
230      mql.addListener(self.mediaQueryChange);
231      mediaQueries.push({rule: rule, mql:mql});
232  });
233
234  // swap mediaRules with the new set
235  mediaRules.length = 0;
236  mediaRules = newMediaRules;
237};
238
239
240self.rescanMediaQueries = function rescanMediaQueries() {
241    self.scanMediaQueries();
242    Array.prototype.forEach.call(grids, self.recreateColumns);
243};
244
245
246self.nextElementColumnIndex = function nextElementColumnIndex(grid, fragments) {
247  // returns the index of the column where the given element must be added.
248
249  var children = grid.children
250    , m = children.length
251    , lowestRowCount = 0
252    , child
253    , currentRowCount
254    , i
255    , index = 0
256  ;
257  for (i = 0; i < m; i++) {
258    child = children[i];
259    currentRowCount = child.children.length + (fragments[i].children || fragments[i].childNodes).length;
260  if(lowestRowCount === 0) {
261    lowestRowCount = currentRowCount;
262  }
263    if(currentRowCount < lowestRowCount) {
264      index = i;
265      lowestRowCount = currentRowCount;
266    }
267  }
268
269  return index;
270};
271
272
273self.createFragmentsList = function createFragmentsList(quantity) {
274  // returns a list of fragments
275
276  var fragments = new Array(quantity)
277    , i = 0
278  ;
279
280  while (i !== quantity) {
281    fragments[i] = document.createDocumentFragment();
282    i++;
283  }
284
285  return fragments;
286};
287
288
289self.appendElements = function appendElements(grid, elements) {
290  // adds a list of elements to the end of a grid
291
292  var columns = grid.children
293    , numberOfColumns = columns.length
294    , fragments = self.createFragmentsList(numberOfColumns)
295  ;
296
297  Array.prototype.forEach.call(elements, function append_to_next_fragment(element) {
298    var columnIndex = self.nextElementColumnIndex(grid, fragments);
299    fragments[columnIndex].appendChild(element);
300  });
301
302  Array.prototype.forEach.call(columns, function insert_column(column, index) {
303    column.appendChild(fragments[index]);
304  });
305};
306
307
308self.prependElements = function prependElements(grid, elements) {
309  // adds a list of elements to the start of a grid
310
311  var columns = grid.children
312    , numberOfColumns = columns.length
313    , fragments = self.createFragmentsList(numberOfColumns)
314    , columnIndex = numberOfColumns - 1
315  ;
316
317  elements.forEach(function append_to_next_fragment(element) {
318    var fragment = fragments[columnIndex];
319    fragment.insertBefore(element, fragment.firstChild);
320    if (columnIndex === 0) {
321      columnIndex = numberOfColumns - 1;
322    } else {
323      columnIndex--;
324    }
325  });
326
327  Array.prototype.forEach.call(columns, function insert_column(column, index) {
328    column.insertBefore(fragments[index], column.firstChild);
329  });
330
331  // populates a fragment with n columns till the right
332  var fragment = document.createDocumentFragment()
333    , numberOfColumnsToExtract = elements.length % numberOfColumns
334  ;
335
336  while (numberOfColumnsToExtract-- !== 0) {
337    fragment.appendChild(grid.lastChild);
338  }
339
340  // adds the fragment to the left
341  grid.insertBefore(fragment, grid.firstChild);
342};
343
344
345self.registerGrid = function registerGrid (grid) {
346  if (global.getComputedStyle(grid).display === "none") {
347    return;
348  }
349
350  // retrieve the list of items from the grid itself
351  var range = document.createRange();
352  range.selectNodeContents(grid);
353
354  var items = document.createElement("div");
355  items.appendChild(range.extractContents());
356
357
358  add_to_dataset(items, 'columns', 0);
359  self.addColumns(grid, items);
360  grids.push(grid);
361};
362
363
364self.init = function init() {
365  // adds required CSS rule to hide 'content' based
366  // configuration.
367
368  var css = document.createElement("style");
369  css.innerHTML = "[data-columns]::before{visibility:hidden;position:absolute;font-size:1px;}";
370  document.head.appendChild(css);
371
372  // scans all the grids in the document and generates
373  // columns from their configuration.
374
375  var gridElements = document.querySelectorAll("[data-columns]");
376  Array.prototype.forEach.call(gridElements, self.registerGrid);
377  self.scanMediaQueries();
378};
379
380self.init();
381
382return {
383  appendElements: self.appendElements,
384  prependElements: self.prependElements,
385  registerGrid: self.registerGrid,
386  recreateColumns: self.recreateColumns,
387  rescanMediaQueries: self.rescanMediaQueries,
388
389  // maintains backwards compatibility with underscore style method names
390  append_elements: self.appendElements,
391  prepend_elements: self.prependElements,
392  register_grid: self.registerGrid,
393  recreate_columns: self.recreateColumns,
394  rescan_media_queries: self.rescanMediaQueries
395};
396
397})(window, window.document);

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.