Skip to content

Commit

Permalink
Merge pull request #20 from seanpdoyle/provide-field-elements
Browse files Browse the repository at this point in the history
Support `scope:` option to scope selector query and `fields:` option to skip selector query
  • Loading branch information
theinterned authored Jan 24, 2024
2 parents 9358f76 + 357e2f8 commit cee83c0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ The `restoreResumableFields(id: string, options)` function supports optional con
The `persistResumableFields(id: string, options)` function supports optional configurations:

* `storage:` - [`Storage`][] instance (defaults to [`window.sessionStorage`][])
* `selector:` - `string` used to query field elements (defaults to `".js-session-resumable"`)
* `storageFilter:` - `(field: HTMLInputElement | HTMLTextAreaElement) => boolean` predicate to determine whether or not to store a field (defaults to `(field) => field.value !== field.defaultValue`)
* `keyPrefix:` - `string` prepended onto the storage key (defaults to `"session-resume"`)
* `scope:` - `ParentNode` used to query field elements (defaults to `document`)
* `selector:` - `string` used to query field elements (defaults to `".js-session-resumable"`)
* `fields:` - `NodeList | Node[]` provide field elements as an alternative to querying (defaults to `options.scope.querySelectorAll(options.selector)`)

**Note:** When `fields` is specified, `scope` and `selectors` will be ignored.

[`Storage`]: https://developer.mozilla.org/en-US/docs/Web/API/Storage
[`window.sessionStorage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
Expand Down
17 changes: 15 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,29 @@ function valueIsUnchanged(field: HTMLInputElement | HTMLTextAreaElement): boolea

type StorageFilter = (field: HTMLInputElement | HTMLTextAreaElement) => boolean

type PersistOptions = {
type PersistOptionsWithSelector = {
scope?: ParentNode
selector?: string
fields?: never
}

type PersistOptionsWithFields = {
fields?: NodeList | Node[]
selector?: never
scope?: never
}

type PersistOptions = (PersistOptionsWithSelector | PersistOptionsWithFields) & {
keyPrefix?: string
storage?: Pick<Storage, 'getItem' | 'setItem'>
storageFilter?: StorageFilter
}

// Write all ids and values of the selected fields on the page into sessionStorage.
export function persistResumableFields(id: string, options?: PersistOptions): void {
const scope = options?.scope ?? document
const selector = options?.selector ?? '.js-session-resumable'
const elements = options?.fields ?? scope.querySelectorAll(selector)
const keyPrefix = options?.keyPrefix ?? 'session-resume:'
const storageFilter = options?.storageFilter ?? valueIsUnchanged

Expand All @@ -35,7 +48,7 @@ export function persistResumableFields(id: string, options?: PersistOptions): vo
const key = `${keyPrefix}${id}`
const resumables = []

for (const el of document.querySelectorAll(selector)) {
for (const el of elements) {
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
resumables.push(el)
}
Expand Down
45 changes: 44 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-unresolved, import/extensions
// eslint-disable-next-line import/extensions, import/no-unresolved
import {persistResumableFields, restoreResumableFields} from '../dist/index.js'

describe('session-resume', function () {
Expand Down Expand Up @@ -156,5 +156,48 @@ describe('session-resume', function () {
['my-second-field', 'test2']
])
})

it('scopes fields based on the selector: option', function () {
document.getElementById('my-first-field').value = 'test1'
document.getElementById('my-second-field').value = 'test2'

sessionStorage.clear()
persistResumableFields('test-persist', {selector: '#my-first-field'})

assert.deepEqual(JSON.parse(sessionStorage.getItem('session-resume:test-persist')), [['my-first-field', 'test1']])
})

it('scopes fields based on the scope: option', function () {
// eslint-disable-next-line github/no-inner-html
document.body.innerHTML = `
<form>
<input id="my-first-field" value="first-field-value" class="js-session-resumable" />
<input id="my-second-field" value="second-field-value" class="js-session-resumable" />
</form>
<input id="my-third-field" value="second-third-value" class="js-session-resumable" />
`
document.getElementById('my-first-field').value = 'test1'
document.getElementById('my-second-field').value = 'test2'
document.getElementById('my-third-field').value = 'test3'

sessionStorage.clear()
persistResumableFields('test-persist', {scope: document.querySelector('form')})

assert.deepEqual(JSON.parse(sessionStorage.getItem('session-resume:test-persist')), [
['my-first-field', 'test1'],
['my-second-field', 'test2']
])
})
it('scopes fields based on the fields: option', function () {
document.getElementById('my-first-field').value = 'test1'
document.getElementById('my-second-field').value = 'test2'

sessionStorage.clear()
persistResumableFields('test-persist', {fields: document.querySelectorAll('#my-second-field')})

assert.deepEqual(JSON.parse(sessionStorage.getItem('session-resume:test-persist')), [
['my-second-field', 'test2']
])
})
})
})

0 comments on commit cee83c0

Please sign in to comment.