From 124ef00f958aefde075d6325d3cfff3bb17bc979 Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Wed, 25 Nov 2020 15:45:45 +0100
Subject: [PATCH 01/12] core dom: Add find_parents to find all parents of an
element matching a CSS selector.
---
CHANGES.md | 1 +
src/core/dom.js | 15 +++++++++++++++
src/core/dom.test.js | 30 ++++++++++++++++++++++++++++++
3 files changed, 46 insertions(+)
diff --git a/CHANGES.md b/CHANGES.md
index 2cd14e7ca..79773dfdc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -45,6 +45,7 @@
- core dom: Add ``querySelectorAllAndMe`` to do a querySelectorAll including the starter element.
- core dom: Add ``wrap`` wrap an element with a wrapper element.
- core dom: Add ``hide`` and ``show`` for DOM elements which retain the original display value.
+- core dom: Add ``find_parents`` to find all parents of an element matching a CSS selector.
- pat date picker: Support updating a date if it is before another dependent date.
- pat tabs: Refactor based on ``ResizeObserver`` and fix problems calculating the with with transitions.
- pat tabs: When clicking on the ``extra-tabs`` element, toggle between ``open`` and ``closed`` classes to allow opening/closing an extra-tabs menu via CSS.
diff --git a/src/core/dom.js b/src/core/dom.js
index 93e527b91..71c9b9065 100644
--- a/src/core/dom.js
+++ b/src/core/dom.js
@@ -52,12 +52,27 @@ const show = (el) => {
delete el[DATA_STYLE_DISPLAY];
};
+const find_parents = (el, selector) => {
+ // Return all direct parents of ``el`` matching ``selector``.
+ // This matches against all parents but not the element itself.
+ // The order of elements is from the search starting point up to higher
+ // DOM levels.
+ let parent = el.parentNode?.closest(selector) || null;
+ const ret = [];
+ while (parent) {
+ ret.push(parent);
+ parent = parent.parentNode?.closest(selector) || null;
+ }
+ return ret;
+};
+
const dom = {
toNodeArray: toNodeArray,
querySelectorAllAndMe: querySelectorAllAndMe,
wrap: wrap,
hide: hide,
show: show,
+ find_parents: find_parents,
};
export default dom;
diff --git a/src/core/dom.test.js b/src/core/dom.test.js
index 59d871fa5..08e910531 100644
--- a/src/core/dom.test.js
+++ b/src/core/dom.test.js
@@ -4,6 +4,10 @@ import dom from "./dom";
describe("core.dom tests", () => {
// Tests from the core.dom module
+ afterEach(() => {
+ document.body.innerHTML = "";
+ });
+
describe("toNodeArray tests", () => {
it("returns an array of nodes, if a jQuery object was passed.", (done) => {
const html = document.createElement("div");
@@ -146,4 +150,30 @@ describe("core.dom tests", () => {
done();
});
});
+
+ describe("find_parents", () => {
+ it("it finds all parents matching a selector.", (done) => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+
+
+ `;
+ const res = dom.find_parents(
+ document.querySelector(".starthere"),
+ ".findme"
+ );
+
+ // level4 is not found - it's about to find parents.
+ expect(res.length).toEqual(2);
+ expect(res[0]).toEqual(document.querySelector(".level3")); // inner dom levels first // prettier-ignore
+ expect(res[1]).toEqual(document.querySelector(".level1"));
+
+ done();
+ });
+ });
});
From 566b4eda37ee242e249aaa1867e92a8a45318556 Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Wed, 25 Nov 2020 16:04:15 +0100
Subject: [PATCH 02/12] core dom: Add ``find_scoped`` to search for elements
matching the given selector within the current scope of the given element
unless an ``id`` selector is given - in that case the search is done
globally.
---
CHANGES.md | 2 ++
src/core/dom.js | 9 +++++++++
src/core/dom.test.js | 47 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
diff --git a/CHANGES.md b/CHANGES.md
index 79773dfdc..85d742d5b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -46,6 +46,8 @@
- core dom: Add ``wrap`` wrap an element with a wrapper element.
- core dom: Add ``hide`` and ``show`` for DOM elements which retain the original display value.
- core dom: Add ``find_parents`` to find all parents of an element matching a CSS selector.
+- core dom: Add ``find_scoped`` to search for elements matching the given selector within the current scope of the given element
+ unless an ``id`` selector is given - in that case the search is done globally.
- pat date picker: Support updating a date if it is before another dependent date.
- pat tabs: Refactor based on ``ResizeObserver`` and fix problems calculating the with with transitions.
- pat tabs: When clicking on the ``extra-tabs`` element, toggle between ``open`` and ``closed`` classes to allow opening/closing an extra-tabs menu via CSS.
diff --git a/src/core/dom.js b/src/core/dom.js
index 71c9b9065..64eeb5bf1 100644
--- a/src/core/dom.js
+++ b/src/core/dom.js
@@ -66,6 +66,14 @@ const find_parents = (el, selector) => {
return ret;
};
+const find_scoped = (el, selector) => {
+ // If the selector starts with an object id do a global search,
+ // otherwise do a local search.
+ return (selector.indexOf("#") === 0 ? document : el).querySelectorAll(
+ selector
+ );
+};
+
const dom = {
toNodeArray: toNodeArray,
querySelectorAllAndMe: querySelectorAllAndMe,
@@ -73,6 +81,7 @@ const dom = {
hide: hide,
show: show,
find_parents: find_parents,
+ find_scoped: find_scoped,
};
export default dom;
diff --git a/src/core/dom.test.js b/src/core/dom.test.js
index 08e910531..9b4d520b9 100644
--- a/src/core/dom.test.js
+++ b/src/core/dom.test.js
@@ -176,4 +176,51 @@ describe("core.dom tests", () => {
done();
});
});
+
+ describe("find_scoped", () => {
+ it("Find all instances within the current structure.", (done) => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+
+
+ `;
+
+ const res = dom.find_scoped(
+ document.querySelector(".starthere"),
+ ".findme"
+ );
+
+ expect(res.length).toEqual(2);
+ expect(res[0]).toEqual(document.querySelector(".level3")); // outer dom levels first // prettier-ignore
+ expect(res[1]).toEqual(document.querySelector(".level4"));
+
+ done();
+ });
+
+ it("Find all instances within the current structure.", (done) => {
+ document.body.innerHTML = `
+
+
+
+
+
+
+ `;
+
+ const res = dom.find_scoped(
+ document.querySelector(".starthere"),
+ "#findme"
+ );
+
+ expect(res.length).toEqual(1);
+ expect(res[0]).toEqual(document.querySelector(".level1"));
+
+ done();
+ });
+ });
});
From 4a70cbb54b928bed39ebe2bc49adb50ca52bf783 Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Wed, 25 Nov 2020 16:22:46 +0100
Subject: [PATCH 03/12] core dom: Add is_visible to check if an element is
visible or not. tests skipped as jsDom doesn't update offsetHeight/Width
properly.
---
CHANGES.md | 1 +
src/core/dom.js | 7 +++++++
src/core/dom.test.js | 26 ++++++++++++++++++++++++++
3 files changed, 34 insertions(+)
diff --git a/CHANGES.md b/CHANGES.md
index 85d742d5b..d88843c6f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -47,6 +47,7 @@
- core dom: Add ``hide`` and ``show`` for DOM elements which retain the original display value.
- core dom: Add ``find_parents`` to find all parents of an element matching a CSS selector.
- core dom: Add ``find_scoped`` to search for elements matching the given selector within the current scope of the given element
+- core dom: Add ``is_visible`` to check if an element is visible or not.
unless an ``id`` selector is given - in that case the search is done globally.
- pat date picker: Support updating a date if it is before another dependent date.
- pat tabs: Refactor based on ``ResizeObserver`` and fix problems calculating the with with transitions.
diff --git a/src/core/dom.js b/src/core/dom.js
index 64eeb5bf1..3514a1ed0 100644
--- a/src/core/dom.js
+++ b/src/core/dom.js
@@ -74,6 +74,12 @@ const find_scoped = (el, selector) => {
);
};
+const is_visible = (el) => {
+ // Check, if element is visible in DOM.
+ // https://stackoverflow.com/a/19808107/1337474
+ return el.offsetWidth > 0 && el.offsetHeight > 0;
+};
+
const dom = {
toNodeArray: toNodeArray,
querySelectorAllAndMe: querySelectorAllAndMe,
@@ -82,6 +88,7 @@ const dom = {
show: show,
find_parents: find_parents,
find_scoped: find_scoped,
+ is_visible: is_visible,
};
export default dom;
diff --git a/src/core/dom.test.js b/src/core/dom.test.js
index 9b4d520b9..baf851fa4 100644
--- a/src/core/dom.test.js
+++ b/src/core/dom.test.js
@@ -223,4 +223,30 @@ describe("core.dom tests", () => {
done();
});
});
+
+ describe("is_visible", () => {
+ it.skip("checks, if an element is visible or not.", (done) => {
+ const div1 = document.createElement("div");
+ div1.setAttribute("id", "div1");
+
+ const div2 = document.createElement("div");
+ div2.setAttribute("id", "div2");
+
+ const div3 = document.createElement("div");
+ div3.setAttribute("id", "div3");
+
+ div2.style.display = "none";
+ div3.style.visibility = "hidden";
+
+ document.body.appendChild(div1);
+ document.body.appendChild(div2);
+ document.body.appendChild(div3);
+
+ expect(dom.is_visible(document.querySelector("#div1"))).toBeTruthy(); // prettier-ignore
+ expect(dom.is_visible(document.querySelector("#div2"))).toBeFalsy();
+ expect(dom.is_visible(document.querySelector("#div3"))).toBeFalsy();
+
+ done();
+ });
+ });
});
From a68753613c6f2aaa57483ddf80614e6e9e9c558c Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Wed, 25 Nov 2020 15:42:54 +0100
Subject: [PATCH 04/12] pat checkbox changes need label polyfill.
---
src/polyfills.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/polyfills.js b/src/polyfills.js
index 0f71b259a..bcfbca57f 100644
--- a/src/polyfills.js
+++ b/src/polyfills.js
@@ -18,3 +18,5 @@ import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observe
if ("ResizeObserver" in window === false) {
window.ResizeObserver = ResizeObserverPolyfill;
}
+
+// input.labels polyfill
From f80af5728061cf05dad0248efeb0bd84a0200c61 Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Wed, 25 Nov 2020 15:42:42 +0100
Subject: [PATCH 05/12] pat checklist: Refactor code.
---
src/pat/checklist/checklist.js | 302 +++++++++++----------------------
1 file changed, 100 insertions(+), 202 deletions(-)
diff --git a/src/pat/checklist/checklist.js b/src/pat/checklist/checklist.js
index 348396711..0f02e890f 100644
--- a/src/pat/checklist/checklist.js
+++ b/src/pat/checklist/checklist.js
@@ -1,246 +1,144 @@
-/**
- * Patterns checklist - Easily (un)check all checkboxes
- *
- * Copyright 2012-2013 Simplon B.V. - Wichert Akkerman
- * Copyright 2012-2013 Florian Friesdorf
- */
-import $ from "jquery";
+import Base from "../../core/base";
import Parser from "../../core/parser";
-import registry from "../../core/registry";
+import dom from "../../core/dom";
import utils from "../../core/utils";
import "../../core/jquery-ext";
-var parser = new Parser("checklist");
+const parser = new Parser("checklist");
parser.addArgument("select", ".select-all");
parser.addArgument("deselect", ".deselect-all");
-var _ = {
+export default Base.extend({
name: "checklist",
trigger: ".pat-checklist",
jquery_plugin: true,
+ all_selects: [],
+ all_deselects: [],
+ all_checkboxes: [],
+ all_radios: [],
+
+ init() {
+ this.options = parser.parse(this.el, this.options, false);
+ this.$el.on("patterns-injected", this._init.bind(this));
+ this._init();
+ },
+
+ _init() {
+ this.all_checkboxes = this.el.querySelectorAll("input[type=checkbox]");
+ this.all_radios = this.el.querySelectorAll("input[type=radio]");
- init: function ($el, opts) {
- function _init() {
- return $el.each(function () {
- var $trigger = $(this),
- options = parser.parse($trigger, opts, false);
-
- $trigger.data("patternChecklist", options);
- $trigger
- .scopedFind(options.select)
- .on(
- "click.pat-checklist",
- { trigger: $trigger },
- _.onSelectAll
- );
- $trigger
- .scopedFind(options.deselect)
- .on(
- "click.pat-checklist",
- { trigger: $trigger },
- _.onDeselectAll
- );
-
- $trigger.on("change", () => _.onChange($trigger));
- // update select/deselect button status
- _.onChange($trigger);
-
- $trigger
- .find("input[type=checkbox]")
- .each(_._onChangeCheckbox)
- .on("change.pat-checklist", _._onChangeCheckbox);
-
- $trigger
- .find("input[type=radio]")
- .each(_._initRadio)
- .on("change.pat-checklist", _._onChangeRadio);
+ this.all_selects = dom.find_scoped(this.el, this.options.select);
+ for (const btn of this.all_selects) {
+ btn.addEventListener("click", (e) => {
+ e.preventDefault();
+ this.select_all(e);
+ });
+ }
+
+ this.all_deselects = dom.find_scoped(this.el, this.options.deselect);
+ for (const btn of this.all_deselects) {
+ btn.addEventListener("click", (e) => {
+ e.preventDefault();
+ this.deselect_all(e);
});
}
- $el.on("patterns-injected", _init);
- return _init();
- },
- destroy: function ($el) {
- return $el.each(function () {
- var $trigger = $(this),
- options = $trigger.data("patternChecklist");
- $trigger.scopedFind(options.select).off(".pat-checklist");
- $trigger.scopedFind(options.deselect).off(".pat-checklist");
- $trigger.off(".pat-checklist", "input[type=checkbox]");
- $trigger.data("patternChecklist", null);
+ // update select/deselect button status
+ this.el.addEventListener("change", () => {
+ utils.debounce(() => this.change_buttons(), 50)();
+ utils.debounce(() => this.change_checked(), 50)();
});
+ this.change_buttons();
+ this.change_checked();
},
- _findSiblings: function (elem, sel) {
- // Looks for the closest elements that match the `sel` selector
- var checkbox_children, $parent;
- var parents = $(elem).parents();
- for (var i = 0; i < parents.length; i++) {
- $parent = $(parents[i]);
- checkbox_children = $parent.find(sel);
- if (checkbox_children.length != 0) {
- return checkbox_children;
- }
- if ($parent.hasClass("pat-checklist")) {
- // we reached the top node and did not find any match,
- // return an empty match
- return $([]);
+ destroy($el) {
+ // TODO, destroy also on patterns-injected.
+ this.$el.scopedFind(this.options.select).off(".pat-checklist");
+ this.$el.scopedFind(this.options.deselect).off(".pat-checklist");
+ this.$el.off(".pat-checklist", "input[type=checkbox]");
+ },
+
+ find_siblings(el, sel) {
+ // Looks for the closest elements within the `el` tree that match the
+ // `sel` selector
+ let res;
+ let parent = el.parentNode;
+ while (parent) {
+ res = parent.querySelectorAll(sel);
+ if (res.length || parent === this.el) {
+ // return if results were found or we reached the pattern top
+ return res;
}
+ parent = parent.parentNode;
}
- // This should not happen because because we expect `elem` to have
- // a .pat-checklist parent
- return $([]);
},
- onChange: function (trigger) {
- const $trigger = $(trigger);
- const options = $trigger.data("patternChecklist");
- let siblings;
-
- let all_selects = $trigger.find(options.select);
- if (all_selects.length === 0) {
- all_selects = $(options.select);
- }
- let all_deselects = $trigger.find(options.deselect);
- if (all_deselects.length === 0) {
- all_deselects = $(options.deselect);
- }
- for (const select of all_selects) {
- siblings = _._findSiblings(select, "input[type=checkbox]:visible");
- if (siblings && siblings.filter(":not(:checked)").length === 0) {
- select.disabled = true;
- } else {
- select.disabled = false;
- }
+
+ change_buttons() {
+ console.log("change buttons");
+ let chkbxs;
+ for (const btn of this.all_selects) {
+ chkbxs = this.find_siblings(btn, "input[type=checkbox]");
+ btn.disabled = [...chkbxs]
+ .map((el) => el.matches(":checked"))
+ .every((it) => it === true);
}
- for (const deselect of all_deselects) {
- siblings = _._findSiblings(
- deselect,
- "input[type=checkbox]:visible"
- );
- if (siblings && siblings.filter(":checked").length === 0) {
- deselect.disabled = true;
- } else {
- deselect.disabled = false;
- }
+ for (const btn of this.all_deselects) {
+ chkbxs = this.find_siblings(btn, "input[type=checkbox]");
+ btn.disabled = [...chkbxs]
+ .map((el) => el.matches(":checked"))
+ .every((it) => it === false);
}
},
- onSelectAll: function (event) {
- event.preventDefault();
-
- /* look up checkboxes which are related to my button by going up one parent
- at a time until I find some for the first time */
- const checkbox_siblings = _._findSiblings(
- event.currentTarget,
+ select_all(e) {
+ const chbxs = this.find_siblings(
+ e.target,
"input[type=checkbox]:not(:checked)"
);
- for (const box of checkbox_siblings) {
+ for (const box of chbxs) {
box.checked = true;
- $(box).trigger("change");
- box.dispatchEvent(new Event("change"));
+ box.dispatchEvent(new Event("change", { bubbles: true }));
}
},
- onDeselectAll: function (event) {
- event.preventDefault();
-
- /* look up checkboxes which are related to my button by going up one parent
- at a time until I find some for the first time */
- const checkbox_siblings = _._findSiblings(
- event.currentTarget,
+ deselect_all(e) {
+ const chbxs = this.find_siblings(
+ e.target,
"input[type=checkbox]:checked"
);
- for (const box of checkbox_siblings) {
+ for (const box of chbxs) {
box.checked = false;
- $(box).trigger("change");
- box.dispatchEvent(new Event("change"));
+ box.dispatchEvent(new Event("change", { bubbles: true }));
}
},
- /* The following methods are moved here from pat-checked-flag, which is being deprecated */
- _getLabelAndFieldset: function (el) {
- var result = new Set();
- result.add($(utils.findLabel(el)));
- result.add($(el).closest("fieldset"));
- return result;
- },
-
- _getSiblingsWithLabelsAndFieldsets: function (el) {
- var selector = 'input[name="' + el.name + '"]',
- $related = el.form === null ? $(selector) : $(selector, el.form);
- var result = new Set();
- var label_and_fieldset;
- $related = $related.not(el);
- $related.each(function (idx, item) {
- result.add(item);
- label_and_fieldset = _._getLabelAndFieldset(item);
- label_and_fieldset.forEach(function (item) {
- result.add(item);
- });
- });
- return result;
- },
-
- _onChangeCheckbox: function () {
- var $el = $(this),
- $label = $(utils.findLabel(this)),
- $fieldset = $el.closest("fieldset");
-
- if ($el.closest("ul.radioList").length) {
- $label = $label.add($el.closest("li"));
- }
-
- if (this.checked) {
- $label.add($fieldset).removeClass("unchecked").addClass("checked");
- } else {
- $label.addClass("unchecked").removeClass("checked");
- if ($fieldset.find("input:checked").length) {
- $fieldset.removeClass("unchecked").addClass("checked");
- } else $fieldset.addClass("unchecked").removeClass("checked");
- }
- },
-
- _initRadio: function () {
- _._updateRadio(this, false);
- },
-
- _onChangeRadio: function () {
- _._updateRadio(this, true);
- },
-
- _updateRadio: function (input, update_siblings) {
- var $el = $(input),
- $label = $(utils.findLabel(input)),
- $fieldset = $el.closest("fieldset"),
- siblings = _._getSiblingsWithLabelsAndFieldsets(input);
- if ($el.closest("ul.radioList").length) {
- $label = $label.add($el.closest("li"));
- var newset = new Set();
- siblings.forEach(function (sibling) {
- newset.add($(sibling).closest("li"));
- });
- siblings = newset;
+ change_checked() {
+ console.log("change checked");
+ for (const it of [...this.all_checkboxes].concat([
+ ...this.all_radios,
+ ])) {
+ for (const label of it.labels) {
+ label.classList.remove("unchecked");
+ label.classList.remove("checked");
+ label.classList.add(it.checked ? "checked" : "unchecked");
+ }
}
- if (update_siblings) {
- siblings.forEach(function (sibling) {
- $(sibling).removeClass("checked").addClass("unchecked");
- });
- }
- if (input.checked) {
- $label.add($fieldset).removeClass("unchecked").addClass("checked");
- } else {
- $label.addClass("unchecked").removeClass("checked");
- if ($fieldset.find("input:checked").length) {
- $fieldset.removeClass("unchecked").addClass("checked");
+ for (const fieldset of dom.querySelectorAllAndMe(this.el, "fieldset")) {
+ if (
+ fieldset.querySelectorAll(
+ "input[type=checkbox]:checked, input[type=radio]:checked"
+ ).length
+ ) {
+ fieldset.classList.remove("unchecked");
+ fieldset.classList.add("checked");
} else {
- $fieldset.addClass("unchecked").removeClass("checked");
+ fieldset.classList.remove("checked");
+ fieldset.classList.add("unchecked");
}
}
},
-};
-registry.register(_);
-
-export default _;
+});
From 7014542e7d34e4fd596c79365b0ac2bc71c0ca1a Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Thu, 26 Nov 2020 11:27:50 +0100
Subject: [PATCH 06/12] pat-checklist: Use nested checkboxes example with
nested fieldsets
---
src/pat/checklist/index.html | 237 ++++++-----------------------------
1 file changed, 37 insertions(+), 200 deletions(-)
diff --git a/src/pat/checklist/index.html b/src/pat/checklist/index.html
index 21c6ffd3b..37ff62943 100644
--- a/src/pat/checklist/index.html
+++ b/src/pat/checklist/index.html
@@ -9,6 +9,11 @@
type="text/javascript"
charset="utf-8"
>
+
-
-
From 93084d15dcdeb196f8060c887b9e6d6af26535b9 Mon Sep 17 00:00:00 2001
From: Johannes Raggam
Date: Thu, 26 Nov 2020 11:48:08 +0100
Subject: [PATCH 07/12] pat-checklist: For global de/select buttons, do not
change any other checkboxes than the ones the de/select button belongs to.
---
CHANGES.md | 1 +
src/pat/checklist/checklist.js | 26 ++++++++++++++++----------
src/pat/checklist/index.html | 24 +++++++++++++-----------
3 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index d88843c6f..f73ada77b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -93,6 +93,7 @@
- pat autofocus: Implement documented behavior to not focus on prefilled element, if there is another autofocus element which is empty.
- pat autofocus: Instead of calling autofocus for each element call it only once.
- pat autofocus: Register event handler only once.
+- pat-checklist: For global de/select buttons, do not change any other checkboxes than the ones the de/select button belongs to.
## 3.0.0-dev - unreleased
diff --git a/src/pat/checklist/checklist.js b/src/pat/checklist/checklist.js
index 0f02e890f..75bd3a990 100644
--- a/src/pat/checklist/checklist.js
+++ b/src/pat/checklist/checklist.js
@@ -74,17 +74,26 @@ export default Base.extend({
}
},
+ find_checkboxes(ref_el, sel) {
+ let chkbxs = [];
+ if (this.options.select.indexOf("#") === 0) {
+ chkbxs = this.el.querySelectorAll(sel);
+ } else {
+ chkbxs = this.find_siblings(ref_el, sel);
+ }
+ return chkbxs;
+ },
+
change_buttons() {
- console.log("change buttons");
let chkbxs;
for (const btn of this.all_selects) {
- chkbxs = this.find_siblings(btn, "input[type=checkbox]");
+ chkbxs = this.find_checkboxes(btn, "input[type=checkbox]");
btn.disabled = [...chkbxs]
.map((el) => el.matches(":checked"))
.every((it) => it === true);
}
for (const btn of this.all_deselects) {
- chkbxs = this.find_siblings(btn, "input[type=checkbox]");
+ chkbxs = this.find_checkboxes(btn, "input[type=checkbox]");
btn.disabled = [...chkbxs]
.map((el) => el.matches(":checked"))
.every((it) => it === false);
@@ -92,31 +101,28 @@ export default Base.extend({
},
select_all(e) {
- const chbxs = this.find_siblings(
+ const chkbxs = this.find_checkboxes(
e.target,
"input[type=checkbox]:not(:checked)"
);
-
- for (const box of chbxs) {
+ for (const box of chkbxs) {
box.checked = true;
box.dispatchEvent(new Event("change", { bubbles: true }));
}
},
deselect_all(e) {
- const chbxs = this.find_siblings(
+ const chkbxs = this.find_checkboxes(
e.target,
"input[type=checkbox]:checked"
);
-
- for (const box of chbxs) {
+ for (const box of chkbxs) {
box.checked = false;
box.dispatchEvent(new Event("change", { bubbles: true }));
}
},
change_checked() {
- console.log("change checked");
for (const it of [...this.all_checkboxes].concat([
...this.all_radios,
])) {
diff --git a/src/pat/checklist/index.html b/src/pat/checklist/index.html
index 37ff62943..9f17a4ca9 100644
--- a/src/pat/checklist/index.html
+++ b/src/pat/checklist/index.html
@@ -16,9 +16,19 @@
+