Skip to content

Commit

Permalink
Merge pull request #1232 from Patternslib/fix-pat-depends
Browse files Browse the repository at this point in the history
Fix pat depends
  • Loading branch information
thet authored Jan 31, 2025
2 parents 8efe802 + af5ecc5 commit 8c40b70
Show file tree
Hide file tree
Showing 5 changed files with 416 additions and 9 deletions.
19 changes: 19 additions & 0 deletions src/core/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,24 @@ const is_input = (el) => {
return re_input.test(el.nodeName);
};

/**
* Test, if a element is a button-like input type.
*
* @param {Node} el - The DOM node to test.
* @returns {Boolean} - True if the element is a input-type element.
*/
const is_button = (el) => {
return el.matches(`
button,
input[type=image],
input[type=button],
input[type=reset],
input[type=submit]
`);
};



/**
* Return all direct parents of ``el`` matching ``selector``.
* This matches against all parents but not the element itself.
Expand Down Expand Up @@ -613,6 +631,7 @@ const dom = {
acquire_attribute: acquire_attribute,
is_visible: is_visible,
is_input: is_input,
is_button: is_button,
create_from_string: create_from_string,
get_css_value: get_css_value,
find_scroll_container: find_scroll_container,
Expand Down
41 changes: 41 additions & 0 deletions src/core/dom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,47 @@ describe("core.dom tests", () => {
});
});

describe("is_button", () => {
it("checks, if an element is a button-like element or not.", (done) => {

const button = document.createElement("button");
const button_button = document.createElement("button");
button_button.setAttribute("type", "button");
const button_submit = document.createElement("button");
button_submit.setAttribute("type", "submit");

const input_button = document.createElement("input");
input_button.setAttribute("type", "button");
const input_submit = document.createElement("input");
input_submit.setAttribute("type", "submit");
const input_reset = document.createElement("input");
input_reset.setAttribute("type", "reset");
const input_image = document.createElement("input");
input_image.setAttribute("type", "image");

expect(dom.is_button(button)).toBe(true);
expect(dom.is_button(button_button)).toBe(true);
expect(dom.is_button(button_submit)).toBe(true);
expect(dom.is_button(input_button)).toBe(true);
expect(dom.is_button(input_image)).toBe(true);
expect(dom.is_button(input_reset)).toBe(true);
expect(dom.is_button(input_submit)).toBe(true);

const input_text = document.createElement("input");
input_text.setAttribute("type", "text");

expect(dom.is_button(input_text)).toBe(false);
expect(dom.is_button(document.createElement("input"))).toBe(false);
expect(dom.is_button(document.createElement("select"))).toBe(false);
expect(dom.is_button(document.createElement("textarea"))).toBe(false);
expect(dom.is_button(document.createElement("form"))).toBe(false);
expect(dom.is_button(document.createElement("div"))).toBe(false);

done();
});
});


describe("create_from_string", () => {
it("Creates a DOM element from a string", (done) => {
const res = dom.create_from_string(`
Expand Down
79 changes: 75 additions & 4 deletions src/pat/depends/depends.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ parser.addArgument("transition", "none", ["none", "css", "fade", "slide"]);
parser.addArgument("effect-duration", "fast");
parser.addArgument("effect-easing", "swing");


// A custom input event which differs from the one in `core/events` in that it
// accepts a `detail` object to pass arbitrary information around.
// TODO: The events in `core/events` should be refactored to accept a `detail`
// object.
const input_event = (detail = {}) => {
return new CustomEvent("input", {
bubbles: true,
cancelable: false,
detail: detail,
});
};


class Pattern extends BasePattern {
static name = "depends";
static trigger = ".pat-depends";
Expand Down Expand Up @@ -44,7 +58,14 @@ class Pattern extends BasePattern {
input,
"input",
`pat-depends--input--${this.uuid}`,
this.set_state.bind(this)
(e) => {
if (e?.detail?.pattern_uuid === this.uuid) {
// Ignore input events invoked from this pattern
// instance to avoid infinite loops.
return;
}
this.set_state();
}
);

if (input.form) {
Expand Down Expand Up @@ -74,15 +95,40 @@ class Pattern extends BasePattern {
enable() {
const inputs = dom.find_inputs(this.el);
for (const input of inputs) {
if (input.disabled === false) {
// Do not re-enable an already enabled input.
continue;
}

// Now, enable the input element.
input.disabled = false;
// Trigger the input after disabling so that any other bound

if (input === this.el) {
// Do not re-trigger this pattern on it's own element to avoid
// infinite loops.
continue;
}

if (dom.is_button(input)) {
// Do not trigger the input event on buttons as they do not
// support it.
continue;
}

// Trigger the input after enabling so that any other bound
// actions can react on that.
input.dispatchEvent(events.input_event());
input.dispatchEvent(input_event({ pattern_uuid: this.uuid }));
}

// Restore the original click behavior for anchor elements.
if (this.el.tagName === "A") {
events.remove_event_listener(this.el, "pat-depends--click");
}

// Remove the disabled class from the element.
this.el.classList.remove("disabled");

// Trigger the pat-update event to notify other patterns about enabling.
this.$el.trigger("pat-update", {
pattern: "depends",
action: "attribute-changed",
Expand All @@ -94,17 +140,42 @@ class Pattern extends BasePattern {
disable() {
const inputs = dom.find_inputs(this.el);
for (const input of inputs) {
if (input.disabled === true) {
// Do not re-disable an already disabled input.
continue;
}

// Now, disable the input element.
input.disabled = true;

if (input === this.el) {
// Do not re-trigger this pattern on it's own element to avoid
// infinite loops.
continue;
}

if (dom.is_button(input)) {
// Do not trigger the input event on buttons as they do not
// support it.
continue;
}

// Trigger the input after disabling so that any other bound
// actions can react on that.
input.dispatchEvent(events.input_event());
input.dispatchEvent(input_event({ pattern_uuid: this.uuid }));
}

// Prevent the default click behavior for anchor elements.
if (this.el.tagName === "A") {
events.add_event_listener(this.el, "click", "pat-depends--click", (e) =>
e.preventDefault()
);
}

// Add the disabled class to the element.
this.el.classList.add("disabled");

// Trigger the pat-update event to notify other patterns about disabling.
this.$el.trigger("pat-update", {
pattern: "depends",
action: "attribute-changed",
Expand Down
Loading

0 comments on commit 8c40b70

Please sign in to comment.