14 KiB
layout | title |
---|---|
layout.njk | </> kutty - high power tools for html |
Contents
Kutty in a Nutshell
Kutty is a library that allows you to access modern browser features directly from HTML, rather than using javascript.
To understand kutty, first lets take a look at an anchor tag:
<a href="/blog">Blog</a>
This anchor tag tells a browser:
"When a user clicks on this link, issue an HTTP GET request to '/blog' and load the response content into the browser window".
With that in mind, consider the following bit of HTML:
<div kt-post="/clicked">Click Me!</div>
This tells kutty:
"When a user clicks on this div, issue an HTTP POST request to '/clicked' and load the response content into the inner html of this element"
Kutty extends the basic idea of that anchor tag, but opens up many more possibilities:
- Any element can issue a HTTP request
- Any event can trigger the request (not just clicks or form submissions)
- HTTP requests are done via AJAX
- Different HTTP verbs can used
- The response replaces the content of the element, rather than the entire page
When you are using kutty, you respond to the AJAX calls with HTML rather than JSON, often just a small amount of HTML rather than the whole page.
Note that if you prefer, you can use the data-
prefix when using kutty:
<a data-kt-post="/click">Click Me!</a>
Installing
Kutty is a dependency-free javascript library. It can be used via NPM as "kutty.org
" or
downloaded or included from unpkg:
<script src="https://unpkg.com/kutty.org@0.0.1"></script>
AJAX
One of the primary features kutty provides are attributes to allow you to issue AJAX requests directly from HTML:
- kt-get - Issues a
GET
request to the given URL - kt-post - Issues a
POST
request to the given URL - kt-put - Issues a
PUT
request to the given URL (see details) - kt-patch - Issues a
PATCH
request to the given URL (see details) - kt-delete - Issues a
GET
request to the given URL (see details)
Each of these attributes takes a URL to issue an AJAX request to. The element will issue a request of the specified type to the given URL when the element is triggered:
<div kt-put="/messages">Put To Messages</div>
This tells the browser:
When a user clicks on this div, PUT to the URL /messages and load the response into the div
Triggering Requests
By default AJAX requests are triggered by the "natural" event of an element:
input
,textarea
&select
: thechange
eventform
: thesubmit
event- everything else: the
click
event
If you don't want the request to happen on the default event, you can use the kt-trigger
attribute to specify the event of interest. Here is a div
that posts to /mouse_entered
when a mouse enters it:
<div kt-post="/mouse_entered" kt-trigger="mouseenter">
[Here Mouse, Mouse!]
</div>
If you want a request to only happen once, you can use the kt-trigger-once attribute:
<div kt-post="/mouse_entered" kt-trigger="mouseenter"
kt-trigger-once="true">
[Here Mouse, Mouse!]
</div>
There are two additional modifiers you can use for trigger:
- kt-trigger-changed-only - when set to
true
the element will only issue a request if its value has changed - kt-trigger-delay - tells kutty to wait the given amount of time (e.g.
1s
) before issuing the request. If the event triggers again, the countdown is reset.
You can use these two attributes to implement a common UX pattern, Live Search:
<input type="text" name="q"
kt-get="/trigger_delay"
kt-trigger="keyup"
kt-target="#search-results"
kt-trigger-delay="500ms" placeholder="Search..."/>
<div id="search-results"></div>
This input will issue a request 500 milliseconds after a key up event if the input has been changed and puts the results
into the div#search-results
.
Special Events
kutty provides a few special events for use in kt-trigger:
load
- fires once when the element is first loadedrevealed
- fires once when an element first scrolls into the viewport
You can also use custom events to trigger requests if you have an advanced use case.
Polling
If you want an element to poll the given URL rather than wait for an event, you can use the every
syntax:
<div kt-get="/news" trigger="every 2s"></div>
This tells kutty
Every 2 seconds, issue a GET to /news and load the response into the div
Server Sent Events
Server Sent Events are a way for servers to send events to browsers. It provides a higher-level mechanism for communication between the server and the browser than websockets.
If you want an element to respond to a Server Sent Event via kutty, you need to do two things:
-
Define an SSE source. To do this, add a kt-sse-src attribute on a parent element that specifies the URL from which Server Sent Events will be received.
-
Specify the Server Sent Event that will trigger the element, with the prefix
sse:
Here is an example:
<body kt-sse-src="/sse_messages">
<div trigger="sse:new_news" kt-get="/news"></div>
</body>
Depending on your implementation, this may be more efficient than the polling example above since the server would notify the div if there was new news to get, rather than the steady requests that a poll causes.
Request Indicators
When an AJAX request is issued it is often good to let the user know that something is happening, since the browser
will not give them any feedback. You can accomplish this in kutty by using the kt-indicator
attribute, the kutty-show-indicator
class and some CSS.
By default the kutty-show-indicator
class will be put on the element issuing the request. This can be used to show a
spinner gif, for example:
<style>
.indicator { display: none }
.kutty-show-indicator .indicator { display: inline }
</style>
<button kt-get="/click">
Click Me!
<img class="indicator" src="/spinner.gif"/>
</button>
If you want the kutty-show-indicator
class added to a different element, you can use the kt-indicator
attribute with a CSS selector to do so:
<style>
.indicator { display: none }
.kutty-show-indicator .indicator { display: inline }
</style>
<div id="parent-div">
<button kt-get="/click" kt-indicator="#parent-div">
Click Me!
</button>
<img class="indicator" src="/spinner.gif"/>
</div>
Targets
If you want the response to be loaded into a different element other than the one that made the request, you can use the kt-target attribute, which takes a CSS selector. Looking back at our Live Search example:
<input type="text" name="q"
kt-get="/trigger_delay"
kt-trigger="keyup"
kt-target="#search-results"
kt-trigger-delay="500ms" placeholder="Search..."/>
<div id="search-results"></div>
You can see that the results from the search are going to be loaded into div#search-results
, rather than into the
input tag.
Swapping
kutty offers a few different ways to swap the HTML returned into the DOM. By default, the content replaces the
innerHTML
of the target element. You can modify this by using the kt-swap attribute
with any of the following values:
innerHTML
- the default, puts the content inside the target elementouterHTML
- replaces the entire target element with the returned contentprepend
- prepends the content before the first child inside the targetprependBefore
- prepends the content before the target in the targets parent elementappend
- appends the content after the last child inside the targetappendAfter
- appends the content after the target in the targets parent element
Out of Band Swaps
If you want to swap content from a response directly into the DOM by using the id
attribute you can use the
kt-swap-oob attribute in the response html:
<div id="message" kt-swap-oob="true">Swap me directly!</div>
Additional Content
In this response, div#message
would be swapped directly into the matching DOM element, while the additional content
would be swapped into the target in the normal manner.
You can use this technique to "piggy-back" updates on other requests.
Note that out of band elements must be in the top level of the response, and not children of the top level elements.
Selecting Content To Swap
If you want to select a subset of the response HTML to swap into the target, you can use the kt-select attribute, which takes a CSS selector and selects the matching elements from the response.
Forms & Input Values
By default, an element will include its value if it has one. Additionally, if the element is in a form, all values in the form will be included in the request.
If you wish to include the values of other elements, you can use the kt-include attribute with a CSS selector of all the elements whose values you want to include in the request.
Finally, if you want to programatically modify the arguments, you can use the values.kutty event to do so.
History Support
kutty provides a simple mechanism for interacting with the browser history API:
If you want a given element to push its request into the browser navigation bar and add the current state of the page to the browser's history, include the kt-push attribute:
<a kt-get="/Blog" kt-push="true">Blog</a>
When a user clicks on this link, kutty will snapshot the current DOM and store it before it makes a request to /blog. It then does the swap and pushes a new location onto the history stack.
When a user hits the back button, kutty will retrieve the old content from storage and swap it back into the target, simulating "going back" to the previous state.
Specifying History Snapshot Element
By default, kutty will use the body
to take and restore the history snapshop from. This is usually the right thing, but
if you want to use a narrower element for snapshotting you can use the kt-history-element
attribute to specify a different one.
Careful: this element will need to be on all pages or restoring from history won't work reliably.
Requests & Responses
Request Headers
kutty includes a number of useful headers in requests:
X-KT-Request
- will be set to "true"X-KT-Trigger-Id
- will be set to the id of the element that triggered the requestX-KT-Trigger-Name
- will be set to the name of the element that triggered the requestX-KT-Target-Id
- will be set to the id of the target elementX-KT-Current-URL
- will be set to the URL of the browserX-KT-Prompt
- will be set to the value entered by the user when prompted via kt-promptX-KT-Event-Target
- the id of the original target of the event that triggered the requestX-KT-Active-Element
- the id of the current active elementX-KT-Active-Element-Value
- the value of the current active element
Response Headers
kutty supports two special response headers:
X-KT-Trigger
- can be used to trigger client side events, see the documentation for examples.X-KT-Push
- can be used to push a new URL into the browsers address bar
Request Order of Operations
The order of operations in a kutty request are:
- The element is triggered and begins a request
- Values are gathered for the request
- The
kutty-show-indicator
class is applied to the appropriate elements - The request is then issued asynchronously via AJAX
- Upon getting a response the target element is marked with the
kutty-swapping
class - An optional swap delay is done (default: no delay)
- The actual content swap is done
- A settle delay is done (default: 100ms)
- The DOM is settled
- Upon getting a response the target element is marked with the