From 978ca6adf500162940c57d6ec2ce450fa22f0313 Mon Sep 17 00:00:00 2001 From: n4j1Br4ch1D Date: Sun, 18 Aug 2024 15:16:58 +0100 Subject: [PATCH 1/3] classe-event add tests --- src/class-tools/test/ext/class-tools.js | 85 +++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/class-tools/test/ext/class-tools.js b/src/class-tools/test/ext/class-tools.js index 157a0c6..a3cc24e 100644 --- a/src/class-tools/test/ext/class-tools.js +++ b/src/class-tools/test/ext/class-tools.js @@ -74,4 +74,89 @@ describe('class-tools extension', function() { done() }, 100) }) + + it('does not add classes if event is not triggered', function(done) { + var div = make('
Test
') + should.equal(div.classList.contains('foo'), false) + setTimeout(function() { + should.equal(div.classList.contains('foo'), false) + done() + }, 100) + }) + + it('toggles classes properly on custom event trigger, class set', function(done) { + var div = make(` +
+
Test
+ +
+ `) + var toggleDiv = div.querySelector('[classes]') + should.equal(toggleDiv.classList.contains('foo'), false) + var button = div.querySelector('button') + button.click() + setTimeout(function() { + should.equal(toggleDiv.classList.contains('foo'), true) + done() + }, 100) + }) + + it('toggles classes properly on custom event trigger, class unset', function(done) { + var div = make(` +
+
Test
+ +
+ `) + var toggleDiv = div.querySelector('[classes]') + should.equal(toggleDiv.classList.contains('foo'), true) + var button = div.querySelector('button') + button.click() + setTimeout(function() { + should.equal(toggleDiv.classList.contains('foo'), false) + done() + }, 100) + }) + + it('toggles classes properly on multiple elements with custom event', function(done) { + var container = make(` +
+
Test 1
+
Test 2
+ +
+ `) + var div1 = container.querySelector('#div1') + var div2 = container.querySelector('#div2') + should.equal(div1.classList.contains('foo'), false) + should.equal(div2.classList.contains('bar'), false) + var button = container.querySelector('button') + button.click() + setTimeout(function() { + should.equal(div1.classList.contains('foo'), true) + should.equal(div2.classList.contains('bar'), true) + done() + }, 100) + }) + + it('toggles multiple classes properly on custom event trigger', function(done) { + var div = make(` +
+
Test
+ +
+ `) + var toggleDiv = div.querySelector('[classes]') + should.equal(toggleDiv.classList.contains('foo'), false) + should.equal(toggleDiv.classList.contains('bar'), false) + var button = div.querySelector('button') + button.click() + setTimeout(function() { + should.equal(toggleDiv.classList.contains('foo'), true) + should.equal(toggleDiv.classList.contains('bar'), true) + done() + }, 100) + }) + + // add }) From cb73d2cb545e0bd4255f5dfe94ff527f681402bd Mon Sep 17 00:00:00 2001 From: n4j1Br4ch1D Date: Sun, 18 Aug 2024 15:17:29 +0100 Subject: [PATCH 2/3] classe-event add feature --- src/class-tools/class-tools.js | 48 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/class-tools/class-tools.js b/src/class-tools/class-tools.js index f9520da..80f2c0a 100644 --- a/src/class-tools/class-tools.js +++ b/src/class-tools/class-tools.js @@ -13,7 +13,7 @@ if (classDef.indexOf(':') > 0) { var splitCssClass = classDef.split(':') cssClass = splitCssClass[0] - delay = htmx.parseInterval(splitCssClass[1]) + delay = splitCssClass[1] === '!' ? null : htmx.parseInterval(splitCssClass[1]) } else { cssClass = classDef delay = 100 @@ -28,16 +28,20 @@ } } - function performOperation(elt, classOperation, classList, currentRunTime) { + function call(elt, classOperation) { + elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass) + } + + function performOperation(elt, classOperation, currentRunTime) { setTimeout(function() { - elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass) + call(elt, classOperation) }, currentRunTime) } - function toggleOperation(elt, classOperation, classList, currentRunTime) { + function toggleOperation(elt, classOperation, currentRunTime) { setTimeout(function() { setInterval(function() { - elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass) + call(elt, classOperation) }, classOperation.delay) }, currentRunTime) } @@ -54,11 +58,15 @@ var classOperation = parseClassOperation(trimmedValue) if (classOperation) { if (classOperation.operation === 'toggle') { - toggleOperation(elt, classOperation, classList, currentRunTime) - currentRunTime = currentRunTime + classOperation.delay + if (classOperation.delay) { + toggleOperation(elt, classOperation, currentRunTime) + currentRunTime += classOperation.delay + } else { + call(elt, classOperation) + } } else { - currentRunTime = currentRunTime + classOperation.delay - performOperation(elt, classOperation, classList, currentRunTime) + currentRunTime += classOperation.delay + performOperation(elt, classOperation, currentRunTime) } } } @@ -68,7 +76,15 @@ function maybeProcessClasses(elt) { if (elt.getAttribute) { var classList = elt.getAttribute('classes') || elt.getAttribute('data-classes') - if (classList) { + var eventTrigger = elt.getAttribute('classes-event-trigger') || elt.getAttribute('data-classes-event-trigger') + if (eventTrigger) { + var handleEvent = function() { + processClassList(elt, classList) + elt.removeEventListener(eventTrigger, handleEvent) + } + elt.addEventListener(eventTrigger, handleEvent, { once: true }) + document.addEventListener(eventTrigger, handleEvent) + } else if (classList) { processClassList(elt, classList) } } @@ -79,14 +95,14 @@ if (name === 'htmx:afterProcessNode') { var elt = evt.detail.elt maybeProcessClasses(elt) - var classList = elt.getAttribute("apply-parent-classes") || elt.getAttribute("data-apply-parent-classes"); + var classList = elt.getAttribute('apply-parent-classes') || elt.getAttribute('data-apply-parent-classes') if (classList) { - var parent = elt.parentElement; - parent.removeChild(elt); - parent.setAttribute("classes", classList); - maybeProcessClasses(parent); + var parent = elt.parentElement + parent.removeChild(elt) + parent.setAttribute('classes', classList) + maybeProcessClasses(parent) } else if (elt.querySelectorAll) { - var children = elt.querySelectorAll('[classes], [data-classes]') + var children = elt.querySelectorAll('[classes], [data-classes], [classes-event-trigger], [data-classes-event-trigger]') for (var i = 0; i < children.length; i++) { maybeProcessClasses(children[i]) } From 28ab422199d60114410b6fe67431e70ea5cceb4f Mon Sep 17 00:00:00 2001 From: n4j1Br4ch1D Date: Sun, 18 Aug 2024 15:17:44 +0100 Subject: [PATCH 3/3] classe-event add readme --- src/class-tools/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/class-tools/README.md b/src/class-tools/README.md index 64a82bc..e996af7 100644 --- a/src/class-tools/README.md +++ b/src/class-tools/README.md @@ -15,6 +15,10 @@ Within a run, a `,` character separates distinct class operations. A class operation is an operation name `add`, `remove`, or `toggle`, followed by a CSS class name, optionally followed by a colon `:` and a time delay. +## On event trigger class manipulation +This feature allows for dynamic class manipulation in response to specific events using the `classes-event-trigger` or `data-classes-event-trigger` attribute. + + ## Out-of-band class manipulation There is also the option to use `apply-parent-classes`, or `data-apply-parent-classes`, which take the same format as `classes` @@ -44,6 +48,14 @@ so it should ideally be used as part of an `hx-swap-oob="beforeend: #some-elemen
+ +
+
Class foo wil be added after 1s
+
Class foo wil be toggled
+
Class foo & bar wil be toggled
+ +
+