@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.
@@ -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
@@ -0,0 +1,4 @@
1
+ import serialize from './serialize'
2
+ import deserialize from './deserialize'
3
+
4
+ export { serialize, deserialize }
@@ -0,0 +1,3 @@
1
+ export default function keyJoiner (parentKey, childKey) {
2
+ return parentKey + '[' + childKey + ']'
3
+ }
@@ -0,0 +1,9 @@
1
+ export default function keySplitter (key) {
2
+ const matches = key.match(/[^[\]]+/g)
3
+ let lastKey
4
+ if (key.length > 1 && key.indexOf('[]') === key.length - 2) {
5
+ lastKey = matches.pop()
6
+ matches.push([lastKey])
7
+ }
8
+ return matches
9
+ }
@@ -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
+ }