Add group select
This commit is contained in:
parent
9bdd1447ad
commit
307796dfcb
|
@ -8,8 +8,8 @@
|
||||||
<body style="padding: 50px">
|
<body style="padding: 50px">
|
||||||
<event-form
|
<event-form
|
||||||
style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)"
|
style="--primary: hsl(181, 75%, 26%); --secondary: hsl(181, 75%, 35%); --font: hsl(181, 84%, 78%); --circle: hsl(181, 86%, 16%)"
|
||||||
fields='[{"id":"TextField","name":"Text","default":{"name":"","type":"TextField","columns":{"mobile":2,"tablet":4,"desktop":12},"default":"","required":false}}]'
|
value='{"sections":[{"name":"ff","intro":"ff","fields":[{"name":"sdsdsd","type":"CheckboxField","columns":{"mobile":2,"tablet":4,"desktop":6},"default":false,"required":true,"description":"sds","key":"sdsdsd"},{"name":"Bezirk","type":"GroupField","columns":{"mobile":2,"tablet":4,"desktop":6},"default":"","required":true,"parent_field":null,"parent_group":120,"key":"bezirk"},{"name":"Stamm","type":"GroupField","columns":{"mobile":2,"tablet":4,"desktop":6},"default":"","required":true,"parent_field":"bezirk","parent_group":null,"key":"stamm"}]}]}'
|
||||||
value='{"sections":[{"name":"a","fields":[{"name":"test","type":"CheckboxesField","columns":{"mobile":2,"tablet":4,"desktop":6},"default":[],"required":false,"options":["a","b"],"key":"test"},{"name":"eee","type":"CheckboxField","columns":{"mobile":2,"tablet":4,"desktop":5},"default":false,"required":true,"description":"test","key":"eee"},{"name":"dd","type":"DropdownField","columns":{"mobile":1,"tablet":2,"desktop":4},"default":null,"required":true,"options":["a","b","c"],"key":"dd"},{"name":"aaaa","type":"RadioField","columns":{"mobile":2,"tablet":4,"desktop":6},"default":null,"required":true,"options":["a","d"],"key":"aaaa"},{"name":"assa","type":"TextareaField","columns":{"mobile":2,"tablet":4,"desktop":6},"default":null,"required":true,"rows":5,"key":"assa"}]}]}'
|
base-url="http://localhost:8000"
|
||||||
editable
|
editable
|
||||||
></event-form>
|
></event-form>
|
||||||
<script type="module" src="src/main.js"></script>
|
<script type="module" src="src/main.js"></script>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/container-queries": "^0.1.1",
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
"@vitejs/plugin-vue": "^4.5.2",
|
"@vitejs/plugin-vue": "^4.5.2",
|
||||||
"change-case": "^5.3.0",
|
"axios": "^1.6.3",
|
||||||
"vite": "^5.0.8",
|
"vite": "^5.0.8",
|
||||||
"vue3-carousel": "^0.3.1"
|
"vue3-carousel": "^0.3.1"
|
||||||
}
|
}
|
||||||
|
@ -875,6 +875,23 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz",
|
||||||
|
"integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
@ -925,12 +942,6 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/change-case": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/change-case/-/change-case-5.3.0.tgz",
|
|
||||||
"integrity": "sha512-Eykca0fGS/xYlx2fG5NqnGSnsWauhSGiSXYhB1kO6E909GUfo8S54u4UZNS7lMJmgZumZ2SUpWaoLgAcfQRICg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
|
@ -992,6 +1003,18 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||||
|
@ -1035,6 +1058,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/didyoumean": {
|
"node_modules/didyoumean": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
|
@ -1159,6 +1191,26 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/foreground-child": {
|
"node_modules/foreground-child": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
||||||
|
@ -1176,6 +1228,20 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
@ -1416,6 +1482,27 @@
|
||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "9.0.3",
|
"version": "9.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||||
|
@ -1725,6 +1812,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"@tailwindcss/container-queries": "^0.1.1",
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
"@vitejs/plugin-vue": "^4.5.2",
|
"@vitejs/plugin-vue": "^4.5.2",
|
||||||
"vite": "^5.0.8",
|
"vite": "^5.0.8",
|
||||||
"vue3-carousel": "^0.3.1"
|
"vue3-carousel": "^0.3.1",
|
||||||
|
"axios": "^1.6.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@
|
||||||
[colClasses.desktop[field.columns.desktop]]: true,
|
[colClasses.desktop[field.columns.desktop]]: true,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<component :is="resolveComponentName(field)" v-model="payload[field.key]" :field="field"></component>
|
<component :is="resolveComponentName(field)" v-model="payload[field.key]" :payload="payload" :field="field"></component>
|
||||||
<div v-if="editable" class="right-0 top-0 -mr-2 -mt-2 absolute hidden space-x-2 group-hover:flex">
|
<div v-if="editable" class="right-0 top-0 -mr-2 -mt-2 absolute hidden space-x-2 group-hover:flex">
|
||||||
<a href="#" class="bg-edit rounded-full flex w-5 h-5 items-center justify-center text-font ml-2" @click.prevent.stop="$emit('editField', index, findex)">
|
<a href="#" class="bg-edit rounded-full flex w-5 h-5 items-center justify-center text-font ml-2" @click.prevent.stop="$emit('editField', index, findex)">
|
||||||
<edit-icon class="w-3 h-3 fill-current"></edit-icon>
|
<edit-icon class="w-3 h-3 fill-current"></edit-icon>
|
||||||
|
@ -137,6 +137,7 @@ import FieldText from './components/fields/Text.vue';
|
||||||
import FieldDate from './components/fields/Date.vue';
|
import FieldDate from './components/fields/Date.vue';
|
||||||
import FieldTextarea from './components/fields/Textarea.vue';
|
import FieldTextarea from './components/fields/Textarea.vue';
|
||||||
import FieldDropdown from './components/fields/Dropdown.vue';
|
import FieldDropdown from './components/fields/Dropdown.vue';
|
||||||
|
import FieldGroup from './components/fields/Group.vue';
|
||||||
import FieldCheckboxes from './components/fields/Checkboxes.vue';
|
import FieldCheckboxes from './components/fields/Checkboxes.vue';
|
||||||
import FieldCheckbox from './components/fields/Checkbox.vue';
|
import FieldCheckbox from './components/fields/Checkbox.vue';
|
||||||
import FieldRadio from './components/fields/Radio.vue';
|
import FieldRadio from './components/fields/Radio.vue';
|
||||||
|
@ -184,9 +185,11 @@ const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: () => '{}',
|
default: () => '{}',
|
||||||
},
|
},
|
||||||
fields: {},
|
baseUrl: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
axios.defaults.baseURL = props.baseUrl;
|
||||||
|
|
||||||
const active = ref(0);
|
const active = ref(0);
|
||||||
const payload = ref({});
|
const payload = ref({});
|
||||||
const loaded = ref(false);
|
const loaded = ref(false);
|
||||||
|
@ -211,7 +214,6 @@ const v = computed(() => {
|
||||||
emits('active', values.sections.length ? active.value : null);
|
emits('active', values.sections.length ? active.value : null);
|
||||||
return values;
|
return values;
|
||||||
});
|
});
|
||||||
const f = computed(() => JSON.parse(props.fields));
|
|
||||||
|
|
||||||
const {back, next, backable, nextable} = useNav(active, v.value.sections.length);
|
const {back, next, backable, nextable} = useNav(active, v.value.sections.length);
|
||||||
|
|
||||||
|
@ -221,6 +223,7 @@ function resolveComponentName(field) {
|
||||||
DateField: FieldDate,
|
DateField: FieldDate,
|
||||||
TextareaField: FieldTextarea,
|
TextareaField: FieldTextarea,
|
||||||
DropdownField: FieldDropdown,
|
DropdownField: FieldDropdown,
|
||||||
|
GroupField: FieldGroup,
|
||||||
RadioField: FieldRadio,
|
RadioField: FieldRadio,
|
||||||
CheckboxesField: FieldCheckboxes,
|
CheckboxesField: FieldCheckboxes,
|
||||||
CheckboxField: FieldCheckbox,
|
CheckboxField: FieldCheckbox,
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
<template>
|
||||||
|
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex" :for="field.key">
|
||||||
|
<select
|
||||||
|
:id="field.key"
|
||||||
|
v-model="inner"
|
||||||
|
:disabled="disabled"
|
||||||
|
:name="field.key"
|
||||||
|
class="bg-white rounded-lg focus:outline-none text-gray-600 text-left peer py-1 px-2 @sm:py-2 text-sm @sm:text-base @sm:px-3 w-full"
|
||||||
|
>
|
||||||
|
<option :value="null">-- kein --</option>
|
||||||
|
<option v-for="(option, index) in options" :key="index" :value="option.id" v-text="option.name"></option>
|
||||||
|
</select>
|
||||||
|
<field-label :name="field.name" :required="field.required"></field-label>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref, watch} from 'vue';
|
||||||
|
import FieldLabel from '../FieldLabel.vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
required: true,
|
||||||
|
validator: (value) => value === null || typeof value === 'string' || typeof value === 'number',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
required: true,
|
||||||
|
validator: (value) =>
|
||||||
|
hasKeys(value, ['required', 'type', 'key', 'columns', 'name', 'default', 'parent_field', 'parent_group']) &&
|
||||||
|
typeof value.required === 'boolean' &&
|
||||||
|
typeof value.key === 'string' &&
|
||||||
|
value.key.length > 0 &&
|
||||||
|
typeof value.name === 'string' &&
|
||||||
|
value.name.length > 0 &&
|
||||||
|
hasKeys(value.columns, ['mobile', 'desktop', 'tablet']),
|
||||||
|
},
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const inner = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (v) => emit('update:modelValue', v),
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = ref([]);
|
||||||
|
const disabled = ref(false);
|
||||||
|
|
||||||
|
async function refreshOptions() {
|
||||||
|
if (props.field.parent_group !== null) {
|
||||||
|
emit('update:modelValue', null);
|
||||||
|
options.value = (await axios.get('/api/group/' + props.field.parent_group)).data.data;
|
||||||
|
disabled.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.field.parent_field !== null && props.field.parent_field in props.payload && !props.payload[props.field.parent_field]) {
|
||||||
|
options.value = [];
|
||||||
|
emit('update:modelValue', null);
|
||||||
|
disabled.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.field.parent_field !== null && props.field.parent_field in props.payload && props.payload[props.field.parent_field]) {
|
||||||
|
emit('update:modelValue', null);
|
||||||
|
options.value = (await axios.get('/api/group/' + props.payload[props.field.parent_field])).data.data;
|
||||||
|
disabled.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshOptions();
|
||||||
|
|
||||||
|
if (props.field.parent_field) {
|
||||||
|
watch(
|
||||||
|
() => props.payload[props.field.parent_field],
|
||||||
|
function (oldValue, newValue) {
|
||||||
|
if (oldValue !== newValue) {
|
||||||
|
refreshOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1 @@
|
||||||
|
export default {};
|
|
@ -4,6 +4,9 @@ import carousel from 'vue3-carousel/dist/carousel.css?inline';
|
||||||
import carouselStyle from './carousel.css?inline';
|
import carouselStyle from './carousel.css?inline';
|
||||||
import Navigation from './components/Navigation.vue';
|
import Navigation from './components/Navigation.vue';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
window.axios = axios;
|
||||||
|
|
||||||
window.hasKeys = function (object, expected) {
|
window.hasKeys = function (object, expected) {
|
||||||
return typeof object === 'object' && JSON.stringify(Object.keys(object).sort()) === JSON.stringify(expected.sort());
|
return typeof object === 'object' && JSON.stringify(Object.keys(object).sort()) === JSON.stringify(expected.sort());
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue