From 99e095e0ea80ed80af770f0a03acfff94e94666b Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Fri, 23 Oct 2020 10:30:33 +0200 Subject: [PATCH 01/10] Introduce new ``core/dom`` module for DOM manipulation and traversing. `core/dom`` includes methods which help transition from jQuery to the JavaScript DOM API. --- CHANGES.md | 2 ++ src/core/dom.js | 5 +++++ src/core/dom.test.js | 5 +++++ 3 files changed, 12 insertions(+) create mode 100644 src/core/dom.js create mode 100644 src/core/dom.test.js diff --git a/CHANGES.md b/CHANGES.md index 2ea559542..b321c2e66 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,8 @@ - pat calendar: Store view, date and active categories per URL, allowing to individually customize the calendar per page. - pat tooltip: Use tippy v6 based implementation. - Allow overriding the public path from outside via the definition of a ``window.__patternslib_public_path__`` global variable. +- Introduce new ``core/dom`` module for DOM manipulation and traversing. + ``core/dom`` includes methods which help transition from jQuery to the JavaScript DOM API. ### Technical diff --git a/src/core/dom.js b/src/core/dom.js new file mode 100644 index 000000000..82381cb42 --- /dev/null +++ b/src/core/dom.js @@ -0,0 +1,5 @@ +/* Utilities for DOM traversal or navigation */ + +const dom = {}; + +export default dom; diff --git a/src/core/dom.test.js b/src/core/dom.test.js new file mode 100644 index 000000000..7cc1588b3 --- /dev/null +++ b/src/core/dom.test.js @@ -0,0 +1,5 @@ +import dom from "./dom"; + +describe("core.dom tests", () => { + // Tests from the core.dom module +}); From 142b1106f7351c10a31dc4e196a45532ada179bc Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 22 Oct 2020 17:32:13 +0200 Subject: [PATCH 02/10] core dom: Add ``jqToNode`` to return a DOM node if a jQuery node was passed. --- CHANGES.md | 1 + src/core/dom.js | 12 +++++++++++- src/core/dom.test.js | 13 +++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index b321c2e66..a49829929 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -36,6 +36,7 @@ - Allow overriding the public path from outside via the definition of a ``window.__patternslib_public_path__`` global variable. - Introduce new ``core/dom`` module for DOM manipulation and traversing. ``core/dom`` includes methods which help transition from jQuery to the JavaScript DOM API. +- core dom: Add ``jqToNode`` to return a DOM node if a jQuery node was passed. ### Technical diff --git a/src/core/dom.js b/src/core/dom.js index 82381cb42..ed1dee25b 100644 --- a/src/core/dom.js +++ b/src/core/dom.js @@ -1,5 +1,15 @@ /* Utilities for DOM traversal or navigation */ -const dom = {}; +const jqToNode = (el) => { + // Return a DOM node if a jQuery node was passed. + if (el.jquery) { + el = el[0]; + } + return el; +}; + +const dom = { + jqToNode: jqToNode, +}; export default dom; diff --git a/src/core/dom.test.js b/src/core/dom.test.js index 7cc1588b3..ab33a7f77 100644 --- a/src/core/dom.test.js +++ b/src/core/dom.test.js @@ -1,5 +1,18 @@ +import $ from "jquery"; import dom from "./dom"; describe("core.dom tests", () => { // Tests from the core.dom module + + describe("jqToNode tests", () => { + it("always returns a bare DOM node no matter if a jQuery or bare DOM node was passed.", (done) => { + const el = document.createElement("div"); + const $el = $(el); + + expect(dom.jqToNode($el)).toBe(el); + expect(dom.jqToNode(el)).toBe(el); + + done(); + }); + }); }); From d7c6f66f6e5aa72bc936c628d5e40f7b12ea60d0 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Fri, 23 Oct 2020 10:40:39 +0200 Subject: [PATCH 03/10] core dom: Add ``querySelectorAllAndMe`` to do a querySelectorAll including the starter element. --- CHANGES.md | 1 + src/core/dom.js | 14 ++++++++++++++ src/core/dom.test.js | 27 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index a49829929..0c526ef73 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,6 +37,7 @@ - Introduce new ``core/dom`` module for DOM manipulation and traversing. ``core/dom`` includes methods which help transition from jQuery to the JavaScript DOM API. - core dom: Add ``jqToNode`` to return a DOM node if a jQuery node was passed. +- core dom: Add ``querySelectorAllAndMe`` to do a querySelectorAll including the starter element. ### Technical diff --git a/src/core/dom.js b/src/core/dom.js index ed1dee25b..40f925d38 100644 --- a/src/core/dom.js +++ b/src/core/dom.js @@ -8,8 +8,22 @@ const jqToNode = (el) => { return el; }; +const querySelectorAllAndMe = (el, selector) => { + // Like querySelectorAll but including the element where it starts from. + // Returns an Array, not a NodeList + + el = jqToNode(el); // Ensure real DOM node. + + const all = [...el.querySelectorAll(selector)]; + if (el.matches(selector)) { + all.unshift(el); // start element should be first. + } + return all; +}; + const dom = { jqToNode: jqToNode, + querySelectorAllAndMe: querySelectorAllAndMe, }; export default dom; diff --git a/src/core/dom.test.js b/src/core/dom.test.js index ab33a7f77..58f285546 100644 --- a/src/core/dom.test.js +++ b/src/core/dom.test.js @@ -15,4 +15,31 @@ describe("core.dom tests", () => { done(); }); }); + + describe("querySelectorAllAndMe tests", () => { + it("return also starting node if query matches.", (done) => { + const el = document.createElement("div"); + el.setAttribute("class", "node1"); + el.innerHTML = `hello.`; + + const res1 = dom.querySelectorAllAndMe(el, ".node1"); + expect(res1.length).toBe(1); + expect(res1[0].outerHTML).toBe( + `
hello.
` + ); + + const res2 = dom.querySelectorAllAndMe(el, ".node2"); + expect(res2.length).toBe(1); + expect(res2[0].outerHTML).toBe(`hello.`); + + const res3 = dom.querySelectorAllAndMe(el, "div, span"); + expect(res3.length).toBe(2); + expect(res3[0].outerHTML).toBe( + `
hello.
` + ); + expect(res3[1].outerHTML).toBe(`hello.`); + + done(); + }); + }); }); From 7ef7435a98742aea20557af680a83b8670280042 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Fri, 23 Oct 2020 10:34:32 +0200 Subject: [PATCH 04/10] core dom: Add ``wrap`` wrap an element with a wrapper element. --- CHANGES.md | 1 + src/core/dom.js | 11 +++++++++++ src/core/dom.test.js | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0c526ef73..177a9b437 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -38,6 +38,7 @@ ``core/dom`` includes methods which help transition from jQuery to the JavaScript DOM API. - core dom: Add ``jqToNode`` to return a DOM node if a jQuery node was passed. - core dom: Add ``querySelectorAllAndMe`` to do a querySelectorAll including the starter element. +- core dom: Add ``wrap`` wrap an element with a wrapper element. ### Technical diff --git a/src/core/dom.js b/src/core/dom.js index 40f925d38..fe33c4a54 100644 --- a/src/core/dom.js +++ b/src/core/dom.js @@ -21,9 +21,20 @@ const querySelectorAllAndMe = (el, selector) => { return all; }; +const wrap = (el, wrapper) => { + // Wrap a element with a wrapper element. + // See: https://stackoverflow.com/a/13169465/1337474 + el = jqToNode(el); // Ensure real DOM node. + wrapper = jqToNode(wrapper); // Ensure real DOM node. + + el.parentNode.insertBefore(wrapper, el); + wrapper.appendChild(el); +}; + const dom = { jqToNode: jqToNode, querySelectorAllAndMe: querySelectorAllAndMe, + wrap: wrap, }; export default dom; diff --git a/src/core/dom.test.js b/src/core/dom.test.js index 58f285546..c803a32c2 100644 --- a/src/core/dom.test.js +++ b/src/core/dom.test.js @@ -42,4 +42,20 @@ describe("core.dom tests", () => { done(); }); }); + + describe("wrap tests", () => { + it("wraps an element within another element.", (done) => { + const parent = document.createElement("main"); + const el = document.createElement("div"); + const wrapper = document.createElement("section"); + parent.appendChild(el); + + dom.wrap(el, wrapper); + expect(parent.outerHTML).toBe( + `
` + ); + + done(); + }); + }); }); From 0b8a180416998a7fbb81b3d3f340b879a9a0dd71 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Tue, 27 Oct 2020 18:13:42 +0100 Subject: [PATCH 05/10] core dom: Add ``hide`` and ``show`` for DOM elements which retain the original display value. --- CHANGES.md | 1 + src/core/dom.js | 26 ++++++++++++++++++++++++ src/core/dom.test.js | 47 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 177a9b437..0a2c07977 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -39,6 +39,7 @@ - core dom: Add ``jqToNode`` to return a DOM node if a jQuery node was passed. - 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. ### Technical diff --git a/src/core/dom.js b/src/core/dom.js index fe33c4a54..8974b3cd6 100644 --- a/src/core/dom.js +++ b/src/core/dom.js @@ -1,5 +1,7 @@ /* Utilities for DOM traversal or navigation */ +const DATA_STYLE_DISPLAY = "__patternslib__style__display"; + const jqToNode = (el) => { // Return a DOM node if a jQuery node was passed. if (el.jquery) { @@ -31,10 +33,34 @@ const wrap = (el, wrapper) => { wrapper.appendChild(el); }; +const hide = (el) => { + // Hides the element with ``display: none`` + el = jqToNode(el); // Ensure real DOM node. + if (el.style.display === "none") { + // Nothing to do. + return; + } + if (el.style.display) { + el[DATA_STYLE_DISPLAY] = el.style.display; + } + el.style.display = "none"; +}; + +const show = (el) => { + // Shows element by removing ``display: none`` and restoring the display + // value to whatever it was before. + el = jqToNode(el); // Ensure real DOM node. + const val = el[DATA_STYLE_DISPLAY] || null; + el.style.display = val; + delete el[DATA_STYLE_DISPLAY]; +}; + const dom = { jqToNode: jqToNode, querySelectorAllAndMe: querySelectorAllAndMe, wrap: wrap, + hide: hide, + show: show, }; export default dom; diff --git a/src/core/dom.test.js b/src/core/dom.test.js index c803a32c2..647801097 100644 --- a/src/core/dom.test.js +++ b/src/core/dom.test.js @@ -58,4 +58,51 @@ describe("core.dom tests", () => { done(); }); }); + + describe("show/hide tests", () => { + it("shows or hides and does keeps the CSS display rule value.", (done) => { + const el = document.createElement("div"); + el.style.borderTop = "2em"; + el.style.marginTop = "4em"; + + dom.hide(el); + + expect(el.style.borderTop).toBe("2em"); + expect(el.style.marginTop).toBe("4em"); + expect(el.style.display).toBe("none"); + expect( + el.getAttribute("style").indexOf("display") >= -1 + ).toBeTruthy(); + + dom.show(el); + + expect(el.style.borderTop).toBe("2em"); + expect(el.style.marginTop).toBe("4em"); + expect(el.style.display).toBeFalsy(); + expect( + el.getAttribute("style").indexOf("display") === -1 + ).toBeTruthy(); + + el.style.display = "inline"; + dom.hide(el); + + expect(el.style.borderTop).toBe("2em"); + expect(el.style.marginTop).toBe("4em"); + expect(el.style.display).toBe("none"); + expect( + el.getAttribute("style").indexOf("display") >= -1 + ).toBeTruthy(); + + dom.show(el); + + expect(el.style.borderTop).toBe("2em"); + expect(el.style.marginTop).toBe("4em"); + expect(el.style.display).toBe("inline"); + expect( + el.getAttribute("style").indexOf("display") >= -1 + ).toBeTruthy(); + + done(); + }); + }); }); From 57d77ae091b7b7e2a337716a18acbd11ed64c916 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 22 Oct 2020 17:32:42 +0200 Subject: [PATCH 06/10] pat-select: Modernize code --- src/pat/selectbox/documentation.md | 5 ++ src/pat/selectbox/index.html | 44 +++++++++++++++++ src/pat/selectbox/selectbox.js | 77 +++++++++++++----------------- 3 files changed, 81 insertions(+), 45 deletions(-) create mode 100644 src/pat/selectbox/documentation.md create mode 100644 src/pat/selectbox/index.html diff --git a/src/pat/selectbox/documentation.md b/src/pat/selectbox/documentation.md new file mode 100644 index 000000000..02a48091d --- /dev/null +++ b/src/pat/selectbox/documentation.md @@ -0,0 +1,5 @@ +## Description + +the __selectbox__ pattern adds ``data-option`` and ``data-option-value`` attributes on the parent element. +If the parent element is not a ``