%PDF- %PDF-
| Direktori : /home/opti/workflow/src/public/app-assets/vendors/formBuilder-master/src/js/ |
| Current File : /home/opti/workflow/src/public/app-assets/vendors/formBuilder-master/src/js/layout.js |
// LAYOUT.JS
import utils from './utils'
/**
* Base class for controlling the layout of each 'row' on the form
* Can be extended & customised with the new object being passed to FormRender as the new layout object
* Controls things like the label, help text, and how they fit together with the control itself
*/
export default class layout {
/**
* Prepare the templates for layout
* @param {Object} templates object containing custom or overwrite templates
* @param {Boolean} preview - are we rendering a preview for the formBuilder stage
*/
constructor(templates, preview) {
this.preview = preview
// supported templates for outputting a field
// preferred layout template can be indicated by specifying a 'layout' in the return object of control::build
this.templates = {
label: null, // can be overridden with a function(labelDOMElements, data) to generate the label element - returns a DOM element
help: null, // can be overridden with a function(helpText, data) to generate the help element - returns a DOM element
default: (field, label, help, data) => {
// append help into the label
if (help) {
label.appendChild(help)
}
// wrap the output in a form-group div & return
let className = data.id ? `fb-${data.type} form-group field-${data.id}` : ''
// Lift any col- and row- type class to the form-group wrapper. The row- class denotes the row group it should go to
if(data.className){
const classes = data.className.split(' ').filter(className => (/^col-(xs|sm|md|lg)-([^\s]+)/.test(className) || className.startsWith('row-')));
if(classes && classes.length > 0){
className += ` ${classes.join(' ')}`;
// Now that the col- types were lifted, remove from the actual input field
for (let index = 0; index < classes.length; index++) {
const element = classes[index];
field.classList.remove(element)
}
}
}
return this.markup('div', [label, field], {
className: className,
})
},
noLabel: (field, label, help, data) => {
// wrap the output in a form-group div & return without a label element
const className = data.id ? `fb-${data.type} form-group field-${data.id}` : ''
return this.markup('div', field, {
className: className,
})
},
hidden: (field, label, help, data) => {
// no wrapper any any visible elements
return field
},
}
// merge in any custom templates
if (templates) {
this.templates = jQuery.extend(this.templates, templates)
}
this.configure()
}
/**
* this method is called by the constructor and should be overwritten for custom layouts that need to
* process the configuration arguments prior to rendering
*/
configure() {}
/**
* Process the configuration from an element from the standard formData array
* building the control, label and help text, and then putting them all together.
* Should support the control object returning a DOM element, or an object containing
* configuration properties:
* - field - the DOM element
* - noLabel - this control shouldn't have a label (nor a space for a label)
* - hidden - this control shouldn't render anything visible to the page
* @param {Object} renderControl - the relevant control class
* @param {Object} data - configuration data passed through formData for this control
* @param {String} forceTemplate - programatically force the template with which this control to be rendered
* @return {Object} element
*/
build(renderControl, data, forceTemplate) {
// prepare the data
if (this.preview) {
if (data.name) {
data.name = data.name + '-preview'
} else {
data.name = utils.nameAttr(data) + '-preview'
}
}
data.id = data.name
this.data = jQuery.extend({}, data)
// build the control
const control = new renderControl(data, this.preview)
let field = control.build()
if (typeof field !== 'object' || !field.field) {
field = { field: field }
}
// build the label & help text
const label = this.label()
const help = this.help()
// process the relevant layout template
let elementTemplate
if (forceTemplate && this.isTemplate(forceTemplate)) {
elementTemplate = forceTemplate
} else {
elementTemplate = this.isTemplate(field.layout) ? field.layout : 'default'
}
const element = this.processTemplate(elementTemplate, field.field, label, help)
// execute prerender events
control.on('prerender')(element)
// bind control on render events
element.addEventListener('fieldRendered', control.on('render'))
return element
}
/**
* Build a label element
* @return {Object} dom element to render the label
*/
label() {
const label = this.data.label || ''
const labelText = utils.parsedHtml(label)
const labelContents = [labelText]
if (this.data.required) {
labelContents.push(this.markup('span', '*', { className: 'fb-required' }))
}
// support an override template for labels
if (this.isTemplate('label')) {
return this.processTemplate('label', labelContents)
}
// generate a label element
return this.markup('label', labelContents, {
for: this.data.id,
className: `fb-${this.data.type}-label`,
})
}
/**
* Build a help element
* @return {Object} dom element to render the help text
*/
help() {
if (!this.data.description) {
return null
}
// support an override template for labels
if (this.isTemplate('help')) {
return this.processTemplate('help', this.data.description)
}
// generate the default help element
return this.markup('span', '?', {
className: 'tooltip-element',
tooltip: this.data.description,
})
}
/**
* Determines if a template is defined for the specified key
* @param {String} template string template key to check for
* @return {Boolean}
*/
isTemplate(template) {
return typeof this.templates[template] === 'function'
}
/**
* Process a template & prepare the results
* @param {String} template - template key to execute
* @param {Array} args - any number of args that should be passed to the template. this.data is sent as the last parameter to any template.
* @return {DOMElement}
*/
processTemplate(template, ...args) {
let processed = this.templates[template](...args, this.data)
if (processed.jquery) {
processed = processed[0]
}
return processed
}
/**
* link to the utils.markup method
* ideally this would be inherited from a parent 'dom' type element supporting dom helper type methods
* @param {String} tag
* @param {Object|String|Array} content
* @param {Object} attributes
* @return {Object} DOM element
*/
markup(tag, content = '', attributes = {}) {
return utils.markup(tag, content, attributes)
}
}