mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-10-03 07:45:21 +00:00
Merge branch 'master' into dev
This commit is contained in:
commit
533da1c71c
11
README.md
11
README.md
@ -8,15 +8,16 @@
|
||||
|
||||
## introduction
|
||||
|
||||
htmx is a set of HTML extensions give you to access to [AJAX](https://htmx.org/docs#ajax),
|
||||
htmx allows you to access [AJAX](https://htmx.org/docs#ajax),
|
||||
[WebSockets](https://htmx.org/docs#websockets) and [Server Sent Events](https://htmx.org/docs#sse)
|
||||
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
|
||||
directly in HTML, using [attributes](https://htmx.org/reference#attributes), so you can build
|
||||
[modern user interfaces](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 ([~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
|
||||
[extendable](https://htmx.org/extensions) &
|
||||
IE11 compatible
|
||||
|
||||
## quick start
|
||||
|
||||
@ -43,7 +44,7 @@ htmx is the successor to [intercooler.js](http://intercoolerjs.org)
|
||||
## contributing
|
||||
|
||||
* please write code, including tests, in ES5 for [IE 11 compatibility](https://stackoverflow.com/questions/39902809/support-for-es6-in-internet-explorer-11)
|
||||
* please include test cases in `/test` and docs in `/www`
|
||||
* please include test cases in [`/test`](https://github.com/bigskysoftware/htmx/tree/dev/test) and docs in [`/www`](https://github.com/bigskysoftware/htmx/tree/dev/www)
|
||||
* if you are adding a feature, consider doing it as an [extension](https://htmx.org/extensions) instead to
|
||||
keep the core htmx code tidy
|
||||
* development pull requests should be against the `dev` branch, docs fixes can be made directly against `master`
|
||||
|
@ -1,7 +1,7 @@
|
||||
htmx.defineExtension('json-enc', {
|
||||
encodeParameters : function(xhr, parameters, elt) {
|
||||
xhr.requestHeaders['Content-Type'] = 'application/json';
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.overrideMimeType('text/json');
|
||||
return (JSON.stringify(parameters));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -54,12 +54,12 @@ CSS. Here is an example that uses `display` rather than opacity:
|
||||
}
|
||||
```
|
||||
|
||||
Note that the target of the `ic-indicator` selector need not be the exact element that you
|
||||
Note that the target of the `hx-indicator` selector need not be the exact element that you
|
||||
want to show: it can be any element in the parent hierarchy of the indicator.
|
||||
|
||||
Finally, note that the `htmx-request` class by default is added to the element causing
|
||||
the request, so you can place an indicator inside of that element and not need to explictly
|
||||
call it out with the `ic-indicator` attribute:
|
||||
call it out with the `hx-indicator` attribute:
|
||||
|
||||
```html
|
||||
<button hx-post="/example">
|
||||
@ -81,4 +81,4 @@ This simulates what a spinner might look like in that situation:
|
||||
|
||||
* `hx-indicator` is inherited and can be placed on a parent element
|
||||
* In the absence of an explicit indicator, the `htmx-request` class will be added to the element triggering the
|
||||
request
|
||||
request
|
||||
|
@ -9,7 +9,7 @@ The `hx-target` attribute allows you to target a different element for swapping
|
||||
request. The value of this attribute can be:
|
||||
|
||||
* a CSS query selector of the element to target
|
||||
* `this` which indicates that the element that the `ic-target` attribute is on is the target
|
||||
* `this` which indicates that the element that the `hx-target` attribute is on is the target
|
||||
* `closest <CSS selector>` which will find the closest parent ancestor that matches the given CSS selector.
|
||||
(e.g. `closest tr` will target the closest table row to the element)
|
||||
|
||||
|
@ -75,7 +75,7 @@ within the language:
|
||||
* Now any element, not just the entire window, can be the target for update by the request
|
||||
|
||||
Note that when you are using htmx, on the server side you respond with *HTML*, not *JSON*. This keeps you firmly
|
||||
within the [original web programming model]((https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)),
|
||||
within the [original web programming model](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm),
|
||||
using [Hypertext As The Engine Of Application State](https://en.wikipedia.org/wiki/HATEOAS)
|
||||
without even needing to really understand that concept.
|
||||
|
||||
@ -147,7 +147,7 @@ Here is a `div` that posts to `/mouse_entered` when a mouse enters it:
|
||||
If you want a request to only happen once, you can use the `once` modifier for the trigger:
|
||||
|
||||
```html
|
||||
<div hx-post="/mouse_entered" hx-trigger="mouseenter once"">
|
||||
<div hx-post="/mouse_entered" hx-trigger="mouseenter once">
|
||||
[Here Mouse, Mouse!]
|
||||
</div>
|
||||
```
|
||||
@ -189,7 +189,7 @@ If you want an element to poll the given URL rather than wait for an event, you
|
||||
with the [`hx-trigger`](/attributes/hx-trigger/) attribute:
|
||||
|
||||
```html
|
||||
<div hx-get="/news" trigger="every 2s">
|
||||
<div hx-get="/news" hx-trigger="every 2s">
|
||||
</div>
|
||||
```
|
||||
|
||||
|
@ -226,7 +226,7 @@ than a single value.
|
||||
##### Details
|
||||
|
||||
* `detail.parameters` - the parameters that will be submitted in the request
|
||||
* `detail.unfilteredParameters` - the parameters that were found before filtering by [`ic-select`](/attributes/ic-select)
|
||||
* `detail.unfilteredParameters` - the parameters that were found before filtering by [`hx-select`](/attributes/hx-select)
|
||||
* `detail.headers` - the request headers
|
||||
* `detail.elt` - the element that triggered the request
|
||||
* `detail.target` - the target of the request
|
||||
|
@ -127,12 +127,8 @@ You can see a working examle of this code below.
|
||||
|
||||
// templates
|
||||
function displayUI(contacts) {
|
||||
return `<div hx-include="#checked-contacts" hx-target="#tbody">
|
||||
<a class="btn" hx-put="/activate">Activate</a>
|
||||
<a class="btn" hx-put="/deactivate">Deactivate</a>
|
||||
</div>
|
||||
|
||||
<form id="checked-contacts">
|
||||
return `<h3>Select Rows And Activate Or Deactivate Below<h3>
|
||||
<form id="checked-contacts">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -146,7 +142,12 @@ You can see a working examle of this code below.
|
||||
${displayTable([], contacts, "")}
|
||||
</tbody>
|
||||
</table>
|
||||
</form>`
|
||||
</form>
|
||||
<br/>
|
||||
<div hx-include="#checked-contacts" hx-target="#tbody">
|
||||
<a class="btn" hx-put="/activate">Activate</a>
|
||||
<a class="btn" hx-put="/deactivate">Deactivate</a>
|
||||
</div>`
|
||||
}
|
||||
|
||||
function displayTable(ids, contacts, action) {
|
||||
|
@ -87,7 +87,7 @@ Below is a working demo of this example. The only email that will be accepted i
|
||||
|
||||
// routes
|
||||
init("/demo", function(request, params){
|
||||
return formTemplate();
|
||||
return demoTemplate();
|
||||
});
|
||||
|
||||
onPost("/contact", function(request, params){
|
||||
@ -106,8 +106,13 @@ Below is a working demo of this example. The only email that will be accepted i
|
||||
});
|
||||
|
||||
// templates
|
||||
function formTemplate(page) {
|
||||
return `<h3>Signup Form</h3><form ic-post-to="/contact">
|
||||
function demoTemplate() {
|
||||
|
||||
return `<h3>Signup Form</h3><p>Enter an email into the input below and on tab out it will be validated. Only "test@test.com" will pass.</p> ` + formTemplate();
|
||||
}
|
||||
|
||||
function formTemplate() {
|
||||
return `<form hx-post="/contact">
|
||||
<div hx-target="this" hx-swap="outerHTML">
|
||||
<label>Email Address</label>
|
||||
<input name="email" hx-get="/contact/email" hx-indicator="#ind">
|
||||
@ -121,7 +126,7 @@ Below is a working demo of this example. The only email that will be accepted i
|
||||
<label>Last Name</label>
|
||||
<input type="text" class="form-control" name="lastName">
|
||||
</div>
|
||||
<button class="btn btn-default">Submit</button>
|
||||
<button class="btn btn-default" disabled>Submit</button>
|
||||
</form>`;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,12 @@ To use an extension you use the [hx-ext](/attributes/hx-ext) attribute:
|
||||
Note that the `hx-ext` tag may be placed on parent elements if you want a plugin to apply to an entire swath of the dom,
|
||||
and on the `body` tag for it to apply to all htmx requests.
|
||||
|
||||
**Tip:** To use multiple extensions on one element, separate them with a comma:
|
||||
|
||||
```html
|
||||
<button hx-post="/example" hx-ext="debug, json-enc">This Button Uses Two Extensions</button>
|
||||
```
|
||||
|
||||
## <a name="included"></a> [Included Extensions](#included)
|
||||
|
||||
The following extensions that are tested and distributed with htmx:
|
||||
@ -63,4 +69,4 @@ Extensions can override the following default extension fields:
|
||||
handleSwap : function(swapStyle, target, fragment, settleInfo) {return false;},
|
||||
encodeParameters : function(xhr, parameters, elt) {return null;}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
@ -13,7 +13,7 @@ swapped into the DOM. Currently three client-side templating engines are suppor
|
||||
* [nunjucks](https://mozilla.github.io/nunjucks/)
|
||||
|
||||
When you add this extension on an element, any element below it in the DOM can use one of three attributes named
|
||||
`<template-engine>-temlpate` (e.g. `mustache-template`) with a template ID, and the extension will resolve and render
|
||||
`<template-engine>-template` (e.g. `mustache-template`) with a template ID, and the extension will resolve and render
|
||||
the template the standard way for that template engine:
|
||||
|
||||
* `mustache` - looks a mustache <script> tag up by ID for the template content
|
||||
|
@ -13,7 +13,6 @@ will be evaluated as the fields in a javascript object literal.
|
||||
|
||||
```html
|
||||
<div hx-ext="include-vals">
|
||||
<!-- Removes this div after 1 second -->
|
||||
<div hx-get="/test" include-vals="included:true, computed: computeValue()">
|
||||
Will Include Additional Values
|
||||
</div>
|
||||
@ -22,4 +21,4 @@ will be evaluated as the fields in a javascript object literal.
|
||||
|
||||
### Source
|
||||
|
||||
<https://unpkg.com/htmx.org/dist/ext/remove-me.js>
|
||||
<https://unpkg.com/htmx.org/dist/ext/include-vals.js>
|
||||
|
@ -11,15 +11,16 @@ title: </> htmx - high power tools for html
|
||||
|
||||
## introduction
|
||||
|
||||
htmx is a set of HTML extensions give you to access to [AJAX](https://htmx.org/docs#ajax),
|
||||
htmx allows you to access [AJAX](https://htmx.org/docs#ajax),
|
||||
[WebSockets](https://htmx.org/docs#websockets) and [Server Sent Events](https://htmx.org/docs#sse)
|
||||
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
|
||||
directly in HTML, using [attributes](https://htmx.org/reference#attributes), so you can build
|
||||
[modern user interfaces](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 ([~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
|
||||
[extendable](https://htmx.org/extensions) &
|
||||
IE11 compatible
|
||||
|
||||
## quick start
|
||||
|
||||
|
91
www/locality-of-behaviour.md
Normal file
91
www/locality-of-behaviour.md
Normal file
@ -0,0 +1,91 @@
|
||||
---
|
||||
layout: layout.njk
|
||||
title: </> htmx - high power tools for html
|
||||
---
|
||||
## Locality of Behaviour (LoB)
|
||||
|
||||
> "The primary feature for easy maintenance is locality: Locality is that characteristic of source code that enables a
|
||||
> programmer to understand that source by looking at only a small portion of it." -- [Richard Gabriel](https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf)
|
||||
|
||||
### The LoB Principle:
|
||||
|
||||
> The behaviour of a code unit should be as obvious as possible by looking only at that unit of code
|
||||
|
||||
### Discussion
|
||||
|
||||
The LoB principle is a simple prescriptive formulation of the quoted statement from [Richard Gabriel](https://www.dreamsongs.com).
|
||||
In as much as it is possible, and in balance with other concerns, developers should strive to make the behaviour of
|
||||
a code element obvious on inspection.
|
||||
|
||||
Consider two different implementations of an AJAX request in HTML, the first in [htmx](https://htmx.org):
|
||||
|
||||
```html
|
||||
<div hx-get="/clicked">Click Me</div>
|
||||
```
|
||||
|
||||
and the second in [jQuery](https://jquery.com/):
|
||||
|
||||
```javascript
|
||||
$("#d1").on("click", function(){
|
||||
$.ajax({
|
||||
...
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<div id="d1">Click Me</div>
|
||||
```
|
||||
|
||||
In the former, the behaviour of the `div` element is obvious on inspection, satisfying the LoB principle.
|
||||
|
||||
In the latter, the behaviour of the `div` element is spread out amongst multiple files. It is difficult to know
|
||||
exactly what the div does without a total knowledge of the code base.
|
||||
|
||||
#### Surfacing Behaviour vs. Inlining Implementation
|
||||
|
||||
A common conflation is surfacing behaviour with inlining implementation of that behaviour. These are separate concepts
|
||||
and, while inlining the implementation of a behaviour isn't *always* incorrect, it may *often* be incorrect.
|
||||
|
||||
Increasing the obviousness of the behaviour of an element is, ceteris paribus, a good thing, but it falls to both end-developers
|
||||
and especially framework developers to make LoB as easy as possible.
|
||||
|
||||
#### Conflict With Other Development Principles
|
||||
|
||||
The LoB will often conflict with other software development principles. Two important ones
|
||||
are:
|
||||
|
||||
* [DRY - Don't Repeat Yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
|
||||
|
||||
Software developers typically strive to avoid redundancy in their code or data. This as come to be called "Staying DRY",
|
||||
i.e. Don't Repeat Yourself. Like other software design principles this, on its own, is a good thing. htmx, for example,
|
||||
allows you to place many attributes on parent elements in a DOM and avoid repeating these attributes on children. This is a
|
||||
violation of LoB, in favor of DRY, and such tradeoffs need to be made judiciously by developers.
|
||||
|
||||
Note that the further behaviour gets from the code unit it effects, the more severe the violation of LoB. If it is
|
||||
within a few lines of the code unit, this is less serious than if it is a page away, which is less serious than if
|
||||
it is in a separate file entirely.
|
||||
|
||||
There is no hard and fast rule, but rather subjective tradeoffs that must be made as software developers.
|
||||
|
||||
* [SoC - Separation Of Concerns](https://en.wikipedia.org/wiki/Separation_of_concerns)
|
||||
|
||||
Separation of concerns a design principle for separating a computer program into distinct sections such that each
|
||||
section addresses a separate concern. A canonical example of this is CSS vs. Javascript. Again, on its own and
|
||||
in isolation this may, indeed, be a good thing. Inlining styles has become more prevalent lately, but there are
|
||||
still strong arguments in favor of SoC in this regard.
|
||||
|
||||
Note that SoC is, however, in conflict with LoB. By tweaking a CSS file the look and, to an extent, behaviour of an
|
||||
element can change dramatically, and it is not obvious where this dramatic change came from. Tools help to an extent
|
||||
here, but there is still "spooky action at a distance" going on.
|
||||
|
||||
Again, this isn't to condemn SoC wholesale, just to say that there are subjective tradeoffs that must be made when
|
||||
considering how to structure your code. The fact that inline styles have become more prevalent as of late is an
|
||||
indication that SoC is losing some support amongst developers.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
LoB is a software design principle that can help make a code bases more humane and maintainable. It must be traded
|
||||
off against other design principles and be considered in terms of the limitations of the system a code unit is
|
||||
written in, but, as much as is it is practical, adherence to this principle will increase your developer productivity
|
||||
and well-being.
|
@ -62,7 +62,7 @@ title: </> htmx - Attributes
|
||||
| `X-HX-Active-Element` | the `id` of the active element if it exists
|
||||
| `X-HX-Current-URL` | the current URL of the browser
|
||||
| `X-HX-Event-Target` | the `id` of the original event target
|
||||
| `X-HX-Prompt` | the user response to an [ic-prompt](/attributes/hx-prompt)
|
||||
| `X-HX-Prompt` | the user response to an [hx-prompt](/attributes/hx-prompt)
|
||||
| `X-HX-Request` | always `true`
|
||||
| `X-HX-Target` | the `id` of the target element if it exists
|
||||
| `X-HX-Trigger-Name` | the `name` of the triggered element if it exists
|
||||
|
Loading…
x
Reference in New Issue
Block a user