Skip to content

Commit 297263e

Browse files
author
carson
committed
Clean up tests, change license to BSD, implement initial hx-trigger support
1 parent 0ed30a8 commit 297263e

File tree

5 files changed

+176
-47
lines changed

5 files changed

+176
-47
lines changed

LICENSE

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
1-
MIT License
1+
BSD 2-Clause License
22

3-
Copyright (c) 2020 exht
3+
Copyright (c) 2020, Big Sky Software
4+
All rights reserved.
45

5-
Permission is hereby granted, free of charge, to any person obtaining a copy
6-
of this software and associated documentation files (the "Software"), to deal
7-
in the Software without restriction, including without limitation the rights
8-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
copies of the Software, and to permit persons to whom the Software is
10-
furnished to do so, subject to the following conditions:
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
118

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
1411

15-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

TODO.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
* Dependency-free implementation of intercooler.js-like HTML-driven AJAX functionality
77
* Minimalist functionality, rely heavily on built in functionality
8+
* Support IE11+
89
** CSS transitions only
910
** Pluggable event model
1011
* Smaller than TurboPascal (39.7kb) https://prog21.dadgum.com/116.html

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"HTML"
1616
],
1717
"author": "Carson Gross",
18-
"license": "MIT",
18+
"license": "BSD 2-Clause",
1919
"bugs": {
2020
"url": "https://github.com/bigskysoftware/htmx/issues"
2121
},

src/htmx.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,32 @@ var HTMx = HTMx || (function()
9898
request.send();
9999
}
100100

101+
function matches(el, selector) {
102+
return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector);
103+
}
104+
105+
106+
function getTrigger(elt) {
107+
let explicitTrigger = getClosestAttributeValue(elt, 'hx-trigger');
108+
if (explicitTrigger) {
109+
return explicitTrigger;
110+
} else {
111+
if (matches(elt, 'button')) {
112+
return 'click';
113+
} else if (matches(elt, 'form')) {
114+
return 'submit';
115+
} else if (matches(elt, 'input, textarea, select')) {
116+
return 'change';
117+
} else {
118+
return 'click';
119+
}
120+
}
121+
}
122+
101123
// DOM element processing
102124
function processElement(elt) {
103125
if(elt.getAttribute('hx-get')) {
104-
elt.addEventListener("click", function(evt){
126+
elt.addEventListener(getTrigger(elt), function(evt){
105127
issueAjaxRequest(elt, getAttributeValue(elt, 'hx-get'));
106128
evt.stopPropagation();
107129
});
@@ -125,7 +147,7 @@ var HTMx = HTMx || (function()
125147
processElement(document.body);
126148
})
127149

128-
// public API
150+
// Public API
129151
return {
130152
processElement : processElement,
131153
version : "0.0.1"

test/core.html

Lines changed: 129 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,44 +27,55 @@
2727
function make(htmlStr) {
2828
let range = document.createRange();
2929
let fragment = range.createContextualFragment(htmlStr);
30+
let wa = getWorkArea();
3031
for (let i = fragment.children.length - 1; i >= 0; i--) {
3132
const child = fragment.children[i];
3233
HTMx.processElement(child);
33-
document.body.appendChild(child);
34+
wa.appendChild(child);
3435
}
35-
return document.body.lastChild;
36+
return wa.lastChild;
37+
}
38+
39+
function getWorkArea() {
40+
return byId("work-area");
41+
}
42+
43+
function clearWorkArea() {
44+
getWorkArea().innerHTML = "";
3645
}
3746
</script>
3847

3948
<script>
4049
describe("Core HTMx Tests", function(){
4150
beforeEach(function() {
4251
this.server = sinon.fakeServer.create();
52+
clearWorkArea();
4353
});
4454
afterEach(function() {
4555
this.server.restore();
56+
clearWorkArea();
4657
});
4758

4859
// bootstrap test
4960
it('issues a GET request on click and swaps content', function()
5061
{
51-
this.server.respondWith("GET", "/core_test1", "Clicked!");
62+
this.server.respondWith("GET", "/test", "Clicked!");
5263

53-
let btn = make('<button hx-get="/core_test1">Click Me!</button>')
64+
let btn = make('<button hx-get="/test">Click Me!</button>')
5465
btn.click();
5566
this.server.respond();
5667
btn.innerHTML.should.equal("Clicked!");
5768
});
5869

5970
it('processes inner content properly', function()
6071
{
61-
this.server.respondWith("GET", "/core_test2", '<a hx-get="/core_test2_2">Click Me</a>');
62-
this.server.respondWith("GET", "/core_test2_2", "Clicked!");
72+
this.server.respondWith("GET", "/test", '<a hx-get="/test2">Click Me</a>');
73+
this.server.respondWith("GET", "/test2", "Clicked!");
6374

64-
let div = make('<div hx-get="/core_test2"></div>')
75+
let div = make('<div hx-get="/test"></div>')
6576
div.click();
6677
this.server.respond();
67-
div.innerHTML.should.equal('<a hx-get="/core_test2_2">Click Me</a>');
78+
div.innerHTML.should.equal('<a hx-get="/test2">Click Me</a>');
6879
let a = div.querySelector('a');
6980
a.click();
7081
this.server.respond();
@@ -73,73 +84,161 @@
7384

7485
it('handles swap outerHTML properly', function()
7586
{
76-
this.server.respondWith("GET", "/core_test3", '<a id="a-outer-html-test" hx-get="/core_test3_2">Click Me</a>');
77-
this.server.respondWith("GET", "/core_test3_2", "Clicked!");
87+
this.server.respondWith("GET", "/test", '<a id="a1" hx-get="/test2">Click Me</a>');
88+
this.server.respondWith("GET", "/test2", "Clicked!");
7889

79-
let div = make('<div id="div-outer-html-test" hx-get="/core_test3" hx-swap="outerHTML"></div>')
90+
let div = make('<div id="d1" hx-get="/test" hx-swap="outerHTML"></div>')
8091
div.click();
81-
should.equal(byId("div-outer-html-test"), div);
92+
should.equal(byId("d1"), div);
8293
this.server.respond();
83-
should.equal(byId("div-outer-html-test"), null);
84-
byId("a-outer-html-test").click();
94+
should.equal(byId("d1"), null);
95+
byId("a1").click();
8596
this.server.respond();
86-
byId("a-outer-html-test").innerHTML.should.equal('Clicked!');
97+
byId("a1").innerHTML.should.equal('Clicked!');
8798
});
8899

89100
it('handles prepend properly', function()
90101
{
91102
let i = 0;
92-
this.server.respondWith("GET", "/core_test4", function(xhr){
103+
this.server.respondWith("GET", "/test", function(xhr){
93104
i++;
94-
xhr.respond(200, {}, '<a id="a-prepend-test-' + i + '" hx-get="/core_test4_2" hx-swap="innerHTML">' + i + '</a>');
105+
xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>');
95106
});
96-
this.server.respondWith("GET", "/core_test4_2", "*");
107+
this.server.respondWith("GET", "/test2", "*");
97108

98-
let div = make('<div hx-get="/core_test4" hx-swap="prepend">*</div>')
109+
let div = make('<div hx-get="/test" hx-swap="prepend">*</div>')
99110
div.click();
100111
this.server.respond();
101112
div.innerText.should.equal("1*");
102113

103-
byId("a-prepend-test-1").click();
114+
byId("a1").click();
104115
this.server.respond();
105116
div.innerText.should.equal("**");
106117

107118
div.click();
108119
this.server.respond();
109120
div.innerText.should.equal("2**");
110121

111-
byId("a-prepend-test-2").click();
122+
byId("a2").click();
112123
this.server.respond();
113124
div.innerText.should.equal("***");
114125
});
115126

127+
it('handles prepend properly with no initial content', function()
128+
{
129+
let i = 0;
130+
this.server.respondWith("GET", "/test", function(xhr){
131+
i++;
132+
xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>');
133+
});
134+
this.server.respondWith("GET", "/test2", "*");
135+
136+
let div = make('<div hx-get="/test" hx-swap="prepend"></div>')
137+
div.click();
138+
this.server.respond();
139+
div.innerText.should.equal("1");
140+
141+
byId("a1").click();
142+
this.server.respond();
143+
div.innerText.should.equal("*");
144+
145+
div.click();
146+
this.server.respond();
147+
div.innerText.should.equal("2*");
148+
149+
byId("a2").click();
150+
this.server.respond();
151+
div.innerText.should.equal("**");
152+
});
153+
116154
it('handles append properly', function()
117155
{
118156
let i = 0;
119-
this.server.respondWith("GET", "/core_test5", function(xhr){
157+
this.server.respondWith("GET", "/test", function(xhr){
120158
i++;
121-
xhr.respond(200, {}, '<a id="a-append-test-' + i + '" hx-get="/core_test5_2" hx-swap="innerHTML">' + i + '</a>');
159+
xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>');
122160
});
123-
this.server.respondWith("GET", "/core_test5_2", "*");
161+
this.server.respondWith("GET", "/test2", "*");
124162

125-
let div = make('<div hx-get="/core_test5" hx-swap="append">*</div>')
163+
let div = make('<div hx-get="/test" hx-swap="append">*</div>')
126164
div.click();
127165
this.server.respond();
128166
div.innerText.should.equal("*1");
129167

130-
byId("a-append-test-1").click();
168+
byId("a1").click();
131169
this.server.respond();
132170
div.innerText.should.equal("**");
133171

134172
div.click();
135173
this.server.respond();
136174
div.innerText.should.equal("**2");
137175

138-
byId("a-append-test-2").click();
176+
byId("a2").click();
139177
this.server.respond();
140178
div.innerText.should.equal("***");
141179
});
142180

181+
it('handles append properly with no initial content', function()
182+
{
183+
let i = 0;
184+
this.server.respondWith("GET", "/test", function(xhr){
185+
i++;
186+
xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>');
187+
});
188+
this.server.respondWith("GET", "/test2", "*");
189+
190+
let div = make('<div hx-get="/test" hx-swap="append"></div>')
191+
div.click();
192+
this.server.respond();
193+
div.innerText.should.equal("1");
194+
195+
byId("a1").click();
196+
this.server.respond();
197+
div.innerText.should.equal("*");
198+
199+
div.click();
200+
this.server.respond();
201+
div.innerText.should.equal("*2");
202+
203+
byId("a2").click();
204+
this.server.respond();
205+
div.innerText.should.equal("**");
206+
});
207+
208+
it('handles hx-target properly', function()
209+
{
210+
this.server.respondWith("GET", "/test", "Clicked!");
211+
212+
let btn = make('<button hx-get="/test" hx-target="#s1">Click Me!</button>');
213+
let target = make('<span id="s1">Initial</span>');
214+
btn.click();
215+
target.innerHTML.should.equal("Initial");
216+
this.server.respond();
217+
target.innerHTML.should.equal("Clicked!");
218+
});
219+
220+
it('handles 204 NO CONTENT responses properly', function()
221+
{
222+
this.server.respondWith("GET", "/test", [204, {}, "No Content!"]);
223+
224+
let btn = make('<button hx-get="/test">Click Me!</button>');
225+
btn.click();
226+
btn.innerHTML.should.equal("Click Me!");
227+
this.server.respond();
228+
btn.innerHTML.should.equal("Click Me!");
229+
});
230+
231+
it('handles hx-trigger with non-default value', function()
232+
{
233+
this.server.respondWith("GET", "/test", "Focused!");
234+
235+
let btn = make('<button hx-get="/test" hx-trigger="focus">Focus Me!</button>');
236+
btn.focus();
237+
btn.innerHTML.should.equal("Focus Me!");
238+
this.server.respond();
239+
btn.innerHTML.should.equal("Focused!");
240+
});
241+
143242
})
144243
</script>
145244

@@ -148,5 +247,8 @@
148247
</script>
149248
<em>Work Area</em>
150249
<hr/>
250+
<div id="work-area">
251+
252+
</div>
151253
</body>
152254
</html>

0 commit comments

Comments
 (0)