Skip to content

Commit

Permalink
FIO-8796: Add DynamicWizard component (#47)
Browse files Browse the repository at this point in the history
* remove dist and lib from committed files; update webpack config to include @formio/js as an external dependency; add skipLibCheck for now...; update deps; 5.x updates for resource component

* add DynamicWizard component

* add DynamicWizard component

* remove lockfile

* add dynamic wizard css
  • Loading branch information
brendanbond authored Sep 10, 2024
1 parent 2309828 commit a25ba10
Show file tree
Hide file tree
Showing 35 changed files with 4,164 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"require": "./register.js",
"reporter": "dot"
}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"module": "node",
"scripts": {
"test:coverage": "nyc --reporter=text mocha --reporter spec './{,!(node_modules)/**/}*.spec.js'",
"test": "mocha --require ts-node/register --reporter spec './{,!(node_modules)/**/}*.spec.ts'",
"test": "mocha --require ejsify --require jsdom-global/register --reporter spec './{,!(node_modules)/**/}*.spec.ts'",
"watch": "tsc -w",
"webpack:dev": "webpack",
"webpack:prod": "webpack --config webpack.prod.js",
Expand Down Expand Up @@ -48,11 +48,16 @@
"@types/node": "^18.15.5",
"@types/sinon": "^10.0.13",
"chai": "^4.2.0",
"ejs": "^3.1.10",
"ejsify": "^1.0.0",
"esm": "^3.2.25",
"eventemitter3": "^5.0.1",
"gulp": "^4.0.2",
"gulp-insert": "^0.5.0",
"gulp-rename": "^2.0.0",
"gulp-template": "^5.0.0",
"jsdom": "^25.0.0",
"jsdom-global": "^3.0.2",
"lodash": "^4.17.21",
"mocha": "^10.2.0",
"native-promise-only": "^0.8.1",
Expand Down
12 changes: 12 additions & 0 deletions register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Overrides the tsconfig used for the app.
* In the test environment we need some tweaks.
*/

const tsNode = require('ts-node');

tsNode.register({
files: true,
transpileOnly: true,
project: './tsconfig.spec.json'
});
124 changes: 124 additions & 0 deletions src/Wizard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Displays, Utils } from '@formio/js';
const { _ } = Utils;
const { get } = _;
const OriginalWizard = Displays.displays.wizard;

export default class Wizard extends OriginalWizard {
[x: string]: any;

emitWizardPageSelected(index) {
this.setChangingMode();
this.emit('wizardPageSelected', this.pages[index], index);
}

emitNextPage() {
this.setChangingMode();
this.emit('nextPage', { page: this.page, submission: this.submission });
}

emitPrevPage() {
this.setChangingMode();
this.emit('prevPage', { page: this.page, submission: this.submission });
}

focusOnComponent(key) {
const superFocusOnComponent = super.focusOnComponent(key);
const dynamicWizardComponent = this.hasDynamicWizard();

if (dynamicWizardComponent) {
const component = this.getComponent(key);
dynamicWizardComponent.switchToStep(component);
}
else if (this.element && this.element.classList.contains('dynamicWizard-changingMode')) {
this.element.classList.remove('dynamicWizard-changingMode');
}
return superFocusOnComponent;
}

hasButton(name, nextPage = this.getNextPage()) {
// get page options with global options as default values
const {
previous = this.options.buttonSettings.showPrevious,
cancel = this.options.buttonSettings.showCancel,
submit = this.options.buttonSettings.showSubmit,
next = this.options.buttonSettings.showNext
} = get(this.currentPage, 'component.buttonSettings', {});
const dynamicWizardComponent = this.hasDynamicWizard();
const isDynamicWizardNotActive = !dynamicWizardComponent?.isChangingMode || !dynamicWizardComponent.hasComponents;
const showNavButtons = isDynamicWizardNotActive || this.options.readOnly;

switch (name) {
case 'previous':
return previous && (this.getPreviousPage() > -1) && showNavButtons;
case 'next':
return next && (nextPage !== null) && (nextPage !== -1) && showNavButtons;
case 'cancel':
return cancel && !this.options.readOnly && showNavButtons;
case 'submit':
return submit && !this.options.readOnly && ((nextPage === null) || (this.page === (this.pages.length - 1))) && isDynamicWizardNotActive;
default:
return true;
}
}

setEditMode(submission) {
if (!this.editMode && submission._id && !this.options.readOnly) {
this.editMode = true;
const dynamicWizard = this.hasDynamicWizard();
if (dynamicWizard) {
dynamicWizard.shouldUpdate = false;
dynamicWizard.isChangingMode = false;
}
this.redraw();
}
}

setChangingMode() {
if (this.options.readOnly) {
return;
}

const dynamicWizard = this.hasDynamicWizard();
// If the current page contains dynamicWizard component
if (dynamicWizard && !this.editMode && dynamicWizard.hasComponents) {
if (dynamicWizard.shouldUpdate) {
dynamicWizard.addRow();
dynamicWizard.shouldUpdate = false;
dynamicWizard.secondRender = true;
}

if (this.element && !this.element.classList.contains('dynamicWizard-changingMode')) {
// helps to return nearby components, if validation.maxLength is occurred
if (
dynamicWizard?.editRows.length === get(dynamicWizard?.component, 'validate.maxLength')
&& !dynamicWizard.isOpen(dynamicWizard.editRows[dynamicWizard.changingRowIndex])) {
return;
}
this.element.classList.add('dynamicWizard-changingMode');
this.redraw();
}
}
else if (this.element) {
if (dynamicWizard?.isChangingMode && dynamicWizard.hasComponents) {
dynamicWizard.isChangingMode = false;
this.redraw();
}
if (this.element.classList.contains('dynamicWizard-changingMode')) {
this.element.classList.remove('dynamicWizard-changingMode');
}
}
}

hasDynamicWizard() {
return this.currentPage?.components.find((comp) => comp.component.type === 'dynamicWizard' && comp._parentVisible && comp._visible && !comp._disabled);
}

updatePages() {
this.pages = this.allPages;
const dynamicWizardComponent = this.hasDynamicWizard();

if (this.element && this.element.classList.contains('dynamicWizard-changingMode') && !dynamicWizardComponent) {
this.element.classList.remove('dynamicWizard-changingMode');
}
}
}
34 changes: 34 additions & 0 deletions src/components/DynamicWizard/DynamicWizard.form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Components } from '@formio/js';
const baseEditForm = (Components.components as any).component.editForm;

import DynamicWizardEditData from './editForm/DynamicWizard.edit.data';
import DynamicWizardEditDisplay from './editForm/DynamicWizard.edit.display';
import DynamicWizardEditTemplates from './editForm/DynamicWizard.edit.templates';
import DynamicWizardEditValidation from './editForm/DynamicWizard.edit.validation';

export default function(...extend) {
return baseEditForm([
{
label: 'Templates',
key: 'templates',
weight: 5,
components: DynamicWizardEditTemplates
},
{
key: 'display',
components: DynamicWizardEditDisplay,
},
{
key: 'data',
components: DynamicWizardEditData,
},
{
key: 'validation',
components: DynamicWizardEditValidation
},
{
key: 'addons',
ignore: true
},
], ...extend);
}
Loading

0 comments on commit a25ba10

Please sign in to comment.