PageSourceSearch

https://campus.gov.il/wp-content/themes/campusnew/js/catalog-filter-groups.js?var=170

js campus.gov.il collected 2026-10-02 06:35:03 UTC 6,541 bytes, 171 lines download raw bytes

1/* Catalog filters — select-all for every filter group.
2 *
3 * Ticking a whole group one box at a time is slow and fires one results request per click. This
4 * adds a control checkbox per group that applies the whole group in a single pass, then issues
5 * exactly one request. Groups opt in with data-filter-group (a unique key), data-group-name and
6 * data-all-label on their .choicelist.
7 *
8 * When a group is fully selected its individual tags collapse into one group tag: selecting all of
9 * פיתוח אישי ומיומנויות would otherwise push 16 tags into the active-filter row at once.
10 *
11 * Depends on common.js for filterCheckboxTag, countAllClickedChecboxes, updateWindowParams and
12 * filterResultsAjax; this file must load after it.
13 */
14(function () {
15  'use strict';
16
17  var GROUP = '[data-filter-group]';
18
19  function groups() {
20    return Array.prototype.slice.call(document.querySelectorAll(GROUP));
21  }
22
23  function boxesIn(group) {
24    return Array.prototype.slice.call(group.querySelectorAll('input.inputbox'));
25  }
26
27  function checkedIn(group) {
28    return boxesIn(group).filter(function (b) { return b.checked; });
29  }
30
31  function groupTagId(group) {
32    return 'fgroup' + group.getAttribute('data-filter-group') + 'x';
33  }
34
35  /** Per-group count shown on the collapsed group button. */
36  function syncCount(group) {
37    var boxes = boxesIn(group);
38    if (!boxes.length) return;
39    var target = document.getElementById(boxes[0].getAttribute('data-count'));
40    if (!target) return;
41    var n = checkedIn(group).length;
42    target.innerHTML = n === 0 ? '' : String(n);
43  }
44
45  /** Control checkbox reflects the group: checked when all, indeterminate when some. */
46  function syncControl(group) {
47    var control = group.querySelector('input.inputboxAll');
48    if (!control) return;
49    var boxes = boxesIn(group), checked = checkedIn(group).length;
50    control.checked = boxes.length > 0 && checked === boxes.length;
51    control.indeterminate = checked > 0 && checked < boxes.length;
52  }
53
54  /**
55   * Rebuild this group's tags. Rebuilt rather than patched because the two shapes are mutually
56   * exclusive — one group tag, or one tag per term — and a partial update would leave both.
57   */
58  function syncTags(group) {
59    var list = document.getElementById('catalogSelectedFiltersItems');
60    if (!list) return;
61
62    var existing = document.getElementById(groupTagId(group));
63    if (existing) existing.parentNode.removeChild(existing);
64
65    var boxes = boxesIn(group), checked = checkedIn(group);
66    var whole = boxes.length > 0 && checked.length === boxes.length;
67
68    boxes.forEach(function (box) {
69      var li = document.getElementById(box.id + 'x');
70      // A term's own tag is wrong while the whole group is represented by one tag.
71      if (whole && li) li.parentNode.removeChild(li);
72      if (!whole && typeof window.filterCheckboxTag === 'function') window.filterCheckboxTag(box);
73    });
74
75    if (!whole) return;
76
77    var li = document.createElement('li');
78    li.id = groupTagId(group);
79    li.appendChild(document.createTextNode(
80      group.getAttribute('data-group-name') + ': ' + group.getAttribute('data-all-label')));
81    var remove = document.createElement('a');
82    remove.href = 'javascript:;';
83    remove.textContent = 'x';
84    remove.addEventListener('click', function () { applyGroup(group, false, true); });
85    li.appendChild(remove);
86    list.appendChild(li);
87  }
88
89  function syncGroup(group) {
90    syncCount(group);
91    syncControl(group);
92    syncTags(group);
93  }
94
95  /** Apply a state to every term in the group, then refresh results once. */
96  function applyGroup(group, state, refresh) {
97    boxesIn(group).forEach(function (box) { box.checked = state; });
98    syncGroup(group);
99
100    if (typeof window.countAllClickedChecboxes === 'function') window.countAllClickedChecboxes();
101    if (typeof window.updateWindowParams === 'function') window.updateWindowParams();
102    if (refresh && typeof window.filterResultsAjax === 'function') window.filterResultsAjax();
103  }
104
105  function init() {
106    var all = groups();
107    if (!all.length) return;
108
109    wrapLegacyTagRebuild();
110
111    all.forEach(function (group) {
112      var control = group.querySelector('input.inputboxAll');
113      if (control) {
114        control.addEventListener('change', function () { applyGroup(group, this.checked, true); });
115      }
116      // Runs after common.js's own click handler, so the per-term tag it just added is already in
117      // place and this only has to reconcile the group-level view.
118      boxesIn(group).forEach(function (box) {
119        box.addEventListener('click', function () { syncGroup(group); });
120      });
121      syncGroup(group);
122    });
123
124    // Reset clears .inputbox but knows nothing about the control boxes or the group tags.
125    var reset = document.getElementById('resetFilters');
126    if (reset) {
127      reset.addEventListener('click', function () {
128        all.forEach(function (group) {
129          var control = group.querySelector('input.inputboxAll');
130          if (control) { control.checked = false; control.indeterminate = false; }
131          var tag = document.getElementById(groupTagId(group));
132          if (tag) tag.parentNode.removeChild(tag);
133        });
134      });
135    }
136  }
137
138  /** Reconcile every group's tags and controls. */
139  function syncAll() {
140    groups().forEach(syncGroup);
141  }
142
143  /**
144   * common.js rebuilds the whole tag list from the raw checkboxes in updateFilterTags(), which the
145   * sort handler calls on every sort-driven reload. It knows nothing about groups, so it re-adds a
146   * tag per checked term — leaving a group tag and all its term tags showing together, the two
147   * shapes syncTags() treats as mutually exclusive.
148   *
149   * Wrapped here rather than edited there: the group concept belongs to this module, and common.js
150   * is a shared monolith this fix has no reason to touch. The original still runs first; this only
151   * collapses the per-term tags a fully selected group should not have.
152   */
153  function wrapLegacyTagRebuild() {
154    var original = window.updateFilterTags;
155    if (typeof original !== 'function' || original.cilGroupAware) return;
156
157    var wrapped = function () {
158      var result = original.apply(this, arguments);
159      syncAll();
160      return result;
161    };
162    wrapped.cilGroupAware = true;   // guards against double-wrapping on a re-init
163    window.updateFilterTags = wrapped;
164  }
165
166  if (document.readyState === 'loading') {
167    document.addEventListener('DOMContentLoaded', init);
168  } else {
169    init();
170  }
171})();

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.