switch to typescript
This commit is contained in:
Vendored
-169
@@ -1,169 +0,0 @@
|
|||||||
/** @module FormDataDeep */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Usage: `Array<HTMLElement>.filter(removeChildren)`
|
|
||||||
*
|
|
||||||
* Removes elements from the array which are children of other elements in the array.
|
|
||||||
*/
|
|
||||||
export function removeChildren(element,index,array){
|
|
||||||
for(const sibling of array){
|
|
||||||
if(!sibling.isSameNode(element) && sibling.contains(element)){
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Appends a new value onto an existing key inside an object, or adds the key if it does not already exist.
|
|
||||||
* @param {Object} object
|
|
||||||
* @param {String} name
|
|
||||||
* @param {*} value
|
|
||||||
*/
|
|
||||||
export function append(object,name,value){
|
|
||||||
if(name in object){
|
|
||||||
if(object[name] instanceof Array){
|
|
||||||
object[name].push(value)
|
|
||||||
}else{
|
|
||||||
object[name]=[object[name],value]
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
object[name]=value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get `form` data as an object, including nested forms.
|
|
||||||
* @param {HTMLFormElement} form
|
|
||||||
* @param {Boolean} primitives whether to convert string values to primitives. Defaults `false`.
|
|
||||||
*/
|
|
||||||
export function getFormDataDeep(form,primitives=false){
|
|
||||||
const formDataDeep={}
|
|
||||||
const formData=new FormData(form)
|
|
||||||
for(const name of formData.keys()){
|
|
||||||
const value=formData.getAll(name)
|
|
||||||
if(value.length==0){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if(primitives){
|
|
||||||
for(let i=0;i<value.length;i++){
|
|
||||||
if(!isNaN(+value[i])){
|
|
||||||
value[i]=+value[i]
|
|
||||||
}
|
|
||||||
if(value[i]=='on'){
|
|
||||||
value[i]=true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(value.length==1){
|
|
||||||
formDataDeep[name]=value[0]
|
|
||||||
}else{
|
|
||||||
formDataDeep[name]=value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(const child of [...form.querySelectorAll('form')].filter(removeChildren)){
|
|
||||||
const value=getFormDataDeep(child,primitives)
|
|
||||||
if(Object.keys(value)==0){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const name=child.name
|
|
||||||
append(formDataDeep,name,value)
|
|
||||||
}
|
|
||||||
return formDataDeep
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Convenience class to have a similar interface to FormData
|
|
||||||
*/
|
|
||||||
export class FormDataDeep extends FormData {
|
|
||||||
/**
|
|
||||||
* Get `form` data as an object, including nested forms.
|
|
||||||
* @param {HTMLFormElement | Object} form the root form element, or a JSON Object containing form data.
|
|
||||||
* @param {Boolean} primitives whether to convert string values to primitives. Defaults `false`.
|
|
||||||
*/
|
|
||||||
constructor(form,primitives=false){
|
|
||||||
super()
|
|
||||||
if(form instanceof HTMLFormElement){
|
|
||||||
Object.assign(this,getFormDataDeep(form,primitives))
|
|
||||||
}else{
|
|
||||||
Object.assign(this,form)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
append(name,value,filename=undefined){
|
|
||||||
if(filename!==undefined){
|
|
||||||
value=new File([value],filename)
|
|
||||||
}
|
|
||||||
append(this,name,value)
|
|
||||||
}
|
|
||||||
delete(name){
|
|
||||||
delete this[name]
|
|
||||||
}
|
|
||||||
entries(){
|
|
||||||
return Object.entries(this).filter((value)=>!value instanceof Function)
|
|
||||||
}
|
|
||||||
get(name){
|
|
||||||
if(this[name] instanceof Array){
|
|
||||||
return this[name].at(-1)
|
|
||||||
}else{
|
|
||||||
return this[name]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getAll(name){
|
|
||||||
if(this[name] instanceof Array){
|
|
||||||
return this[name]
|
|
||||||
}else{
|
|
||||||
return [this[name]]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
has(name){
|
|
||||||
return name in this
|
|
||||||
}
|
|
||||||
keys(){
|
|
||||||
return this.entries().keys()
|
|
||||||
}
|
|
||||||
set(name,value,filename=undefined){
|
|
||||||
if(filename!==undefined){
|
|
||||||
value=new File([value],filename)
|
|
||||||
}
|
|
||||||
this[name]=value
|
|
||||||
}
|
|
||||||
values(){
|
|
||||||
return this.entries().values()
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Applies the values in this object to the target form.
|
|
||||||
* @param {HTMLFormElement} form
|
|
||||||
*/
|
|
||||||
apply(form){
|
|
||||||
for(const element of form.elements){
|
|
||||||
const name=element.name
|
|
||||||
if(! name in this){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
let value
|
|
||||||
if(this[name] instanceof Array){
|
|
||||||
value=this[name].shift()
|
|
||||||
}else{
|
|
||||||
value=this[name]
|
|
||||||
delete this[name]
|
|
||||||
}
|
|
||||||
switch(element.type){
|
|
||||||
case 'radio':
|
|
||||||
case 'checkbox':{
|
|
||||||
element.checked=true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default:{
|
|
||||||
element.value=value
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(const child of [...form.querySelectorAll('form')].filter(removeChildren)){
|
|
||||||
const name=child.name
|
|
||||||
if(! name in this){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
new FormDataDeep(this[name]).apply(form)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FormDataDeep
|
|
||||||
Generated
+18
-11
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "js-util",
|
"name": "@sugoidogo/js-util",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "js-util",
|
"name": "@sugoidogo/js-util",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/web": "^0.0.301",
|
"jsdoc": "^4.0.5",
|
||||||
"jsdoc": "^4.0.5"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
@@ -101,13 +101,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/web": {
|
|
||||||
"version": "0.0.301",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.301.tgz",
|
|
||||||
"integrity": "sha512-GAoFovImstIY39EAwGazoeal9+uy+zZz0vLhz/MDbqaHAbK0d8yzF8EKtlSkwNzZu9WEIyYdfSGwVTUSnJMtpw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
|
||||||
"node_modules/argparse": {
|
"node_modules/argparse": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
@@ -328,6 +321,20 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/uc.micro": {
|
"node_modules/uc.micro": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||||
|
|||||||
+9
-3
@@ -2,10 +2,16 @@
|
|||||||
"name": "@sugoidogo/js-util",
|
"name": "@sugoidogo/js-util",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"files": ["dist/"],
|
"scripts": {
|
||||||
|
"prepack": "tsc"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/",
|
||||||
|
"src/"
|
||||||
|
],
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/web": "^0.0.301",
|
"jsdoc": "^4.0.5",
|
||||||
"jsdoc": "^4.0.5"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export async function loadAsset(dataURL,id=undefined,unsafe=false){
|
|||||||
}
|
}
|
||||||
default:{
|
default:{
|
||||||
if(unsafe){
|
if(unsafe){
|
||||||
window[id]=await fetch(dataURL)
|
Object.defineProperty(window,id,await fetch(dataURL))
|
||||||
}
|
}
|
||||||
return await fetch(dataURL)
|
return await fetch(dataURL)
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
* @module CSSRandom
|
* @module CSSRandom
|
||||||
*/
|
*/
|
||||||
(function CSSRandom() {
|
(function CSSRandom() {
|
||||||
document.documentElement.style.setProperty('--random', Math.random())
|
document.documentElement.style.setProperty('--random', Math.random().toString())
|
||||||
requestAnimationFrame(CSSRandom)
|
requestAnimationFrame(CSSRandom)
|
||||||
})()
|
})()
|
||||||
|
|
||||||
|
export {}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
/** @module FormDataDeep */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage: `Array<HTMLElement>.filter(removeChildren)`
|
||||||
|
*
|
||||||
|
* Removes elements from the array which are children of other elements in the array.
|
||||||
|
*/
|
||||||
|
export function removeChildren(element, index, array) {
|
||||||
|
for (const sibling of array) {
|
||||||
|
if (!sibling.isSameNode(element) && sibling.contains(element)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Appends a new value onto an existing key inside an object, or adds the key if it does not already exist.
|
||||||
|
* @param {Object} object
|
||||||
|
* @param {String} name
|
||||||
|
* @param {*} value
|
||||||
|
*/
|
||||||
|
export function append(object, name, value) {
|
||||||
|
if (name in object) {
|
||||||
|
if (object[name] instanceof Array) {
|
||||||
|
object[name].push(value)
|
||||||
|
} else {
|
||||||
|
object[name] = [object[name], value]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
object[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get `form` data as an object, including nested forms.
|
||||||
|
* @param {HTMLFormElement} form
|
||||||
|
* @param {Boolean} primitives whether to convert string values to primitives. Defaults `false`.
|
||||||
|
*/
|
||||||
|
export function getFormDataDeep(form, primitives = false) {
|
||||||
|
const formDataDeep = {}
|
||||||
|
const formData = new FormData(form)
|
||||||
|
for (const name of formData.keys()) {
|
||||||
|
const value: any = formData.getAll(name)
|
||||||
|
if (value.length == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (primitives) {
|
||||||
|
for (let i = 0; i < value.length; i++) {
|
||||||
|
if (!isNaN(+value[i])) {
|
||||||
|
value[i] = +value[i]
|
||||||
|
}
|
||||||
|
if (value[i] == 'on') {
|
||||||
|
value[i] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value.length == 1) {
|
||||||
|
formDataDeep[name] = value[0]
|
||||||
|
} else {
|
||||||
|
formDataDeep[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const child of [...form.querySelectorAll('form')].filter(removeChildren)) {
|
||||||
|
const value = getFormDataDeep(child, primitives)
|
||||||
|
if (Object.keys(value).length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const name = child.name
|
||||||
|
append(formDataDeep, name, value)
|
||||||
|
}
|
||||||
|
return formDataDeep
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Convenience class to have a similar interface to FormData
|
||||||
|
*/
|
||||||
|
export class FormDataDeep implements FormData {
|
||||||
|
#formdatadeep:{[key:string]: any} = {}
|
||||||
|
/**
|
||||||
|
* Get `form` data as an object, including nested forms.
|
||||||
|
* @param {HTMLFormElement | Object} form the root form element, or a JSON Object containing form data.
|
||||||
|
* @param {Boolean} primitives whether to convert string values to primitives. Defaults `false`.
|
||||||
|
*/
|
||||||
|
constructor(form, primitives = false) {
|
||||||
|
if (form instanceof HTMLFormElement) {
|
||||||
|
Object.assign(this.#formdatadeep, getFormDataDeep(form, primitives))
|
||||||
|
} else {
|
||||||
|
Object.assign(this.#formdatadeep, form)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forEach(callbackfn: (value: FormDataEntryValue, key: string, parent: FormData) => void, thisArg: any=this): void {
|
||||||
|
for (const [key,value] of thisArg.entries()) {
|
||||||
|
callbackfn(value,key,thisArg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Symbol.iterator](): FormDataIterator<[string, FormDataEntryValue]> {
|
||||||
|
return this.entries()
|
||||||
|
}
|
||||||
|
append(name, value, filename = undefined) {
|
||||||
|
if (filename !== undefined) {
|
||||||
|
value = new File([value], filename)
|
||||||
|
}
|
||||||
|
append(this.#formdatadeep, name, value)
|
||||||
|
}
|
||||||
|
delete(name) {
|
||||||
|
delete this.#formdatadeep[name]
|
||||||
|
}
|
||||||
|
entries() {
|
||||||
|
return Object.entries(this.#formdatadeep)[Symbol.iterator]()
|
||||||
|
}
|
||||||
|
get(name) {
|
||||||
|
if (this.#formdatadeep[name] instanceof Array) {
|
||||||
|
return this.#formdatadeep[name].at(-1)
|
||||||
|
} else {
|
||||||
|
return this.#formdatadeep[name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getAll(name) {
|
||||||
|
if (this.#formdatadeep[name] instanceof Array) {
|
||||||
|
return this.#formdatadeep[name]
|
||||||
|
} else {
|
||||||
|
return [this.#formdatadeep[name]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has(name) {
|
||||||
|
return name in this.#formdatadeep
|
||||||
|
}
|
||||||
|
keys() {
|
||||||
|
return Object.keys(this.#formdatadeep)[Symbol.iterator]()
|
||||||
|
}
|
||||||
|
set(name, value, filename = undefined) {
|
||||||
|
if (filename !== undefined) {
|
||||||
|
value = new File([value], filename)
|
||||||
|
}
|
||||||
|
this.#formdatadeep[name] = value
|
||||||
|
}
|
||||||
|
values() {
|
||||||
|
return Object.values(this.#formdatadeep)[Symbol.iterator]()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Applies the values in this object to the target form.
|
||||||
|
* @param {HTMLFormElement} form
|
||||||
|
*/
|
||||||
|
apply(form) {
|
||||||
|
for (const element of form.elements) {
|
||||||
|
const name = element.name
|
||||||
|
if (!(name in this.#formdatadeep)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let value
|
||||||
|
if (this.#formdatadeep[name] instanceof Array) {
|
||||||
|
value = this.#formdatadeep[name].shift()
|
||||||
|
} else {
|
||||||
|
value = this.#formdatadeep[name]
|
||||||
|
delete this.#formdatadeep[name]
|
||||||
|
}
|
||||||
|
switch (element.type) {
|
||||||
|
case 'radio':
|
||||||
|
case 'checkbox': {
|
||||||
|
element.checked = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
element.value = value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const child of [...form.querySelectorAll('form')].filter(removeChildren)) {
|
||||||
|
const name = child.name
|
||||||
|
if (!(name in this.#formdatadeep)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
new FormDataDeep(this.#formdatadeep[name]).apply(form)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormDataDeep
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
export async function forAsync<T, U>(iterable: Iterable<T> | AsyncIterable<T>, callback: (value: T) => Promise<U> | U): Promise<Array<U>> {
|
||||||
|
const promises: Array<Promise<U> | U> = []
|
||||||
|
for await (const iterableValue of iterable) {
|
||||||
|
promises.push(callback(iterableValue))
|
||||||
|
}
|
||||||
|
return Promise.all(promises)
|
||||||
|
}
|
||||||
@@ -3,3 +3,4 @@ export * as CSSRandom from './CSSRandom'
|
|||||||
export { FileReaderAsync } from './FileReaderAsync'
|
export { FileReaderAsync } from './FileReaderAsync'
|
||||||
export { fontScale } from './fontScale'
|
export { fontScale } from './fontScale'
|
||||||
export { FormDataDeep, getFormDataDeep } from './FormDataDeep'
|
export { FormDataDeep, getFormDataDeep } from './FormDataDeep'
|
||||||
|
export { forAsync } from './forAsync'
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2022",
|
||||||
|
"module": "es2022",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "dist"
|
||||||
|
},
|
||||||
|
"include": ["src/index.ts"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user