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
+
+
+
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])
}
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(`
+