Skip to content

Commit

Permalink
Merge pull request #1447 from lucasnetau/wildcardUserAttr
Browse files Browse the repository at this point in the history
feat: Support typeUserAttrs and typeUserEvents for all types with a wildcard config key
  • Loading branch information
kevinchappell authored Oct 14, 2023
2 parents 977a9b2 + ac0dcf3 commit 9f60a45
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 9 deletions.
12 changes: 12 additions & 0 deletions docs/formBuilder/options/typeUserAttrs.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,17 @@ const typeUserAttrs = {
};
```

## Example Input for all types
```javascript
const typeUserAttrs = {
'*': {
title: {
label: 'Title',
value: 'Field Title',
}
}
};
```

### Usage
<p data-height="525" data-embed-version="2" data-theme-id="22927" data-slug-hash="yaJbZZ" data-default-tab="js,result" data-user="kevinchappell" class="codepen"></p>
9 changes: 9 additions & 0 deletions docs/formBuilder/options/typeUserEvents.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# typeUserEvents
Add functionality to existing and custom attributes using `onclone` and `onadd` events. Events return JavaScript DOM elements.

For all types the wildcard type **_*_** exists.

`onremove` event exists for removal events

## Usage
```javascript
var options = {
Expand All @@ -14,6 +18,11 @@ var options = {
}
},
typeUserEvents: {
'*': {
onclone: (fld) => {
console.log('field cloned');
}
},
text: {
onadd: function(fld) {
var $patternField = $('.fld-pattern', fld);
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@
"jest": {
"collectCoverage": true,
"coverageDirectory": ".jest/coverage",
"coveragePathIgnorePatterns": [ "tests/" ],
"testEnvironment": "jsdom",
"setupFiles": [
"./tests/setup-jest.js"
Expand Down
14 changes: 10 additions & 4 deletions src/js/form-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ function FormBuilder(opts, element, $) {

const noDisable = ['name', 'className']

const typeUserAttrs = Object.assign({}, opts.typeUserAttrs['*'], opts.typeUserAttrs[type])

Object.keys(fieldAttrs).forEach(index => {
const attr = fieldAttrs[index]
const useDefaultAttr = [true]
Expand All @@ -624,8 +626,8 @@ function FormBuilder(opts, element, $) {
useDefaultAttr.push(!userAttrs.includes(attr))
}

if (opts.typeUserAttrs[type]) {
const userAttrs = Object.keys(opts.typeUserAttrs[type])
if (typeUserAttrs) {
const userAttrs = Object.keys(typeUserAttrs)
useDefaultAttr.push(!userAttrs.includes(attr))
}

Expand All @@ -645,8 +647,8 @@ function FormBuilder(opts, element, $) {
}

// Append custom attributes as defined in typeUserAttrs option
if (opts.typeUserAttrs[type]) {
const customAttr = processTypeUserAttrs(opts.typeUserAttrs[type], values)
if (typeUserAttrs) {
const customAttr = processTypeUserAttrs(typeUserAttrs, values)
advFields.push(customAttr)
}

Expand Down Expand Up @@ -1225,6 +1227,8 @@ function FormBuilder(opts, element, $) {

if (opts.typeUserEvents[type] && opts.typeUserEvents[type].onadd) {
opts.typeUserEvents[type].onadd(field)
} else if (opts.typeUserEvents['*'] && opts.typeUserEvents['*'].onadd) {
opts.typeUserEvents['*'].onadd(field)
}

if (isNew) {
Expand Down Expand Up @@ -1611,6 +1615,8 @@ function FormBuilder(opts, element, $) {

if (opts.typeUserEvents[type] && opts.typeUserEvents[type].onclone) {
opts.typeUserEvents[type].onclone($clone[0])
} else if (opts.typeUserEvents['*'] && opts.typeUserEvents['*'].onclone) {
opts.typeUserEvents['*'].onclone($clone[0])
}

return $clone
Expand Down
6 changes: 3 additions & 3 deletions src/js/form-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ class FormRender {
},
templates: {}, // custom inline defined templates
notify: {
error: error => {
error: /* istanbul ignore next */ error => {
console.log(error)
},
success: success => {
success: /* istanbul ignore next */ success => {
console.log(success)
},
warning: warning => {
warning: /* istanbul ignore next */ warning => {
console.warn(warning)
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/js/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ export default class Helpers {
}
})

const userEvents = config.opts.typeUserEvents[field.type]
const userEvents = Object.assign({}, config.opts.typeUserEvents['*'], config.opts.typeUserEvents[field.type])

if (userEvents && userEvents.onremove) {
userEvents.onremove(field)
Expand Down
128 changes: 127 additions & 1 deletion tests/form-builder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,74 @@ describe('FormBuilder Add/Remove from Stage', () => {
fb.actions.clearFields() //Test no error on empty stage
expect($('.frmb.stage-wrap li', fbWrap).length).toBe(0)
})

test('typeUserEvents onadd called for wildcard', async () => {
const fbWrap = $('<div>')
const cb = jest.fn()
const fb = await $(fbWrap).formBuilder({
typeUserEvents: {
'*': {
onadd: cb,
},
},
}).promise
const field = {
type: 'text',
class: 'form-control',
name: 'on-add-test'
}
fb.actions.addField(field)
expect(cb.mock.calls).toHaveLength(1)
expect(cb.mock.calls[0]).toHaveLength(1)
expect(typeof cb.mock.calls[0][0]).toBe('object')
})

test('typeUserEvents onadd called for type', async () => {
const fbWrap = $('<div>')
const cb = jest.fn()
const fb = await $(fbWrap).formBuilder({
typeUserEvents: {
'text': {
onadd: cb,
},
},
}).promise
const field = {
type: 'text',
class: 'form-control',
name: 'on-add-test'
}
fb.actions.addField(field)
expect(cb.mock.calls).toHaveLength(1)
expect(cb.mock.calls[0]).toHaveLength(1)
expect(typeof cb.mock.calls[0][0]).toBe('object')
})

test('typeUserEvents onadd called for type when wildcard and type keys exist', async () => {
const fbWrap = $('<div>')
const cbType = jest.fn()
const cbWildcard = jest.fn()
const fb = await $(fbWrap).formBuilder({
typeUserEvents: {
'*': {
onadd: cbWildcard,
},
'text': {
onadd: cbType,
},
},
}).promise
const field = {
type: 'text',
class: 'form-control',
name: 'on-add-test'
}
fb.actions.addField(field)
expect(cbType.mock.calls).toHaveLength(1)
expect(cbType.mock.calls[0]).toHaveLength(1)
expect(typeof cbType.mock.calls[0][0]).toBe('object')
expect(cbWildcard.mock.calls).toHaveLength(0)
})
})

describe('FormBuilder can add all default fields via clicking on control panel', () => {
Expand Down Expand Up @@ -131,7 +199,7 @@ describe('FormBuilder stage names translated', () => {
})
})

describe('FormBuilder userAttrType detection', () => {
describe('FormBuilder typeUserAttrs detection', () => {
test('renders text/string user attribute', async () => {
const config = {
typeUserAttrs: {
Expand Down Expand Up @@ -207,6 +275,64 @@ describe('FormBuilder userAttrType detection', () => {
expect(input.length).toBe(1)
expect(input[0].options.length).toBe(2)
})
test('renders text/string user attribute when set by wildcard', async () => {
const config = {
typeUserAttrs: {
'*': {
testAttribute: {
label: 'test',
value: '',
},
},
},
}
const fbWrap = $('<div>')
const fb = await fbWrap.formBuilder(config).promise
fb.actions.addField({ type: 'text'})
let input = fbWrap.find('.text-field .testAttribute-wrap input')
expect(input.attr('type')).toBe('text')
expect(input.val()).toBe('')
fb.actions.addField({ type: 'button'})
input = fbWrap.find('.button-field .testAttribute-wrap input')
expect(input.attr('type')).toBe('text')
expect(input.val()).toBe('')
})
test('user attribute definition by type takes precedence over wildcard definition', async () => {
const config = {
typeUserAttrs: {
'*': {
testAttribute: {
label: 'test',
value: '',
},
},
button: {
testAttribute: {
label: 'override',
value: 'buttonOverride',
},
},
},
}
const fbWrap = $('<div>')
const fb = await fbWrap.formBuilder(config).promise
fb.actions.addField({ type: 'text'})
let input = fbWrap.find('.text-field .testAttribute-wrap input')
expect(input.attr('type')).toBe('text')
expect(input.val()).toBe('')

input = fbWrap.find('.text-field .testAttribute-wrap label')
expect(input.text()).toBe('test')

fb.actions.addField({ type: 'button'})
input = fbWrap.find('.button-field .testAttribute-wrap input')
console.log(input)
expect(input.attr('type')).toBe('text')
expect(input.val()).toBe('buttonOverride')

input = fbWrap.find('.button-field .testAttribute-wrap label')
expect(input.text()).toBe('override')
})
})

describe('FormBuilder can return formData', () => {
Expand Down

0 comments on commit 9f60a45

Please sign in to comment.