content-handler v1.1.5
content-handler
Based on EventTarget, content handlers are an unified system to automate and simply await some DOM (HTML/SVG) contents from the server, ignoring the content origin, avoiding complex logic in your front code, even from AJAX requests or received as Server-Sent Events
Install
npm i content-handler
Quick start
Create your own content-handler based project to build your app/site in seconds!
Browsers support
How a content handler gets the contents?
- Full page loading
- Register your listeners, based on selector events (including your controllers)
- The
ContentHandler
triggers the listeners on the matching elements - Your controllers are awaiting some user events (
click
on an anchor,submit
on a form) - The
ContentSupervisor
triggers the related controllers - Fetching
- The
ContentHandler
parses the response in aDocumentFragment
and returns to step 3.
Get the content handler for a document
Each handler handles a single document!
import ContentHandler from 'content-handler'
// If the document isn't provided, it uses the current window.document
const handler = ContentHandler.getByDocument(document)
Await elements from a handler
Loaded or not
import ContentHandler from 'content-handler'
// Await any main tag, already present in the document or loaded by the content
// handler, to apply the listener on it
ContentHandler
.getByDocument()
.addEventListener('main', ({element}) => {
// Rewrites the content (just to illustrate, don't do that in real projects)
element.innerHTML = `<h1>You're currently testing content-handler</h1>
<p>This main is rewritten by the ContentHandler's listener, even if loaded
or not, but in this case, this node <em>is already contained</em> by the
document, at the page loading.</p>`
})
Loaded only
The fetched elements are not in the current page, they need to be added on it.
import ContentHandler from 'content-handler'
// Await any main tag, but only loaded by the content handler, to apply the
// listener on it
ContentHandler
.getByDocument()
.addEventListener('body:first-child main', ({element}) => {
// Select the current main
const main = document.querySelector('main')
// Replace the current main by the new one
main.parentNode.replaceChild(element, main)
})
Present only
The fetched elements are already in the current page, they don't need to be added on it.
import ContentHandler from 'content-handler'
// Await any main tag, already present in the document, to apply the listener on it
ContentHandler
.getByDocument()
.addEventListener('body:not(:first-child) main', ({element}) => {
// Rewrites the content (just to illustrate, don't do that in real projects)
element.innerHTML = `<h1>You're currently testing content-handler</h1>
<p>This main is rewritten by the ContentHandler's listener, but only if this
node <em>is already contained</em> by the document, at the page loading.</p>`
})
Declare the controllers
A content handler doesn't make anything alone, to automate the fetching ou SSE listening, you need to tell him how to do it.
It also uses the handler.addEventListener()
and should need some controllers
(provided or custom) to define the request behavior, make some pre-validation,
some client optimizations before to send it to the server, etc.
The provided controllers are generic as possible, not required but recommended, to avoid uncommon behaviors between browsers.
It shipped with 3 simple initial controllers with, for each, a default
.selector
to target the related elements (you can define yours), and a
.listen()
method to control the request.
anchor
import ContentHandler from 'content-handler/content-handler.js'
import anchor from 'content-handler/controllers/fetcher/anchor.js'
import cache from 'content-handler/controllers/fetcher/init/cache.js'
import headers from 'content-handler/controllers/fetcher/init/headers.js'
import credentials from 'content-handler/controllers/fetcher/init/credentials.js'
import mode from 'content-handler/controllers/fetcher/init/mode.js'
import redirect from 'content-handler/controllers/fetcher/init/redirect.js'
import referrer from 'content-handler/controllers/fetcher/init/referrer.js'
ContentHandler
.getByDocument()
.addEventListener(anchor.selector, anchor.listen([
cache.default, // follow the default cache rule
headers.xhr, // add the common AJAX header
credentials.sameOrigin, // allow credentials only for the current origin
mode.sameOrigin, // allow requests handling only for the current origin
redirect.follow, // follows the redirects
referrer.client // set request.referrer to "about:client" by default
], {/* optional env object */}))
form
ContentHandler .getByDocument() .addEventListener(form.selector, form.listen( headers.contentType, // detect the content type, if needed cache.default, // follow the default cache rule headers.xhr, // add the common AJAX header credentials.sameOrigin, // allow credentials only for the current origin mode.sameOrigin, // allow requests handling only for the current origin redirect.follow, // follows the redirects referrer.client // set request.referrer to "about:client" by default , {/ optional env object /}))
</details>
### <a name="sse">sse</a>
<details>
<summary>Listen all the event sources at once!</summary>
```js
import ContentHandler from 'content-handler/content-handler.js'
import sse from 'content-handler/controllers/sse/sse.js'
import withCredentials from 'content-handler/controllers/sse/configuration/with-credentials.js'
import input from 'content-handler/controllers/sse/input.js'
ContentHandler
.getByDocument()
.addEventListener(sse.selector, sse.listen([
input.dataset, // get the input url from "data-sse" attribute
withCredentials.sameOrigin // allow credentials only for the current origin
], {/* optional env object */}))
Make your own controller
Making your own controller is really easy, it just a function, receiving a
request config
object and returning a new one based on it.
As a best practice, you never should modify the received object!
For asynchronous operations, in place of returning the new config
object,
you can simply return a Promise
, resolving the config
object.
The unique difference between AJAX/SSE config objects is the
init
/configuration
property