window#
Browser navigation, storage, forms, JSON requests, and file uploads.
Install#
npm i @nodedk/window
Usage#
In a NodeDK scaffold application, the helpers are already exposed on window by the copied @nodedk/browser bundle. Use them directly in app/assets/js/base.js or HTML event handlers:
window.active()
window.store('filters', { status: 'active' })
console.log(window.store('filters')) // { status: 'active' }
See browser for the copy command and app/config/bundle.js setup. Several helpers call one another through window.
With a separate module-aware browser bundler, the exports can be installed directly:
var browser = require('@nodedk/window')
Object.assign(window, browser)
API#
Navigation and display#
active(options = {}): adds a class to links whose pathname matches the current page.options.selectordefaults to'a';options.activedefaults to'active'. Returnsundefined.track(): stores the current URL undersessionStorage.track. Call before navigating away. Returnsundefined.back(): navigates to the storedtrackURL, or/when absent.toggle(name, element): toggles a class on an element and removes it from other elements. Missingelementdoes nothing. Returnsundefined.blur(element): removes.openfrom all elements unless the supplied element is within.toggleor.open. Returnsundefined.copy(input): selects and copies the value of an input or textarea, supplied as an element or selector. Returnsundefined; clipboard completion is not awaited.params(id): string IDs read a query parameter; numeric IDs read a zero-based pathname segment. Missing query values return''; missing path segments returnundefined. Omittingidreturns''.
<input id="share-url" value="https://example.com" readonly />
<button onclick="copy('#share-url')">Copy</button>
<div class="toggle" onclick="toggle('open', this)">Toggle</div>
cookie(key, value, options)#
Omit value to read a decoded cookie string or null. Supply a value to write it; null deletes it. Writes return undefined.
days: lifetime in days, default30;0makes a session cookie.path: default/.domain,sameSite,secure: optional cookie attributes.
window.cookie('locale', 'nb', { days: 0, sameSite: 'Lax' })
console.log(window.cookie('locale')) // nb
window.cookie('locale', null)
store(key, value)#
Stores JSON in sessionStorage. Omit value to read it; missing or invalid JSON returns undefined. Invalid JSON is removed. Writes return the value; null deletes the key and returns the previous value. A falsy key clears all session storage and returns undefined.
flash(message, options = {})#
Shows a text message and returns its element, or null if the target is missing. A missing or empty message is read from a cookie, which is then deleted.
el: target selector, default.flash .message.name: cookie name, defaultflash.time: display duration in milliseconds, default5000; falsy values use the default.class: optional class, removed when the message fades.scroll: set tofalseto avoid scrolling to the top.
<div class="flash"><span class="message"></span></div>
<button onclick="flash('Saved', { class: 'success' })">Save</button>
client(path, data = {}, options = {})#
Sends JSON and returns a promise for the parsed JSON response. path is the URL; data is serialized as the body. options.method defaults to POST; options.headers extends the JSON content-type header. Credentials are always included. Other options are ignored.
The body is always sent, so use a method that accepts a body. HTTP error responses are still parsed as JSON; fetch failures and invalid JSON reject.
async function save() {
var result = await window.client('/account/update', {
params: { name: 'Ada' }
})
if (result.ok === false) return window.flash(result.message)
window.flash('Saved')
}
load(path, into)#
Fetches text and resolves to that text. into is an optional element or selector; when present, its HTML is replaced and inline script contents are evaluated. Use application-controlled HTML. HTTP statuses are not checked.
serialize(form)#
Returns a plain object from a form element or selector; a missing form returns {}. Disabled, unnamed, file, reset, submit, and button fields are skipped. Unchecked checkboxes and radio buttons are omitted; checked checkbox groups and multiple selects produce arrays. Dotted names create nested objects.
data-default supplies the value for an empty input. data-type overrides the input type:
array: comma-separated strings;[]becomes an empty array.number: numeric conversion.date: a Date; an unparseable value falls back to the current time.null:null.bool:false,0, andoffbecomefalse; other nonempty values becometrue.
<form id="profile">
<input name="user.name" value="Ada" />
<input name="user.age" value="32" data-type="number" />
<input name="tags" value="news,events" data-type="array" />
</form>
console.log(window.serialize('#profile'))
// { user: { name: 'Ada', age: 32 }, tags: ['news', 'events'] }
submit(form, options = {})#
Submits a form element through window.client(form.action, { params: values }), using window.serialize. Returns a promise for undefined. A missing or non-form element does nothing.
error: fallback failure message; defaults todata-error.success: message saved to theflashcookie after success; defaults todata-success.redirect: success destination; defaults todata-redirect. Without it, reloads the page.
A response with ok: false displays message and any fields errors in em.<field>-errors. Inputs inside .field clear their associated error on changes. The first submit control is disabled during the request and restored on failure.
<form
action="/account/update"
data-success="Saved"
data-redirect="/account"
onsubmit="
submit(this)
return false
"
>
<div class="field">
<input name="name" required />
<em class="name-errors"></em>
</div>
<button type="submit">Save</button>
</form>
upload(link, file, options = {})#
Uploads a File or Blob and resolves to { url }. Rejects with { error: { message } } on failure.
link.url: upload endpoint.link.method:'PUT'sends the file directly; other values use multipart POST.link.headers: request headers for PUT.link.location: public URL returned after PUT; otherwise the upload URL without its query string.link.fields: form fields for POST. POST also appendsfileand expects a readableLocationresponse header.options.progress(event): receives upload events withloaded,total, andpercentwhen a total is available.options.error: overrides the failure message.
file(input)#
Handles selected files sequentially using window.client and window.upload. Takes a file input element and resolves with undefined. No selection does nothing.
The enclosing .field supplies data-action, which receives { params: { name, type, size } } and must return { data: link }. A response with ok: false stops the upload. Optional children are output, progress, input[type=hidden], picture source, and .spinner.
<div class="field" data-action="/files/presign">
<input type="file" multiple onchange="file(this)" />
<input type="hidden" name="files" />
<output></output>
<progress max="100" value="0"></progress>
</div>
The hidden value becomes comma-separated uploaded URLs; a picture source receives the first URL. The presign endpoint can use @nodedk/s3.
download(input, filename)#
Downloads a Blob, URL string, or element with an href. filename overrides the name; URL downloads otherwise use the last path segment, and Blob downloads default to download.
For Blobs, returns the temporary anchor element. URL downloads start an XMLHttpRequest and return undefined. Downloads are not awaited.
var data = new Blob(['hello'], { type: 'text/plain' })
window.download(data, 'hello.txt')
Created by Vidar Eldøy