Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: setData working intermittently #1201

Merged
merged 1 commit into from
Jun 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/demo/js/actionButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ export const builderActions = {
console.log($('.build-wrap').formBuilder('getData'))
},
setData: () => {
const { value } = document.getElementById('set-form-data-value')
window.sessionStorage.setItem('formData', value)
$('.build-wrap').formBuilder('setData', value)
const fb = $('.build-wrap').formBuilder
const dataInput = fb('markup', 'textarea', fb('getData', 'json', true), {
id: 'setData-value',
rows: 30,
style: 'width: 100%',
})
const click = () => $('.build-wrap').formBuilder('setData', dataInput.value)
const setDataButton = fb('markup', 'button', 'Set Data', { events: { click } })
const dialogContents = fb('markup', 'div', [dataInput, setDataButton])
fb('showDialog', dialogContents, null, 'data-dialog')
},
save: () => {
$('.build-wrap').formBuilder('save')
Expand Down Expand Up @@ -67,8 +74,8 @@ export const renderActions = {
'link',
'alignleft aligncenter alignright alignjustify',
'numlist bullist outdent indent',
'preview'
].join(' | ')
'preview',
].join(' | '),
},
},
formData:
Expand Down
2 changes: 1 addition & 1 deletion src/demo/js/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ jQuery(function ($) {
demoApi.appendChild(generateActionTable(demoActions, columns))

if (formData && formData !== '[]') {
const setFormDataInputValue = document.getElementById('set-form-data-value')
const setFormDataInputValue = document.getElementById('setData-value')
if (setFormDataInputValue) {
setFormDataInputValue.value = window.JSON.stringify(JSON.parse(formData), null, ' ')
}
Expand Down
11 changes: 11 additions & 0 deletions src/demo/sass/demo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,14 @@ body {
align-items: center;
justify-content: space-between;
}

#setData-value {
background-color: transparent;
border: 0 none;
color: #fff;
padding: 0;
}

.form-builder-dialog {
overflow-y: auto;
}
92 changes: 52 additions & 40 deletions src/js/form-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import {
closest,
safename,
forceNumber,
getContentType
getContentType,
} from './utils'
import { css_prefix_text } from '../fonts/config.json'

const DEFAULT_TIMEOUT = 333

const FormBuilder = function(opts, element, $) {
const FormBuilder = function (opts, element, $) {
const formBuilder = this
const i18n = mi18n.current
const formID = `frmb-${new Date().getTime()}`
Expand Down Expand Up @@ -89,7 +89,7 @@ const FormBuilder = function(opts, element, $) {
revert: 150,
beforeStop: (evt, ui) => h.beforeStop.call(h, evt, ui),
distance: 3,
update: function(event, ui) {
update: function (event, ui) {
if (h.doCancel) {
return false
}
Expand Down Expand Up @@ -247,7 +247,7 @@ const FormBuilder = function(opts, element, $) {
formBuilder.prepFieldVars = prepFieldVars

// Parse saved XML template data
const loadFields = function(formData) {
const loadFields = function (formData) {
formData = h.getData(formData)
if (formData && formData.length) {
formData.forEach(fieldData => prepFieldVars(trimObj(fieldData)))
Expand All @@ -272,7 +272,7 @@ const FormBuilder = function(opts, element, $) {
* @param {Object} fieldData
* @return {String} field options markup
*/
const fieldOptions = function(fieldData) {
const fieldOptions = function (fieldData) {
const { type, values } = fieldData
let fieldValues
const optionActions = [m('a', mi18n.get('addOption'), { className: 'add add-opt' })]
Expand All @@ -283,7 +283,7 @@ const FormBuilder = function(opts, element, $) {
return {
selected: false,
label,
value: hyphenCase(label)
value: hyphenCase(label),
}
}

Expand All @@ -307,8 +307,9 @@ const FormBuilder = function(opts, element, $) {
const options = m(
'ol',
fieldValues.map((option, index) => {
const optionData = config.opts.onAddOption(option, {type, index, isMultiple})
return selectFieldOptions(optionData, isMultiple)}),
const optionData = config.opts.onAddOption(option, { type, index, isMultiple })
return selectFieldOptions(optionData, isMultiple)
}),
{
className: 'sortable-options',
},
Expand Down Expand Up @@ -508,7 +509,7 @@ const FormBuilder = function(opts, element, $) {
})

// Append custom attributes as defined in control plugin definition
if (typeClass.definition.hasOwnProperty('defaultAttrs')){
if (typeClass.definition.hasOwnProperty('defaultAttrs')) {
const customAttr = processTypeUserAttrs(typeClass.definition.defaultAttrs, values)
advFields.push(customAttr)
}
Expand Down Expand Up @@ -626,15 +627,15 @@ const FormBuilder = function(opts, element, $) {
}

textAttrs = Object.assign({}, attrs, textAttrs)

const textInput = (() => {
if (textAttrs.type === 'textarea') {
const textValue = textAttrs.value
delete textAttrs.value
return `<textarea ${attrString(textAttrs)}>${textValue}</textarea>`
} else {
return `<input ${attrString(textAttrs)}>`
}
if (textAttrs.type === 'textarea') {
const textValue = textAttrs.value
delete textAttrs.value
return `<textarea ${attrString(textAttrs)}>${textValue}</textarea>`
} else {
return `<input ${attrString(textAttrs)}>`
}
})()

const inputWrap = `<div class="input-wrap">${textInput}</div>`
Expand Down Expand Up @@ -674,7 +675,7 @@ const FormBuilder = function(opts, element, $) {

const label = `<label for="${selectAttrs.id}">${i18n[name]}</label>`

Object.keys(restData).forEach(function(attr) {
Object.keys(restData).forEach(function (attr) {
selectAttrs[attr] = restData[attr]
})

Expand Down Expand Up @@ -904,7 +905,7 @@ const FormBuilder = function(opts, element, $) {
}

// Append the new field to the editor
const appendNewField = function(values, isNew = true) {
const appendNewField = function (values, isNew = true) {
data.lastID = h.incrementId(data.lastID)

const type = values.type || 'text'
Expand Down Expand Up @@ -1012,26 +1013,30 @@ const FormBuilder = function(opts, element, $) {
}

// Select field html, since there may be multiple
const selectFieldOptions = function(optionData, multipleSelect) {
const selectFieldOptions = function (optionData, multipleSelect) {
const optionTemplate = { selected: false, label: '', value: '' }
const optionInputType = {
selected: multipleSelect ? 'checkbox' : 'radio',
}
const optionInputTypeMap = {
boolean: (value, prop) => {
const attrs = {value, type: optionInputType[prop] || 'checkbox'}
const attrs = { value, type: optionInputType[prop] || 'checkbox' }
if (value) {
attrs.checked = !!value
attrs.checked = !!value
}
return['input', null, attrs]
return ['input', null, attrs]
},
number: value => ['input', null, {value, type: 'number'}],
string: (value, prop) => (['input', null, {value, type: 'text', placeholder: mi18n.get(`placeholder.${prop}`) || ''}]),
array: values => ['select', values.map(({label, value}) => m('option', label, {value}))],
object: ({tag, content, ...attrs}) => [tag, content, attrs],
number: value => ['input', null, { value, type: 'number' }],
string: (value, prop) => [
'input',
null,
{ value, type: 'text', placeholder: mi18n.get(`placeholder.${prop}`) || '' },
],
array: values => ['select', values.map(({ label, value }) => m('option', label, { value }))],
object: ({ tag, content, ...attrs }) => [tag, content, attrs],
}

optionData = {...optionTemplate, ...optionData}
optionData = { ...optionTemplate, ...optionData }

const optionInputs = Object.entries(optionData).map(([prop, val]) => {
const optionInputDataType = getContentType(val)
Expand Down Expand Up @@ -1141,7 +1146,7 @@ const FormBuilder = function(opts, element, $) {
})

// toggle fields
$stage.on('click touchstart', '.toggle-form, .close-field', function(e) {
$stage.on('click touchstart', '.toggle-form, .close-field', function (e) {
e.stopPropagation()
e.preventDefault()
if (e.handled !== true) {
Expand Down Expand Up @@ -1217,7 +1222,7 @@ const FormBuilder = function(opts, element, $) {
$stage.on('keyup', 'input.error', ({ target }) => $(target).removeClass('error'))

// update preview for description
$stage.on('keyup', 'input[name="description"]', function(e) {
$stage.on('keyup', 'input[name="description"]', function (e) {
const $field = $(e.target).parents('.form-field:eq(0)')
const closestToolTip = $('.tooltip-element', $field)
const ttVal = $(e.target).val()
Expand Down Expand Up @@ -1248,7 +1253,7 @@ const FormBuilder = function(opts, element, $) {
})

// format name attribute
$stage.on('blur', 'input.fld-name', function(e) {
$stage.on('blur', 'input.fld-name', function (e) {
e.target.value = safename(e.target.value)
if (e.target.value === '') {
$(e.target).addClass('field-error').attr('placeholder', mi18n.get('cannotBeEmpty'))
Expand All @@ -1262,7 +1267,7 @@ const FormBuilder = function(opts, element, $) {
})

// Copy field
$stage.on('click touchstart', `.${css_prefix_text}copy`, function(evt) {
$stage.on('click touchstart', `.${css_prefix_text}copy`, function (evt) {
evt.preventDefault()
const currentItem = $(evt.target).parent().parent('li')
const $clone = cloneItem(currentItem)
Expand All @@ -1287,7 +1292,7 @@ const FormBuilder = function(opts, element, $) {

document.addEventListener(
'modalClosed',
function() {
function () {
$field.removeClass('deleting')
},
false,
Expand Down Expand Up @@ -1323,18 +1328,18 @@ const FormBuilder = function(opts, element, $) {
})

// Attach a callback to toggle roles visibility
$stage.on('click', 'input.fld-access', function(e) {
$stage.on('click', 'input.fld-access', function (e) {
const roles = $(e.target).closest('.form-field').find('.available-roles')
const enableRolesCB = $(e.target)
roles.slideToggle(250, function() {
roles.slideToggle(250, function () {
if (!enableRolesCB.is(':checked')) {
$('input[type=checkbox]', roles).removeAttr('checked')
}
})
})

// Attach a callback to add new options
$stage.on('click', '.add-opt', function(e) {
$stage.on('click', '.add-opt', function (e) {
e.preventDefault()
const type = $(e.target).closest('.form-field').attr('type')
const $optionWrap = $(e.target).closest('.field-options')
Expand All @@ -1350,7 +1355,11 @@ const FormBuilder = function(opts, element, $) {

const optionTemplate = { selected: false, label: '', value: '' }
const $sortableOptions = $('.sortable-options', $optionWrap)
const optionData = config.opts.onAddOption(optionTemplate, {type, index: $sortableOptions.children().length, isMultiple})
const optionData = config.opts.onAddOption(optionTemplate, {
type,
index: $sortableOptions.children().length,
isMultiple,
})
$sortableOptions.append(selectFieldOptions(optionData, isMultiple))
})

Expand Down Expand Up @@ -1394,6 +1403,7 @@ const FormBuilder = function(opts, element, $) {
h.formActionButtons().forEach(button => d.formActions.appendChild(button))
})
},
showDialog: h.dialog.bind(h),
toggleFieldEdit: fieldId => {
const fieldIds = Array.isArray(fieldId) ? fieldId : [fieldId]
fieldIds.forEach(fId => {
Expand Down Expand Up @@ -1452,21 +1462,23 @@ const methods = {
setData: null,
setLang: null,
showData: null,
showDialog: null,
toggleAllFieldEdit: null,
toggleFieldEdit: null,
getCurrentFieldId: null,
},
markup,
get formData() {
return methods.instance.actions.getData && methods.instance.actions.getData('json')
},
promise: new Promise(function(resolve, reject) {
promise: new Promise(function (resolve, reject) {
mi18n
.init(i18nOpts)
.then(() => {
elems.each(i => {
const formBuilder = new FormBuilder(opts, elems[i], jQuery)
jQuery(elems[i]).data('formBuilder', formBuilder)
Object.assign(methods, formBuilder.actions)
Object.assign(methods, formBuilder.actions, { markup })
methods.instance.actions = formBuilder.actions
})
delete methods.instance.promise
Expand All @@ -1483,7 +1495,7 @@ const methods = {
},
}

jQuery.fn.formBuilder = function(methodOrOptions = {}, ...args) {
jQuery.fn.formBuilder = function (methodOrOptions = {}, ...args) {
const isMethod = typeof methodOrOptions === 'string'
if (isMethod) {
if (methods[methodOrOptions]) {
Expand Down
24 changes: 7 additions & 17 deletions src/js/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,11 @@ export default class Helpers {
i18n.clearAllMessage,
() => {
_this.removeAllFields.call(_this, stage)
config.opts.notify.success(i18n.allFieldsRemoved)
if (config.opts.persistDefaultFields && config.opts.defaultFields) {
this.addDefaultFields()
} else {
config.opts.notify.success(i18n.allFieldsRemoved)
}
config.opts.onClearAll()
},
coords,
Expand All @@ -669,7 +673,7 @@ export default class Helpers {
* @param {Boolean} animate whether to animate or not
* @return {void}
*/
removeAllFields(stage, animate = true) {
removeAllFields(stage) {
const i18n = mi18n.current
const opts = config.opts
const fields = stage.querySelectorAll('li.form-field')
Expand All @@ -692,26 +696,12 @@ export default class Helpers {
stage.dataset.content = i18n.getStarted
}

if (animate) {
stage.classList.add('removing')
let outerHeight = 0
forEach(fields, index => (outerHeight += fields[index].offsetHeight + 3))
fields[0].style.marginTop = `${-outerHeight}px`
}

const animationTimeout = animate ? 400 : 0
const animateTimeout = setTimeout(() => {
this.emptyStage(stage)
clearTimeout(animateTimeout)
}, animationTimeout)
this.emptyStage(stage)
}

emptyStage(stage) {
empty(stage).classList.remove('removing')
this.save()
if (config.opts.persistDefaultFields) {
this.addDefaultFields()
}
}

/**
Expand Down