Skip to content
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
1 change: 1 addition & 0 deletions src/demo/js/options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const editorOptions = {
sessionStorage: true,
editPanelOrder: ['attrs', 'options'],
// controlOnLeft: true,
// onLoad: () => {},
}

export const renderOptions = {
Expand Down
74 changes: 51 additions & 23 deletions src/lib/js/components/autocomplete.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import { toTitleCase } from '../common/utils/string.mjs'
const BASE_NAME = 'f-autocomplete'
const HIGHLIGHT_CLASS_NAME = 'highlight-component'

let lastCache = Date.now()
let optionsCache

/**
* Counts the number of occurences of a string in an array of strings
* @param {Array} arr labels
Expand Down Expand Up @@ -93,6 +90,14 @@ export const componentOptions = selectedId => {
* Output an autocomplete form element
*/
export default class Autocomplete {
lastCache = Date.now()
optionsCache = null
/**
* Create an Autocomplete instance
* @param {String} key - The key for the autocomplete instance
* @param {String} value - The initial value for the autocomplete input
* @param {String} i18nKey - The internationalization key for the autocomplete
*/
constructor(key, value, i18nKey) {
this.key = key
this.className = key.replace(/\./g, '-')
Expand Down Expand Up @@ -195,6 +200,8 @@ export default class Autocomplete {

this.hiddenField.value = value
this.value = value

this.setValue({ dataset: { label: value, value } })
},
}

Expand All @@ -220,16 +227,16 @@ export default class Autocomplete {
})

this.dom = dom.create({
children: [this.displayField, this.hiddenField, this.list],
children: [this.displayField, this.hiddenField],
className: this.className,
action: {
onRender: () => {
onRender: element => {
this.stage = element.closest('.formeo-stage')
const component = this.value && Components.getAddress(this.value)
this.label = component && getComponentLabel(component)
if (this.label) {
this.displayField.value = this.label
}
this.updateOptions()
},
},
})
Expand All @@ -238,16 +245,17 @@ export default class Autocomplete {
}

updateOptions() {
let options = this.optionsCache
const now = Date.now()
if (now - lastCache > ANIMATION_SPEED_SLOW) {

if (!options || now - this.lastCache > ANIMATION_SPEED_SLOW * 10) {
dom.empty(this.list)
this.generateOptions()
lastCache = now
options = this.generateOptions()
this.lastCache = now
}
const options = optionsCache || this.generateOptions()

for (const option of options) {
this.list.appendChild(option)
if (!this.list.children.length) {
this.list.append(...options)
}
}

Expand All @@ -261,7 +269,7 @@ export default class Autocomplete {
return target
}

optionsCache = options.map(optionData => {
this.optionsCache = options.map(optionData => {
const { value, textLabel, htmlLabel } = optionData
const optionConfig = {
tag: 'li',
Expand All @@ -288,16 +296,20 @@ export default class Autocomplete {
return dom.create(optionConfig)
})

return optionsCache
return this.optionsCache
}

/**
* Hides autocomplete list and deselects all the options
* @param {Object} list - list of autocomplete options
*/
hideList(list = this.list) {
animate.slideUp(list, ANIMATION_SPEED_FAST)
this.removeHighlight()
setListPosition() {
const { offsetHeight, offsetWidth } = this.displayField
const containerRect = this.displayField.closest('.formeo-stage').getBoundingClientRect()
const triggerRect = this.displayField.getBoundingClientRect()
const listStyle = {
position: 'absolute',
top: `${triggerRect.y + offsetHeight + window.scrollY - containerRect.y}px`,
left: `${triggerRect.x + window.scrollX - containerRect.x}px`,
width: `${offsetWidth + 1}px`,
}
Object.assign(this.list.style, listStyle)
}

/**
Expand All @@ -306,18 +318,34 @@ export default class Autocomplete {
* @param {Object} selectedOption - option to be selected
*/
showList(selectedOption, list = this.list) {
if (!this.stage.contains(this.list)) {
this.stage.appendChild(this.list)
}
this.setListPosition()
this.selectOption(selectedOption)
animate.slideDown(list, ANIMATION_SPEED_FAST)
}

/**
* Hides autocomplete list and deselects all the options
* @param {Object} list - list of autocomplete options
*/
hideList(list = this.list) {
animate.slideUp(list, ANIMATION_SPEED_FAST)
this.removeHighlight()
if (this.stage.contains(this.list)) {
this.stage.removeChild(this.list)
}
}

/**
* Returns first option from autocomplete list with 'active-option' class
* @param {Object} list - list of autocomplete options
* @return {Object} first list option with 'active-option' class
*/
getActiveOption(list = this.list) {
const activeOption = list.getElementsByClassName('active-option')[0]
if (activeOption && activeOption.style.display !== 'none') {
const activeOption = list.querySelector('.active-option')
if (activeOption?.style.display !== 'none') {
return activeOption
}
return null
Expand Down
7 changes: 3 additions & 4 deletions src/lib/js/components/fields/edit-panel-item.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ export default class EditPanelItem {
}

const conditionChangeAction = ({ target }) => {
const row = target.closest('.f-condition-row')
const conditionRow = target.closest('.f-condition-row')
const regex = new RegExp(`${target.className}(?:\\S?)+`, 'gm')
row.className = row.className.replace(regex, '')
row.classList.add([target.className, target.value].filter(Boolean).join('-'))
conditionRow.className = conditionRow.className.replace(regex, '')

const evtData = {
dataPath,
value: target.value,
Expand All @@ -341,7 +341,6 @@ export default class EditPanelItem {
events.formeoUpdated(evtData)
Components.setAddress(dataPath, target.value)

const conditionRow = target.closest('.f-condition-row')
const rowIndex = indexOfNode(conditionRow)
this.processConditionUIState(this.itemFieldGroups[rowIndex])
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const defaults = {
i18n: {
location: 'https://draggable.github.io/formeo/assets/lang/',
},
onLoad: () => {},
}
},
}
10 changes: 6 additions & 4 deletions src/lib/js/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,14 @@ export class FormeoEditor {

promises.push(i18n.init({ ...this.opts.i18n, locale: window.sessionStorage?.getItem(SESSION_LOCALE_KEY) }))

const resolvedPromises = await Promise.all(promises)

if (this.opts.allowEdit) {
this.init()
promises.push(this.init())
}

const resolvedPromises = await Promise.all(promises)

this.opts.onLoad?.(this)

return resolvedPromises
}

Expand All @@ -88,7 +90,7 @@ export class FormeoEditor {
* dom elements, actions events and more.
*/
init() {
Controls.init(this.opts.controls, this.opts.stickyControls).then(controls => {
return Controls.init(this.opts.controls, this.opts.stickyControls).then(controls => {
this.controls = controls
this.load(this.userFormData, this.opts)
this.formId = Components.get('id')
Expand Down
4 changes: 0 additions & 4 deletions src/lib/sass/components/_field-edit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@
list-style: decimal;
}

.active-panel {
background-color: color.$white;
}

.field-prop {
display: flex;
}
Expand Down
4 changes: 0 additions & 4 deletions src/lib/sass/components/_panels.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,6 @@
}
}

.f-panel {
background-color: color.$white;
}

.panel-labels {
div {
flex-direction: row;
Expand Down