@fregante/dom-form-serializer 2.1.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +271 -0
- package/dist/dom-form-serializer.js +354 -0
- package/dist/dom-form-serializer.js.map +1 -0
- package/dist/dom-form-serializer.mjs +345 -0
- package/dist/dom-form-serializer.mjs.map +1 -0
- package/lib/InputReaders.js +59 -0
- package/lib/InputWriters.js +62 -0
- package/lib/KeyAssignmentValidators.js +9 -0
- package/lib/KeyExtractors.js +8 -0
- package/lib/TypeRegistry.js +23 -0
- package/lib/assignKeyValue.js +31 -0
- package/lib/deserialize.js +45 -0
- package/lib/flattenData.js +34 -0
- package/lib/getElementType.js +14 -0
- package/lib/getInputElements.js +39 -0
- package/lib/index.js +4 -0
- package/lib/keyJoiner.js +3 -0
- package/lib/keySplitter.js +9 -0
- package/lib/serialize.js +47 -0
- package/package.json +53 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import KeyExtractors from './KeyExtractors'
|
|
2
|
+
import InputWriters from './InputWriters'
|
|
3
|
+
import flattenData from './flattenData'
|
|
4
|
+
import getInputElements from './getInputElements'
|
|
5
|
+
import getElementType from './getElementType'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Use the given JSON object to populate all of the form inputs, in this element.
|
|
9
|
+
*
|
|
10
|
+
* @param {HTMLElement} Root element
|
|
11
|
+
* @param {object} options
|
|
12
|
+
* @param {object} options.inputWriters
|
|
13
|
+
* @param {object} options.keyExtractors
|
|
14
|
+
* @param {object} options.keySplitter
|
|
15
|
+
* @param {string[]} options.include
|
|
16
|
+
* @param {string[]} options.exclude
|
|
17
|
+
* @param {string[]} options.ignoredTypes
|
|
18
|
+
*/
|
|
19
|
+
export default function deserialize (form, data, options = {}) {
|
|
20
|
+
const flattenedData = flattenData(data, null, options)
|
|
21
|
+
const arrayValueIndexes = {}
|
|
22
|
+
options.keyExtractors = new KeyExtractors(options.keyExtractors || {})
|
|
23
|
+
options.inputWriters = new InputWriters(options.inputWriters || {})
|
|
24
|
+
|
|
25
|
+
Array.prototype.forEach.call(
|
|
26
|
+
getInputElements(form, options),
|
|
27
|
+
(el) => {
|
|
28
|
+
const type = getElementType(el)
|
|
29
|
+
|
|
30
|
+
const keyExtractor = options.keyExtractors.get(type)
|
|
31
|
+
const key = keyExtractor(el)
|
|
32
|
+
|
|
33
|
+
const inputWriter = options.inputWriters.get(type)
|
|
34
|
+
let value = flattenedData[key]
|
|
35
|
+
|
|
36
|
+
if (Array.isArray(value) && key.endsWith('[]') && type !== 'checkbox' && type !== 'select') {
|
|
37
|
+
const index = arrayValueIndexes[key] || 0
|
|
38
|
+
value = value[index]
|
|
39
|
+
arrayValueIndexes[key] = index + 1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
inputWriter(el, value)
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import defaultKeyJoiner from './keyJoiner'
|
|
2
|
+
|
|
3
|
+
export default function flattenData (data, parentKey, options = {}) {
|
|
4
|
+
const flatData = {}
|
|
5
|
+
const keyJoiner = options.keyJoiner || defaultKeyJoiner
|
|
6
|
+
|
|
7
|
+
for (let keyName in data) {
|
|
8
|
+
if (!Object.prototype.hasOwnProperty.call(data, keyName)) {
|
|
9
|
+
continue
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const value = data[keyName]
|
|
13
|
+
let hash = {}
|
|
14
|
+
|
|
15
|
+
// If there is a parent key, join it with
|
|
16
|
+
// the current, child key.
|
|
17
|
+
if (parentKey) {
|
|
18
|
+
keyName = keyJoiner(parentKey, keyName)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
hash[keyName + '[]'] = value
|
|
23
|
+
hash[keyName] = value
|
|
24
|
+
} else if (typeof value === 'object') {
|
|
25
|
+
hash = flattenData(value, keyName, options)
|
|
26
|
+
} else {
|
|
27
|
+
hash[keyName] = value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Object.assign(flatData, hash)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return flatData
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default function getElementType (el) {
|
|
2
|
+
let typeAttr
|
|
3
|
+
const tagName = el.tagName
|
|
4
|
+
let type = tagName
|
|
5
|
+
if (tagName.toLowerCase() === 'input') {
|
|
6
|
+
typeAttr = el.getAttribute('type')
|
|
7
|
+
if (typeAttr) {
|
|
8
|
+
type = typeAttr
|
|
9
|
+
} else {
|
|
10
|
+
type = 'text'
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return type.toLowerCase()
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import getElementType from './getElementType'
|
|
2
|
+
|
|
3
|
+
export default function getInputElements (element, options) {
|
|
4
|
+
return Array.prototype.filter.call(
|
|
5
|
+
element.querySelectorAll('input,select,textarea'),
|
|
6
|
+
(el) => {
|
|
7
|
+
if (el.tagName.toLowerCase() === 'input' && (el.type === 'submit' || el.type === 'reset')) {
|
|
8
|
+
return false
|
|
9
|
+
}
|
|
10
|
+
const myType = getElementType(el)
|
|
11
|
+
const extractor = options.keyExtractors.get(myType)
|
|
12
|
+
const identifier = extractor(el)
|
|
13
|
+
const foundInInclude = (options.include || []).indexOf(identifier) !== -1
|
|
14
|
+
const foundInExclude = (options.exclude || []).indexOf(identifier) !== -1
|
|
15
|
+
let foundInIgnored = false
|
|
16
|
+
let reject = false
|
|
17
|
+
|
|
18
|
+
if (options.ignoredTypes) {
|
|
19
|
+
for (const selector of options.ignoredTypes) {
|
|
20
|
+
if (el.matches(selector)) {
|
|
21
|
+
foundInIgnored = true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (foundInInclude) {
|
|
27
|
+
reject = false
|
|
28
|
+
} else {
|
|
29
|
+
if (options.include) {
|
|
30
|
+
reject = true
|
|
31
|
+
} else {
|
|
32
|
+
reject = (foundInExclude || foundInIgnored)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return !reject
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
}
|
package/lib/index.js
ADDED
package/lib/keyJoiner.js
ADDED
package/lib/serialize.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import KeyExtractors from './KeyExtractors'
|
|
2
|
+
import InputReaders from './InputReaders'
|
|
3
|
+
import KeyAssignmentValidators from './KeyAssignmentValidators'
|
|
4
|
+
import defaultKeySplitter from './keySplitter'
|
|
5
|
+
import getInputElements from './getInputElements'
|
|
6
|
+
import getElementType from './getElementType'
|
|
7
|
+
import assignKeyValue from './assignKeyValue'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get a JSON object that represents all of the form inputs, in this element.
|
|
11
|
+
*
|
|
12
|
+
* @param {HTMLElement} Root element
|
|
13
|
+
* @param {object} options
|
|
14
|
+
* @param {object} options.inputReaders
|
|
15
|
+
* @param {object} options.keyAssignmentValidators
|
|
16
|
+
* @param {object} options.keyExtractors
|
|
17
|
+
* @param {object} options.keySplitter
|
|
18
|
+
* @param {string[]} options.include
|
|
19
|
+
* @param {string[]} options.exclude
|
|
20
|
+
* @param {string[]} options.ignoredTypes
|
|
21
|
+
* @return {object}
|
|
22
|
+
*/
|
|
23
|
+
export default function serialize (element, options = {}) {
|
|
24
|
+
let data = {}
|
|
25
|
+
options.keySplitter = options.keySplitter || defaultKeySplitter
|
|
26
|
+
options.keyExtractors = new KeyExtractors(options.keyExtractors || {})
|
|
27
|
+
options.inputReaders = new InputReaders(options.inputReaders || {})
|
|
28
|
+
options.keyAssignmentValidators = new KeyAssignmentValidators(options.keyAssignmentValidators || {})
|
|
29
|
+
|
|
30
|
+
Array.prototype.forEach.call(
|
|
31
|
+
getInputElements(element, options),
|
|
32
|
+
(el) => {
|
|
33
|
+
const type = getElementType(el)
|
|
34
|
+
const keyExtractor = options.keyExtractors.get(type)
|
|
35
|
+
const key = keyExtractor(el)
|
|
36
|
+
const inputReader = options.inputReaders.get(type)
|
|
37
|
+
const value = inputReader(el)
|
|
38
|
+
const validKeyAssignment = options.keyAssignmentValidators.get(type)
|
|
39
|
+
if (validKeyAssignment(el, key, value)) {
|
|
40
|
+
const keychain = options.keySplitter(key)
|
|
41
|
+
data = assignKeyValue(data, keychain, value)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return data
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fregante/dom-form-serializer",
|
|
3
|
+
"version": "2.1.0-0",
|
|
4
|
+
"description": "Serialize form inputs",
|
|
5
|
+
"main": "dist/dom-form-serializer.js",
|
|
6
|
+
"module": "dist/dom-form-serializer.mjs",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=18"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"lint": "standard",
|
|
16
|
+
"prebuild": "npm run lint",
|
|
17
|
+
"build": "rollup -c",
|
|
18
|
+
"watch": "rollup -c -w",
|
|
19
|
+
"test": "mocha --require @babel/register test/*.js",
|
|
20
|
+
"prepublishOnly": "npm run build && npm test"
|
|
21
|
+
},
|
|
22
|
+
"author": "Jeferson Daniel",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"keywords": [
|
|
25
|
+
"form",
|
|
26
|
+
"serialize",
|
|
27
|
+
"client",
|
|
28
|
+
"browser"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/jefersondaniel/dom-form-serializer.git"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@babel/core": "^7.24.0",
|
|
36
|
+
"@babel/preset-env": "^7.24.0",
|
|
37
|
+
"@babel/register": "^7.23.0",
|
|
38
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
39
|
+
"chai": "^4.4.1",
|
|
40
|
+
"domify": "^1.4.0",
|
|
41
|
+
"global-jsdom": "^24.0.0",
|
|
42
|
+
"jsdom": "^24.0.0",
|
|
43
|
+
"mocha": "^10.4.0",
|
|
44
|
+
"rollup": "^4.13.0",
|
|
45
|
+
"standard": "^17.1.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {},
|
|
48
|
+
"standard": {
|
|
49
|
+
"ignore": [
|
|
50
|
+
"dist"
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|