From 9ffc2cf3ad32b2fa4f488a414aa3e35731ff59d2 Mon Sep 17 00:00:00 2001 From: Nivanka Fonseka Date: Mon, 20 Mar 2023 12:43:41 +1300 Subject: [PATCH 01/15] completed display rules and form navigation logics --- client/dist/js/userforms-cms.js | 507 +++++++++- client/dist/js/userforms-cms.js.map | 1 + client/dist/js/userforms.js | 574 +++++++++++- client/dist/js/userforms.js.map | 1 + client/dist/styles/userforms-cms.css | 3 +- client/dist/styles/userforms-cms.css.map | 1 + client/dist/styles/userforms.css | 3 +- client/dist/styles/userforms.css.map | 1 + client/src/bundles/UserForms.js | 878 +++++------------- client/src/styles/userforms.scss | 8 +- code/Control/UserDefinedFormController.php | 81 +- code/Model/EditableCustomRule.php | 17 +- code/Model/EditableFormField.php | 4 +- package.json | 4 +- .../Form/Includes/UserFormStepNav.ss | 4 +- webpack.config.js | 11 +- yarn.lock | 22 +- 17 files changed, 1383 insertions(+), 737 deletions(-) create mode 100644 client/dist/js/userforms-cms.js.map create mode 100644 client/dist/js/userforms.js.map create mode 100644 client/dist/styles/userforms-cms.css.map create mode 100644 client/dist/styles/userforms.css.map diff --git a/client/dist/js/userforms-cms.js b/client/dist/js/userforms-cms.js index 3e2a5fdc9..051739b0e 100644 --- a/client/dist/js/userforms-cms.js +++ b/client/dist/js/userforms-cms.js @@ -1 +1,506 @@ -!function(e){function o(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,o),n.l=!0,n.exports}var r={};o.m=e,o.c=r,o.i=function(e){return e},o.d=function(e,r,t){o.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},o.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(r,"a",r),r},o.o=function(e,o){return Object.prototype.hasOwnProperty.call(e,o)},o.p="",o(o.s="./client/src/bundles/bundle-cms.js")}({"./client/src/bundles/ConfirmFolder.js":function(e,o,r){"use strict";function t(e){return e&&e.__esModule?e:{default:e}}var n=Object.assign||function(e){for(var o=1;o');var r=e(this).closest("tr").data("id"),t=e(this).closest(".uf-field-editor").data("adminUrl");o.data("id",r),o.data("adminUrl",t),e("body").append(o),o.open()}}}),e("#confirm-folder__dialog-wrapper").entwine({onunmatch:function(){this._clearModal()},open:function(){this._renderModal(!0)},close:function(o){if(!o){var r=e("#confirm-folder__dialog-wrapper").data("id");e(".ss-gridfield-item[data-id='"+r+"'] .dropdown.editable-column-field.form-group--no-label[data-folderconfirmed='0']").val("SilverStripe\\UserForms\\Model\\EditableFormField\\EditableTextField")}this._renderModal(!1)},_renderModal:function(o){var r=this,t=function(){return r._handleHideModal.apply(r,arguments)},i=function(){return r._handleSubmitModal.apply(r,arguments)},l=d.default._t("UserForms.FILE_CONFIRMATION_TITLE","Select file upload folder"),s=e(this).data("id"),a=e(this).data("adminUrl"),f=F.default.parse(a+"user-forms/confirmfolderformschema"),m=h.default.parse(f.query);m.ID=s;var p=F.default.format(n({},f,{search:h.default.stringify(m)}));u.default.render(c.default.createElement(g,{title:l,isOpen:o,onSubmit:i,onClosed:t,schemaUrl:p,bodyClassName:"modal__dialog",className:"confirm-folder-modal",responseClassBad:"modal__response modal__response--error",responseClassGood:"modal__response modal__response--good",identifier:"UserForms.ConfirmFolder"}),this[0])},_clearModal:function(){u.default.unmountComponentAtNode(this[0])},_handleHideModal:function(){return this.close()},_handleSubmitModal:function(o,r,t){var n=this;return t().then(function(){s.default.noticeAdd({text:d.default._t("UserForms.FILE_CONFIRMATION_CONFIRMATION","Folder confirmed successfully."),stay:!1,type:"success"}),n.close(!0),e("[name=action_doSave], [name=action_save]").click()}).catch(function(e){s.default.noticeAdd({text:e.message,stay:!1,type:"error"})})}}),e("#Form_ConfirmFolderForm_action_cancel").entwine({onclick:function(){e("#confirm-folder__dialog-wrapper").close()}})})},"./client/src/bundles/FieldEditor.js":function(e,o,r){"use strict";var t=r(0);(function(e){return e&&e.__esModule?e:{default:e}})(t).default.entwine("ss",function(e){var o=null;e(".uf-field-editor .ss-gridfield-items").entwine({onmatch:function(){var r=0,t=0,n=e(".uf-field-editor .ss-gridfield-buttonrow").addClass("sticky-buttons"),i=e(".cms-content-header.north").first().height()+parseInt(e(".sticky-buttons").css("padding-top"),10),d=e(".uf-field-editor");this._super(),this.find(".ss-gridfield-item").each(function(o,n){switch(e(n).data("class")){case"SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep":return void(t=0);case"SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup":t+=1,r=t;break;case"SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd":r=t,t-=1;break;default:r=t}e(n).toggleClass("infieldgroup",r>0);for(var i=1;i<=5;i++)e(n).toggleClass("infieldgroup-level-"+i,r>=i)}),o=setInterval(function(){var e=d.offset().top;n.width("100%"),e>i||0===e?n.removeClass("sticky-buttons"):n.addClass("sticky-buttons")},300)},onunmatch:function(){this._super(),clearInterval(o)}}),e(".uf-field-editor .ss-gridfield-buttonrow .action").entwine({onclick:function(e){this._super(e),this.trigger("addnewinline")}}),e(".uf-field-editor").entwine({onmatch:function(){var o=this;this._super(),this.on("addnewinline",function(){o.one("reload",function(){var r=o.find(".ss-gridfield-item").last(),t=null;"SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd"===r.attr("data-class")?(t=r,t.prev().find(".col-Title input").focus(),r=t.add(t.prev()),t.css("visibility","hidden")):r.find(".col-Title input").focus(),r.addClass("flashBackground");var n=e(".cms-content-fields");n.length>0&&n.scrollTop(n[0].scrollHeight),t&&t.css("visibility","visible")})})},onummatch:function(){this._super()}})})},"./client/src/bundles/Recipient.js":function(e,o,r){"use strict";var t=r(0);(function(e){return e&&e.__esModule?e:{default:e}})(t).default.entwine("ss",function(e){var o={updateFormatSpecificFields:function(){var o=e('input[name="SendPlain"]').is(":checked");e(".field.toggle-html-only")[o?"hide":"show"](),e(".field.toggle-plain-only")[o?"show":"hide"]()}};e("#Form_ItemEditForm .EmailRecipientForm").entwine({onmatch:function(){o.updateFormatSpecificFields()},onunmatch:function(){(void 0)._super()}}),e('#Form_ItemEditForm .EmailRecipientForm input[name="SendPlain"]').entwine({onchange:function(){o.updateFormatSpecificFields()}})})},"./client/src/bundles/bundle-cms.js":function(e,o,r){"use strict";r("./client/src/bundles/FieldEditor.js"),r("./client/src/bundles/ConfirmFolder.js"),r("./client/src/bundles/Recipient.js")},0:function(e,o){e.exports=jQuery},1:function(e,o){e.exports=Injector},2:function(e,o){e.exports=NodeUrl},3:function(e,o){e.exports=React},4:function(e,o){e.exports=ReactDom},5:function(e,o){e.exports=i18n},6:function(e,o){e.exports=qs}}); \ No newline at end of file +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./client/src/bundles/bundle-cms.js"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./client/src/bundles/ConfirmFolder.js": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _i18n = __webpack_require__(5); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +var _react = __webpack_require__(3); + +var _react2 = _interopRequireDefault(_react); + +var _reactDom = __webpack_require__(4); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +var _Injector = __webpack_require__(1); + +var _url = __webpack_require__(2); + +var _url2 = _interopRequireDefault(_url); + +var _qs = __webpack_require__(6); + +var _qs2 = _interopRequireDefault(_qs); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var FormBuilderModal = (0, _Injector.loadComponent)('FormBuilderModal'); + +_jquery2.default.entwine('ss', function ($) { + $('#Form_EditForm_Fields').entwine({ + onmatch: function onmatch() { + var _this = this; + + this._super(); + + this.on('addnewinline', function () { + _this.one('reload', function () { + var newField = _this.find('.ss-gridfield-item').last(); + newField.find('.col-ClassName select').attr('data-folderconfirmed', 0); + }); + }); + } + }); + + function toggleVisibility(check, show, hide) { + if (check) { + $(show).show(); + $(hide).hide(); + } else { + $(hide).show(); + $(show).hide(); + } + } + + $('#Form_ConfirmFolderForm_FolderOptions-new').entwine({ + onmatch: function onmatch() { + $('#Form_ConfirmFolderForm_CreateFolder_Holder').detach().appendTo($('#Form_ConfirmFolderForm_FolderOptions-new').parent().parent()); + toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_CreateFolder_Holder', '#Form_ConfirmFolderForm_FolderID_Holder'); + }, + onchange: function onchange() { + toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_CreateFolder_Holder', '#Form_ConfirmFolderForm_FolderID_Holder'); + } + }); + + $('#Form_ConfirmFolderForm_FolderOptions-existing').entwine({ + onmatch: function onmatch() { + $('#Form_ConfirmFolderForm_FolderID_Holder').detach().appendTo($('#Form_ConfirmFolderForm_FolderOptions-existing').parent().parent()); + toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_FolderID_Holder', '#Form_ConfirmFolderForm_CreateFolder_Holder'); + }, + onchange: function onchange() { + toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_FolderID_Holder', '#Form_ConfirmFolderForm_CreateFolder_Holder'); + } + }); + + $('#Form_ConfirmFolderForm_FolderID_Holder .treedropdownfield.is-open,#Form_ItemEditForm_FolderID .treedropdownfield.is-open').entwine({ + onunmatch: function onunmatch() { + var _this2 = this; + + var adminUrl = $(this).closest('#Form_ConfirmFolderForm').data('adminUrl'); + var parsedURL = _url2.default.parse(adminUrl + 'user-forms/getfoldergrouppermissions'); + var parsedQs = _qs2.default.parse(parsedURL.query); + parsedQs.FolderID = $(this).find('input[name=FolderID]').val(); + var fetchURL = _url2.default.format(_extends({}, parsedURL, { search: _qs2.default.stringify(parsedQs) })); + + return fetch(fetchURL, { + credentials: 'same-origin' + }).then(function (response) { + return response.json(); + }).then(function (response) { + $(_this2).siblings('.form__field-description').html(response); + $(_this2).parent().siblings('.form__field-description').html(response); + return response; + }).catch(function (error) { + _jquery2.default.noticeAdd({ text: error.message, stay: false, type: 'error' }); + }); + } + }); + + $(".uf-field-editor .ss-gridfield-items .dropdown.editable-column-field.form-group--no-label:not([data-folderconfirmed='1'])").entwine({ + onchange: function onchange() { + if (this.get(0).value !== 'SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFileField') { + return; + } + + if ($(".uf-field-editor .ss-gridfield-items .dropdown.editable-column-field.form-group--no-label[data-folderconfirmed='1']").length) { + return; + } + + var dialog = $('#confirm-folder__dialog-wrapper'); + + if (dialog.length) { + dialog.remove(); + } + + dialog = $('
'); + var id = $(this).closest('tr').data('id'); + var adminUrl = $(this).closest('.uf-field-editor').data('adminUrl'); + dialog.data('id', id); + dialog.data('adminUrl', adminUrl); + $('body').append(dialog); + + dialog.open(); + } + }); + + $('#confirm-folder__dialog-wrapper').entwine({ + onunmatch: function onunmatch() { + this._clearModal(); + }, + open: function open() { + this._renderModal(true); + }, + close: function close(noRevert) { + if (!noRevert) { + var id = $('#confirm-folder__dialog-wrapper').data('id'); + var select = $('.ss-gridfield-item[data-id=\'' + id + '\'] .dropdown.editable-column-field.form-group--no-label[data-folderconfirmed=\'0\']'); + select.val('SilverStripe\\UserForms\\Model\\EditableFormField\\EditableTextField'); + } + + this._renderModal(false); + }, + _renderModal: function _renderModal(isOpen) { + var _this3 = this; + + var handleHide = function handleHide() { + return _this3._handleHideModal.apply(_this3, arguments); + }; + var handleSubmit = function handleSubmit() { + return _this3._handleSubmitModal.apply(_this3, arguments); + }; + var title = _i18n2.default._t('UserForms.FILE_CONFIRMATION_TITLE', 'Select file upload folder'); + var editableFileFieldID = $(this).data('id'); + + var adminUrl = $(this).data('adminUrl'); + var parsedURL = _url2.default.parse(adminUrl + 'user-forms/confirmfolderformschema'); + var parsedQs = _qs2.default.parse(parsedURL.query); + parsedQs.ID = editableFileFieldID; + var schemaUrl = _url2.default.format(_extends({}, parsedURL, { search: _qs2.default.stringify(parsedQs) })); + + _reactDom2.default.render(_react2.default.createElement(FormBuilderModal, { + title: title, + isOpen: isOpen, + onSubmit: handleSubmit, + onClosed: handleHide, + schemaUrl: schemaUrl, + bodyClassName: 'modal__dialog', + className: 'confirm-folder-modal', + responseClassBad: 'modal__response modal__response--error', + responseClassGood: 'modal__response modal__response--good', + identifier: 'UserForms.ConfirmFolder' + }), this[0]); + }, + _clearModal: function _clearModal() { + _reactDom2.default.unmountComponentAtNode(this[0]); + }, + _handleHideModal: function _handleHideModal() { + return this.close(); + }, + _handleSubmitModal: function _handleSubmitModal(data, action, submitFn) { + var _this4 = this; + + return submitFn().then(function () { + _jquery2.default.noticeAdd({ text: _i18n2.default._t('UserForms.FILE_CONFIRMATION_CONFIRMATION', 'Folder confirmed successfully.'), stay: false, type: 'success' }); + _this4.close(true); + $('[name=action_doSave], [name=action_save]').click(); + }).catch(function (error) { + _jquery2.default.noticeAdd({ text: error.message, stay: false, type: 'error' }); + }); + } + }); + + $('#Form_ConfirmFolderForm_action_cancel').entwine({ + onclick: function onclick() { + $('#confirm-folder__dialog-wrapper').close(); + } + }); +}); + +/***/ }), + +/***/ "./client/src/bundles/FieldEditor.js": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +_jquery2.default.entwine('ss', function ($) { + var stickyHeaderInterval = null; + + $('.uf-field-editor .ss-gridfield-items').entwine({ + onmatch: function onmatch() { + var thisLevel = 0; + var depth = 0; + var $buttonrow = $('.uf-field-editor .ss-gridfield-buttonrow').addClass('sticky-buttons'); + var navHeight = $('.cms-content-header.north').first().height() + parseInt($('.sticky-buttons').css('padding-top'), 10); + var fieldEditor = $('.uf-field-editor'); + + this._super(); + + this.find('.ss-gridfield-item').each(function (index, el) { + switch ($(el).data('class')) { + case 'SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep': + { + depth = 0; + return; + } + case 'SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup': + { + depth += 1; + thisLevel = depth; + break; + } + case 'SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd': + { + thisLevel = depth; + depth -= 1; + break; + } + default: + { + thisLevel = depth; + } + } + + $(el).toggleClass('infieldgroup', thisLevel > 0); + for (var i = 1; i <= 5; i++) { + $(el).toggleClass('infieldgroup-level-' + i, thisLevel >= i); + } + }); + + stickyHeaderInterval = setInterval(function () { + var offsetTop = fieldEditor.offset().top; + $buttonrow.width('100%'); + if (offsetTop > navHeight || offsetTop === 0) { + $buttonrow.removeClass('sticky-buttons'); + } else { + $buttonrow.addClass('sticky-buttons'); + } + }, 300); + }, + onunmatch: function onunmatch() { + this._super(); + + clearInterval(stickyHeaderInterval); + } + }); + + $('.uf-field-editor .ss-gridfield-buttonrow .action').entwine({ + onclick: function onclick(e) { + this._super(e); + + this.trigger('addnewinline'); + } + }); + + $('.uf-field-editor').entwine({ + onmatch: function onmatch() { + var _this = this; + + this._super(); + + this.on('addnewinline', function () { + _this.one('reload', function () { + var $newField = _this.find('.ss-gridfield-item').last(); + var $groupEnd = null; + var fqcn = 'SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd'; + if ($newField.attr('data-class') === fqcn) { + $groupEnd = $newField; + $groupEnd.prev().find('.col-Title input').focus(); + $newField = $groupEnd.add($groupEnd.prev()); + $groupEnd.css('visibility', 'hidden'); + } else { + $newField.find('.col-Title input').focus(); + } + + $newField.addClass('flashBackground'); + var $contenFields = $('.cms-content-fields'); + if ($contenFields.length > 0) { + $contenFields.scrollTop($contenFields[0].scrollHeight); + } + if ($groupEnd) { + $groupEnd.css('visibility', 'visible'); + } + }); + }); + }, + onummatch: function onummatch() { + this._super(); + } + }); +}); + +/***/ }), + +/***/ "./client/src/bundles/Recipient.js": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +_jquery2.default.entwine('ss', function ($) { + var recipient = { + updateFormatSpecificFields: function updateFormatSpecificFields() { + var sendPlainChecked = $('input[name="SendPlain"]').is(':checked'); + + $('.field.toggle-html-only')[sendPlainChecked ? 'hide' : 'show'](); + $('.field.toggle-plain-only')[sendPlainChecked ? 'show' : 'hide'](); + } + }; + + $('#Form_ItemEditForm .EmailRecipientForm').entwine({ + onmatch: function onmatch() { + recipient.updateFormatSpecificFields(); + }, + + onunmatch: function onunmatch() { + undefined._super(); + } + }); + + $('#Form_ItemEditForm .EmailRecipientForm input[name="SendPlain"]').entwine({ + onchange: function onchange() { + recipient.updateFormatSpecificFields(); + } + }); +}); + +/***/ }), + +/***/ "./client/src/bundles/bundle-cms.js": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +__webpack_require__("./client/src/bundles/FieldEditor.js"); + +__webpack_require__("./client/src/bundles/ConfirmFolder.js"); + +__webpack_require__("./client/src/bundles/Recipient.js"); + +/***/ }), + +/***/ 0: +/***/ (function(module, exports) { + +module.exports = jQuery; + +/***/ }), + +/***/ 1: +/***/ (function(module, exports) { + +module.exports = Injector; + +/***/ }), + +/***/ 2: +/***/ (function(module, exports) { + +module.exports = NodeUrl; + +/***/ }), + +/***/ 3: +/***/ (function(module, exports) { + +module.exports = React; + +/***/ }), + +/***/ 4: +/***/ (function(module, exports) { + +module.exports = ReactDom; + +/***/ }), + +/***/ 5: +/***/ (function(module, exports) { + +module.exports = i18n; + +/***/ }), + +/***/ 6: +/***/ (function(module, exports) { + +module.exports = qs; + +/***/ }) + +/******/ }); +//# sourceMappingURL=userforms-cms.js.map \ No newline at end of file diff --git a/client/dist/js/userforms-cms.js.map b/client/dist/js/userforms-cms.js.map new file mode 100644 index 000000000..835541861 --- /dev/null +++ b/client/dist/js/userforms-cms.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap b68f729ec16dc9ebd9f2","webpack:///./client/src/bundles/ConfirmFolder.js","webpack:///./client/src/bundles/FieldEditor.js","webpack:///./client/src/bundles/Recipient.js","webpack:///./client/src/bundles/bundle-cms.js","webpack:///external \"jQuery\"","webpack:///external \"Injector\"","webpack:///external \"NodeUrl\"","webpack:///external \"React\"","webpack:///external \"ReactDom\"","webpack:///external \"i18n\"","webpack:///external \"qs\""],"names":["FormBuilderModal","jQuery","entwine","$","onmatch","_super","on","one","newField","find","last","attr","toggleVisibility","check","show","hide","detach","appendTo","parent","prop","onchange","onunmatch","adminUrl","closest","data","parsedURL","url","parse","parsedQs","qs","query","FolderID","val","fetchURL","format","search","stringify","fetch","credentials","then","response","json","siblings","html","catch","error","noticeAdd","text","message","stay","type","get","value","length","dialog","remove","id","append","open","_clearModal","_renderModal","close","noRevert","select","isOpen","handleHide","_handleHideModal","handleSubmit","_handleSubmitModal","title","i18n","_t","editableFileFieldID","ID","schemaUrl","ReactDOM","render","unmountComponentAtNode","action","submitFn","click","onclick","stickyHeaderInterval","thisLevel","depth","$buttonrow","addClass","navHeight","first","height","parseInt","css","fieldEditor","each","index","el","toggleClass","i","setInterval","offsetTop","offset","top","width","removeClass","clearInterval","e","trigger","$newField","$groupEnd","fqcn","prev","focus","add","$contenFields","scrollTop","scrollHeight","onummatch","recipient","updateFormatSpecificFields","sendPlainChecked","is"],"mappings":"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","file":"js/userforms-cms.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./client/src/bundles/bundle-cms.js\");\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap b68f729ec16dc9ebd9f2","/* global window */\nimport i18n from 'i18n';\nimport jQuery from 'jquery';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { loadComponent } from 'lib/Injector';\nimport url from 'url';\nimport qs from 'qs';\n\nconst FormBuilderModal = loadComponent('FormBuilderModal');\n\njQuery.entwine('ss', ($) => {\n /** Mark newly added fields as new */\n $('#Form_EditForm_Fields').entwine({\n onmatch() {\n this._super();\n\n this.on('addnewinline', () => {\n this.one('reload', () => {\n const newField = this.find('.ss-gridfield-item').last();\n newField.find('.col-ClassName select').attr('data-folderconfirmed', 0);\n });\n });\n }\n });\n\n function toggleVisibility(check, show, hide) {\n if (check) {\n $(show).show();\n $(hide).hide();\n } else {\n $(hide).show();\n $(show).hide();\n }\n }\n\n /** Move our options under the radio button areas */\n $('#Form_ConfirmFolderForm_FolderOptions-new').entwine({\n onmatch() {\n $('#Form_ConfirmFolderForm_CreateFolder_Holder').detach().appendTo($('#Form_ConfirmFolderForm_FolderOptions-new').parent().parent());\n toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_CreateFolder_Holder', '#Form_ConfirmFolderForm_FolderID_Holder');\n },\n onchange() {\n toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_CreateFolder_Holder', '#Form_ConfirmFolderForm_FolderID_Holder');\n }\n });\n\n /** Move our options under the radio button areas */\n $('#Form_ConfirmFolderForm_FolderOptions-existing').entwine({\n onmatch() {\n $('#Form_ConfirmFolderForm_FolderID_Holder').detach().appendTo($('#Form_ConfirmFolderForm_FolderOptions-existing').parent().parent());\n toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_FolderID_Holder', '#Form_ConfirmFolderForm_CreateFolder_Holder');\n },\n onchange() {\n toggleVisibility($(this).prop('checked'), '#Form_ConfirmFolderForm_FolderID_Holder', '#Form_ConfirmFolderForm_CreateFolder_Holder');\n }\n });\n\n /** Display permissions for folder selected */\n $('#Form_ConfirmFolderForm_FolderID_Holder .treedropdownfield.is-open,#Form_ItemEditForm_FolderID .treedropdownfield.is-open').entwine({\n onunmatch() {\n // Build url\n const adminUrl = $(this).closest('#Form_ConfirmFolderForm').data('adminUrl');\n const parsedURL = url.parse(`${adminUrl}user-forms/getfoldergrouppermissions`);\n const parsedQs = qs.parse(parsedURL.query);\n parsedQs.FolderID = $(this).find('input[name=FolderID]').val();\n const fetchURL = url.format({ ...parsedURL, search: qs.stringify(parsedQs) });\n\n return fetch(fetchURL, {\n credentials: 'same-origin',\n })\n .then(response => response.json())\n .then(response => {\n $(this).siblings('.form__field-description').html(response);\n $(this).parent().siblings('.form__field-description').html(response);\n return response;\n })\n .catch((error) => {\n jQuery.noticeAdd({ text: error.message, stay: false, type: 'error' });\n });\n }\n });\n\n /**\n * Monitor new fields to intercept when EditableFileField is selected\n */\n $(\".uf-field-editor .ss-gridfield-items .dropdown.editable-column-field.form-group--no-label:not([data-folderconfirmed='1'])\").entwine({\n onchange() {\n // ensure EditableFileField is selected\n if (this.get(0).value !== 'SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFileField') {\n return;\n }\n\n // ensure there are no other EditableFileField confirmed\n if ($(\".uf-field-editor .ss-gridfield-items .dropdown.editable-column-field.form-group--no-label[data-folderconfirmed='1']\").length) {\n return;\n }\n\n // open folder confirmation dialog\n let dialog = $('#confirm-folder__dialog-wrapper');\n\n if (dialog.length) {\n dialog.remove();\n }\n\n dialog = $('
');\n const id = $(this).closest('tr').data('id');\n const adminUrl = $(this).closest('.uf-field-editor').data('adminUrl');\n dialog.data('id', id);\n dialog.data('adminUrl', adminUrl);\n $('body').append(dialog);\n\n dialog.open();\n },\n });\n\n /** handle modal rendering */\n $('#confirm-folder__dialog-wrapper').entwine({\n onunmatch() {\n // solves errors given by ReactDOM \"no matched root found\" error.\n this._clearModal();\n },\n\n open() {\n this._renderModal(true);\n },\n\n close(noRevert) {\n if (!noRevert) {\n // revert field to TextField\n const id = $('#confirm-folder__dialog-wrapper').data('id');\n const select = $(`.ss-gridfield-item[data-id='${id}'] .dropdown.editable-column-field.form-group--no-label[data-folderconfirmed='0']`);\n select.val('SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableTextField');\n }\n\n this._renderModal(false);\n },\n\n _renderModal(isOpen) {\n const handleHide = (...args) => this._handleHideModal(...args);\n const handleSubmit = (...args) => this._handleSubmitModal(...args);\n const title = i18n._t('UserForms.FILE_CONFIRMATION_TITLE', 'Select file upload folder');\n const editableFileFieldID = $(this).data('id');\n\n // Build schema url\n const adminUrl = $(this).data('adminUrl');\n const parsedURL = url.parse(`${adminUrl}user-forms/confirmfolderformschema`);\n const parsedQs = qs.parse(parsedURL.query);\n parsedQs.ID = editableFileFieldID;\n const schemaUrl = url.format({ ...parsedURL, search: qs.stringify(parsedQs) });\n\n ReactDOM.render(\n ,\n this[0]\n );\n },\n\n _clearModal() {\n ReactDOM.unmountComponentAtNode(this[0]);\n // this.empty();\n },\n\n _handleHideModal() {\n // close the modal\n return this.close();\n },\n\n _handleSubmitModal(data, action, submitFn) {\n return submitFn()\n .then(() => {\n jQuery.noticeAdd({ text: i18n._t('UserForms.FILE_CONFIRMATION_CONFIRMATION', 'Folder confirmed successfully.'), stay: false, type: 'success' });\n this.close(true);\n $('[name=action_doSave], [name=action_save]').click();\n })\n .catch((error) => {\n jQuery.noticeAdd({ text: error.message, stay: false, type: 'error' });\n });\n },\n });\n\n $('#Form_ConfirmFolderForm_action_cancel').entwine({\n onclick() {\n $('#confirm-folder__dialog-wrapper').close();\n }\n });\n});\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/bundles/ConfirmFolder.js","/**\n * form builder behaviour.\n */\n\nimport jQuery from 'jquery';\n\njQuery.entwine('ss', ($) => {\n let stickyHeaderInterval = null;\n\n $('.uf-field-editor .ss-gridfield-items').entwine({\n onmatch() {\n let thisLevel = 0;\n let depth = 0;\n const $buttonrow = $('.uf-field-editor .ss-gridfield-buttonrow').addClass('sticky-buttons');\n const navHeight = $('.cms-content-header.north').first().height()\n + parseInt($('.sticky-buttons').css('padding-top'), 10);\n const fieldEditor = $('.uf-field-editor');\n\n this._super();\n\n // Loop through all rows and set necessary styles\n this.find('.ss-gridfield-item').each((index, el) => {\n switch ($(el).data('class')) {\n case 'SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep': {\n depth = 0;\n return;\n }\n case 'SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroup': {\n depth += 1;\n thisLevel = depth;\n break;\n }\n case 'SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd': {\n thisLevel = depth;\n depth -= 1;\n break;\n }\n default: {\n thisLevel = depth;\n }\n }\n\n $(el).toggleClass('infieldgroup', thisLevel > 0);\n for (let i = 1; i <= 5; i++) {\n $(el).toggleClass(`infieldgroup-level-${i}`, thisLevel >= i);\n }\n });\n\n // Make sure gridfield buttons stick to top of page when user scrolls down\n stickyHeaderInterval = setInterval(() => {\n const offsetTop = fieldEditor.offset().top;\n $buttonrow.width('100%');\n if (offsetTop > navHeight || offsetTop === 0) {\n $buttonrow.removeClass('sticky-buttons');\n } else {\n $buttonrow.addClass('sticky-buttons');\n }\n }, 300);\n },\n onunmatch() {\n this._super();\n\n clearInterval(stickyHeaderInterval);\n },\n });\n\n // When new fields are added.\n $('.uf-field-editor .ss-gridfield-buttonrow .action').entwine({\n onclick(e) {\n this._super(e);\n\n this.trigger('addnewinline');\n },\n });\n\n $('.uf-field-editor').entwine({\n onmatch() {\n this._super();\n\n // When the 'Add field' button is clicked set a one time listener.\n // When the GridField is reloaded focus on the newly added field.\n this.on('addnewinline', () => {\n this.one('reload', () => {\n // If fieldgroup, focus on the start marker\n let $newField = this.find('.ss-gridfield-item').last();\n let $groupEnd = null;\n const fqcn = 'SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd';\n if ($newField.attr('data-class') === fqcn) {\n $groupEnd = $newField;\n $groupEnd.prev().find('.col-Title input').focus();\n $newField = $groupEnd.add($groupEnd.prev());\n $groupEnd.css('visibility', 'hidden');\n } else {\n $newField.find('.col-Title input').focus();\n }\n\n $newField.addClass('flashBackground');\n const $contenFields = $('.cms-content-fields');\n if ($contenFields.length > 0) {\n $contenFields.scrollTop($contenFields[0].scrollHeight);\n }\n if ($groupEnd) {\n $groupEnd.css('visibility', 'visible');\n }\n });\n });\n },\n onummatch() {\n this._super();\n },\n });\n});\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/bundles/FieldEditor.js","/**\n * Email recipient behaviour.\n */\n\nimport jQuery from 'jquery';\n\njQuery.entwine('ss', ($) => {\n const recipient = {\n // Some fields are only visible when HTML email are being sent.\n updateFormatSpecificFields: () => {\n const sendPlainChecked = $('input[name=\"SendPlain\"]').is(':checked');\n\n $('.field.toggle-html-only')[sendPlainChecked ? 'hide' : 'show']();\n $('.field.toggle-plain-only')[sendPlainChecked ? 'show' : 'hide']();\n },\n };\n\n $('#Form_ItemEditForm .EmailRecipientForm').entwine({\n onmatch: () => {\n recipient.updateFormatSpecificFields();\n },\n\n onunmatch: () => {\n this._super();\n },\n });\n\n $('#Form_ItemEditForm .EmailRecipientForm input[name=\"SendPlain\"]').entwine({\n onchange: () => {\n recipient.updateFormatSpecificFields();\n },\n });\n});\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/bundles/Recipient.js","// Used for CMS form fields\nimport 'bundles/FieldEditor';\nimport 'bundles/ConfirmFolder';\nimport 'bundles/Recipient';\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/bundles/bundle-cms.js","module.exports = jQuery;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"jQuery\"\n// module id = 0\n// module chunks = 0","module.exports = Injector;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"Injector\"\n// module id = 1\n// module chunks = 0","module.exports = NodeUrl;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"NodeUrl\"\n// module id = 2\n// module chunks = 0","module.exports = React;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"React\"\n// module id = 3\n// module chunks = 0","module.exports = ReactDom;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"ReactDom\"\n// module id = 4\n// module chunks = 0","module.exports = i18n;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"i18n\"\n// module id = 5\n// module chunks = 0","module.exports = qs;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"qs\"\n// module id = 6\n// module chunks = 0"],"sourceRoot":""} \ No newline at end of file diff --git a/client/dist/js/userforms.js b/client/dist/js/userforms.js index 0533c2bb4..180498b05 100644 --- a/client/dist/js/userforms.js +++ b/client/dist/js/userforms.js @@ -1 +1,573 @@ -!function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,e),i.l=!0,i.exports}var r={};e.m=t,e.c=r,e.i=function(t){return t},e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s="./client/src/bundles/bundle.js")}({"./client/src/bundles/UserForms.js":function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{default:t}}var i=r(1),s=n(i),o=r(0),a=n(o);(0,s.default)(document).ready(function(t){function e(e){return this.$el=e instanceof t?e:t(e),this.$el.find("h4").text(a.default._t("UserForms.ERROR_CONTAINER_HEADER","Please correct the following errors and try again:")),this}function r(r){var n=this;this.$el=r instanceof t?r:t(r);var i=this.$el.closest(".userform").data("inst");return this.$elButton=t(".step-button-wrapper[data-for='"+this.$el.prop("id")+"']"),this.viewed=!1,this.valid=!1,this.id=null,this.hide(),u.DISPLAY_ERROR_MESSAGES_AT_TOP&&(this.errorContainer=new e(this.$el.find(".error-container")),i.$el.on("userform.form.error",function(e,r){n.$el.is(":visible")&&t.each(r.errorList,function(e,r){n.errorContainer.updateErrorMessage(t(r.element),r.message)})}),i.$el.on("userform.form.valid",function(t,e){n.errorContainer.removeErrorMessage(e)})),this.$elButton.on("userform.field.hide userform.field.show",function(){i.$el.trigger("userform.form.conditionalstep")}),this}function n(e){var r=this;this.$el=e instanceof t?e:t(e),this.$buttons=this.$el.find(".step-button-jump"),this.$jsAlign=this.$el.find(".js-align");var n=this.$el.closest(".userform").data("inst");return this.$buttons.each(function(e,n){t(n).on("click",function(e){e.preventDefault();var n=parseInt(t(e.target).data("step"),10);r.$el.trigger("userform.progress.changestep",n)})}),n.$el.on("userform.form.changestep",function(t,e){r.update(e)}),n.$el.on("userform.form.conditionalstep",function(){var e=r.$buttons.filter(":visible");e.each(function(e,r){t(r).text(e+1)}),r.$el.find(".progress-bar").attr("aria-valuemax",e.length),r.$el.find(".total-step-number").text(e.length)}),this.$jsAlign.each(function(e,n){var i=t(n),s=100/(r.$jsAlign.length-1)*e,o=s+"%",a=i.innerWidth()/2*-1;i.css({left:o,marginLeft:a}),e===r.$jsAlign.length-1?i.css({marginLeft:2*a}):0===e&&i.css({marginLeft:0})}),this}function i(e){var r=this;this.$el=e instanceof t?e:t(e);var n=this.$el.closest(".userform");this.userformInstance=n.data("inst"),this.$prevButton=this.$el.find(".step-button-prev"),this.$nextButton=this.$el.find(".step-button-next"),this.$prevButton.parent().attr("aria-hidden",!1).show(),this.$nextButton.parent().attr("aria-hidden",!1).show();var i=function(){var e=n.offset();t("html, body").animate({scrollTop:e.top},"slow")};return this.$prevButton.on("click",function(t){t.preventDefault(),i(),r.$el.trigger("userform.action.prev")}),this.$nextButton.on("click",function(t){t.preventDefault(),i(),r.$el.trigger("userform.action.next")}),this.userformInstance.$el.on("userform.form.changestep userform.form.conditionalstep",function(){r.update()}),this}function s(r){var n=this;return this.$el=r instanceof t?r:t(r),this.steps=[],this.errorContainer=new e(this.$el.children(".error-container")),this.$el.on("userform.action.prev",function(){n.prevStep()}),this.$el.on("userform.action.next",function(){n.nextStep()}),this.$el.find(".userform-progress").on("userform.progress.changestep",function(t,e){n.jumpToStep(e-1)}),this.$el.on("userform.form.valid",function(t,e){n.errorContainer.removeStepLink(e)}),this.$el.validate(this.validationOptions),this.$el.find(".optionset.requiredField input").each(function(e,r){t(r).rules("add",{required:!0})}),this}function o(o,d){var f=this,c=t(d);if(0!==c.length){u.ENABLE_LIVE_VALIDATION=void 0!==c.data("livevalidation"),u.DISPLAY_ERROR_MESSAGES_AT_TOP=void 0!==c.data("toperrors"),!1===u.ENABLE_LIVE_VALIDATION&&t.extend(s.prototype.validationOptions,{onfocusout:!1}),u.DISPLAY_ERROR_MESSAGES_AT_TOP&&t.extend(s.prototype.validationOptions,{invalidHandler:function(t,e){c.trigger("userform.form.error",[e])},onfocusout:!1}),c.find(".userform-progress, .step-navigation").attr("aria-hidden",!1).show(),t.extend(r.prototype,l),t.extend(e.prototype,l);var h=new s(c);c.data("inst",h),u.HIDE_FIELD_LABELS&&c.find("label.left").each(function(){var e=t(f);t('[name="'+e.attr("for")+'"]').attr("placeholder",e.text()),e.remove()}),h.$el.find(".form-step").each(function(t,e){var n=new r(e);h.addStep(n)}),h.setCurrentStep(h.steps[0]);var p=c.find(".userform-progress");p.length&&new n(p).update(0);var m=c.find(".step-navigation");m.length&&new i(m).update(),t(document).on("click","input.text[data-showcalendar]",function(){var e=t(f);e.ssDatepicker(),e.data("datepicker")&&e.datepicker("show")}),setInterval(function(){t.ajax({url:"UserDefinedFormController/ping"})},18e4),void 0!==c.areYouSure&&c.areYouSure({message:a.default._t("UserForms.LEAVE_CONFIRMATION","You have unsaved changes!")})}}var u={},l={show:function(){this.$el.attr("aria-hidden",!1).show()},hide:function(){this.$el.attr("aria-hidden",!0).hide()}};e.prototype.hasErrors=function(){return this.$el.find(".error-list").children().length>0},e.prototype.removeErrorMessage=function(t){this.$el.find("#"+t+"-top-error").remove(),this.hasErrors()||this.hide()},e.prototype.addStepLink=function(e){var r=this.$el.closest(".userform").data("inst"),n=e.$el.attr("id")+"-error-link",i=this.$el.find("#"+n),s=e.$el.attr("id"),o=e.$el.data("title");i.length||(i=t('
  • '+o+"
  • "),i.on("click",function(t){t.preventDefault(),r.jumpToStep(e.id)}),this.$el.find(".error-list").append(i))},e.prototype.removeStepLink=function(e){var r=t("#"+e).closest(".form-step").attr("id");this.$el.find("#"+r+"-error-link").remove(),this.$el.find(".error-list").is(":empty")&&this.hide()},e.prototype.updateErrorMessage=function(e,r){var n=this,i=e.attr("id"),s="#"+i,o=i+"-top-error",a=t("#"+o),u=e.attr("aria-describedby");if(!r)return void a.addClass("fixed");a.removeClass("fixed"),this.show(),1===a.length?a.show().find("a").html(r):(e.closest(".field[id]").each(function(){var e=t(n).attr("id");e&&(s="#"+e)}),a=t("
  • "),a.attr("id",o).find("a").attr("href",location.pathname+location.search+s).html(r),this.$el.find("ul").append(a),u?u.match(new RegExp("\\b"+o+"\\b"))||(u+=" "+o):u=o,e.attr("aria-describedby",u))},r.prototype.conditionallyHidden=function(){return!this.$elButton.find("button").is(":visible")},n.prototype.update=function(e){var r=t(this.$el.parent(".userform").find(".form-step")[e]),n=0,i=e/(this.$buttons.length-1)*100;this.$buttons.each(function(r,i){return!(r>e||(t(i).is(":visible")&&(n+=1),0))}),this.$el.find(".current-step-number").each(function(e,r){t(r).text(n)}),this.$el.find("[aria-valuenow]").each(function(e,r){t(r).attr("aria-valuenow",n)}),this.$buttons.each(function(e,r){var i=t(r),s=i.parent();if(parseInt(i.data("step"),10)===n&&i.is(":visible"))return s.addClass("current viewed"),void i.removeAttr("disabled");s.removeClass("current")}),this.$el.siblings(".progress-title").text(r.data("title")),i=i?i+"%":"",this.$el.find(".progress-bar").width(i)},i.prototype.update=function(){var t=this.userformInstance.steps.length,e=this.userformInstance.currentStep?this.userformInstance.currentStep.id:0,r=null,n=null;for(this.$el.find(".step-button-prev")[0===e?"hide":"show"](),r=t-1;r>=0;r--)if(n=this.userformInstance.steps[r],!n.conditionallyHidden()){this.$el.find(".step-button-next")[e>=r?"hide":"show"](),this.$el.find(".btn-toolbar")[e>=r?"show":"hide"]();break}},s.prototype.validationOptions={ignore:":hidden,ul",errorClass:"error",errorElement:"span",errorPlacement:function(t,e){t.addClass("message"),e.is(":radio")||e.parents(".checkboxset").length>0?t.appendTo(e.closest(".middleColumn, .field")):e.parents(".checkbox").length>0?t.appendTo(e.closest(".field")):t.insertAfter(e)},invalidHandler:function(t,e){setTimeout(function(){e.currentElements.filter(".error").first().focus()},0)},submitHandler:function(e){var r=!0,n=t(e).closest(".userform").data("inst");if(n.currentStep&&(n.currentStep.valid=t(e).valid()),t.each(n.steps,function(t,e){e.valid||e.conditionallyHidden()||(r=!1,n.errorContainer.addStepLink(e))}),r){var i=t(e).find(".field.requiredField.hide input");i.length>0&&i.removeAttr("required aria-required data-rule-required").valid(),t(e).removeClass("dirty"),e.submit(),n.$el.trigger("userform.form.submit")}else n.errorContainer.show()},success:function(e){var r=t(e).closest(".userform").data("inst"),n=t(e).attr("id"),i=n.substr(0,n.indexOf("-error")).replace(/[\\[\\]]/,"");e.remove(),r.$el.trigger("userform.form.valid",[i])}},s.prototype.addStep=function(t){t instanceof r&&(t.id=this.steps.length,this.steps.push(t))},s.prototype.setCurrentStep=function(t){t instanceof r&&(this.currentStep=t,this.currentStep.show(),this.currentStep.viewed=!0,this.currentStep.$el.addClass("viewed"))},s.prototype.jumpToStep=function(t,e){var r=this.steps[t],n=!1,i=void 0===e||e;if(void 0!==r){if(r.conditionallyHidden())return void(i?this.jumpToStep(t+1,e):this.jumpToStep(t-1,e));n=this.$el.valid(),this.currentStep.valid=n,!1===n&&!1===r.viewed||(this.currentStep.hide(),this.setCurrentStep(r),this.$el.trigger("userform.form.changestep",[r.id]))}},s.prototype.nextStep=function(){this.jumpToStep(this.steps.indexOf(this.currentStep)+1,!0)},s.prototype.prevStep=function(){this.jumpToStep(this.steps.indexOf(this.currentStep)-1,!1)},t(".userform").each(o)})},"./client/src/bundles/bundle.js":function(t,e,r){"use strict";r("./client/src/bundles/UserForms.js")},0:function(t,e){t.exports=i18n},1:function(t,e){t.exports=jQuery}}); \ No newline at end of file +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./client/src/bundles/bundle.js"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./client/src/bundles/UserForms.js": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _i18n = __webpack_require__(0); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +document.addEventListener("DOMContentLoaded", function () { + + var forms = document.querySelectorAll('form.userform'); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = forms[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var form = _step.value; + + var userForm = new UserForm(form); + userForm.init(); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } +}); + +var ProgressBar = function () { + function ProgressBar(dom, userForm) { + _classCallCheck(this, ProgressBar); + + this.dom = dom; + this.userForm = userForm; + this.progressTitle = this.userForm.dom.querySelector('.progress-title'); + this.buttons = this.dom.querySelectorAll('.step-button-jump'); + this.currentStepNumber = this.dom.querySelector('.current-step-number'); + this.init(); + } + + _createClass(ProgressBar, [{ + key: 'init', + value: function init() { + var _this = this; + + this.dom.style.display = 'initial'; + var buttons = this.buttons; + + var _loop = function _loop(button) { + button.addEventListener('click', function (e) { + e.preventDefault(); + var stepNumber = parseInt(button.getAttribute('data-step'), 10); + _this.userForm.jumpToStep(stepNumber); + return false; + }); + }; + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = buttons[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var button = _step2.value; + + _loop(button); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + this.userForm.dom.addEventListener('userform.form.changestep', function (e) { + _this.update(e.detail.stepId); + }); + + this.update(0); + } + }, { + key: 'isVisible', + value: function isVisible(element) { + return !(element.style.display !== 'none' && element.style.visibility !== 'hidden' && element.classList.contains('hide')); + } + }, { + key: 'update', + value: function update(stepId) { + var stepNumber = this.userForm.getCurrentStepID() + 1; + var newStep = this.userForm.getStep(stepId); + var newStepElement = newStep.step; + var barWidth = stepId / (this.buttons.length - 1) * 100; + + this.currentStepNumber.innerText = stepNumber; + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = this.dom.querySelectorAll('[aria-valuenow]')[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var e = _step3.value; + + e.setAttribute('aria-valuenow', stepNumber); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = this.buttons[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + var button = _step4.value; + + var parent = button.parentNode; + if (parseInt(button.getAttribute('data-step'), 10) === stepNumber && this.isVisible(button)) { + parent.classList.add('current'); + parent.classList.add('viewed'); + + button.disabled = false; + break; + } + parent.classList.remove('current'); + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + + this.progressTitle.innerText = newStepElement.getAttribute('data-title'); + + barWidth = barWidth ? barWidth + '%' : ''; + this.dom.querySelector('.progress-bar').style.width = barWidth; + } + }]); + + return ProgressBar; +}(); + +var FormStep = function () { + function FormStep(step, userForm) { + _classCallCheck(this, FormStep); + + this.step = step; + this.userForm = userForm; + this.viewed = false; + this.buttonHolder = null; + this.id = 0; + + this.init(); + } + + _createClass(FormStep, [{ + key: 'init', + value: function init() { + var _this2 = this; + + var id = this.getHTMLId(); + this.buttonHolder = document.querySelector('.step-button-wrapper[data-for=\'' + id + '\']'); + ['userform.field.hide', 'userform.field.show'].forEach(function (action) { + _this2.buttonHolder.addEventListener(action, function () { + _this2.userForm.dom.trigger('userform.form.conditionalstep'); + }); + }); + } + }, { + key: 'setId', + value: function setId(id) { + this.id = id; + } + }, { + key: 'getHTMLId', + value: function getHTMLId() { + return this.step.getAttribute('id'); + } + }, { + key: 'show', + value: function show() { + this.step.setAttribute('aria-hidden', false); + this.step.classList.remove('hide'); + this.step.classList.add('viewed'); + this.viewed = true; + } + }, { + key: 'hide', + value: function hide() { + this.step.setAttribute('aria-hidden', true); + this.step.classList.add('hide'); + } + }, { + key: 'conditionallyHidden', + value: function conditionallyHidden() { + var button = this.buttonHolder.querySelector('button'); + return !(button.style.display !== 'none' && button.visibility !== 'hidden' && button.classList.contains('hide')); + } + }]); + + return FormStep; +}(); + +var FormActions = function () { + function FormActions(dom, userForm) { + _classCallCheck(this, FormActions); + + this.dom = dom; + this.userForm = userForm; + this.prevButton = dom.querySelector('.step-button-prev'); + this.nextButton = dom.querySelector('.step-button-next'); + + this.init(); + } + + _createClass(FormActions, [{ + key: 'init', + value: function init() { + var _this3 = this; + + this.prevButton.addEventListener('click', function (e) { + e.preventDefault(); + + window.triggerDispatchEvent(_this3.userForm.dom, 'userform.action.prev'); + }); + this.nextButton.addEventListener('click', function (e) { + e.preventDefault(); + + window.triggerDispatchEvent(_this3.userForm.dom, 'userform.action.next'); + }); + + this.update(); + + this.userForm.dom.addEventListener('userform.form.changestep', function () { + _this3.update(); + }); + + this.userForm.dom.addEventListener('userform.form.conditionalstep', function () { + _this3.update(); + }); + } + }, { + key: 'update', + value: function update() { + var numberOfSteps = this.userForm.getNumberOfSteps(); + var stepID = this.userForm.getCurrentStepID(); + var i = null; + var lastStep = null; + for (i = numberOfSteps - 1; i >= 0; i--) { + lastStep = this.userForm.getStep(i); + if (!lastStep.conditionallyHidden()) { + if (stepID >= i) { + this.nextButton.parentNode.classList.add('hide'); + this.prevButton.parentNode.classList.remove('hide'); + } else { + this.nextButton.parentNode.classList.remove('hide'); + this.prevButton.parentNode.classList.add('hide'); + } + + if (stepID >= i) { + this.dom.querySelector('.btn-toolbar').classList.remove('hide'); + } else { + this.dom.querySelector('.btn-toolbar').classList.add('hide'); + } + + break; + } + } + } + }]); + + return FormActions; +}(); + +var UserForm = function () { + function UserForm(form) { + _classCallCheck(this, UserForm); + + this.dom = form; + this.CONSTANTS = {}; + this.steps = []; + this.progressBar = null; + this.actions = null; + this.currentStep = null; + + this.CONSTANTS.ENABLE_LIVE_VALIDATION = this.dom.getAttribute('livevalidation') !== undefined; + this.CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP = this.dom.getAttribute('toperrors') !== undefined; + } + + _createClass(UserForm, [{ + key: 'init', + value: function init() { + this.initialiseFormSteps(); + } + }, { + key: 'initialiseFormSteps', + value: function initialiseFormSteps() { + var _this4 = this; + + var steps = this.dom.querySelectorAll('.form-step'); + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = steps[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + var stepDom = _step5.value; + + var step = new FormStep(stepDom, this); + step.hide(); + this.addStep(step); + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + this.setCurrentStep(this.steps[0]); + + var progressBarDom = this.dom.querySelector('.userform-progress'); + if (progressBarDom) { + this.progressBar = new ProgressBar(progressBarDom, this); + } + + var stepNavigation = this.dom.querySelector('.step-navigation'); + if (stepNavigation) { + this.formActions = new FormActions(stepNavigation, this); + this.formActions.update(); + } + + this.setUpPing(); + + this.dom.addEventListener('userform.action.next', function () { + _this4.nextStep(); + }); + + this.dom.addEventListener('userform.action.prev', function () { + _this4.prevStep(); + }); + } + }, { + key: 'setCurrentStep', + value: function setCurrentStep(step) { + if (!(step instanceof FormStep)) { + return; + } + this.currentStep = step; + this.currentStep.show(); + } + }, { + key: 'addStep', + value: function addStep(step) { + if (!(step instanceof FormStep)) { + return; + } + step.setId(this.steps.length); + this.steps.push(step); + } + }, { + key: 'getNumberOfSteps', + value: function getNumberOfSteps() { + return this.steps.length; + } + }, { + key: 'getCurrentStepID', + value: function getCurrentStepID() { + return this.currentStep.id ? this.currentStep.id : 0; + } + }, { + key: 'getStep', + value: function getStep(index) { + return this.steps[index]; + } + }, { + key: 'nextStep', + value: function nextStep() { + this.jumpToStep(this.steps.indexOf(this.currentStep) + 1, true); + } + }, { + key: 'prevStep', + value: function prevStep() { + this.jumpToStep(this.steps.indexOf(this.currentStep) - 1, true); + } + }, { + key: 'jumpToStep', + value: function jumpToStep(stepNumber, direction) { + var targetStep = this.steps[stepNumber]; + var isValid = false; + var forward = direction === undefined ? true : direction; + + if (targetStep === undefined) { + return; + } + + if (targetStep.conditionallyHidden()) { + if (forward) { + this.jumpToStep(stepNumber + 1, direction); + } else { + this.jumpToStep(stepNumber - 1, direction); + } + return; + } + + if (this.currentStep) { + this.currentStep.hide(); + } + + this.setCurrentStep(targetStep); + + window.triggerDispatchEvent(this.dom, 'userform.form.changestep', { + stepId: targetStep.id + }); + } + }, { + key: 'setUpPing', + value: function setUpPing() { + window.setInterval(function () { + fetch('UserDefinedFormController/ping'); + }, 180 * 1000); + } + }]); + + return UserForm; +}(); + +/***/ }), + +/***/ "./client/src/bundles/bundle.js": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +__webpack_require__("./client/src/bundles/UserForms.js"); + +/***/ }), + +/***/ 0: +/***/ (function(module, exports) { + +module.exports = i18n; + +/***/ }) + +/******/ }); +//# sourceMappingURL=userforms.js.map \ No newline at end of file diff --git a/client/dist/js/userforms.js.map b/client/dist/js/userforms.js.map new file mode 100644 index 000000000..089496ca7 --- /dev/null +++ b/client/dist/js/userforms.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap e2f07d8e3ae6498ec04b","webpack:///./client/src/bundles/UserForms.js","webpack:///./client/src/bundles/bundle.js","webpack:///external \"i18n\""],"names":["document","addEventListener","forms","querySelectorAll","form","userForm","UserForm","init","ProgressBar","dom","progressTitle","querySelector","buttons","currentStepNumber","style","display","button","e","preventDefault","stepNumber","parseInt","getAttribute","jumpToStep","update","detail","stepId","element","visibility","classList","contains","getCurrentStepID","newStep","getStep","newStepElement","step","barWidth","length","innerText","setAttribute","parent","parentNode","isVisible","add","disabled","remove","width","FormStep","viewed","buttonHolder","id","getHTMLId","forEach","action","trigger","FormActions","prevButton","nextButton","window","triggerDispatchEvent","numberOfSteps","getNumberOfSteps","stepID","i","lastStep","conditionallyHidden","CONSTANTS","steps","progressBar","actions","currentStep","ENABLE_LIVE_VALIDATION","undefined","DISPLAY_ERROR_MESSAGES_AT_TOP","initialiseFormSteps","stepDom","hide","addStep","setCurrentStep","progressBarDom","stepNavigation","formActions","setUpPing","nextStep","prevStep","show","setId","push","index","indexOf","direction","targetStep","isValid","forward","setInterval","fetch"],"mappings":"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","file":"js/userforms.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./client/src/bundles/bundle.js\");\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap e2f07d8e3ae6498ec04b","/**\n * @file Manages the multi-step navigation.\n */\n\nimport i18n from 'i18n';\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n\n const forms = document.querySelectorAll('form.userform');\n for (const form of forms) {\n const userForm = new UserForm(form);\n userForm.init();\n }\n\n});\n\n\nclass ProgressBar {\n\n constructor(dom, userForm) {\n this.dom = dom;\n this.userForm = userForm;\n this.progressTitle = this.userForm.dom.querySelector('.progress-title');\n this.buttons = this.dom.querySelectorAll('.step-button-jump');\n this.currentStepNumber = this.dom.querySelector('.current-step-number');\n this.init();\n }\n\n init() {\n this.dom.style.display = 'initial';\n const buttons = this.buttons;\n for (const button of buttons) {\n button.addEventListener('click', (e) => {\n e.preventDefault();\n const stepNumber = parseInt(button.getAttribute('data-step'), 10);\n this.userForm.jumpToStep(stepNumber);\n return false;\n });\n }\n\n this.userForm.dom.addEventListener('userform.form.changestep', (e) => {\n this.update(e.detail.stepId);\n });\n\n this.update(0)\n\n }\n\n isVisible(element) {\n return !(element.style.display !== 'none' && element.style.visibility !== 'hidden' && element.classList.contains('hide'))\n }\n\n update(stepId) {\n let stepNumber = this.userForm.getCurrentStepID() + 1;\n let newStep = this.userForm.getStep(stepId);\n let newStepElement = newStep.step;\n let barWidth = (stepId / (this.buttons.length - 1)) * 100;\n\n this.currentStepNumber.innerText = stepNumber;\n\n for (const e of this.dom.querySelectorAll('[aria-valuenow]')) {\n e.setAttribute('aria-valuenow', stepNumber);\n }\n\n for (const button of this.buttons) {\n const parent = button.parentNode;\n if (parseInt(button.getAttribute('data-step'), 10) === stepNumber\n && this.isVisible(button)) {\n parent.classList.add('current');\n parent.classList.add('viewed');\n\n button.disabled = false; // .removeAttribute('disabled');\n break;\n }\n parent.classList.remove('current');\n\n }\n\n\n this.progressTitle.innerText = newStepElement.getAttribute('data-title');\n\n // Update the width of the progress bar.\n barWidth = barWidth ? `${barWidth}%` : '';\n this.dom.querySelector('.progress-bar').style.width = barWidth;\n }\n\n}\n\nclass FormStep {\n\n constructor(step, userForm) {\n this.step = step;\n this.userForm = userForm;\n this.viewed = false;\n this.buttonHolder = null;\n this.id = 0;\n\n this.init();\n }\n\n init() {\n const id = this.getHTMLId();\n this.buttonHolder = document.querySelector(`.step-button-wrapper[data-for='${id}']`);\n ['userform.field.hide', 'userform.field.show'].forEach((action) => {\n this.buttonHolder.addEventListener(action, () => {\n this.userForm.dom.trigger('userform.form.conditionalstep')\n });\n })\n }\n\n setId(id) {\n this.id = id;\n }\n\n getHTMLId() {\n return this.step.getAttribute('id');\n }\n\n show() {\n this.step.setAttribute('aria-hidden', false);\n this.step.classList.remove('hide');\n this.step.classList.add('viewed');\n this.viewed = true;\n }\n\n hide() {\n this.step.setAttribute('aria-hidden', true);\n this.step.classList.add('hide');\n }\n\n conditionallyHidden() {\n const button = this.buttonHolder.querySelector('button');\n return !(button.style.display !== 'none' && button.visibility !== 'hidden' && button.classList.contains('hide'))\n }\n\n}\n\nclass FormActions {\n\n constructor(dom, userForm) {\n this.dom = dom;\n this.userForm = userForm;\n this.prevButton = dom.querySelector('.step-button-prev');\n this.nextButton = dom.querySelector('.step-button-next');\n\n this.init();\n }\n\n init() {\n this.prevButton.addEventListener('click', (e) => {\n e.preventDefault();\n // scrollUpFx();\n window.triggerDispatchEvent(this.userForm.dom, 'userform.action.prev');\n });\n this.nextButton.addEventListener('click', (e) => {\n e.preventDefault();\n // scrollUpFx();\n window.triggerDispatchEvent(this.userForm.dom, 'userform.action.next');\n });\n\n this.update();\n\n this.userForm.dom.addEventListener('userform.form.changestep', () => {\n this.update();\n });\n\n this.userForm.dom.addEventListener('userform.form.conditionalstep', () => {\n this.update();\n });\n\n }\n\n update() {\n const numberOfSteps = this.userForm.getNumberOfSteps();\n const stepID = this.userForm.getCurrentStepID();\n let i = null;\n let lastStep = null;\n for (i = numberOfSteps - 1; i >= 0; i--) {\n lastStep = this.userForm.getStep(i);\n if (!lastStep.conditionallyHidden()) {\n if (stepID >= i) {\n this.nextButton.parentNode.classList.add('hide');\n this.prevButton.parentNode.classList.remove('hide');\n } else {\n this.nextButton.parentNode.classList.remove('hide');\n this.prevButton.parentNode.classList.add('hide');\n }\n\n if (stepID >= i) {\n this.dom.querySelector('.btn-toolbar').classList.remove('hide');\n } else {\n this.dom.querySelector('.btn-toolbar').classList.add('hide');\n }\n\n // this.userForm.dom.querySelector('.btn-toolbar');\n break;\n }\n }\n }\n\n}\n\n\nclass UserForm {\n\n constructor(form) {\n this.dom = form;\n this.CONSTANTS = {}; // Settings that come from the CMS.\n this.steps = [];\n this.progressBar = null;\n this.actions = null;\n this.currentStep = null;\n\n this.CONSTANTS.ENABLE_LIVE_VALIDATION = this.dom.getAttribute('livevalidation') !== undefined;\n this.CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP = this.dom.getAttribute('toperrors') !== undefined;\n }\n\n init() {\n this.initialiseFormSteps();\n }\n\n initialiseFormSteps() {\n const steps = this.dom.querySelectorAll('.form-step');\n for (const stepDom of steps) {\n const step = new FormStep(stepDom, this);\n step.hide();\n this.addStep(step);\n }\n\n this.setCurrentStep(this.steps[0]);\n\n const progressBarDom = this.dom.querySelector('.userform-progress');\n if (progressBarDom) {\n this.progressBar = new ProgressBar(progressBarDom, this);\n }\n\n const stepNavigation = this.dom.querySelector('.step-navigation');\n if (stepNavigation) {\n this.formActions = new FormActions(stepNavigation, this);\n this.formActions.update();\n }\n\n this.setUpPing();\n\n this.dom.addEventListener('userform.action.next', () => {\n this.nextStep();\n })\n\n this.dom.addEventListener('userform.action.prev', () => {\n this.prevStep();\n })\n\n }\n\n setCurrentStep(step) {\n // Make sure we're dealing with a form step.\n if (!(step instanceof FormStep)) {\n return;\n }\n this.currentStep = step;\n this.currentStep.show();\n }\n\n addStep(step) {\n if (!(step instanceof FormStep)) {\n return;\n }\n step.setId(this.steps.length);\n this.steps.push(step);\n }\n\n getNumberOfSteps() {\n return this.steps.length;\n }\n\n getCurrentStepID() {\n return this.currentStep.id ? this.currentStep.id : 0;\n }\n\n getStep(index) {\n return this.steps[index];\n }\n\n nextStep() {\n this.jumpToStep(this.steps.indexOf(this.currentStep) + 1, true);\n }\n\n prevStep() {\n this.jumpToStep(this.steps.indexOf(this.currentStep) - 1, true);\n }\n\n jumpToStep(stepNumber, direction)\n {\n const targetStep = this.steps[stepNumber];\n let isValid = false;\n const forward = direction === undefined ? true : direction;\n\n if (targetStep === undefined) {\n return;\n }\n\n if (targetStep.conditionallyHidden()) {\n if (forward) {\n this.jumpToStep(stepNumber + 1, direction);\n } else {\n this.jumpToStep(stepNumber - 1, direction);\n }\n return;\n }\n\n if (this.currentStep) {\n this.currentStep.hide();\n }\n\n this.setCurrentStep(targetStep);\n\n window.triggerDispatchEvent(this.dom, 'userform.form.changestep', {\n stepId: targetStep.id\n });\n }\n\n setUpPing() {\n // Make sure the form doesn't expire on the user. Pings every 3 mins.\n window.setInterval(() => {\n fetch('UserDefinedFormController/ping');\n }, 180 * 1000);\n }\n\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/bundles/UserForms.js","// Used for frontend userforms\nimport 'bundles/UserForms';\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/bundles/bundle.js","module.exports = i18n;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"i18n\"\n// module id = 0\n// module chunks = 0"],"sourceRoot":""} \ No newline at end of file diff --git a/client/dist/styles/userforms-cms.css b/client/dist/styles/userforms-cms.css index 13130a19d..5cec85730 100644 --- a/client/dist/styles/userforms-cms.css +++ b/client/dist/styles/userforms-cms.css @@ -1 +1,2 @@ -.uf-field-editor{padding-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item{height:46px}.uf-field-editor .grid-field__table .ss-gridfield-item,.uf-field-editor .grid-field__table .ss-gridfield-item:hover{background:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item td{border-right-width:0;vertical-align:middle;padding-top:6px;padding-bottom:6px}.uf-field-editor .grid-field__table .ss-gridfield-item td:last-child{border-right-width:1px}.uf-field-editor .grid-field__table .ss-gridfield-item .handle{min-height:46px}.uf-field-editor .grid-field__table .ss-gridfield-item.flash-background{-webkit-animation:flash-background 2s linear;-o-animation:flash-background 2s linear;animation:flash-background 2s linear}.uf-field-editor .grid-field__table .ss-gridfield-item.ui-sortable-placeholder{height:50px}.uf-field-editor .grid-field__table .ss-gridfield-item .form-group{padding:0;margin-bottom:2px;color:#43536d}.uf-field-editor .grid-field__table .ss-gridfield-item .form-group:after{border-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item .form-group .form__field-label{-webkit-box-flex:1;-webkit-flex:auto;flex:auto;max-width:100%;padding-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup,.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup:hover{background:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup .col-reorder,.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup .handle{background:#ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep],.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep]:hover{background:#566b8d;color:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep] label{font-weight:700;color:#fff;font-size:15px;padding-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep]+.ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup] td{border-top:3px solid #ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep] .grid-field__icon-action:before{color:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep] .grid-field__icon-action:hover:before{color:#566b8d}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup] td{border-top:3px solid #ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup] .form__field-label{font-weight:700;padding-bottom:0;color:#43536d}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd] td{border-bottom:3px solid #ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd]+.ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd]{border-top:0}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd] .col-buttons .action{display:none}.uf-field-editor .sticky-buttons{position:fixed;top:73px;z-index:1;background:#fafbfc;border-bottom:1px solid #dbe0e9;padding:12px;margin-left:-12px}.uf-field-editor .sticky-buttons button.action{margin-bottom:0}.uf-field-editor .sticky-buttons~.ss-gridfield-table{margin-top:73px}.cms .grid-field__table .grid-field__uf-filter-header{padding:0}.cms .grid-field__table .grid-field__uf-filter-header .form__fieldgroup-label{color:#fff}.cms .grid-field__table .grid-field__uf-filter-header .ss-gridfield-button-filter:not(.trigger),.cms .grid-field__table .grid-field__uf-filter-header .ss-gridfield-button-filter:not(.trigger):hover{background-color:#3fa142}.cms .grid-field__table .grid-field__uf-filter-header table{width:100%}.cms-preview{z-index:2}.userform-field__allowed-length .form__fieldgroup-item{margin-top:0}.userform-field__allowed-length .field.text{min-width:auto}.userform-field__allowed-length input.text{width:4rem}.userform-field__allowed-length-separator{display:inline-block;margin:0 .6rem .6rem 0}.userform-confirm-folder .form__field-description{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.userform-confirm-folder .form__field-description .icon:before{font-size:16px;line-height:inherit;margin-right:6px;vertical-align:middle} \ No newline at end of file +.uf-field-editor{padding-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item{height:46px}.uf-field-editor .grid-field__table .ss-gridfield-item,.uf-field-editor .grid-field__table .ss-gridfield-item:hover{background:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item td{border-right-width:0;vertical-align:middle;padding-top:6px;padding-bottom:6px}.uf-field-editor .grid-field__table .ss-gridfield-item td:last-child{border-right-width:1px}.uf-field-editor .grid-field__table .ss-gridfield-item .handle{min-height:46px}.uf-field-editor .grid-field__table .ss-gridfield-item.flash-background{-webkit-animation:flash-background 2s linear;-o-animation:flash-background 2s linear;animation:flash-background 2s linear}.uf-field-editor .grid-field__table .ss-gridfield-item.ui-sortable-placeholder{height:50px}.uf-field-editor .grid-field__table .ss-gridfield-item .form-group{padding:0;margin-bottom:2px;color:#43536d}.uf-field-editor .grid-field__table .ss-gridfield-item .form-group:after{border-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item .form-group .form__field-label{-webkit-box-flex:1;-webkit-flex:auto;flex:auto;max-width:100%;padding-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup,.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup:hover{background:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup .col-reorder,.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup .handle{background:#ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep],.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep]:hover{background:#566b8d;color:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep] label{font-weight:700;color:#fff;font-size:15px;padding-bottom:0}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep]+.ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup] td{border-top:3px solid #ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep] .grid-field__icon-action:before{color:#fff}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFormStep] .grid-field__icon-action:hover:before{color:#566b8d}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup] td{border-top:3px solid #ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroup] .form__field-label{font-weight:700;padding-bottom:0;color:#43536d}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd] td{border-bottom:3px solid #ced5e1}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd]+.ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd]{border-top:0}.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=SilverStripe\\UserForms\\Model\\EditableFormField\\EditableFieldGroupEnd] .col-buttons .action{display:none}.uf-field-editor .sticky-buttons{position:fixed;top:73px;z-index:1;background:#fafbfc;border-bottom:1px solid #dbe0e9;padding:12px;margin-left:-12px}.uf-field-editor .sticky-buttons button.action{margin-bottom:0}.uf-field-editor .sticky-buttons~.ss-gridfield-table{margin-top:73px}.cms .grid-field__table .grid-field__uf-filter-header{padding:0}.cms .grid-field__table .grid-field__uf-filter-header .form__fieldgroup-label{color:#fff}.cms .grid-field__table .grid-field__uf-filter-header .ss-gridfield-button-filter:not(.trigger),.cms .grid-field__table .grid-field__uf-filter-header .ss-gridfield-button-filter:not(.trigger):hover{background-color:#3fa142}.cms .grid-field__table .grid-field__uf-filter-header table{width:100%}.cms-preview{z-index:2}.userform-field__allowed-length .form__fieldgroup-item{margin-top:0}.userform-field__allowed-length .field.text{min-width:auto}.userform-field__allowed-length input.text{width:4rem}.userform-field__allowed-length-separator{display:inline-block;margin:0 .6rem .6rem 0}.userform-confirm-folder .form__field-description{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center}.userform-confirm-folder .form__field-description .icon:before{font-size:16px;line-height:inherit;margin-right:6px;vertical-align:middle} +/*# sourceMappingURL=userforms-cms.css.map*/ \ No newline at end of file diff --git a/client/dist/styles/userforms-cms.css.map b/client/dist/styles/userforms-cms.css.map new file mode 100644 index 000000000..164c8c021 --- /dev/null +++ b/client/dist/styles/userforms-cms.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./client/src/styles/userforms-cms.scss?61a4","webpack:///./client/src/styles/bundle-cms.scss?147d"],"names":[],"mappings":"AAAA,iBACE,iBCCD,uDDKK,YCDL,oHDKO,gBCAP,0DDIO,qBACA,sBACA,gBACA,mBCAP,qEDGS,uBCCT,+DDIO,gBCAP,wEDIO,0HCAP,+EDIO,YCAP,mEDIO,UACA,kBACA,cCAP,yEDGS,gBCCT,sFDGS,+CACA,eACA,iBCCT,8IDOO,gBCFP,6JDOO,mBCFP,oRDSO,mBACA,WCJP,6IDQO,gBACA,WACA,eACA,iBCJP,+ODQO,6BCJP,uKDSS,WCLT,6KDUW,cCNX,4IDcO,6BCVP,4JDcO,gBACA,iBACA,cCVP,+IDgBO,gCCZP,oPDgBO,aCZP,iKDgBO,aCZP,iCDkBG,eACA,SACA,UACA,mBACA,gCACA,aACA,kBCdH,+CDiBK,gBCbL,qDDiBK,gBCbL,sDDmBC,UCfD,8EDkBG,WCdH,sMDsBG,yBCdH,4DDkBG,WCdH,aDqBC,UCjBD,uDDyBK,aCrBL,4CDyBK,eCrBL,2CDyBK,WCrBL,0CD0BG,qBACA,uBCtBH,kDD2BC,sDACA,uECvBD,+DD2BK,eACA,oBACA,iBACA","file":"styles/userforms-cms.css","sourcesContent":[".uf-field-editor {\n padding-bottom: 0;\n\n // Row styles\n .grid-field__table {\n // Standard rows\n .ss-gridfield-item {\n height: 46px;\n\n &,\n &:hover {\n background: $white;\n }\n\n td {\n border-right-width: 0;\n vertical-align: middle;\n padding-top: 6px;\n padding-bottom: 6px;\n\n &:last-child {\n border-right-width: 1px;\n }\n }\n\n .handle {\n min-height: 46px;\n }\n\n &.flash-background {\n animation: flash-background 2s linear;\n }\n\n &.ui-sortable-placeholder {\n height: 50px;\n }\n\n .form-group {\n padding: 0;\n margin-bottom: 2px;\n color: $gray-700;\n\n &:after {\n border-bottom: 0;\n }\n\n .form__field-label {\n flex: auto;\n max-width: 100%;\n padding-bottom: 0;\n }\n }\n }\n\n .ss-gridfield-item.infieldgroup {\n &,\n &:hover {\n background: $white;\n }\n\n .col-reorder,\n .handle {\n background: $gray-200;\n }\n }\n\n .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"] {\n &,\n &:hover {\n background: $gray-600;\n color: $white;\n }\n\n label {\n font-weight: bold;\n color: $white;\n font-size: 15px;\n padding-bottom: 0;\n }\n\n + .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroup\"] td {\n border-top: 3px solid $gray-200;\n }\n\n .grid-field__icon-action {\n &:before {\n color: $white;\n }\n\n &:hover {\n &:before {\n color: $gray-600;\n }\n }\n }\n }\n\n .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroup\"] {\n td {\n border-top: 3px solid $gray-200;\n }\n\n .form__field-label {\n font-weight: bold;\n padding-bottom: 0;\n color: $gray-700;\n }\n }\n\n .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd\"] {\n td {\n border-bottom: 3px solid $gray-200;\n }\n\n + .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd\"] {\n border-top: 0;\n }\n\n .col-buttons .action {\n display: none;\n }\n }\n }\n\n .sticky-buttons {\n position: fixed;\n top: 73px;\n z-index: 1;\n background: $body-bg;\n border-bottom: 1px solid $border-color-light;\n padding: 12px;\n margin-left: -12px;\n\n & button.action {\n margin-bottom: 0;\n }\n\n ~ .ss-gridfield-table {\n margin-top: 73px;\n }\n }\n}\n\n.cms .grid-field__table .grid-field__uf-filter-header {\n padding: 0;\n\n .form__fieldgroup-label {\n color: $white;\n }\n\n .ss-gridfield-button-filter:not(.trigger) {\n background-color: $brand-success;\n }\n\n .ss-gridfield-button-filter:not(.trigger):hover {\n background-color: $brand-success;\n }\n\n table {\n width: 100%;\n }\n}\n\n// The preview's Z-index needs to be higher than the .sticky-buttons one, so the form's toolbar won't extend into the\n// preview area\n.cms-preview {\n z-index: 2;\n}\n\n// Custom styles for userforms fields in the CMS\n.userform-field {\n &__allowed-length {\n .form__fieldgroup-item {\n // Removing default margin-top from field group, this one already has one in its parent container\n margin-top: 0;\n }\n\n .field.text {\n min-width: auto;\n }\n\n input.text {\n width: 4rem;\n }\n }\n\n &__allowed-length-separator {\n display: inline-block;\n margin: 0 .6rem .6rem 0;\n }\n}\n\n.userform-confirm-folder .form__field-description {\n display: flex;\n align-items: center;\n\n .icon {\n &::before {\n font-size: 16px;\n line-height: inherit;\n margin-right: 6px;\n vertical-align: middle;\n }\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/userforms-cms.scss",".uf-field-editor {\n padding-bottom: 0;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item {\n height: 46px;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item,\n.uf-field-editor .grid-field__table .ss-gridfield-item:hover {\n background: #fff;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item td {\n border-right-width: 0;\n vertical-align: middle;\n padding-top: 6px;\n padding-bottom: 6px;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item td:last-child {\n border-right-width: 1px;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item .handle {\n min-height: 46px;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item.flash-background {\n animation: flash-background 2s linear;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item.ui-sortable-placeholder {\n height: 50px;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item .form-group {\n padding: 0;\n margin-bottom: 2px;\n color: #43536d;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item .form-group:after {\n border-bottom: 0;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item .form-group .form__field-label {\n flex: auto;\n max-width: 100%;\n padding-bottom: 0;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup,\n.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup:hover {\n background: #fff;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup .col-reorder,\n.uf-field-editor .grid-field__table .ss-gridfield-item.infieldgroup .handle {\n background: #ced5e1;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"],\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"]:hover {\n background: #566b8d;\n color: #fff;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"] label {\n font-weight: bold;\n color: #fff;\n font-size: 15px;\n padding-bottom: 0;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"] + .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroup\"] td {\n border-top: 3px solid #ced5e1;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"] .grid-field__icon-action:before {\n color: #fff;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFormStep\"] .grid-field__icon-action:hover:before {\n color: #566b8d;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroup\"] td {\n border-top: 3px solid #ced5e1;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroup\"] .form__field-label {\n font-weight: bold;\n padding-bottom: 0;\n color: #43536d;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd\"] td {\n border-bottom: 3px solid #ced5e1;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd\"] + .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd\"] {\n border-top: 0;\n}\n\n.uf-field-editor .grid-field__table .ss-gridfield-item[data-class=\"SilverStripe\\\\UserForms\\\\Model\\\\EditableFormField\\\\EditableFieldGroupEnd\"] .col-buttons .action {\n display: none;\n}\n\n.uf-field-editor .sticky-buttons {\n position: fixed;\n top: 73px;\n z-index: 1;\n background: #fafbfc;\n border-bottom: 1px solid #dbe0e9;\n padding: 12px;\n margin-left: -12px;\n}\n\n.uf-field-editor .sticky-buttons button.action {\n margin-bottom: 0;\n}\n\n.uf-field-editor .sticky-buttons ~ .ss-gridfield-table {\n margin-top: 73px;\n}\n\n.cms .grid-field__table .grid-field__uf-filter-header {\n padding: 0;\n}\n\n.cms .grid-field__table .grid-field__uf-filter-header .form__fieldgroup-label {\n color: #fff;\n}\n\n.cms .grid-field__table .grid-field__uf-filter-header .ss-gridfield-button-filter:not(.trigger) {\n background-color: #3fa142;\n}\n\n.cms .grid-field__table .grid-field__uf-filter-header .ss-gridfield-button-filter:not(.trigger):hover {\n background-color: #3fa142;\n}\n\n.cms .grid-field__table .grid-field__uf-filter-header table {\n width: 100%;\n}\n\n.cms-preview {\n z-index: 2;\n}\n\n.userform-field__allowed-length .form__fieldgroup-item {\n margin-top: 0;\n}\n\n.userform-field__allowed-length .field.text {\n min-width: auto;\n}\n\n.userform-field__allowed-length input.text {\n width: 4rem;\n}\n\n.userform-field__allowed-length-separator {\n display: inline-block;\n margin: 0 .6rem .6rem 0;\n}\n\n.userform-confirm-folder .form__field-description {\n display: flex;\n align-items: center;\n}\n\n.userform-confirm-folder .form__field-description .icon::before {\n font-size: 16px;\n line-height: inherit;\n margin-right: 6px;\n vertical-align: middle;\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/bundle-cms.scss"],"sourceRoot":""} \ No newline at end of file diff --git a/client/dist/styles/userforms.css b/client/dist/styles/userforms.css index 3754af860..f8144654c 100644 --- a/client/dist/styles/userforms.css +++ b/client/dist/styles/userforms.css @@ -1 +1,2 @@ -.userform-progress .progress{position:relative;height:1em;background:#ced5e1}.userform-progress .progress-bar{position:absolute;height:1em;background:#566b8d}.userform-progress .step-buttons{margin-left:0;position:relative}.userform-progress .step-button-wrapper{display:inline-block;list-style-type:none}.userform-progress .step-button-wrapper.viewed .step-button-jump{opacity:1}.userform-progress .step-button-jump{position:absolute;top:0;opacity:.7}.step-navigation .step-buttons{margin-left:0}.step-navigation .step-button-wrapper{display:inline-block;list-style-type:none}.userform{clear:both;width:100%;max-width:100%}.userform .hide{display:none}.userform .field label.right{color:#303b4d}.userformsgroup{border:1px solid #aebace;border-radius:4px;padding:8px;margin-top:12px;margin-bottom:12px}.userformsgroup>legend{padding-left:4px;padding-right:4px;border:0;width:auto}.right-title{clear:both;display:block}.checkbox .right-title{display:inline}.userform .left{margin-bottom:5px;font-weight:700} \ No newline at end of file +.userform-progress .progress{position:relative;height:1em;background:#ced5e1}.userform-progress .progress-bar{position:absolute;height:1em;background:#566b8d}.userform-progress .step-buttons{margin-left:0;padding-left:0;width:100%;display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;position:relative}.userform-progress .step-button-wrapper{display:inline-block;list-style-type:none}.userform-progress .step-button-wrapper.viewed .step-button-jump{opacity:1}.userform-progress .step-button-jump{opacity:.7}.step-navigation .step-buttons{margin-left:0}.step-navigation .step-button-wrapper{display:inline-block;list-style-type:none}.userform{clear:both;width:100%;max-width:100%}.userform .hide{display:none}.userform .field label.right{color:#303b4d}.userformsgroup{border:1px solid #aebace;border-radius:4px;padding:8px;margin-top:12px;margin-bottom:12px}.userformsgroup>legend{padding-left:4px;padding-right:4px;border:0;width:auto}.right-title{clear:both;display:block}.checkbox .right-title{display:inline}.userform .left{margin-bottom:5px;font-weight:700} +/*# sourceMappingURL=userforms.css.map*/ \ No newline at end of file diff --git a/client/dist/styles/userforms.css.map b/client/dist/styles/userforms.css.map new file mode 100644 index 000000000..1dc436c42 --- /dev/null +++ b/client/dist/styles/userforms.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./client/src/styles/userforms.scss?1f22","webpack:///./client/src/styles/bundle.scss?71e6"],"names":[],"mappings":"AAEA,6BAEI,kBACA,WACA,mBCFH,iCDMG,kBACA,WACA,mBCFH,iCDMG,cACA,eACA,WACA,sDACA,6FACA,kBCFH,wCDMG,qBACA,qBCFH,iEDKK,UCDL,qCDQG,WCJH,+BDUG,cCNH,sCDUG,qBACA,qBCNH,UDWC,WACA,WACA,eCPD,gBDUG,aCNH,6BDUG,cCNH,gBDWC,yBACA,kBACA,YACA,gBACA,mBCPD,uBDUG,iBACA,kBACA,SACA,WCNH,aDWC,WACA,cCPD,uBDWC,eCPD,gBDWC,kBACA","file":"styles/userforms.css","sourcesContent":["// Lightweight base styles for the front-end form.\n\n.userform-progress {\n .progress {\n position: relative;\n height: 1em;\n background: $gray-200;\n }\n\n .progress-bar {\n position: absolute;\n height: 1em;\n background: $gray-600;\n }\n\n .step-buttons {\n margin-left: 0;\n padding-left: 0;\n width: 100%;\n display: flex;\n justify-content: space-between;\n position: relative;\n }\n\n .step-button-wrapper {\n display: inline-block;\n list-style-type: none;\n\n &.viewed .step-button-jump {\n opacity: 1;\n }\n }\n\n .step-button-jump {\n //position: absolute;\n //top: 0;\n opacity: .7;\n }\n}\n\n.step-navigation {\n .step-buttons {\n margin-left: 0;\n }\n\n .step-button-wrapper {\n display: inline-block;\n list-style-type: none;\n }\n}\n\n.userform {\n clear: both;\n width: 100%;\n max-width: 100%;\n\n .hide {\n display: none;\n }\n\n .field label.right {\n color: $gray-800;\n }\n}\n\n.userformsgroup {\n border: 1px solid $gray-300;\n border-radius: 4px;\n padding: 8px;\n margin-top: 12px;\n margin-bottom: 12px;\n\n > legend {\n padding-left: 4px;\n padding-right: 4px;\n border: 0;\n width: auto;\n }\n}\n\n.right-title {\n clear: both;\n display: block;\n}\n\n.checkbox .right-title {\n display: inline;\n}\n\n.userform .left {\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/userforms.scss",".userform-progress .progress {\n position: relative;\n height: 1em;\n background: #ced5e1;\n}\n\n.userform-progress .progress-bar {\n position: absolute;\n height: 1em;\n background: #566b8d;\n}\n\n.userform-progress .step-buttons {\n margin-left: 0;\n padding-left: 0;\n width: 100%;\n display: flex;\n justify-content: space-between;\n position: relative;\n}\n\n.userform-progress .step-button-wrapper {\n display: inline-block;\n list-style-type: none;\n}\n\n.userform-progress .step-button-wrapper.viewed .step-button-jump {\n opacity: 1;\n}\n\n.userform-progress .step-button-jump {\n opacity: .7;\n}\n\n.step-navigation .step-buttons {\n margin-left: 0;\n}\n\n.step-navigation .step-button-wrapper {\n display: inline-block;\n list-style-type: none;\n}\n\n.userform {\n clear: both;\n width: 100%;\n max-width: 100%;\n}\n\n.userform .hide {\n display: none;\n}\n\n.userform .field label.right {\n color: #303b4d;\n}\n\n.userformsgroup {\n border: 1px solid #aebace;\n border-radius: 4px;\n padding: 8px;\n margin-top: 12px;\n margin-bottom: 12px;\n}\n\n.userformsgroup > legend {\n padding-left: 4px;\n padding-right: 4px;\n border: 0;\n width: auto;\n}\n\n.right-title {\n clear: both;\n display: block;\n}\n\n.checkbox .right-title {\n display: inline;\n}\n\n.userform .left {\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/bundle.scss"],"sourceRoot":""} \ No newline at end of file diff --git a/client/src/bundles/UserForms.js b/client/src/bundles/UserForms.js index aeea16723..7396eee99 100644 --- a/client/src/bundles/UserForms.js +++ b/client/src/bundles/UserForms.js @@ -2,773 +2,329 @@ * @file Manages the multi-step navigation. */ -import jQuery from 'jquery'; import i18n from 'i18n'; -jQuery(document).ready(($) => { - // Settings that come from the CMS. - const CONSTANTS = {}; - - // Common functions that extend multiple classes. - const commonMixin = { - /** - * @func show - * @desc Show the form step. Looks after aria attributes too. - */ - show() { - this.$el.attr('aria-hidden', false).show(); - }, - /** - * @func hide - * @desc Hide the form step. Looks after aria attributes too. - */ - hide() { - this.$el.attr('aria-hidden', true).hide(); - }, - }; - - /** - * @func ErrorContainer - * @constructor - * @param {object} element - The error container element. - * @return {object} - The ErrorContainer instance. - * @desc Creates an error container. Used to display step error messages at the top. - */ - function ErrorContainer(element) { - this.$el = element instanceof $ ? element : $(element); - - // Set the error container's heading. - this.$el.find('h4').text(i18n._t('UserForms.ERROR_CONTAINER_HEADER', - 'Please correct the following errors and try again:')); - - return this; - } - - /** - * @func hasErrors - * @return boolean - * @desc Checks if the error container has any error messages. - */ - ErrorContainer.prototype.hasErrors = function hasErrors() { - return this.$el.find('.error-list').children().length > 0; - }; - - /** - * @func removeErrorMessage - * @desc Removes an error message from the error container. - */ - ErrorContainer.prototype.removeErrorMessage = function removeErrorMessage(fieldId) { - this.$el.find(`#${fieldId}-top-error`).remove(); - - // If there are no more error then hide the container. - if (!this.hasErrors()) { - this.hide(); - } - }; - - /** - * @func addStepLink - * @param {object} step - FormStep instance. - * @desc Adds a link to a form step as an error message. - */ - ErrorContainer.prototype.addStepLink = function addStepLink(step) { - const userform = this.$el.closest('.userform').data('inst'); - const itemID = `${step.$el.attr('id')}-error-link`; - let $itemElement = this.$el.find(`#${itemID}`); - const stepID = step.$el.attr('id'); - const stepTitle = step.$el.data('title'); - - // If the item already exists we don't need to do anything. - if ($itemElement.length) { - return; - } +document.addEventListener("DOMContentLoaded", () => { - $itemElement = $(`
  • ${stepTitle}
  • `); + const forms = document.querySelectorAll('form.userform'); + for (const form of forms) { + const userForm = new UserForm(form); + userForm.init(); + } - $itemElement.on('click', (e) => { - e.preventDefault(); - userform.jumpToStep(step.id); - }); +}); - this.$el.find('.error-list').append($itemElement); - }; - /** - * @func removeStepLink - * @param {object} step - FormStep instance. - * @desc Removes a step link from the error container. - */ - ErrorContainer.prototype.removeStepLink = function removeStepLink(fieldId) { - const stepID = $(`#${fieldId}`).closest('.form-step').attr('id'); +class ProgressBar { - this.$el.find(`#${stepID}-error-link`).remove(); + constructor(dom, userForm) { + this.dom = dom; + this.userForm = userForm; + this.progressTitle = this.userForm.dom.querySelector('.progress-title'); + this.buttons = this.dom.querySelectorAll('.step-button-jump'); + this.currentStepNumber = this.dom.querySelector('.current-step-number'); + this.init(); + } - // Hide the error container if we've just removed the last error. - if (this.$el.find('.error-list').is(':empty')) { - this.hide(); - } - }; - - /** - * @func ErrorContainer.updateErrorMessage - * @param {object} $input - The jQuery input object which contains the field to validate. - * @param {object} message - The error message to display (html escaped). - * @desc Update an error message (displayed at the top of the form). - */ - ErrorContainer.prototype.updateErrorMessage = function updateErrorMessage($input, message) { - const inputID = $input.attr('id'); - let anchor = `#${inputID}`; - const elementID = `${inputID}-top-error`; - let messageElement = $(`#${elementID}`); - let describedBy = $input.attr('aria-describedby'); - - // The 'message' param will be an empty string if the field is valid. - if (!message) { - // Style issues as fixed if they already exist - messageElement.addClass('fixed'); - return; + init() { + this.dom.style.display = 'initial'; + const buttons = this.buttons; + for (const button of buttons) { + button.addEventListener('click', (e) => { + e.preventDefault(); + const stepNumber = parseInt(button.getAttribute('data-step'), 10); + this.userForm.jumpToStep(stepNumber); + return false; + }); } - messageElement.removeClass('fixed'); + this.userForm.dom.addEventListener('userform.form.changestep', (e) => { + this.update(e.detail.stepId); + }); - this.show(); + this.update(0) - if (messageElement.length === 1) { - // Update the existing error message. - messageElement.show().find('a').html(message); - } else { - // Generate better link to field - $input.closest('.field[id]').each(() => { - const anchorID = $(this).attr('id'); + } - if (!anchorID) { - return; - } + isVisible(element) { + return !(element.style.display !== 'none' && element.style.visibility !== 'hidden' && element.classList.contains('hide')) + } - anchor = `#${anchorID}`; - }); + update(stepId) { + let stepNumber = this.userForm.getCurrentStepID() + 1; + let newStep = this.userForm.getStep(stepId); + let newStepElement = newStep.step; + let barWidth = (stepId / (this.buttons.length - 1)) * 100; - // Add a new error message - messageElement = $('
  • '); - messageElement - .attr('id', elementID) - .find('a') - .attr('href', location.pathname + location.search + anchor) - .html(message); - - this.$el.find('ul').append(messageElement); - - // Link back to original input via aria - // Respect existing non-error aria-describedby - if (!describedBy) { - describedBy = elementID; - } else if (!describedBy.match(new RegExp(`\\b${elementID}\\b`))) { - // Add to end of list if not already present - describedBy += ` ${elementID}`; - } + this.currentStepNumber.innerText = stepNumber; - $input.attr('aria-describedby', describedBy); + for (const e of this.dom.querySelectorAll('[aria-valuenow]')) { + e.setAttribute('aria-valuenow', stepNumber); } - }; - /** - * @func FormStep - * @constructor - * @param {object} element - * @return {object} - The FormStep instance. - * @desc Creates a form step. - */ - function FormStep(element) { - const self = this; + for (const button of this.buttons) { + const parent = button.parentNode; + if (parseInt(button.getAttribute('data-step'), 10) === stepNumber + && this.isVisible(button)) { + parent.classList.add('current'); + parent.classList.add('viewed'); - this.$el = element instanceof $ ? element : $(element); - - const userform = this.$el.closest('.userform').data('inst'); - - // Find button for this step - this.$elButton = $(`.step-button-wrapper[data-for='${this.$el.prop('id')}']`); - - // Has the step been viewed by the user? - this.viewed = false; - - // Is the form step valid? - // This value is used on form submission, which fails, if any of the steps are invalid. - this.valid = false; + button.disabled = false; // .removeAttribute('disabled'); + break; + } + parent.classList.remove('current'); - // The internal id of the step. Used for getting the step from the UserForm.steps array. - this.id = null; + } - this.hide(); - if (CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP) { - this.errorContainer = new ErrorContainer(this.$el.find('.error-container')); + this.progressTitle.innerText = newStepElement.getAttribute('data-title'); - // Listen for errors on the UserForm. - userform.$el.on('userform.form.error', (e, validator) => { - // The step only cares about errors if it's currently visible. - if (!self.$el.is(':visible')) { - return; - } + // Update the width of the progress bar. + barWidth = barWidth ? `${barWidth}%` : ''; + this.dom.querySelector('.progress-bar').style.width = barWidth; + } - // Add or update each error in the list. - $.each(validator.errorList, (i, error) => { - self.errorContainer.updateErrorMessage($(error.element), error.message); - }); - }); +} - // Listen for fields becoming valid - userform.$el.on('userform.form.valid', (e, fieldId) => { - self.errorContainer.removeErrorMessage(fieldId); - }); - } +class FormStep { - // Ensure that page visibilty updates the step navigation - this - .$elButton - .on('userform.field.hide userform.field.show', () => { - userform.$el.trigger('userform.form.conditionalstep'); - }); + constructor(step, userForm) { + this.step = step; + this.userForm = userForm; + this.viewed = false; + this.buttonHolder = null; + this.id = 0; - return this; + this.init(); } - /** - * Determine if this step is conditionally disabled - * - * @returns {Boolean} - */ - // Because the element itself could be visible but 0 height, so check visibility of button - FormStep.prototype.conditionallyHidden = function conditionallyHidden() { - return !this.$elButton.find('button').is(':visible'); - }; - - /** - * @func ProgressBar - * @constructor - * @param {object} element - * @return {object} - The Progress bar instance. - * @desc Creates a progress bar. - */ - function ProgressBar(element) { - const self = this; - - this.$el = element instanceof $ ? element : $(element); - this.$buttons = this.$el.find('.step-button-jump'); - this.$jsAlign = this.$el.find('.js-align'); - const userform = this.$el.closest('.userform').data('inst'); - - // Update the progress bar when 'step' buttons are clicked. - this.$buttons.each((i, stepButton) => { - $(stepButton).on('click', (e) => { - e.preventDefault(); - const stepNumber = parseInt($(e.target).data('step'), 10); - self.$el.trigger('userform.progress.changestep', stepNumber); + init() { + const id = this.getHTMLId(); + this.buttonHolder = document.querySelector(`.step-button-wrapper[data-for='${id}']`); + ['userform.field.hide', 'userform.field.show'].forEach((action) => { + this.buttonHolder.addEventListener(action, () => { + this.userForm.dom.trigger('userform.form.conditionalstep') }); - }); + }) + } - // Update the progress bar when 'prev' and 'next' buttons are clicked. - userform.$el.on('userform.form.changestep', (e, stepID) => { - self.update(stepID); - }); + setId(id) { + this.id = id; + } - // Listen for steps being conditionally shown / hidden by display rules. - // We need to update step related UI like the number of step buttons - // and any text that shows the total number of steps. - userform.$el.on('userform.form.conditionalstep', () => { - // Update the step numbers on the buttons. - const $visibleButtons = self.$buttons.filter(':visible'); + getHTMLId() { + return this.step.getAttribute('id'); + } - $visibleButtons.each((i, button) => { - $(button).text(i + 1); - }); + show() { + this.step.setAttribute('aria-hidden', false); + this.step.classList.remove('hide'); + this.step.classList.add('viewed'); + this.viewed = true; + } - // Update the actual progress bar. - self.$el.find('.progress-bar').attr('aria-valuemax', $visibleButtons.length); + hide() { + this.step.setAttribute('aria-hidden', true); + this.step.classList.add('hide'); + } - // Update any text that uses the total number of steps. - self.$el.find('.total-step-number').text($visibleButtons.length); - }); + conditionallyHidden() { + const button = this.buttonHolder.querySelector('button'); + return !(button.style.display !== 'none' && button.visibility !== 'hidden' && button.classList.contains('hide')) + } - // Spaces out the steps below progress bar evenly - this.$jsAlign.each((index, button) => { - const $button = $(button); - const leftPercent = (100 / (self.$jsAlign.length - 1)) * index; - const leftPercentCssValue = `${leftPercent}%`; - const buttonOffset = -1 * ($button.innerWidth() / 2); +} - $button.css({ - left: leftPercentCssValue, - marginLeft: buttonOffset, - }); +class FormActions { - // First and last buttons are kept within userform-progress container - if (index === self.$jsAlign.length - 1) { - $button.css({ marginLeft: buttonOffset * 2 }); - } else if (index === 0) { - $button.css({ marginLeft: 0 }); - } - }); + constructor(dom, userForm) { + this.dom = dom; + this.userForm = userForm; + this.prevButton = dom.querySelector('.step-button-prev'); + this.nextButton = dom.querySelector('.step-button-next'); - return this; + this.init(); } - /** - * @func ProgressBar.update - * @param {number} stepID - Zero based index of the new step. - * @desc Update the progress element to show a new step. - */ - ProgressBar.prototype.update = function update(stepID) { - const $newStepElement = $(this.$el.parent('.userform').find('.form-step')[stepID]); - let stepNumber = 0; - let barWidth = (stepID / (this.$buttons.length - 1)) * 100; - - // Set the current step number. - this.$buttons.each((i, button) => { - if (i > stepID) { - // Break the loop - return false; - } - - if ($(button).is(':visible')) { - stepNumber += 1; - } - return true; - }); - - // Update elements that contain the current step number. - this.$el.find('.current-step-number').each((i, element) => { - $(element).text(stepNumber); - }); - - // Update aria attributes. - this.$el.find('[aria-valuenow]').each((i, element) => { - $(element).attr('aria-valuenow', stepNumber); + init() { + this.prevButton.addEventListener('click', (e) => { + e.preventDefault(); + // scrollUpFx(); + window.triggerDispatchEvent(this.userForm.dom, 'userform.action.prev'); }); - - // Update the CSS classes on step buttons. - this.$buttons.each((i, element) => { - const $element = $(element); - const $item = $element.parent(); - - if (parseInt($element.data('step'), 10) === stepNumber && $element.is(':visible')) { - $item.addClass('current viewed'); - $element.removeAttr('disabled'); - - return; - } - - $item.removeClass('current'); + this.nextButton.addEventListener('click', (e) => { + e.preventDefault(); + // scrollUpFx(); + window.triggerDispatchEvent(this.userForm.dom, 'userform.action.next'); }); - // Update the progress bar's title with the new step's title. - this.$el.siblings('.progress-title').text($newStepElement.data('title')); + this.update(); - // Update the width of the progress bar. - barWidth = barWidth ? `${barWidth}%` : ''; - this.$el.find('.progress-bar').width(barWidth); - }; - - /** - * @func FormActions - * @constructor - * @param {object} element - * @desc Creates the navigation and actions (Prev, Next, Submit buttons). - */ - function FormActions(element) { - const self = this; - - this.$el = element instanceof $ ? element : $(element); - const $elFormItself = this.$el.closest('.userform'); - - this.userformInstance = $elFormItself.data('inst'); - - this.$prevButton = this.$el.find('.step-button-prev'); - this.$nextButton = this.$el.find('.step-button-next'); - - // Show the buttons. - this.$prevButton.parent().attr('aria-hidden', false).show(); - this.$nextButton.parent().attr('aria-hidden', false).show(); - - // Scroll up to the next page... - const scrollUpFx = function () { - const scrollTop = $elFormItself.offset(); - $('html, body').animate({ scrollTop: scrollTop.top }, 'slow'); - }; - - // Bind the step navigation event listeners. - this.$prevButton.on('click', (e) => { - e.preventDefault(); - scrollUpFx(); - self.$el.trigger('userform.action.prev'); - }); - this.$nextButton.on('click', (e) => { - e.preventDefault(); - scrollUpFx(); - self.$el.trigger('userform.action.next'); + this.userForm.dom.addEventListener('userform.form.changestep', () => { + this.update(); }); - // Listen for changes to the current form step, or conditional pages, - // so we can show hide buttons appropriately. - this.userformInstance.$el.on('userform.form.changestep userform.form.conditionalstep', () => { - self.update(); + this.userForm.dom.addEventListener('userform.form.conditionalstep', () => { + this.update(); }); - return this; } - /** - * @func FormActions.update - * @param {number} stepID - Zero based ID of the current step. - * @desc Updates the form actions element to reflect the current state of the page. - */ - FormActions.prototype.update = function update() { - const numberOfSteps = this.userformInstance.steps.length; - const stepID = this.userformInstance.currentStep ? this.userformInstance.currentStep.id : 0; + update() { + const numberOfSteps = this.userForm.getNumberOfSteps(); + const stepID = this.userForm.getCurrentStepID(); let i = null; let lastStep = null; - - // Update the "Prev" button. - this.$el.find('.step-button-prev')[stepID === 0 ? 'hide' : 'show'](); - - // Find last step, skipping hidden ones for (i = numberOfSteps - 1; i >= 0; i--) { - lastStep = this.userformInstance.steps[i]; - - // Skip if step is hidden + lastStep = this.userForm.getStep(i); if (!lastStep.conditionallyHidden()) { - // Update the "Next" button. - this.$el.find('.step-button-next')[stepID >= i ? 'hide' : 'show'](); + if (stepID >= i) { + this.nextButton.parentNode.classList.add('hide'); + this.prevButton.parentNode.classList.remove('hide'); + } else { + this.nextButton.parentNode.classList.remove('hide'); + this.prevButton.parentNode.classList.add('hide'); + } - // Update the "Actions". - this.$el.find('.btn-toolbar')[stepID >= i ? 'show' : 'hide'](); + if (stepID >= i) { + this.dom.querySelector('.btn-toolbar').classList.remove('hide'); + } else { + this.dom.querySelector('.btn-toolbar').classList.add('hide'); + } - // Stop processing last step + // this.userForm.dom.querySelector('.btn-toolbar'); break; } } - }; - - /** - * @func UserForm - * @constructor - * @param {object} element - * @return {object} - The UserForm instance. - * @desc The form - */ - function UserForm(element) { - const self = this; - - this.$el = element instanceof $ ? element : $(element); - this.steps = []; - - // Add an error container which displays a list of invalid steps on form submission. - this.errorContainer = new ErrorContainer(this.$el.children('.error-container')); + } - // Listen for events triggered by form steps. - this.$el.on('userform.action.prev', () => { - self.prevStep(); - }); - this.$el.on('userform.action.next', () => { - self.nextStep(); - }); +} - // Listen for events triggered by the progress bar. - this.$el.find('.userform-progress').on('userform.progress.changestep', (e, stepNumber) => { - self.jumpToStep(stepNumber - 1); - }); - // When a field becomes valid, remove errors from the error container. - this.$el.on('userform.form.valid', (e, fieldId) => { - self.errorContainer.removeStepLink(fieldId); - }); +class UserForm { - this.$el.validate(this.validationOptions); + constructor(form) { + this.dom = form; + this.CONSTANTS = {}; // Settings that come from the CMS. + this.steps = []; + this.progressBar = null; + this.actions = null; + this.currentStep = null; - // Ensure checkbox groups are validated correctly - this.$el.find('.optionset.requiredField input').each((a, field) => { - $(field).rules('add', { - required: true, - }); - }); + this.CONSTANTS.ENABLE_LIVE_VALIDATION = this.dom.getAttribute('livevalidation') !== undefined; + this.CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP = this.dom.getAttribute('toperrors') !== undefined; + } - return this; + init() { + this.initialiseFormSteps(); } - /* - * Default options for step validation. These get extended in main(). - */ - UserForm.prototype.validationOptions = { - ignore: ':hidden,ul', - errorClass: 'error', - errorElement: 'span', - errorPlacement: (error, element) => { - error.addClass('message'); - - if (element.is(':radio') || element.parents('.checkboxset').length > 0) { - error.appendTo(element.closest('.middleColumn, .field')); - } else if (element.parents('.checkbox').length > 0) { - error.appendTo(element.closest('.field')); - } else { - error.insertAfter(element); - } - }, - invalidHandler: (event, validator) => { - // setTimeout 0 so it runs after errorPlacement - setTimeout(() => { - validator.currentElements.filter('.error').first().focus(); - }, 0); - }, - // Callback for handling the actual submit when the form is valid. - // Submission in the jQuery.validate sence is handled at step level. - // So when the final step is submitted we have to also check all previous steps are valid. - submitHandler: (form) => { - let isValid = true; - const userform = $(form).closest('.userform').data('inst'); - - // Validate the current step - if (userform.currentStep) { - userform.currentStep.valid = $(form).valid(); - } + initialiseFormSteps() { + const steps = this.dom.querySelectorAll('.form-step'); + for (const stepDom of steps) { + const step = new FormStep(stepDom, this); + step.hide(); + this.addStep(step); + } - // Check for invalid previous steps. - $.each(userform.steps, (i, step) => { - if (!step.valid && !step.conditionallyHidden()) { - isValid = false; - userform.errorContainer.addStepLink(step); - } - }); + this.setCurrentStep(this.steps[0]); - if (isValid) { - // Remove required attributes on hidden fields - const hiddenInputs = $(form).find('.field.requiredField.hide input'); - if (hiddenInputs.length > 0) { - hiddenInputs.removeAttr('required aria-required data-rule-required').valid(); - } + const progressBarDom = this.dom.querySelector('.userform-progress'); + if (progressBarDom) { + this.progressBar = new ProgressBar(progressBarDom, this); + } - // When using the "are you sure?" plugin, ensure the form immediately submits. - $(form).removeClass('dirty'); + const stepNavigation = this.dom.querySelector('.step-navigation'); + if (stepNavigation) { + this.formActions = new FormActions(stepNavigation, this); + this.formActions.update(); + } - form.submit(); - userform.$el.trigger('userform.form.submit'); - } else { - userform.errorContainer.show(); - } - }, - // When a field becomes valid. - success: (error) => { - const userform = $(error).closest('.userform').data('inst'); - const errorId = $(error).attr('id'); - const fieldId = errorId.substr(0, errorId.indexOf('-error')).replace(/[\\[\\]]/, ''); - - // Remove square brackets since jQuery.validate.js uses idOrName, - // which breaks further on when using a selector that end with - // square brackets. - - error.remove(); - - // Pass the field's ID with the event - userform.$el.trigger('userform.form.valid', [fieldId]); - }, - }; - - /** - * @func UserForm.addStep - * @param {object} step - An instance of FormStep. - * @desc Adds a step to the UserForm. - */ - UserForm.prototype.addStep = function addStep(step) { + this.setUpPing(); + + this.dom.addEventListener('userform.action.next', () => { + this.nextStep(); + }) + + this.dom.addEventListener('userform.action.prev', () => { + this.prevStep(); + }) + + } + + setCurrentStep(step) { // Make sure we're dealing with a form step. if (!(step instanceof FormStep)) { return; } + this.currentStep = step; + this.currentStep.show(); + } - // eslint-disable-next-line no-param-reassign - step.id = this.steps.length; - - this.steps.push(step); - }; - - /** - * @func UserForm.setCurrentStep - * @param {object} step - An instance of FormStep. - * @desc Sets the step the user is currently on. - */ - UserForm.prototype.setCurrentStep = function setCurrentStep(step) { - // Make sure we're dealing with a form step. + addStep(step) { if (!(step instanceof FormStep)) { return; } + step.setId(this.steps.length); + this.steps.push(step); + } - this.currentStep = step; - this.currentStep.show(); + getNumberOfSteps() { + return this.steps.length; + } + + getCurrentStepID() { + return this.currentStep.id ? this.currentStep.id : 0; + } + + getStep(index) { + return this.steps[index]; + } + + nextStep() { + this.jumpToStep(this.steps.indexOf(this.currentStep) + 1, true); + } + + prevStep() { + this.jumpToStep(this.steps.indexOf(this.currentStep) - 1, true); + } - // Record the user has viewed the step. - this.currentStep.viewed = true; - this.currentStep.$el.addClass('viewed'); - }; - - /** - * @func UserForm.jumpToStep - * @param {number} stepNumber - * @param {boolean} [direction] - Defaults to forward (true). - * @desc Jumps to a specific form step. - */ - UserForm.prototype.jumpToStep = function jumpToStep(stepNumber, direction) { + jumpToStep(stepNumber, direction) + { const targetStep = this.steps[stepNumber]; let isValid = false; const forward = direction === undefined ? true : direction; - // Make sure the target step exists. if (targetStep === undefined) { return; } - // Make sure the step we're trying to set as current is not - // hidden by custom display rules. If it is then jump to the next step. if (targetStep.conditionallyHidden()) { if (forward) { this.jumpToStep(stepNumber + 1, direction); } else { this.jumpToStep(stepNumber - 1, direction); } - return; } - // Validate the form. - // This well effectivly validate the current step and not the entire form. - // This is because hidden fields are excluded from validation, and all fields - // on all other steps, are currently hidden. - isValid = this.$el.valid(); - - // Set the 'valid' property on the current step. - this.currentStep.valid = isValid; - - // Users can navigate to step's they've already viewed even if the current step is invalid. - if (isValid === false && targetStep.viewed === false) { - return; + if (this.currentStep) { + this.currentStep.hide(); } - this.currentStep.hide(); this.setCurrentStep(targetStep); - this.$el.trigger('userform.form.changestep', [targetStep.id]); - }; - - /** - * @func UserForm.nextStep - * @desc Advances the form to the next step. - */ - UserForm.prototype.nextStep = function nextStep() { - this.jumpToStep(this.steps.indexOf(this.currentStep) + 1, true); - }; - - /** - * @func UserForm.prevStep - * @desc Goes back one step (not bound to browser history). - */ - UserForm.prototype.prevStep = function prevStep() { - this.jumpToStep(this.steps.indexOf(this.currentStep) - 1, false); - }; - - /** - * @func main - * @desc Bootstraps the front-end. - */ - function main(index, userformElement) { - const $userform = $(userformElement); - - // If there's no userform, do nothing. - if ($userform.length === 0) { - return; - } - - CONSTANTS.ENABLE_LIVE_VALIDATION = $userform.data('livevalidation') !== undefined; - CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP = $userform.data('toperrors') !== undefined; - - // Extend the default validation options with conditional options - // that are set by the user in the CMS. - if (CONSTANTS.ENABLE_LIVE_VALIDATION === false) { - $.extend(UserForm.prototype.validationOptions, { - onfocusout: false, - }); - } - - if (CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP) { - $.extend(UserForm.prototype.validationOptions, { - // Callback for custom code when an invalid form / step is submitted. - invalidHandler: (event, validator) => { - $userform.trigger('userform.form.error', [validator]); - }, - onfocusout: false, - }); - } - - // Display all the things that are hidden when JavaScript is disabled. - $userform.find('.userform-progress, .step-navigation').attr('aria-hidden', false).show(); - - // Extend classes with common functionality. - $.extend(FormStep.prototype, commonMixin); - $.extend(ErrorContainer.prototype, commonMixin); - - const userform = new UserForm($userform); - $userform.data('inst', userform); - - // Conditionally hide field labels and use HTML5 placeholder instead. - if (CONSTANTS.HIDE_FIELD_LABELS) { - $userform.find('label.left').each(() => { - const $label = $(this); - - $(`[name="${$label.attr('for')}"]`).attr('placeholder', $label.text()); - $label.remove(); - }); - } - - // Initialise the form steps. - userform.$el.find('.form-step').each((i, element) => { - const step = new FormStep(element); - - userform.addStep(step); - }); - - userform.setCurrentStep(userform.steps[0]); - - // Initialise actions and progressbar - const $progressEl = $userform.find('.userform-progress'); - if ($progressEl.length) { - const progressBar = new ProgressBar($progressEl); - progressBar.update(0); - } - - const $formActionsEl = $userform.find('.step-navigation'); - if ($formActionsEl.length) { - const formActions = new FormActions($formActionsEl); - formActions.update(); - } - - // Enable jQuery UI datepickers - $(document).on('click', 'input.text[data-showcalendar]', () => { - const $element = $(this); - - $element.ssDatepicker(); - - if ($element.data('datepicker')) { - $element.datepicker('show'); - } + window.triggerDispatchEvent(this.dom, 'userform.form.changestep', { + stepId: targetStep.id }); + } + setUpPing() { // Make sure the form doesn't expire on the user. Pings every 3 mins. - setInterval(() => { - $.ajax({ url: 'UserDefinedFormController/ping' }); + window.setInterval(() => { + fetch('UserDefinedFormController/ping'); }, 180 * 1000); - - // Bind a confirmation message when navigating away from a partially completed form. - if (typeof $userform.areYouSure !== 'undefined') { - $userform.areYouSure({ - message: i18n._t('UserForms.LEAVE_CONFIRMATION', 'You have unsaved changes!'), - }); - } } - $('.userform').each(main); -}); +} + diff --git a/client/src/styles/userforms.scss b/client/src/styles/userforms.scss index e612cd415..fbfd81ed0 100644 --- a/client/src/styles/userforms.scss +++ b/client/src/styles/userforms.scss @@ -15,6 +15,10 @@ .step-buttons { margin-left: 0; + padding-left: 0; + width: 100%; + display: flex; + justify-content: space-between; position: relative; } @@ -28,8 +32,8 @@ } .step-button-jump { - position: absolute; - top: 0; + //position: absolute; + //top: 0; opacity: .7; } } diff --git a/code/Control/UserDefinedFormController.php b/code/Control/UserDefinedFormController.php index 8d838dc7a..9d2f717b3 100644 --- a/code/Control/UserDefinedFormController.php +++ b/code/Control/UserDefinedFormController.php @@ -73,16 +73,16 @@ protected function init() $page = $this->data(); // load the css - if (!$page->config()->get('block_default_userforms_css')) { + if (1 || !$page->config()->get('block_default_userforms_css')) { Requirements::css('silverstripe/userforms:client/dist/styles/userforms.css'); } // load the jquery - if (!$page->config()->get('block_default_userforms_js')) { - Requirements::javascript('silverstripe/userforms:client/dist/js/jquery.min.js'); - Requirements::javascript( - 'silverstripe/userforms:client/dist/js/jquery-validation/jquery.validate.min.js' - ); + if (1 || !$page->config()->get('block_default_userforms_js')) { +// Requirements::javascript('silverstripe/userforms:client/dist/js/jquery.min.js'); +// Requirements::javascript( +// 'silverstripe/userforms:client/dist/js/jquery-validation/jquery.validate.min.js' +// ); Requirements::javascript('silverstripe/admin:client/dist/js/i18n.js'); Requirements::add_i18n_javascript('silverstripe/userforms:client/lang'); Requirements::javascript('silverstripe/userforms:client/dist/js/userforms.js'); @@ -91,9 +91,10 @@ protected function init() // Bind a confirmation message when navigating away from a partially completed form. if ($page::config()->get('enable_are_you_sure')) { - Requirements::javascript( - 'silverstripe/userforms:client/dist/js/jquery.are-you-sure/jquery.are-you-sure.js' - ); +// TODO: +// Requirements::javascript( +// 'silverstripe/userforms:client/dist/js/jquery.are-you-sure/jquery.are-you-sure.js' +// ); } } } @@ -215,11 +216,9 @@ public function generateConditionalJavascript() // Only add customScript if $default or $rules is defined if ($rules) { Requirements::customScript(<<ID); } @@ -626,10 +625,11 @@ public function finished() */ protected function buildWatchJS($watch) { + $result = ''; foreach ($watch as $key => $rule) { - $events = implode(' ', $rule['events']); - $selectors = implode(', ', $rule['selectors']); + $events = implode(',', $rule['events']); + $selectors = implode(',', $rule['selectors']); $conjunction = $rule['conjunction']; $operations = implode(" {$conjunction} ", $rule['operations']); $target = $rule['targetFieldID']; @@ -638,17 +638,40 @@ protected function buildWatchJS($watch) $result .= <<isCheckBoxField(); $radioField = $formFieldWatch->isRadioField(); - $target = sprintf('$("%s")', $formFieldWatch->getSelectorFieldOnly()); + $target = $formFieldWatch->getSelectorFieldOnly(); $fieldValue = Convert::raw2js($this->FieldValue); $conditionOptions = [ @@ -174,7 +174,8 @@ public function buildExpression() switch ($this->ConditionOption) { case 'IsNotBlank': case 'IsBlank': - $expression = ($checkboxField || $radioField) ? "!{$target}.is(\":checked\")" : "{$target}.val() == ''"; + $expression = ($checkboxField || $radioField) ? "!{$target}.is(\":checked\")" + : "document.querySelector(\"{$target}\").value == ''"; if ((string) $this->ConditionOption === 'IsNotBlank') { //Negate $expression = "!({$expression})"; @@ -195,12 +196,12 @@ public function buildExpression() } elseif ($radioField) { // We cannot simply get the value of the radio group, we need to find the checked option first. $expression = sprintf( - '%s.closest(".field, .control-group").find("input:checked").val() == "%s"', + 'closest(document.querySelector("%s"), ".field, .control-group").querySelector("input:checked").value == "%s"', $target, $fieldValue ); } else { - $expression = sprintf('%s.val() == "%s"', $target, $fieldValue); + $expression = sprintf('%s.value == "%s"', $target, $fieldValue); } if ((string) $this->ConditionOption === 'ValueNot') { @@ -213,7 +214,7 @@ public function buildExpression() case 'ValueGreaterThan': case 'ValueGreaterThanEqual': $expression = sprintf( - '%s.val() %s parseFloat("%s")', + 'document.querySelector("%s").value %s parseFloat("%s")', $target, $conditionOptions[$this->ConditionOption], $fieldValue @@ -299,11 +300,11 @@ public function validateAgainstFormData(array $data) */ public function toggleDisplayText($initialState, $invert = false) { - $action = strtolower($initialState ?? '') === 'hide' ? 'removeClass' : 'addClass'; + $action = strtolower($initialState ?? '') === 'hide' ? 'remove' : 'add'; if ($invert) { - $action = $action === 'removeClass' ? 'addClass' : 'removeClass'; + $action = $action === 'remove' ? 'add' : 'remove'; } - return sprintf('%s("hide")', $action); + return sprintf('classList.%s("hide")', $action); } /** diff --git a/code/Model/EditableFormField.php b/code/Model/EditableFormField.php index 4cd748dd8..24d1e1121 100755 --- a/code/Model/EditableFormField.php +++ b/code/Model/EditableFormField.php @@ -863,7 +863,7 @@ public function getInlineTitleField($column) */ public function getSelectorHolder() { - return sprintf('$("%s")', $this->getSelectorOnly()); + return sprintf('document.querySelector("%s")', $this->getSelectorOnly()); } /** @@ -886,7 +886,7 @@ public function getSelectorOnly() */ public function getSelectorField(EditableCustomRule $rule, $forOnLoad = false) { - return sprintf("$(%s)", $this->getSelectorFieldOnly()); + return sprintf("document.querySelector(%s)", $this->getSelectorFieldOnly()); } /** diff --git a/package.json b/package.json index 050be44db..f56126471 100644 --- a/package.json +++ b/package.json @@ -38,9 +38,7 @@ }, "dependencies": { "babel-preset-es2016": "^6.24.1", - "jquery": "^3.5.0", - "jquery-validation": "^1.19.5", - "jquery.are-you-sure": "^1.9.0", + "validator": "13.9.0", "mime": "^1.4.1", "qs": "^6.9.4", "react": "^16.13.1", diff --git a/templates/SilverStripe/UserForms/Form/Includes/UserFormStepNav.ss b/templates/SilverStripe/UserForms/Form/Includes/UserFormStepNav.ss index f7c9440a2..0b4fd6be6 100644 --- a/templates/SilverStripe/UserForms/Form/Includes/UserFormStepNav.ss +++ b/templates/SilverStripe/UserForms/Form/Includes/UserFormStepNav.ss @@ -4,12 +4,12 @@ If JavaScript is disabled multi-step forms are displayed as a single page so the 'prev' and 'next' button are not used. These buttons are made visible via JavaScript. --%> - -