final countdown for publishing 0.0.4

This commit is contained in:
carson 2020-05-26 12:14:03 -07:00
parent 7b7f00baa0
commit f8dfe727b3
15 changed files with 319 additions and 45 deletions

View File

@ -13,7 +13,7 @@ htmx is a set of HTML extensions give you to access to [AJAX](https://htmx.org/d
via [attributes](https://htmx.org/reference#attributes), allowing you to build [modern UI](https://htmx.org/examples) with the [simplicity](https://en.wikipedia.org/wiki/HATEOAS) and
[power](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) of hypertext
htmx is small ([~6k min.gz'd](https://unpkg.com/htmx.org/dist/)),
htmx is small ([~7k min.gz'd](https://unpkg.com/htmx.org/dist/)),
[dependency-free](https://github.com/bigskysoftware/htmx/blob/master/package.json),
[extendable](https://htmx.org/extensions),
IE11 compatible & you can try it out quickly, without a huge rewrite

24
dist/ext/include-vals.js vendored Normal file
View File

@ -0,0 +1,24 @@
(function(){
function mergeObjects(obj1, obj2) {
for (var key in obj2) {
if (obj2.hasOwnProperty(key)) {
obj1[key] = obj2[key];
}
}
return obj1;
}
htmx.defineExtension('include-vals', {
onEvent: function (name, evt) {
if (name === "configRequest.htmx") {
var includeValsElt = htmx.closest(evt.detail.elt, "[include-vals],[data-include-vals]");
if (includeValsElt) {
var includeVals = includeValsElt.getAttribute("include-vals") || includeValsElt.getAttribute("data-include-vals");
var valuesToInclude = eval("({" + includeVals + "})");
mergeObjects(evt.detail.parameters, valuesToInclude);
}
}
}
});
})();

17
dist/ext/remove-me.js vendored Normal file
View File

@ -0,0 +1,17 @@
(function(){
htmx.defineExtension('remove-me', {
onEvent: function (name, evt) {
if (name === "processedNode.htmx") {
var elt = evt.detail.elt;
if (elt.getAttribute) {
var timing = elt.getAttribute("remove-me") || elt.getAttribute("data-remove-me");
if (timing) {
setTimeout(function () {
elt.parentElement.removeChild(elt);
}, htmx.parseInterval(timing));
}
}
}
}
});
})();

54
dist/htmx.js vendored
View File

@ -332,8 +332,12 @@ return (function () {
var extensions = getExtensions(target);
for (var i = 0; i < extensions.length; i++) {
var extension = extensions[i];
if (extension.isInlineSwap(swapStyle)) {
return true;
try {
if (extension.isInlineSwap(swapStyle)) {
return true;
}
} catch(e) {
logError(e);
}
}
return swapStyle === "outerHTML";
@ -492,8 +496,12 @@ return (function () {
var extensions = getExtensions(elt);
for (var i = 0; i < extensions.length; i++) {
var ext = extensions[i];
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
return;
try {
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
return;
}
} catch (e) {
logError(e);
}
}
swapInnerHTML(target, fragment, settleInfo);
@ -708,7 +716,7 @@ return (function () {
}
var response = event.data;
forEach(getExtensions(elt), function(extension){
withExtensions(elt, function(extension){
response = extension.transformResponse(response, null, elt);
});
@ -904,13 +912,31 @@ return (function () {
}
function triggerErrorEvent(elt, eventName, detail) {
triggerEvent(elt, eventName, mergeObjects({isError:true}, detail));
triggerEvent(elt, eventName, mergeObjects({error:eventName}, detail));
}
function ignoreEventForLogging(eventName) {
return eventName === "processedNode.htmx"
}
function withExtensions(elt, toDo) {
forEach(getExtensions(elt), function(extension){
try {
toDo(extension);
} catch (e) {
logError(e);
}
});
}
function logError(msg) {
if(console.error) {
console.error(msg);
} else if (console.log) {
console.log("ERROR: ", msg);
}
}
function triggerEvent(elt, eventName, detail) {
if (detail == null) {
detail = {};
@ -920,13 +946,14 @@ return (function () {
if (htmx.logger && !ignoreEventForLogging(eventName)) {
htmx.logger(elt, eventName, detail);
}
if (detail.isError) {
if (detail.error) {
logError(detail.error);
sendError(elt, eventName, detail);
}
var eventResult = elt.dispatchEvent(event);
forEach(getExtensions(elt), function (extension) {
withExtensions(elt, function (extension) {
eventResult = eventResult && (extension.onEvent(eventName, event) !== false)
})
});
return eventResult;
}
@ -1239,7 +1266,7 @@ return (function () {
function encodeParamsForBody(xhr, elt, filteredParameters) {
var encodedParameters = null;
forEach(getExtensions(elt), function (extension) {
withExtensions(elt, function (extension) {
if (encodedParameters == null) {
encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt);
}
@ -1361,7 +1388,7 @@ return (function () {
if (!triggerEvent(elt, 'beforeSwap.htmx', eventDetail)) return;
var resp = this.response;
forEach(getExtensions(elt), function(extension){
withExtensions(elt, function(extension){
resp = extension.transformResponse(resp, xhr, elt);
});
@ -1421,11 +1448,10 @@ return (function () {
}
}
} else {
triggerErrorEvent(elt, 'responseError.htmx', eventDetail);
triggerErrorEvent(elt, 'responseError.htmx', mergeObjects({error: "Response Status Error Code " + this.status + " from " + path}, eventDetail));
}
} catch (e) {
eventDetail['exception'] = e;
triggerErrorEvent(elt, 'onLoadError.htmx', eventDetail);
triggerErrorEvent(elt, 'onLoadError.htmx', mergeObjects({error:e}, eventDetail));
throw e;
} finally {
removeRequestIndicatorClasses(elt);

2
dist/htmx.min.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/htmx.min.js.gz vendored

Binary file not shown.

View File

@ -16,7 +16,7 @@ htmx is a set of HTML extensions give you to access to [AJAX](https://htmx.org/d
via [attributes](https://htmx.org/reference#attributes), allowing you to build [modern UI](https://htmx.org/examples) with the [simplicity](https://en.wikipedia.org/wiki/HATEOAS) and
[power](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) of hypertext
htmx is small ([~6k min.gz'd](https://unpkg.com/htmx.org/dist/)),
htmx is small ([~7k min.gz'd](https://unpkg.com/htmx.org/dist/)),
[dependency-free](https://github.com/bigskysoftware/htmx/blob/master/package.json),
[extendable](/extensions),
IE11 compatible & you can try it out quickly, without a huge rewrite

View File

@ -332,8 +332,12 @@ return (function () {
var extensions = getExtensions(target);
for (var i = 0; i < extensions.length; i++) {
var extension = extensions[i];
if (extension.isInlineSwap(swapStyle)) {
return true;
try {
if (extension.isInlineSwap(swapStyle)) {
return true;
}
} catch(e) {
logError(e);
}
}
return swapStyle === "outerHTML";
@ -492,8 +496,12 @@ return (function () {
var extensions = getExtensions(elt);
for (var i = 0; i < extensions.length; i++) {
var ext = extensions[i];
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
return;
try {
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
return;
}
} catch (e) {
logError(e);
}
}
swapInnerHTML(target, fragment, settleInfo);
@ -708,7 +716,7 @@ return (function () {
}
var response = event.data;
forEach(getExtensions(elt), function(extension){
withExtensions(elt, function(extension){
response = extension.transformResponse(response, null, elt);
});
@ -904,13 +912,31 @@ return (function () {
}
function triggerErrorEvent(elt, eventName, detail) {
triggerEvent(elt, eventName, mergeObjects({isError:true}, detail));
triggerEvent(elt, eventName, mergeObjects({error:eventName}, detail));
}
function ignoreEventForLogging(eventName) {
return eventName === "processedNode.htmx"
}
function withExtensions(elt, toDo) {
forEach(getExtensions(elt), function(extension){
try {
toDo(extension);
} catch (e) {
logError(e);
}
});
}
function logError(msg) {
if(console.error) {
console.error(msg);
} else if (console.log) {
console.log("ERROR: ", msg);
}
}
function triggerEvent(elt, eventName, detail) {
if (detail == null) {
detail = {};
@ -920,13 +946,14 @@ return (function () {
if (htmx.logger && !ignoreEventForLogging(eventName)) {
htmx.logger(elt, eventName, detail);
}
if (detail.isError) {
if (detail.error) {
logError(detail.error);
sendError(elt, eventName, detail);
}
var eventResult = elt.dispatchEvent(event);
forEach(getExtensions(elt), function (extension) {
withExtensions(elt, function (extension) {
eventResult = eventResult && (extension.onEvent(eventName, event) !== false)
})
});
return eventResult;
}
@ -1239,7 +1266,7 @@ return (function () {
function encodeParamsForBody(xhr, elt, filteredParameters) {
var encodedParameters = null;
forEach(getExtensions(elt), function (extension) {
withExtensions(elt, function (extension) {
if (encodedParameters == null) {
encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt);
}
@ -1361,7 +1388,7 @@ return (function () {
if (!triggerEvent(elt, 'beforeSwap.htmx', eventDetail)) return;
var resp = this.response;
forEach(getExtensions(elt), function(extension){
withExtensions(elt, function(extension){
resp = extension.transformResponse(resp, xhr, elt);
});
@ -1421,11 +1448,10 @@ return (function () {
}
}
} else {
triggerErrorEvent(elt, 'responseError.htmx', eventDetail);
triggerErrorEvent(elt, 'responseError.htmx', mergeObjects({error: "Response Status Error Code " + this.status + " from " + path}, eventDetail));
}
} catch (e) {
eventDetail['exception'] = e;
triggerErrorEvent(elt, 'onLoadError.htmx', eventDetail);
triggerErrorEvent(elt, 'onLoadError.htmx', mergeObjects({error:e}, eventDetail));
throw e;
} finally {
removeRequestIndicatorClasses(elt);

View File

@ -0,0 +1,24 @@
(function(){
function mergeObjects(obj1, obj2) {
for (var key in obj2) {
if (obj2.hasOwnProperty(key)) {
obj1[key] = obj2[key];
}
}
return obj1;
}
htmx.defineExtension('include-vals', {
onEvent: function (name, evt) {
if (name === "configRequest.htmx") {
var includeValsElt = htmx.closest(evt.detail.elt, "[include-vals],[data-include-vals]");
if (includeValsElt) {
var includeVals = includeValsElt.getAttribute("include-vals") || includeValsElt.getAttribute("data-include-vals");
var valuesToInclude = eval("({" + includeVals + "})");
mergeObjects(evt.detail.parameters, valuesToInclude);
}
}
}
});
})();

View File

@ -0,0 +1,17 @@
(function(){
htmx.defineExtension('remove-me', {
onEvent: function (name, evt) {
if (name === "processedNode.htmx") {
var elt = evt.detail.elt;
if (elt.getAttribute) {
var timing = elt.getAttribute("remove-me") || elt.getAttribute("data-remove-me");
if (timing) {
setTimeout(function () {
elt.parentElement.removeChild(elt);
}, htmx.parseInterval(timing));
}
}
}
}
});
})();

View File

@ -332,8 +332,12 @@ return (function () {
var extensions = getExtensions(target);
for (var i = 0; i < extensions.length; i++) {
var extension = extensions[i];
if (extension.isInlineSwap(swapStyle)) {
return true;
try {
if (extension.isInlineSwap(swapStyle)) {
return true;
}
} catch(e) {
logError(e);
}
}
return swapStyle === "outerHTML";
@ -492,8 +496,12 @@ return (function () {
var extensions = getExtensions(elt);
for (var i = 0; i < extensions.length; i++) {
var ext = extensions[i];
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
return;
try {
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
return;
}
} catch (e) {
logError(e);
}
}
swapInnerHTML(target, fragment, settleInfo);
@ -708,7 +716,7 @@ return (function () {
}
var response = event.data;
forEach(getExtensions(elt), function(extension){
withExtensions(elt, function(extension){
response = extension.transformResponse(response, null, elt);
});
@ -904,13 +912,31 @@ return (function () {
}
function triggerErrorEvent(elt, eventName, detail) {
triggerEvent(elt, eventName, mergeObjects({isError:true}, detail));
triggerEvent(elt, eventName, mergeObjects({error:eventName}, detail));
}
function ignoreEventForLogging(eventName) {
return eventName === "processedNode.htmx"
}
function withExtensions(elt, toDo) {
forEach(getExtensions(elt), function(extension){
try {
toDo(extension);
} catch (e) {
logError(e);
}
});
}
function logError(msg) {
if(console.error) {
console.error(msg);
} else if (console.log) {
console.log("ERROR: ", msg);
}
}
function triggerEvent(elt, eventName, detail) {
if (detail == null) {
detail = {};
@ -920,13 +946,14 @@ return (function () {
if (htmx.logger && !ignoreEventForLogging(eventName)) {
htmx.logger(elt, eventName, detail);
}
if (detail.isError) {
if (detail.error) {
logError(detail.error);
sendError(elt, eventName, detail);
}
var eventResult = elt.dispatchEvent(event);
forEach(getExtensions(elt), function (extension) {
withExtensions(elt, function (extension) {
eventResult = eventResult && (extension.onEvent(eventName, event) !== false)
})
});
return eventResult;
}
@ -1239,7 +1266,7 @@ return (function () {
function encodeParamsForBody(xhr, elt, filteredParameters) {
var encodedParameters = null;
forEach(getExtensions(elt), function (extension) {
withExtensions(elt, function (extension) {
if (encodedParameters == null) {
encodedParameters = extension.encodeParameters(xhr, filteredParameters, elt);
}
@ -1361,7 +1388,7 @@ return (function () {
if (!triggerEvent(elt, 'beforeSwap.htmx', eventDetail)) return;
var resp = this.response;
forEach(getExtensions(elt), function(extension){
withExtensions(elt, function(extension){
resp = extension.transformResponse(resp, xhr, elt);
});
@ -1421,11 +1448,10 @@ return (function () {
}
}
} else {
triggerErrorEvent(elt, 'responseError.htmx', eventDetail);
triggerErrorEvent(elt, 'responseError.htmx', mergeObjects({error: "Response Status Error Code " + this.status + " from " + path}, eventDetail));
}
} catch (e) {
eventDetail['exception'] = e;
triggerErrorEvent(elt, 'onLoadError.htmx', eventDetail);
triggerErrorEvent(elt, 'onLoadError.htmx', mergeObjects({error:e}, eventDetail));
throw e;
} finally {
removeRequestIndicatorClasses(elt);

View File

@ -0,0 +1,27 @@
describe("bad extension", function() {
htmx.defineExtension("bad-extension", {
onEvent : function(name, evt) {throw "onEvent"},
transformResponse : function(text, xhr, elt) {throw "transformRequest"},
isInlineSwap : function(swapStyle) {throw "isInlineSwap"},
handleSwap : function(swapStyle, target, fragment, settleInfo) {throw "handleSwap"},
encodeParameters : function(xhr, parameters, elt) {throw "encodeParmeters"}
}
)
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it('does not blow up rendering', function () {
this.server.respondWith("GET", "/test", "clicked!");
var div = make('<div hx-get="/test" hx-ext="bad-extension">Click Me!</div>')
div.click();
this.server.respond();
div.innerHTML.should.equal("clicked!");
});
});

View File

@ -0,0 +1,23 @@
describe("include-vals extension", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it('Includes values properly', function () {
var params = {};
this.server.respondWith("POST", "/test", function (xhr) {
params = getParameters(xhr);
xhr.respond(200, {}, "clicked");
});
var btn = make('<button hx-post="/test" hx-ext="include-vals" include-vals="foo:\'bar\'">Click Me!</button>')
btn.click();
this.server.respond();
params['foo'].should.equal("bar");
});
});

View File

@ -0,0 +1,55 @@
describe("remove-me extension", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('removes elements properly', function(done)
{
var div = make('<div id="d1" hx-ext="remove-me" remove-me="20ms">Click Me!</div>')
byId("d1").should.equal(div)
setTimeout(function(){
should.equal(byId("d1"), null);
done();
}, 40);
});
it('removes classes properly', function(done)
{
var div = make('<div class="foo bar" hx-ext="class-tools" classes="remove bar">Click Me!</div>')
should.equal(div.classList.contains("foo"), true);
should.equal(div.classList.contains("bar"), true);
setTimeout(function(){
should.equal(div.classList.contains("foo"), true);
should.equal(div.classList.contains("bar"), false);
done();
}, 100);
});
it('adds classes properly w/ data-* prefix', function(done)
{
var div = make('<div hx-ext="class-tools" data-classes="add c1">Click Me!</div>')
should.equal(div.classList.length, 0);
setTimeout(function(){
should.equal(div.classList.contains("c1"), true);
done();
}, 100);
});
it('extension can be on parent', function(done)
{
var div = make('<div hx-ext="class-tools"><div id="d1" classes="add c1">Click Me!</div></div>')
should.equal(div.classList.length, 0);
setTimeout(function(){
should.equal(div.classList.contains("c1"), false);
should.equal(byId("d1").classList.contains("c1"), true);
done();
}, 100);
});
})

View File

@ -107,6 +107,15 @@
<script src="../src/ext/class-tools.js"></script>
<script src="ext/class-tools.js"></script>
<script src="ext/bad-extension.js"></script>
<script src="../src/ext/remove-me.js"></script>
<script src="ext/remove-me.js"></script>
<script src="../src/ext/include-vals.js"></script>
<script src="ext/include-vals.js"></script>
<!-- events last so they don't screw up other tests -->
<script src="core/events.js"></script>