diff --git a/src/Element.js b/src/Element.js index 17c890c388..91385e9bac 100644 --- a/src/Element.js +++ b/src/Element.js @@ -75,6 +75,8 @@ export default class Element { * * @param {string} event - The event you wish to register the handler for. * @param {function} cb - The callback handler to handle this event. + * @param {boolean} [internal] - This is an internal event handler. + * @param {boolean} [once] - This event should only fire once. */ on(event, cb, internal, once = false) { if (!this.events) { diff --git a/src/WebformBuilder.js b/src/WebformBuilder.js index 857223a819..ea86442243 100644 --- a/src/WebformBuilder.js +++ b/src/WebformBuilder.js @@ -182,7 +182,7 @@ export default class WebformBuilder extends Component { return element; } // Attach container and component to element for later reference. - const containerElement = element.querySelector(`[ref="${component.component.key}-container"]`) || element; + const containerElement = element.querySelector(`[${this._referenceAttributeName}="${component.component.key}-container"]`) || element; containerElement.formioContainer = container; containerElement.formioComponent = component; @@ -1175,7 +1175,7 @@ export default class WebformBuilder extends Component { this.preview.form.components.forEach(component => this.replaceDoubleQuotes(component, fieldsToRemoveDoubleQuotes)); - const previewElement = this.componentEdit.querySelector('[ref="preview"]'); + const previewElement = this.componentEdit.querySelector(`[${this._referenceAttributeName}="preview"]`); if (previewElement) { this.setContent(previewElement, this.preview.render(), null, sanitizeConfig); this.preview.attach(previewElement); @@ -1384,7 +1384,7 @@ export default class WebformBuilder extends Component { } attachEditComponentControls(component, parent, isNew, original, ComponentClass) { - const cancelButtons = this.componentEdit.querySelectorAll('[ref="cancelButton"]'); + const cancelButtons = this.componentEdit.querySelectorAll(`[${this._referenceAttributeName}="cancelButton"]`); cancelButtons.forEach((cancelButton) => { this.editForm.addEventListener(cancelButton, 'click', (event) => { event.preventDefault(); @@ -1395,7 +1395,7 @@ export default class WebformBuilder extends Component { }); }); - const removeButtons = this.componentEdit.querySelectorAll('[ref="removeButton"]'); + const removeButtons = this.componentEdit.querySelectorAll(`[${this._referenceAttributeName}="removeButton"]`); removeButtons.forEach((removeButton) => { this.editForm.addEventListener(removeButton, 'click', (event) => { event.preventDefault(); @@ -1408,7 +1408,7 @@ export default class WebformBuilder extends Component { }); }); - const saveButtons = this.componentEdit.querySelectorAll('[ref="saveButton"]'); + const saveButtons = this.componentEdit.querySelectorAll(`[${this._referenceAttributeName}="saveButton"]`); saveButtons.forEach((saveButton) => { this.editForm.addEventListener(saveButton, 'click', (event) => { event.preventDefault(); @@ -1425,7 +1425,7 @@ export default class WebformBuilder extends Component { }); }); - const previewButtons = this.componentEdit.querySelectorAll('[ref="previewButton"]'); + const previewButtons = this.componentEdit.querySelectorAll(`[${this._referenceAttributeName}="previewButton"]`); previewButtons.forEach((previewButton) => { this.editForm.addEventListener(previewButton, 'click', (event) => { event.preventDefault(); @@ -1438,7 +1438,7 @@ export default class WebformBuilder extends Component { showPreview: this.showPreview, helplinks: this.helplinks, })); - this.editForm.attach(this.componentEdit.querySelector('[ref="editForm"]')); + this.editForm.attach(this.componentEdit.querySelector(`[${this._referenceAttributeName}="editForm"]`)); this.attachEditComponentControls(component, parent, isNew, original, ComponentClass); }); }); @@ -1556,7 +1556,7 @@ export default class WebformBuilder extends Component { this.dialog = this.createModal(this.componentEdit, _.get(this.options, 'dialogAttr', {})); // This is the attach step. - this.editForm.attach(this.componentEdit.querySelector('[ref="editForm"]')); + this.editForm.attach(this.componentEdit.querySelector(`[${this._referenceAttributeName}="editForm"]`)); this.hook('editFormWrapper'); diff --git a/src/components/_classes/component/Component.js b/src/components/_classes/component/Component.js index e3016006a1..9daa721c25 100644 --- a/src/components/_classes/component/Component.js +++ b/src/components/_classes/component/Component.js @@ -386,6 +386,11 @@ export default class Component extends Element { this._visible = this._parentVisible && this.conditionallyVisible(null, data); this._parentDisabled = false; + /** + * The reference attribute name for this component + */ + this._referenceAttributeName = 'ref'; + /** * Used to trigger a new change in this component. * @type {function} - Call to trigger a change in this component. @@ -910,15 +915,15 @@ export default class Component extends Element { const templatesByName = Templates.defaultTemplates[name]; if (!templatesByName) { - return `Unknown template: ${name}`; + return { template: `Unknown template: ${name}` }; } const templateByMode = this.checkTemplateMode(templatesByName, modes); if (templateByMode) { - return templateByMode; + return { template: templateByMode }; } - return templatesByName.form; + return { template: templatesByName.form }; } checkTemplate(templates, names, modes) { @@ -926,9 +931,10 @@ export default class Component extends Element { const templatesByName = templates[name]; if (templatesByName) { + const { referenceAttributeName } = templatesByName; const templateByMode = this.checkTemplateMode(templatesByName, modes); if (templateByMode) { - return templateByMode; + return { template: templateByMode, referenceAttributeName }; } } } @@ -995,9 +1001,13 @@ export default class Component extends Element { ]; // Allow template alters. + const { referenceAttributeName, template } = this.getTemplate(names, mode); + if (referenceAttributeName) { + this._referenceAttributeName = referenceAttributeName; + } return this.hook( `render${name.charAt(0).toUpperCase() + name.substring(1, name.length)}`, - this.interpolate(this.getTemplate(names, mode), data), + this.interpolate(template, data), data, mode ); @@ -1138,12 +1148,20 @@ export default class Component extends Element { return currentTimezone(); } - loadRefs(element, refs) { + /** + * + * @param {HTMLElement} element - The containing DOM element to query for the ref value. + * @param {object} refs - The references to load. + * @param {string} [referenceAttributeName] - The attribute name to use for the reference. + */ + loadRefs(element, refs, referenceAttributeName) { for (const ref in refs) { const refType = refs[ref]; const isString = typeof refType === 'string'; - const selector = isString && refType.includes('scope') ? `:scope > [ref="${ref}"]` : `[ref="${ref}"]`; + const selector = isString && refType.includes('scope') + ? `:scope > [${referenceAttributeName || this._referenceAttributeName || 'ref'}="${ref}"]` + : `[${referenceAttributeName || this._referenceAttributeName || 'ref'}="${ref}"]`; if (isString && refType.startsWith('single')) { this.refs[ref] = element.querySelector(selector); @@ -1230,7 +1248,7 @@ export default class Component extends Element { } createComponentModal(element, modalShouldBeOpened, currentValue) { - return new ComponentModal(this, element, modalShouldBeOpened, currentValue); + return new ComponentModal(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName); } attach(element) { diff --git a/src/components/_classes/componentModal/ComponentModal.js b/src/components/_classes/componentModal/ComponentModal.js index 8268683ca5..019988ff0f 100644 --- a/src/components/_classes/componentModal/ComponentModal.js +++ b/src/components/_classes/componentModal/ComponentModal.js @@ -11,7 +11,8 @@ export default class ComponentModal { }); } - constructor(component, element, isOpened, currentValue) { + constructor(component, element, isOpened, currentValue, referenceAttributeName = 'ref') { + this._referenceAttributeName = referenceAttributeName; this.isOpened = isOpened; this.component = component; this.element = element; @@ -165,10 +166,10 @@ export default class ComponentModal { showDialog() { this.dialogElement = this.component.ce('div'); const dialogContent = ` -

${this.component.t('Do you want to clear changes?')}

+

${this.component.t('Do you want to clear changes?')}

- - + +
`; diff --git a/src/components/_classes/input/Input.js b/src/components/_classes/input/Input.js index b6cbf7e02f..ba3ba94fda 100644 --- a/src/components/_classes/input/Input.js +++ b/src/components/_classes/input/Input.js @@ -122,7 +122,7 @@ export default class Input extends Multivalue { }).trim(); if (this.component.prefix !== calendarIcon) { // converting string to HTML markup to render correctly DateTime component in portal.form.io - return convertStringToHTMLElement(calendarIcon, '[ref="icon"]'); + return convertStringToHTMLElement(calendarIcon, `[${this._referenceAttributeName}="icon"]`); } } return this.component.suffix; diff --git a/src/components/_classes/multivalue/Multivalue.js b/src/components/_classes/multivalue/Multivalue.js index 4cf3ef5abf..03e8d971c4 100644 --- a/src/components/_classes/multivalue/Multivalue.js +++ b/src/components/_classes/multivalue/Multivalue.js @@ -42,7 +42,7 @@ export default class Multivalue extends Field { // If single value field. if (!this.useWrapper()) { return super.render( - `
+ `
${this.renderElement( this.component.type !== 'hidden' ? this.dataValue : '' )} diff --git a/src/components/datagrid/DataGrid.js b/src/components/datagrid/DataGrid.js index 56e615de88..fa029029ca 100644 --- a/src/components/datagrid/DataGrid.js +++ b/src/components/datagrid/DataGrid.js @@ -311,7 +311,7 @@ export default class DataGridComponent extends NestedArrayComponent { super.loadRefs(element, refs); if (refs['messageContainer'] === 'single') { - const container = _.last(element.querySelectorAll('[ref=messageContainer]')); + const container = _.last(element.querySelectorAll(`[${this._referenceAttributeName}=messageContainer]`)); this.refs['messageContainer'] = container || this.refs['messageContainer']; } } diff --git a/src/components/editgrid/EditGrid.js b/src/components/editgrid/EditGrid.js index d62aa44a94..500e09fbf6 100644 --- a/src/components/editgrid/EditGrid.js +++ b/src/components/editgrid/EditGrid.js @@ -129,10 +129,10 @@ export default class EditGridComponent extends NestedArrayComponent { get defaultDialogTemplate() { return ` -

${this.t('Do you want to clear data?')}

+

${this.t('Do you want to clear data?')}

- - + +
`; } diff --git a/src/components/form/Form.js b/src/components/form/Form.js index 9d2eea961b..0141cb6c6e 100644 --- a/src/components/form/Form.js +++ b/src/components/form/Form.js @@ -332,7 +332,7 @@ export default class FormComponent extends Component { if (!this.builderMode && this.component.modalEdit) { const modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false; const currentValue = modalShouldBeOpened ? this.componentModal.currentValue : this.dataValue; - this.componentModal = new ComponentModal(this, element, modalShouldBeOpened, currentValue); + this.componentModal = new ComponentModal(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName); this.setOpenModalElement(); } diff --git a/src/components/signature/Signature.js b/src/components/signature/Signature.js index 7549230af2..d493fb2918 100644 --- a/src/components/signature/Signature.js +++ b/src/components/signature/Signature.js @@ -198,7 +198,7 @@ export default class SignatureComponent extends Input { getModalPreviewTemplate() { return this.renderTemplate('modalPreview', { previewText: this.dataValue ? - `` : + `` : this.t('Click to Sign') }); } diff --git a/src/components/textarea/TextArea.js b/src/components/textarea/TextArea.js index 3639aedafe..cb64c9d41b 100644 --- a/src/components/textarea/TextArea.js +++ b/src/components/textarea/TextArea.js @@ -65,7 +65,7 @@ export default class TextAreaComponent extends TextFieldComponent { info.content = value; if ((this.options.readOnly || this.disabled) && !this.isHtmlRenderMode()) { const elementStyle = this.info.attr.style || ''; - const children = `
`; + const children = `
`; return this.renderTemplate('well', { children,