mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
NEW Add sass-lint configuration and refactor. Refactor JS for AirBnB ES6 syntax
This commit is contained in:
parent
c8698d99bd
commit
51631a167a
@ -10,7 +10,7 @@ indent_style = space
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[{*.yml,package.json}]
|
[{*.yml,package.json,*.js,*.scss}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
# The indent size used in the package.json file cannot be changed:
|
# The indent size used in the package.json file cannot be changed:
|
||||||
|
179
.sass-lint.yml
Normal file
179
.sass-lint.yml
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
# sass-lint config to match the AirBNB style guide
|
||||||
|
# See silverstripe-admin
|
||||||
|
files:
|
||||||
|
include: '**/client/src/**/*.scss'
|
||||||
|
ignore:
|
||||||
|
- 'client/src/styles/legacy/*'
|
||||||
|
- 'src/**/*'
|
||||||
|
options:
|
||||||
|
formatter: stylish
|
||||||
|
merge-default-rules: false
|
||||||
|
rules:
|
||||||
|
# Warnings
|
||||||
|
# Things that require actual refactoring are marked as warnings
|
||||||
|
class-name-format:
|
||||||
|
- 1
|
||||||
|
- convention: hyphenatedbem
|
||||||
|
placeholder-name-format:
|
||||||
|
- 1
|
||||||
|
- convention: hyphenatedlowercase
|
||||||
|
nesting-depth:
|
||||||
|
- 1
|
||||||
|
- max-depth: 3
|
||||||
|
no-ids: 1
|
||||||
|
no-important: 1
|
||||||
|
no-misspelled-properties:
|
||||||
|
- 1
|
||||||
|
- extra-properties:
|
||||||
|
- "-moz-border-radius-topleft"
|
||||||
|
- "-moz-border-radius-topright"
|
||||||
|
- "-moz-border-radius-bottomleft"
|
||||||
|
- "-moz-border-radius-bottomright"
|
||||||
|
variable-name-format:
|
||||||
|
- 1
|
||||||
|
- allow-leading-underscore: true
|
||||||
|
convention: hyphenatedlowercase
|
||||||
|
no-extends: 1
|
||||||
|
|
||||||
|
# Warnings: these things are preferential rather than mandatory
|
||||||
|
no-css-comments: 1
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
# Things that can be easily fixed are marked as errors
|
||||||
|
indentation:
|
||||||
|
- 2
|
||||||
|
- size: 2
|
||||||
|
final-newline:
|
||||||
|
- 2
|
||||||
|
- include: true
|
||||||
|
no-trailing-whitespace: 2
|
||||||
|
border-zero:
|
||||||
|
- 2
|
||||||
|
- convention: '0'
|
||||||
|
brace-style:
|
||||||
|
- 2
|
||||||
|
- allow-single-line: true
|
||||||
|
clean-import-paths:
|
||||||
|
- 2
|
||||||
|
- filename-extension: false
|
||||||
|
leading-underscore: false
|
||||||
|
no-debug: 2
|
||||||
|
no-empty-rulesets: 2
|
||||||
|
no-invalid-hex: 2
|
||||||
|
no-mergeable-selectors: 2
|
||||||
|
# no-qualifying-elements:
|
||||||
|
# - 1
|
||||||
|
# - allow-element-with-attribute: false
|
||||||
|
# allow-element-with-class: false
|
||||||
|
# allow-element-with-id: false
|
||||||
|
no-trailing-zero: 2
|
||||||
|
no-url-protocols: 2
|
||||||
|
quotes:
|
||||||
|
- 2
|
||||||
|
- style: double
|
||||||
|
space-after-bang:
|
||||||
|
- 2
|
||||||
|
- include: false
|
||||||
|
space-after-colon:
|
||||||
|
- 2
|
||||||
|
- include: true
|
||||||
|
space-after-comma:
|
||||||
|
- 2
|
||||||
|
- include: true
|
||||||
|
space-before-bang:
|
||||||
|
- 2
|
||||||
|
- include: true
|
||||||
|
space-before-brace:
|
||||||
|
- 2
|
||||||
|
- include: true
|
||||||
|
space-before-colon: 2
|
||||||
|
space-between-parens:
|
||||||
|
- 2
|
||||||
|
- include: false
|
||||||
|
trailing-semicolon: 2
|
||||||
|
url-quotes: 2
|
||||||
|
zero-unit: 2
|
||||||
|
single-line-per-selector: 2
|
||||||
|
one-declaration-per-line: 2
|
||||||
|
empty-line-between-blocks:
|
||||||
|
- 2
|
||||||
|
- ignore-single-line-rulesets: true
|
||||||
|
|
||||||
|
|
||||||
|
# Missing rules
|
||||||
|
# There are no sass-lint rules for the following AirBNB style items, but thess
|
||||||
|
# - Put comments on their own line
|
||||||
|
# - Put property delcarations before mixins
|
||||||
|
|
||||||
|
# Disabled rules
|
||||||
|
|
||||||
|
# These are other rules that we may wish to consider using in the future
|
||||||
|
# They are not part of the AirBNB CSS standard but they would introduce some strictness
|
||||||
|
# bem-depth: 0
|
||||||
|
# variable-for-property: 0
|
||||||
|
# no-transition-all: 0
|
||||||
|
# hex-length:
|
||||||
|
# - 1
|
||||||
|
# - style: short
|
||||||
|
# hex-notation:
|
||||||
|
# - 1
|
||||||
|
# - style: lowercase
|
||||||
|
# property-units:
|
||||||
|
# - 1
|
||||||
|
# - global:
|
||||||
|
# - ch
|
||||||
|
# - em
|
||||||
|
# - ex
|
||||||
|
# - rem
|
||||||
|
# - cm
|
||||||
|
# - in
|
||||||
|
# - mm
|
||||||
|
# - pc
|
||||||
|
# - pt
|
||||||
|
# - px
|
||||||
|
# - q
|
||||||
|
# - vh
|
||||||
|
# - vw
|
||||||
|
# - vmin
|
||||||
|
# - vmax
|
||||||
|
# - deg
|
||||||
|
# - grad
|
||||||
|
# - rad
|
||||||
|
# - turn
|
||||||
|
# - ms
|
||||||
|
# - s
|
||||||
|
# - Hz
|
||||||
|
# - kHz
|
||||||
|
# - dpi
|
||||||
|
# - dpcm
|
||||||
|
# - dppx
|
||||||
|
# - '%'
|
||||||
|
# per-property: {}
|
||||||
|
# force-attribute-nesting: 1
|
||||||
|
# force-element-nesting: 1
|
||||||
|
# force-pseudo-nesting: 1
|
||||||
|
# function-name-format:
|
||||||
|
# - 1
|
||||||
|
# - allow-leading-underscore: true
|
||||||
|
# convention: hyphenatedlowercase
|
||||||
|
# no-color-literals: 1
|
||||||
|
# no-duplicate-properties: 1
|
||||||
|
# mixin-name-format:
|
||||||
|
# - 1
|
||||||
|
# - allow-leading-underscore: true
|
||||||
|
# convention: hyphenatedlowercase
|
||||||
|
# shorthand-values:
|
||||||
|
# - 1
|
||||||
|
# - allowed-shorthands:
|
||||||
|
# - 1
|
||||||
|
# - 2
|
||||||
|
# - 3
|
||||||
|
# leading-zero:
|
||||||
|
# - 1
|
||||||
|
# - include: false
|
||||||
|
# no-vendor-prefixes:
|
||||||
|
# - 1
|
||||||
|
# - additional-identifiers: []
|
||||||
|
# excluded-identifiers: []
|
||||||
|
# placeholder-in-extend: 1
|
||||||
|
# no-color-keywords: 2
|
2
client/dist/js/userforms-cms.js
vendored
2
client/dist/js/userforms-cms.js
vendored
@ -1 +1 @@
|
|||||||
!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=3)}([function(t,e){t.exports=jQuery},function(t,e,n){(function(t){!function(t){t.entwine("ss",function(t){var e;t(".uf-field-editor tbody").entwine({onmatch:function(){var n,i,o=0,s=t(".uf-field-editor .ss-gridfield-buttonrow").addClass("stickyButtons"),c=t(".cms-content-header.north").height()+parseInt(t(".stickyButtons").css("padding-top"),10),r=t(".uf-field-editor");this._super(),this.find(".ss-gridfield-item").each(function(){switch(t(this).data("class")){case"EditableFormStep":return void(o=0);case"EditableFieldGroup":i=++o;break;case"EditableFieldGroupEnd":i=o--;break;default:i=o}for(t(this).toggleClass("inFieldGroup",i>0),n=1;n<=5;n++)t(this).toggleClass("inFieldGroup-level-"+n,i>=n)}),e=setInterval(function(){var t=r.offset().top;s.width("100%"),t>c||0===t?s.removeClass("stickyButtons"):s.addClass("stickyButtons")},300)},onunmatch:function(){this._super(),clearInterval(e)}}),t(".uf-field-editor .ss-gridfield-buttonrow .action").entwine({onclick:function(t){this._super(t),this.trigger("addnewinline")}}),t(".uf-field-editor").entwine({onmatch:function(){var e=this;this._super(),this.on("addnewinline",function(){e.one("reload",function(){var n,i=e.find(".ss-gridfield-item").last();"EditableFieldGroupEnd"===i.attr("data-class")?(n=i,n.prev().find(".col-Title input").focus(),i=n.add(n.prev()),n.css("visibility","hidden")):i.find(".col-Title input").focus(),void 0!==document.createElement("div").style.animationName&&i.addClass("newField"),setTimeout(function(){i.removeClass("newField").addClass("flashBackground"),t(".cms-content-fields").scrollTop(t(".cms-content-fields")[0].scrollHeight),n&&n.css("visibility","visible")},500)})})},onummatch:function(){this._super()}})})}(t)}).call(e,n(0))},function(t,e,n){(function(t){!function(t){t(document).ready(function(){var e={updateFormatSpecificFields:function(){var e=t("#SendPlain").find('input[type="checkbox"]').is(":checked");t(".field.toggle-html-only")[e?"hide":"show"](),t(".field.toggle-plain-only")[e?"show":"hide"]()}};t.entwine("udf.recipient",function(t){t("#Form_ItemEditForm").entwine({onmatch:function(){e.updateFormatSpecificFields()},onunmatch:function(){this._super()}}),t("#SendPlain").entwine({onchange:function(){e.updateFormatSpecificFields()}})})})}(t)}).call(e,n(0))},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=(n.n(i),n(2));n.n(o)}]);
|
!function(e){function t(i){if(n[i])return n[i].exports;var o=n[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,i){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:i})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=3)}([function(e,t){e.exports=jQuery},function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=this;o.a.entwine("ss",function(){var e=null;o()(".uf-field-editor tbody").entwine({onmatch:function(){var t=0,n=0,i=0,s=o()(".uf-field-editor .ss-gridfield-buttonrow").addClass("sticky-buttons"),c=o()(".cms-content-header.north").height()+parseInt(o()(".sticky-buttons").css("padding-top"),10),u=o()(".uf-field-editor");r._super(),r.find(".ss-gridfield-item").each(function(){switch(o()(r).data("class")){case"EditableFormStep":return void(i=0);case"EditableFieldGroup":n=++i;break;case"EditableFieldGroupEnd":n=i--;break;default:n=i}for(o()(r).toggleClass("infieldgroup",n>0),t=1;t<=5;t++)o()(r).toggleClass("infieldgroup-level-"+t,n>=t)}),e=setInterval(function(){var e=u.offset().top;s.width("100%"),e>c||0===e?s.removeClass("sticky-buttons"):s.addClass("sticky-buttons")},300)},onunmatch:function(){r._super(),clearInterval(e)}}),o()(".uf-field-editor .ss-gridfield-buttonrow .action").entwine({onclick:function(e){r._super(e),r.trigger("addnewinline")}}),o()(".uf-field-editor").entwine({onmatch:function(){r._super(),r.on("addnewinline",function(){r.one("reload",function(){var e=r.find(".ss-gridfield-item").last(),t=null;"EditableFieldGroupEnd"===e.attr("data-class")?(t=e,t.prev().find(".col-Title input").focus(),e=t.add(t.prev()),t.css("visibility","hidden")):e.find(".col-Title input").focus(),e.addClass("flashBackground"),o()(".cms-content-fields").scrollTop(o()(".cms-content-fields")[0].scrollHeight),t&&t.css("visibility","visible")})})},onummatch:function(){r._super()}})})},function(e,t,n){"use strict";var i=n(0),o=n.n(i),r=this;o()(document).ready(function(){var e=o()('input[name="SendPlain"]'),t={updateFormatSpecificFields:function(){var t=e.is(":checked");o()(".field.toggle-html-only")[t?"hide":"show"](),o()(".field.toggle-plain-only")[t?"show":"hide"]()}};o.a.entwine("udf.recipient",function(){o()("#Form_ItemEditForm").entwine({onmatch:function(){t.updateFormatSpecificFields()},onunmatch:function(){r._super()}}),e.entwine({onchange:function(){t.updateFormatSpecificFields()}})})})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(1),n(2)}]);
|
2
client/dist/js/userforms.js
vendored
2
client/dist/js/userforms.js
vendored
File diff suppressed because one or more lines are too long
1
client/dist/js/userforms.js.map
vendored
Normal file
1
client/dist/js/userforms.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
client/dist/styles/userforms-cms.css
vendored
2
client/dist/styles/userforms-cms.css
vendored
@ -1 +1 @@
|
|||||||
@-webkit-keyframes rowSlide{0%{top:20%}to{top:80%}}@-o-keyframes rowSlide{0%{top:20%}to{top:80%}}@keyframes rowSlide{0%{top:20%}to{top:80%}}@-webkit-keyframes flashBackground{0%{background-color:#fff}10%{background-color:#dcfedd}70%{background-color:#dcfedd}}@-o-keyframes flashBackground{0%{background-color:#fff}10%{background-color:#dcfedd}70%{background-color:#dcfedd}}@keyframes flashBackground{0%{background-color:#fff}10%{background-color:#dcfedd}70%{background-color:#dcfedd}}.cms .uf-field-editor{padding-bottom:0}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item{height:46px}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item,.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item:hover{background:#fff}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item td{border-right-width:0;border-top:1px solid #eee}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item td:last-child{border-right-width:1px}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item .handle{min-height:46px}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.newField{position:fixed;-webkit-animation:rowSlide .5s ease forwards;-o-animation:rowSlide .5s ease forwards;animation:rowSlide .5s ease forwards}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.flashBackground{-webkit-animation:flashBackground 2s linear;-o-animation:flashBackground 2s linear;animation:flashBackground 2s linear}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.ui-sortable-placeholder{height:50px}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup,.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup:hover{background:#f2f9fd}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup td{border-bottom:0;border-top:1px solid #eee}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup .col-reorder,.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup .handle{background:#bee0f8;border-top:0}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup.inFieldGroup-level-2 .col-reorder,.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup.inFieldGroup-level-2 .handle{background:#99cef4;border-top:0}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup.inFieldGroup-level-3 .col-reorder,.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item.inFieldGroup.inFieldGroup-level-3 .handle{background:#89bef4;border-top:0}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep],.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep]:hover{background:#dae2e7}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep] label{font-weight:700;color:#000;font-size:1.1em}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep] td{border-top:1px solid #a6b6c1}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep]+.ss-gridfield-item td{border-top:1px solid #dae2e7}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroup] td,.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep]+.ss-gridfield-item[data-class=EditableFieldGroup] td{border-top:1px solid #a8d7f5}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroup] label{font-weight:700;color:#444}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd] td{border-bottom:1px solid #a8d7f5}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd]+.ss-gridfield-item[data-class=EditableFieldGroupEnd]{border-top:0}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd] .col-buttons .action{display:none}.cms .uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd] label{color:#777}.cms .uf-field-editor .stickyButtons{position:fixed;top:40px;z-index:2;background:#e6eaed;-webkit-box-shadow:0 12px 4px -8px #999;box-shadow:0 12px 4px -8px #999;padding:12px;margin-left:-12px}.cms .uf-field-editor .stickyButtons button.action{margin-bottom:0}.cms .uf-field-editor .stickyButtons~.ss-gridfield-table{margin-top:40px}
|
@-webkit-keyframes flash-background{0%{background-color:#fff}10%{background-color:#dcfedd}70%{background-color:#dcfedd}}@-o-keyframes flash-background{0%{background-color:#fff}10%{background-color:#dcfedd}70%{background-color:#dcfedd}}@keyframes flash-background{0%{background-color:#fff}10%{background-color:#dcfedd}70%{background-color:#dcfedd}}.uf-field-editor{padding-bottom:0}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item{height:46px}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item,.uf-field-editor table.ss-gridfield-table .ss-gridfield-item:hover{background:#fff}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item td{border-right-width:0;border-top:1px solid #999}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item td:last-child{border-right-width:1px}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item .handle{min-height:46px}.uf-field-editor table.ss-gridfield-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 table.ss-gridfield-table .ss-gridfield-item.ui-sortable-placeholder{height:50px}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup,.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup:hover{background:#f2f9fd}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup td{border-bottom:0;border-top:1px solid #999}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup .col-reorder,.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup .handle{background:#bee0f8;border-top:0}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup.infieldgroup-level-2 .col-reorder,.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup.infieldgroup-level-2 .handle{background:#99cef4;border-top:0}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup.infieldgroup-level-3 .col-reorder,.uf-field-editor table.ss-gridfield-table .ss-gridfield-item.infieldgroup.infieldgroup-level-3 .handle{background:#89bef4;border-top:0}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep],.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep]:hover{background:#dae2e7}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep] label{font-weight:700;color:#000;font-size:1.1em}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep] td{border-top:1px solid #a6b6c1}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep]+.ss-gridfield-item td{border-top:1px solid #dae2e7}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroup] td,.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFormStep]+.ss-gridfield-item[data-class=EditableFieldGroup] td{border-top:1px solid #a8d7f5}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroup] label{font-weight:700;color:#444}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd] td{border-bottom:1px solid #a8d7f5}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd]+.ss-gridfield-item[data-class=EditableFieldGroupEnd]{border-top:0}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd] .col-buttons .action{display:none}.uf-field-editor table.ss-gridfield-table .ss-gridfield-item[data-class=EditableFieldGroupEnd] label{color:#777}.uf-field-editor .sticky-buttons{position:fixed;top:40px;z-index:2;background:#999;-webkit-box-shadow:0 12px -4px #999;box-shadow:0 12px -4px #999;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:40px}
|
@ -2,107 +2,106 @@
|
|||||||
* form builder behaviour.
|
* form builder behaviour.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function($) {
|
import $ from 'jquery';
|
||||||
$.entwine('ss', function($) {
|
|
||||||
var stickyHeaderInterval;
|
|
||||||
|
|
||||||
$(".uf-field-editor tbody").entwine({
|
$.entwine('ss', () => {
|
||||||
onmatch: function() {
|
let stickyHeaderInterval = null;
|
||||||
var i,
|
|
||||||
thisLevel,
|
|
||||||
depth = 0,
|
|
||||||
$buttonrow = $('.uf-field-editor .ss-gridfield-buttonrow').addClass('stickyButtons'),
|
|
||||||
navHeight = $('.cms-content-header.north').height() + parseInt($('.stickyButtons').css('padding-top'), 10),
|
|
||||||
fieldEditor = $('.uf-field-editor'),
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
this._super();
|
$('.uf-field-editor tbody').entwine({
|
||||||
|
onmatch: () => {
|
||||||
|
let i = 0;
|
||||||
|
let thisLevel = 0;
|
||||||
|
let depth = 0;
|
||||||
|
const $buttonrow = $('.uf-field-editor .ss-gridfield-buttonrow').addClass('sticky-buttons');
|
||||||
|
const navHeight = $('.cms-content-header.north').height()
|
||||||
|
+ parseInt($('.sticky-buttons').css('padding-top'), 10);
|
||||||
|
const fieldEditor = $('.uf-field-editor');
|
||||||
|
|
||||||
// Loop through all rows and set necessary styles
|
this._super();
|
||||||
this.find('.ss-gridfield-item').each(function() {
|
|
||||||
switch($(this).data('class')) {
|
|
||||||
case 'EditableFormStep': {
|
|
||||||
depth = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 'EditableFieldGroup': {
|
|
||||||
thisLevel = ++depth;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'EditableFieldGroupEnd': {
|
|
||||||
thisLevel = depth--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
thisLevel = depth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(this).toggleClass('inFieldGroup', thisLevel > 0);
|
// Loop through all rows and set necessary styles
|
||||||
for(i = 1; i <= 5; i++) {
|
this.find('.ss-gridfield-item').each(() => {
|
||||||
$(this).toggleClass('inFieldGroup-level-'+i, thisLevel >= i);
|
switch ($(this).data('class')) {
|
||||||
}
|
case 'EditableFormStep': {
|
||||||
});
|
depth = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 'EditableFieldGroup': {
|
||||||
|
thisLevel = ++depth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'EditableFieldGroupEnd': {
|
||||||
|
thisLevel = depth--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
thisLevel = depth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure gridfield buttons stick to top of page when user scrolls down
|
$(this).toggleClass('infieldgroup', thisLevel > 0);
|
||||||
stickyHeaderInterval = setInterval(function () {
|
for (i = 1; i <= 5; i++) {
|
||||||
var offsetTop = fieldEditor.offset().top;
|
$(this).toggleClass(`infieldgroup-level-${i}`, thisLevel >= i);
|
||||||
$buttonrow.width('100%');
|
}
|
||||||
if (offsetTop > navHeight || offsetTop === 0) {
|
});
|
||||||
$buttonrow.removeClass('stickyButtons');
|
|
||||||
} else {
|
|
||||||
$buttonrow.addClass('stickyButtons');
|
|
||||||
};
|
|
||||||
}, 300);
|
|
||||||
},
|
|
||||||
onunmatch: function () {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
clearInterval(stickyHeaderInterval);
|
// Make sure gridfield buttons stick to top of page when user scrolls down
|
||||||
}
|
stickyHeaderInterval = setInterval(() => {
|
||||||
});
|
const offsetTop = fieldEditor.offset().top;
|
||||||
|
$buttonrow.width('100%');
|
||||||
|
if (offsetTop > navHeight || offsetTop === 0) {
|
||||||
|
$buttonrow.removeClass('sticky-buttons');
|
||||||
|
} else {
|
||||||
|
$buttonrow.addClass('sticky-buttons');
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
onunmatch: () => {
|
||||||
|
this._super();
|
||||||
|
|
||||||
// When new fields are added..
|
clearInterval(stickyHeaderInterval);
|
||||||
$('.uf-field-editor .ss-gridfield-buttonrow .action').entwine({
|
},
|
||||||
onclick: function (e) {
|
});
|
||||||
this._super(e);
|
|
||||||
|
|
||||||
this.trigger('addnewinline');
|
// When new fields are added.
|
||||||
}
|
$('.uf-field-editor .ss-gridfield-buttonrow .action').entwine({
|
||||||
});
|
onclick: (e) => {
|
||||||
|
this._super(e);
|
||||||
|
|
||||||
$('.uf-field-editor').entwine({
|
this.trigger('addnewinline');
|
||||||
onmatch: function () {
|
},
|
||||||
var self = this;
|
});
|
||||||
|
|
||||||
this._super();
|
$('.uf-field-editor').entwine({
|
||||||
|
onmatch: () => {
|
||||||
|
this._super();
|
||||||
|
|
||||||
// When the 'Add field' button is clicked set a one time listener.
|
// When the 'Add field' button is clicked set a one time listener.
|
||||||
// When the GridField is reloaded focus on the newly added field.
|
// When the GridField is reloaded focus on the newly added field.
|
||||||
this.on('addnewinline', function () {
|
this.on('addnewinline', () => {
|
||||||
self.one('reload', function () {
|
this.one('reload', () => {
|
||||||
//If fieldgroup, focus on the start marker
|
// If fieldgroup, focus on the start marker
|
||||||
var $newField = self.find('.ss-gridfield-item').last(), $groupEnd;
|
let $newField = this.find('.ss-gridfield-item').last();
|
||||||
if ($newField.attr('data-class') === 'EditableFieldGroupEnd') {
|
let $groupEnd = null;
|
||||||
$groupEnd = $newField;
|
if ($newField.attr('data-class') === 'EditableFieldGroupEnd') {
|
||||||
$groupEnd.prev().find('.col-Title input').focus();
|
$groupEnd = $newField;
|
||||||
$newField = $groupEnd.add($groupEnd.prev());
|
$groupEnd.prev().find('.col-Title input').focus();
|
||||||
$groupEnd.css('visibility', 'hidden');
|
$newField = $groupEnd.add($groupEnd.prev());
|
||||||
} else {
|
$groupEnd.css('visibility', 'hidden');
|
||||||
$newField.find('.col-Title input').focus();
|
} else {
|
||||||
}
|
$newField.find('.col-Title input').focus();
|
||||||
|
}
|
||||||
|
|
||||||
$newField.addClass('flashBackground');
|
$newField.addClass('flashBackground');
|
||||||
$(".cms-content-fields").scrollTop($(".cms-content-fields")[0].scrollHeight);
|
$('.cms-content-fields').scrollTop($('.cms-content-fields')[0].scrollHeight);
|
||||||
if($groupEnd) {
|
if ($groupEnd) {
|
||||||
$groupEnd.css('visibility', 'visible');
|
$groupEnd.css('visibility', 'visible');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onummatch: function () {
|
onummatch: () => {
|
||||||
this._super();
|
this._super();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}(jQuery));
|
|
||||||
|
@ -2,32 +2,32 @@
|
|||||||
* Email recipient behaviour.
|
* Email recipient behaviour.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function($) {
|
import $ from 'jquery';
|
||||||
$.entwine('ss', function($) {
|
|
||||||
var recipient = {
|
|
||||||
// Some fields are only visible when HTML email are being sent.
|
|
||||||
updateFormatSpecificFields: function () {
|
|
||||||
var sendPlainChecked = $('input[name="SendPlain"]').is(':checked');
|
|
||||||
|
|
||||||
$('.field.toggle-html-only')[sendPlainChecked ? 'hide' : 'show']();
|
$.entwine('ss', () => {
|
||||||
$('.field.toggle-plain-only')[sendPlainChecked ? 'show' : 'hide']();
|
const recipient = {
|
||||||
}
|
// Some fields are only visible when HTML email are being sent.
|
||||||
};
|
updateFormatSpecificFields: () => {
|
||||||
|
const sendPlainChecked = $('input[name="SendPlain"]').is(':checked');
|
||||||
|
|
||||||
$('#Form_ItemEditForm .EmailRecipientForm').entwine({
|
$('.field.toggle-html-only')[sendPlainChecked ? 'hide' : 'show']();
|
||||||
onmatch: function () {
|
$('.field.toggle-plain-only')[sendPlainChecked ? 'show' : 'hide']();
|
||||||
recipient.updateFormatSpecificFields();
|
},
|
||||||
},
|
};
|
||||||
|
|
||||||
onunmatch: function () {
|
$('#Form_ItemEditForm .EmailRecipientForm').entwine({
|
||||||
this._super();
|
onmatch: () => {
|
||||||
}
|
recipient.updateFormatSpecificFields();
|
||||||
});
|
},
|
||||||
|
|
||||||
$('#Form_ItemEditForm .EmailRecipientForm input[name="SendPlain"]').entwine({
|
onunmatch: () => {
|
||||||
onchange: function () {
|
this._super();
|
||||||
recipient.updateFormatSpecificFields();
|
},
|
||||||
}
|
});
|
||||||
});
|
|
||||||
});
|
$('#Form_ItemEditForm .EmailRecipientForm input[name="SendPlain"]').entwine({
|
||||||
}(jQuery));
|
onchange: () => {
|
||||||
|
recipient.updateFormatSpecificFields();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,738 +1,740 @@
|
|||||||
/**
|
/**
|
||||||
* @file Manages the multi-step navigation.
|
* @file Manages the multi-step navigation.
|
||||||
*/
|
*/
|
||||||
jQuery(function ($) {
|
|
||||||
|
import $ from 'jquery';
|
||||||
// A reference to the UserForm instance.
|
|
||||||
var userform = null;
|
$(document).ready(() => {
|
||||||
|
// A reference to the UserForm instance.
|
||||||
// Settings that come from the CMS.
|
let userform = null;
|
||||||
var CONSTANTS = {};
|
|
||||||
|
// Settings that come from the CMS.
|
||||||
// Common functions that extend multiple classes.
|
const CONSTANTS = {};
|
||||||
var commonMixin = {
|
|
||||||
/**
|
// Common functions that extend multiple classes.
|
||||||
* @func show
|
const commonMixin = {
|
||||||
* @desc Show the form step. Looks after aria attributes too.
|
/**
|
||||||
*/
|
* @func show
|
||||||
show: function () {
|
* @desc Show the form step. Looks after aria attributes too.
|
||||||
this.$el.attr('aria-hidden', false).show();
|
*/
|
||||||
},
|
show: () => {
|
||||||
/**
|
this.$el.attr('aria-hidden', false).show();
|
||||||
* @func hide
|
},
|
||||||
* @desc Hide the form step. Looks after aria attributes too.
|
/**
|
||||||
*/
|
* @func hide
|
||||||
hide: function () {
|
* @desc Hide the form step. Looks after aria attributes too.
|
||||||
this.$el.attr('aria-hidden', true).hide();
|
*/
|
||||||
}
|
hide: () => {
|
||||||
};
|
this.$el.attr('aria-hidden', true).hide();
|
||||||
|
},
|
||||||
/**
|
};
|
||||||
* @func UserForm
|
|
||||||
* @constructor
|
/**
|
||||||
* @param {object} element
|
* @func ErrorContainer
|
||||||
* @return {object} - The UserForm instance.
|
* @constructor
|
||||||
* @desc The form
|
* @param {object} element - The error container element.
|
||||||
*/
|
* @return {object} - The ErrorContainer instance.
|
||||||
function UserForm(element) {
|
* @desc Creates an error container. Used to display step error messages at the top.
|
||||||
var self = this;
|
*/
|
||||||
|
function ErrorContainer(element) {
|
||||||
this.$el = element instanceof jQuery ? element : $(element);
|
this.$el = element instanceof $ ? element : $(element);
|
||||||
this.steps = [];
|
|
||||||
|
// Set the error container's heading.
|
||||||
// Add an error container which displays a list of invalid steps on form submission.
|
this.$el.find('h4').text(window.ss.i18n._t('UserForms.ERROR_CONTAINER_HEADER',
|
||||||
this.errorContainer = new ErrorContainer(this.$el.children('.error-container'));
|
'Please correct the following errors and try again:'));
|
||||||
|
|
||||||
// Listen for events triggered by form steps.
|
return this;
|
||||||
this.$el.on('userform.action.prev', function (e) {
|
}
|
||||||
self.prevStep();
|
|
||||||
});
|
/**
|
||||||
this.$el.on('userform.action.next', function (e) {
|
* @func hasErrors
|
||||||
self.nextStep();
|
* @return boolean
|
||||||
});
|
* @desc Checks if the error container has any error messages.
|
||||||
|
*/
|
||||||
// Listen for events triggered by the progress bar.
|
ErrorContainer.prototype.hasErrors = () => (
|
||||||
$('#userform-progress').on('userform.progress.changestep', function (e, stepNumber) {
|
this.$el.find('.error-list').children().length > 0
|
||||||
self.jumpToStep(stepNumber - 1);
|
);
|
||||||
});
|
|
||||||
|
/**
|
||||||
// When a field becomes valid, remove errors from the error container.
|
* @func removeErrorMessage
|
||||||
this.$el.on('userform.form.valid', function (e, fieldId) {
|
* @desc Removes an error message from the error container.
|
||||||
self.errorContainer.removeStepLink(fieldId);
|
*/
|
||||||
});
|
ErrorContainer.prototype.removeErrorMessage = (fieldId) => {
|
||||||
|
this.$el.find(`#${fieldId}-top-error`).remove();
|
||||||
this.$el.validate(this.validationOptions);
|
|
||||||
|
// If there are no more error then hide the container.
|
||||||
// Ensure checkbox groups are validated correctly
|
if (!this.hasErrors()) {
|
||||||
$('.optionset.requiredField input').each(function() {
|
this.hide();
|
||||||
$(this).rules('add', {
|
}
|
||||||
required: true
|
};
|
||||||
});
|
|
||||||
});
|
/**
|
||||||
|
* @func addStepLink
|
||||||
return this;
|
* @param {object} step - FormStep instance.
|
||||||
}
|
* @desc Adds a link to a form step as an error message.
|
||||||
|
*/
|
||||||
/*
|
ErrorContainer.prototype.addStepLink = (step) => {
|
||||||
* Default options for step validation. These get extended in main().
|
const itemID = `${step.$el.attr('id')}-error-link`;
|
||||||
*/
|
let $itemElement = this.$el.find(`#${itemID}`);
|
||||||
UserForm.prototype.validationOptions = {
|
const stepID = step.$el.attr('id');
|
||||||
ignore: ':hidden,ul',
|
const stepTitle = step.$el.data('title');
|
||||||
errorClass: 'error',
|
|
||||||
errorElement: 'span',
|
// If the item already exists we don't need to do anything.
|
||||||
errorPlacement: function (error, element) {
|
if ($itemElement.length) {
|
||||||
error.addClass('message');
|
return;
|
||||||
|
}
|
||||||
if (element.is(':radio') || element.parents('.checkboxset').length > 0) {
|
|
||||||
error.insertAfter(element.closest('ul'));
|
$itemElement = $(`<li id="${itemID}"><a href="#${stepID}">${stepTitle}</a></li>`);
|
||||||
} else if (element.parents('.checkbox').length > 0) {
|
|
||||||
error.insertAfter(element.next('label'));
|
$itemElement.on('click', (e) => {
|
||||||
} else {
|
e.preventDefault();
|
||||||
error.insertAfter(element);
|
userform.jumpToStep(step.id);
|
||||||
}
|
});
|
||||||
},
|
|
||||||
invalidHandler: function (event, validator) {
|
this.$el.find('.error-list').append($itemElement);
|
||||||
//setTimeout 0 so it runs after errorPlacement
|
};
|
||||||
setTimeout(function () {
|
|
||||||
validator.currentElements.filter('.error').first().focus();
|
/**
|
||||||
}, 0);
|
* @func removeStepLink
|
||||||
},
|
* @param {object} step - FormStep instance.
|
||||||
// Callback for handling the actual submit when the form is valid.
|
* @desc Removes a step link from the error container.
|
||||||
// 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.
|
ErrorContainer.prototype.removeStepLink = (fieldId) => {
|
||||||
submitHandler: function (form, e) {
|
const stepID = $(`#${fieldId}`).closest('.form-step').attr('id');
|
||||||
var isValid = true;
|
|
||||||
|
this.$el.find(`#${stepID}-error-link`).remove();
|
||||||
// validate the current step
|
|
||||||
if(userform.currentStep) {
|
// Hide the error container if we've just removed the last error.
|
||||||
userform.currentStep.valid = $(form).valid();
|
if (this.$el.find('.error-list').is(':empty')) {
|
||||||
}
|
this.hide();
|
||||||
|
}
|
||||||
// Check for invalid previous steps.
|
};
|
||||||
$.each(userform.steps, function (i, step) {
|
|
||||||
if (!step.valid && !step.conditionallyHidden()) {
|
/**
|
||||||
isValid = false;
|
* @func ErrorContainer.updateErrorMessage
|
||||||
userform.errorContainer.addStepLink(step);
|
* @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).
|
||||||
|
*/
|
||||||
if (isValid) {
|
ErrorContainer.prototype.updateErrorMessage = ($input, message) => {
|
||||||
|
const inputID = $input.attr('id');
|
||||||
// When using the "are you sure?" plugin, ensure the form immediately submits.
|
let anchor = `#${inputID}`;
|
||||||
$(form).removeClass('dirty');
|
const elementID = `${inputID}-top-error`;
|
||||||
|
let messageElement = $(`#${elementID}`);
|
||||||
form.submit();
|
let describedBy = $input.attr('aria-describedby');
|
||||||
} else {
|
|
||||||
userform.errorContainer.show();
|
// The 'message' param will be an empty string if the field is valid.
|
||||||
}
|
if (!message) {
|
||||||
},
|
// Style issues as fixed if they already exist
|
||||||
// When a field becomes valid.
|
messageElement.addClass('fixed');
|
||||||
success: function (error) {
|
return;
|
||||||
var errorId = $(error).attr('id'),
|
}
|
||||||
fieldId = errorId.substr(0, errorId.indexOf('-error')).replace(/[\\[\\]]/, '');
|
|
||||||
|
messageElement.removeClass('fixed');
|
||||||
// Remove square brackets since jQuery.validate.js uses idOrName,
|
|
||||||
// which breaks further on when using a selector that end with
|
this.show();
|
||||||
// square brackets.
|
|
||||||
|
if (messageElement.length === 1) {
|
||||||
error.remove();
|
// Update the existing error message.
|
||||||
|
messageElement.show().find('a').html(message);
|
||||||
// Pass the field's ID with the event.
|
} else {
|
||||||
userform.$el.trigger('userform.form.valid', [fieldId]);
|
// Generate better link to field
|
||||||
}
|
$input.closest('.field[id]').each(() => {
|
||||||
};
|
anchor = `#${$(this).attr('id')}`;
|
||||||
|
});
|
||||||
/**
|
|
||||||
* @func UserForm.addStep
|
// Add a new error message
|
||||||
* @param {object} step - An instance of FormStep.
|
messageElement = $('<li><a></a></li>');
|
||||||
* @desc Adds a step to the UserForm.
|
messageElement
|
||||||
*/
|
.attr('id', elementID)
|
||||||
UserForm.prototype.addStep = function (step) {
|
.find('a')
|
||||||
// Make sure we're dealing with a form step.
|
.attr('href', location.pathname + location.search + anchor)
|
||||||
if (!step instanceof FormStep) {
|
.html(message);
|
||||||
return;
|
|
||||||
}
|
this.$el.find('ul').append(messageElement);
|
||||||
|
|
||||||
step.id = this.steps.length;
|
// Link back to original input via aria
|
||||||
|
// Respect existing non-error aria-describedby
|
||||||
this.steps.push(step);
|
if (!describedBy) {
|
||||||
};
|
describedBy = elementID;
|
||||||
|
} else if (!describedBy.match(new RegExp(`\\b${elementID}\\b`))) {
|
||||||
/**
|
// Add to end of list if not already present
|
||||||
* @func UserForm.setCurrentStep
|
describedBy += ` ${elementID}`;
|
||||||
* @param {object} step - An instance of FormStep.
|
}
|
||||||
* @desc Sets the step the user is currently on.
|
|
||||||
*/
|
$input.attr('aria-describedby', describedBy);
|
||||||
UserForm.prototype.setCurrentStep = function (step) {
|
}
|
||||||
// Make sure we're dealing with a form step.
|
};
|
||||||
if (!(step instanceof FormStep)) {
|
|
||||||
return;
|
/**
|
||||||
}
|
* @func FormStep
|
||||||
|
* @constructor
|
||||||
this.currentStep = step;
|
* @param {object} element
|
||||||
this.currentStep.show();
|
* @return {object} - The FormStep instance.
|
||||||
|
* @desc Creates a form step.
|
||||||
// Record the user has viewed the step.
|
*/
|
||||||
step.viewed = true;
|
function FormStep(element) {
|
||||||
step.$el.addClass('viewed');
|
const self = this;
|
||||||
};
|
|
||||||
|
this.$el = element instanceof $ ? element : $(element);
|
||||||
/**
|
|
||||||
* @func UserForm.jumpToStep
|
// Find button for this step
|
||||||
* @param {number} stepNumber
|
this.$elButton = $(`.step-button-wrapper[data-for='${this.$el.prop('id')}]`);
|
||||||
* @param {boolean} [direction] - Defaults to forward (true).
|
|
||||||
* @desc Jumps to a specific form step.
|
// Has the step been viewed by the user?
|
||||||
*/
|
this.viewed = false;
|
||||||
UserForm.prototype.jumpToStep = function (stepNumber, direction) {
|
|
||||||
var targetStep = this.steps[stepNumber],
|
// Is the form step valid?
|
||||||
isValid = false,
|
// This value is used on form submission, which fails, if any of the steps are invalid.
|
||||||
forward = direction === void 0 ? true : direction;
|
this.valid = false;
|
||||||
|
|
||||||
// Make sure the target step exists.
|
// The internal id of the step. Used for getting the step from the UserForm.steps array.
|
||||||
if (targetStep === void 0) {
|
this.id = null;
|
||||||
return;
|
|
||||||
}
|
this.hide();
|
||||||
|
|
||||||
// Make sure the step we're trying to set as current is not
|
if (CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP) {
|
||||||
// hidden by custom display rules. If it is then jump to the next step.
|
this.errorContainer = new ErrorContainer(this.$el.find('.error-container'));
|
||||||
if (targetStep.conditionallyHidden()) {
|
|
||||||
if (forward) {
|
// Listen for errors on the UserForm.
|
||||||
this.jumpToStep(stepNumber + 1);
|
userform.$el.on('userform.form.error', (e, validator) => {
|
||||||
} else {
|
// The step only cares about errors if it's currently visible.
|
||||||
this.jumpToStep(stepNumber - 1);
|
if (!self.$el.is(':visible')) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
return;
|
|
||||||
}
|
// Add or update each error in the list.
|
||||||
|
$.each(validator.errorList, (i, error) => {
|
||||||
// Validate the form.
|
self.errorContainer.updateErrorMessage($(error.element), error.message);
|
||||||
// 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();
|
// Listen for fields becoming valid
|
||||||
|
userform.$el.on('userform.form.valid', (e, fieldId) => {
|
||||||
// Set the 'valid' property on the current step.
|
self.errorContainer.removeErrorMessage(fieldId);
|
||||||
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) {
|
// Ensure that page visibilty updates the step navigation
|
||||||
return;
|
this
|
||||||
}
|
.$elButton
|
||||||
|
.on('userform.field.hide userform.field.show', () => {
|
||||||
this.currentStep.hide();
|
userform.$el.trigger('userform.form.conditionalstep');
|
||||||
this.setCurrentStep(targetStep);
|
});
|
||||||
|
|
||||||
this.$el.trigger('userform.form.changestep', [targetStep.id]);
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @func UserForm.nextStep
|
* Determine if this step is conditionally disabled
|
||||||
* @desc Advances the form to the next step.
|
*
|
||||||
*/
|
* @returns {Boolean}
|
||||||
UserForm.prototype.nextStep = function () {
|
*/
|
||||||
this.jumpToStep(this.steps.indexOf(this.currentStep) + 1, true);
|
// Because the element itself could be visible but 0 height, so check visibility of button
|
||||||
};
|
FormStep.prototype.conditionallyHidden = () => (
|
||||||
|
!this.$elButton.find('button').is(':visible')
|
||||||
/**
|
);
|
||||||
* @func UserForm.prevStep
|
|
||||||
* @desc Goes back one step (not bound to browser history).
|
/**
|
||||||
*/
|
* @func ProgressBar
|
||||||
UserForm.prototype.prevStep = function () {
|
* @constructor
|
||||||
this.jumpToStep(this.steps.indexOf(this.currentStep) - 1, false);
|
* @param {object} element
|
||||||
};
|
* @return {object} - The Progress bar instance.
|
||||||
|
* @desc Creates a progress bar.
|
||||||
/**
|
*/
|
||||||
* @func ErrorContainer
|
function ProgressBar(element) {
|
||||||
* @constructor
|
const self = this;
|
||||||
* @param {object} element - The error container element.
|
|
||||||
* @return {object} - The ErrorContainer instance.
|
this.$el = element instanceof $ ? element : $(element);
|
||||||
* @desc Creates an error container. Used to display step error messages at the top.
|
this.$buttons = this.$el.find('.step-button-jump');
|
||||||
*/
|
this.$jsAlign = this.$el.find('.js-align');
|
||||||
function ErrorContainer(element) {
|
|
||||||
this.$el = element instanceof jQuery ? element : $(element);
|
// Update the progress bar when 'step' buttons are clicked.
|
||||||
|
this.$buttons.each((i, stepButton) => {
|
||||||
// Set the error container's heading.
|
$(stepButton).on('click', (e) => {
|
||||||
this.$el.find('h4').text(ss.i18n._t('UserForms.ERROR_CONTAINER_HEADER', 'Please correct the following errors and try again:'));
|
e.preventDefault();
|
||||||
|
self.$el.trigger('userform.progress.changestep', [parseInt($(this).data('step'), 10)]);
|
||||||
return this;
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
// Update the progress bar when 'prev' and 'next' buttons are clicked.
|
||||||
* @func hasErrors
|
userform.$el.on('userform.form.changestep', (e, stepID) => {
|
||||||
* @return boolean
|
self.update(stepID);
|
||||||
* @desc Checks if the error container has any error messages.
|
});
|
||||||
*/
|
|
||||||
ErrorContainer.prototype.hasErrors = function () {
|
// Listen for steps being conditionally shown / hidden by display rules.
|
||||||
return this.$el.find('.error-list').children().length > 0;
|
// 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.
|
||||||
* @func removeErrorMessage
|
const $visibleButtons = self.$buttons.filter(':visible');
|
||||||
* @desc Removes an error message from the error container.
|
|
||||||
*/
|
$visibleButtons.each((i, button) => {
|
||||||
ErrorContainer.prototype.removeErrorMessage = function (fieldId) {
|
$(button).text(i + 1);
|
||||||
this.$el.find('#' + fieldId + '-top-error').remove();
|
});
|
||||||
|
|
||||||
// If there are no more error then hide the container.
|
// Update the actual progress bar.
|
||||||
if (!this.hasErrors()) {
|
self.$el.find('.progress-bar').attr('aria-valuemax', $visibleButtons.length);
|
||||||
this.hide();
|
|
||||||
}
|
// Update any text that uses the total number of steps.
|
||||||
};
|
self.$el.find('.total-step-number').text($visibleButtons.length);
|
||||||
|
});
|
||||||
/**
|
|
||||||
* @func addStepLink
|
// Spaces out the steps below progress bar evenly
|
||||||
* @param {object} step - FormStep instance.
|
this.$jsAlign.each((index, button) => {
|
||||||
* @desc Adds a link to a form step as an error message.
|
const $button = $(button);
|
||||||
*/
|
const leftPercent = (100 / (self.$jsAlign.length - 1) * `${index}%`);
|
||||||
ErrorContainer.prototype.addStepLink = function (step) {
|
const buttonOffset = -1 * ($button.innerWidth() / 2);
|
||||||
var self = this,
|
|
||||||
itemID = step.$el.attr('id') + '-error-link',
|
$button.css({ left: leftPercent, marginLeft: buttonOffset });
|
||||||
$itemElement = this.$el.find('#' + itemID),
|
|
||||||
stepID = step.$el.attr('id'),
|
// First and last buttons are kept within userform-progress container
|
||||||
stepTitle = step.$el.data('title');
|
if (index === self.$jsAlign.length - 1) {
|
||||||
|
$button.css({ marginLeft: buttonOffset * 2 });
|
||||||
// If the item already exists we don't need to do anything.
|
} else if (index === 0) {
|
||||||
if ($itemElement.length) {
|
$button.css({ marginLeft: 0 });
|
||||||
return;
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
$itemElement = $('<li id="' + itemID + '"><a href="#' + stepID + '">' + stepTitle + '</a></li>');
|
this.update(0);
|
||||||
|
|
||||||
$itemElement.on('click', function (e) {
|
return this;
|
||||||
e.preventDefault();
|
}
|
||||||
userform.jumpToStep(step.id);
|
|
||||||
});
|
/**
|
||||||
|
* @func ProgressBar.update
|
||||||
this.$el.find('.error-list').append($itemElement);
|
* @param {number} stepID - Zero based index of the new step.
|
||||||
};
|
* @desc Update the progress element to show a new step.
|
||||||
|
*/
|
||||||
/**
|
ProgressBar.prototype.update = (stepID) => {
|
||||||
* @func removeStepLink
|
const $newStepElement = $($('.form-step')[stepID]);
|
||||||
* @param {object} step - FormStep instance.
|
let stepNumber = 0;
|
||||||
* @desc Removes a step link from the error container.
|
let barWidth = stepID / (this.$buttons.length - 1) * 100;
|
||||||
*/
|
|
||||||
ErrorContainer.prototype.removeStepLink = function (fieldId) {
|
// Set the current step number.
|
||||||
var stepID = $('#' + fieldId).closest('.form-step').attr('id');
|
this.$buttons.each((i, button) => {
|
||||||
|
if (i > stepID) {
|
||||||
this.$el.find('#' + stepID + '-error-link').remove();
|
// Break the loop
|
||||||
|
return false;
|
||||||
// Hide the error container if we've just removed the last error.
|
}
|
||||||
if (this.$el.find('.error-list').is(':empty')) {
|
|
||||||
this.hide();
|
if ($(button).is(':visible')) {
|
||||||
}
|
stepNumber += 1;
|
||||||
};
|
}
|
||||||
|
return true;
|
||||||
/**
|
});
|
||||||
* @func ErrorContainer.updateErrorMessage
|
|
||||||
* @param {object} $input - The jQuery input object which contains the field to validate.
|
// Update elements that contain the current step number.
|
||||||
* @param {object} message - The error message to display (html escaped).
|
this.$el.find('.current-step-number').each((i, element) => {
|
||||||
* @desc Update an error message (displayed at the top of the form).
|
$(element).text(stepNumber);
|
||||||
*/
|
});
|
||||||
ErrorContainer.prototype.updateErrorMessage = function ($input, message) {
|
|
||||||
var inputID = $input.attr('id'),
|
// Update aria attributes.
|
||||||
anchor = '#' + inputID,
|
this.$el.find('[aria-valuenow]').each((i, element) => {
|
||||||
elementID = inputID + '-top-error',
|
$(element).attr('aria-valuenow', stepNumber);
|
||||||
messageElement = $('#' + elementID),
|
});
|
||||||
describedBy = $input.attr('aria-describedby');
|
|
||||||
|
// Update the CSS classes on step buttons.
|
||||||
// The 'message' param will be an empty string if the field is valid.
|
this.$buttons.each((i, element) => {
|
||||||
if (!message) {
|
const $element = $(element);
|
||||||
// Style issues as fixed if they already exist
|
const $item = $element.parent();
|
||||||
messageElement.addClass('fixed');
|
|
||||||
return;
|
if (parseInt($element.data('step'), 10) === stepNumber && $element.is(':visible')) {
|
||||||
}
|
$item.addClass('current viewed');
|
||||||
|
$element.removeAttr('disabled');
|
||||||
messageElement.removeClass('fixed');
|
|
||||||
|
return;
|
||||||
this.show();
|
}
|
||||||
|
|
||||||
if (messageElement.length === 1) {
|
$item.removeClass('current');
|
||||||
// Update the existing error message.
|
});
|
||||||
messageElement.show().find('a').html(message);
|
|
||||||
} else {
|
// Update the progress bar's title with the new step's title.
|
||||||
// Generate better link to field
|
this.$el.siblings('.progress-title').text($newStepElement.data('title'));
|
||||||
$input.closest('.field[id]').each(function(){
|
|
||||||
anchor = '#' + $(this).attr('id');
|
// Update the width of the progress bar.
|
||||||
});
|
barWidth = barWidth ? `${barWidth}%` : '';
|
||||||
|
this.$el.find('.progress-bar').width(barWidth);
|
||||||
// Add a new error message
|
};
|
||||||
messageElement = $('<li><a></a></li>');
|
|
||||||
messageElement
|
/**
|
||||||
.attr('id', elementID)
|
* @func FormActions
|
||||||
.find('a')
|
* @constructor
|
||||||
.attr('href', location.pathname + location.search + anchor)
|
* @param {object} element
|
||||||
.html(message);
|
* @desc Creates the navigation and actions (Prev, Next, Submit buttons).
|
||||||
|
*/
|
||||||
this.$el.find('ul').append(messageElement);
|
function FormActions(element) {
|
||||||
|
const self = this;
|
||||||
// link back to original input via aria
|
|
||||||
// Respect existing non-error aria-describedby
|
this.$el = element instanceof $ ? element : $(element);
|
||||||
if (!describedBy) {
|
|
||||||
describedBy = elementID;
|
this.$prevButton = this.$el.find('.step-button-prev');
|
||||||
} else if (!describedBy.match(new RegExp('\\b' + elementID + '\\b'))) {
|
this.$nextButton = this.$el.find('.step-button-next');
|
||||||
// Add to end of list if not already present
|
|
||||||
describedBy += " " + elementID;
|
// Show the buttons.
|
||||||
}
|
this.$prevButton.parent().attr('aria-hidden', false).show();
|
||||||
|
this.$nextButton.parent().attr('aria-hidden', false).show();
|
||||||
$input.attr('aria-describedby', describedBy);
|
|
||||||
}
|
// Bind the step navigation event listeners.
|
||||||
};
|
this.$prevButton.on('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
/**
|
self.$el.trigger('userform.action.prev');
|
||||||
* @func FormStep
|
});
|
||||||
* @constructor
|
this.$nextButton.on('click', (e) => {
|
||||||
* @param {object} element
|
e.preventDefault();
|
||||||
* @return {object} - The FormStep instance.
|
self.$el.trigger('userform.action.next');
|
||||||
* @desc Creates a form step.
|
});
|
||||||
*/
|
|
||||||
function FormStep(element) {
|
// Listen for changes to the current form step, or conditional pages,
|
||||||
var self = this;
|
// so we can show hide buttons appropriately.
|
||||||
|
userform.$el.on('userform.form.changestep userform.form.conditionalstep', () => {
|
||||||
this.$el = element instanceof jQuery ? element : $(element);
|
self.update();
|
||||||
|
});
|
||||||
// Find button for this step
|
|
||||||
this.$elButton = $(".step-button-wrapper[data-for='" + this.$el.prop('id') + "']");
|
this.update();
|
||||||
|
|
||||||
// Has the step been viewed by the user?
|
return this;
|
||||||
this.viewed = false;
|
}
|
||||||
|
|
||||||
// Is the form step valid?
|
/**
|
||||||
// This value is used on form submission, which fails, if any of the steps are invalid.
|
* @func FormActions.update
|
||||||
this.valid = false;
|
* @param {number} stepID - Zero based ID of the current step.
|
||||||
|
* @desc Updates the form actions element to reflect the current state of the page.
|
||||||
// The internal id of the step. Used for getting the step from the UserForm.steps array.
|
*/
|
||||||
this.id = null;
|
FormActions.prototype.update = () => {
|
||||||
|
const numberOfSteps = userform.steps.length;
|
||||||
this.hide();
|
const stepID = userform.currentStep ? userform.currentStep.id : 0;
|
||||||
|
let i = null;
|
||||||
if (CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP) {
|
let lastStep = null;
|
||||||
this.errorContainer = new ErrorContainer(this.$el.find('.error-container'));
|
|
||||||
|
// Update the "Prev" button.
|
||||||
// Listen for errors on the UserForm.
|
this.$el.find('.step-button-prev')[stepID === 0 ? 'hide' : 'show']();
|
||||||
userform.$el.on('userform.form.error', function (e, validator) {
|
|
||||||
// The step only cares about errors if it's currently visible.
|
// Find last step, skipping hidden ones
|
||||||
if (!self.$el.is(':visible')) {
|
for (i = numberOfSteps - 1; i >= 0; i--) {
|
||||||
return;
|
lastStep = userform.steps[i];
|
||||||
}
|
|
||||||
|
// Skip if step is hidden
|
||||||
// Add or update each error in the list.
|
if (lastStep.conditionallyHidden()) {
|
||||||
$.each(validator.errorList, function (i, error) {
|
continue;
|
||||||
self.errorContainer.updateErrorMessage($(error.element), error.message);
|
}
|
||||||
});
|
|
||||||
});
|
// Update the "Next" button.
|
||||||
|
this.$el.find('.step-button-next')[stepID >= i ? 'hide' : 'show']();
|
||||||
// Listen for fields becoming valid
|
|
||||||
userform.$el.on('userform.form.valid', function (e, fieldId) {
|
// Update the "Actions".
|
||||||
self.errorContainer.removeErrorMessage(fieldId);
|
this.$el.find('.Actions')[stepID >= i ? 'show' : 'hide']();
|
||||||
});
|
|
||||||
}
|
// Stop processing last step
|
||||||
|
break;
|
||||||
// Ensure that page visibilty updates the step navigation
|
}
|
||||||
this
|
};
|
||||||
.$elButton
|
|
||||||
.on('userform.field.hide userform.field.show', function(){
|
/**
|
||||||
userform.$el.trigger('userform.form.conditionalstep');
|
* @func UserForm
|
||||||
});
|
* @constructor
|
||||||
|
* @param {object} element
|
||||||
return this;
|
* @return {object} - The UserForm instance.
|
||||||
}
|
* @desc The form
|
||||||
|
*/
|
||||||
/**
|
function UserForm(element) {
|
||||||
* Determine if this step is conditionally disabled
|
const self = this;
|
||||||
*
|
|
||||||
* @returns {Boolean}
|
this.$el = element instanceof $ ? element : $(element);
|
||||||
*/
|
this.steps = [];
|
||||||
FormStep.prototype.conditionallyHidden = function(){
|
|
||||||
// Because the element itself could be visible but 0 height, so check visibility of button
|
// Add an error container which displays a list of invalid steps on form submission.
|
||||||
return ! this
|
this.errorContainer = new ErrorContainer(this.$el.children('.error-container'));
|
||||||
.$elButton
|
|
||||||
.find('button')
|
// Listen for events triggered by form steps.
|
||||||
.is(':visible');
|
this.$el.on('userform.action.prev', () => {
|
||||||
};
|
self.prevStep();
|
||||||
|
});
|
||||||
/**
|
this.$el.on('userform.action.next', () => {
|
||||||
* @func ProgressBar
|
self.nextStep();
|
||||||
* @constructor
|
});
|
||||||
* @param {object} element
|
|
||||||
* @return {object} - The Progress bar instance.
|
// Listen for events triggered by the progress bar.
|
||||||
* @desc Creates a progress bar.
|
$('#userform-progress').on('userform.progress.changestep', (e, stepNumber) => {
|
||||||
*/
|
self.jumpToStep(stepNumber - 1);
|
||||||
function ProgressBar(element) {
|
});
|
||||||
var self = this;
|
|
||||||
|
// When a field becomes valid, remove errors from the error container.
|
||||||
this.$el = element instanceof jQuery ? element : $(element);
|
this.$el.on('userform.form.valid', (e, fieldId) => {
|
||||||
this.$buttons = this.$el.find('.step-button-jump');
|
self.errorContainer.removeStepLink(fieldId);
|
||||||
this.$jsAlign = this.$el.find('.js-align');
|
});
|
||||||
|
|
||||||
// Update the progress bar when 'step' buttons are clicked.
|
this.$el.validate(this.validationOptions);
|
||||||
this.$buttons.each(function (i, stepButton) {
|
|
||||||
$(stepButton).on('click', function (e) {
|
// Ensure checkbox groups are validated correctly
|
||||||
e.preventDefault();
|
$('.optionset.requiredField input').each(() => {
|
||||||
self.$el.trigger('userform.progress.changestep', [parseInt($(this).data('step'), 10)]);
|
$(this).rules('add', {
|
||||||
});
|
required: true,
|
||||||
});
|
});
|
||||||
|
});
|
||||||
// Update the progress bar when 'prev' and 'next' buttons are clicked.
|
|
||||||
userform.$el.on('userform.form.changestep', function (e, stepID) {
|
return this;
|
||||||
self.update(stepID);
|
}
|
||||||
});
|
|
||||||
|
/*
|
||||||
// Listen for steps being conditionally shown / hidden by display rules.
|
* Default options for step validation. These get extended in main().
|
||||||
// We need to update step related UI like the number of step buttons
|
*/
|
||||||
// and any text that shows the total number of steps.
|
UserForm.prototype.validationOptions = {
|
||||||
userform.$el.on('userform.form.conditionalstep', function () {
|
ignore: ':hidden,ul',
|
||||||
// Update the step numbers on the buttons.
|
errorClass: 'error',
|
||||||
var $visibleButtons = self.$buttons.filter(':visible');
|
errorElement: 'span',
|
||||||
|
errorPlacement: (error, element) => {
|
||||||
$visibleButtons.each(function (i, button) {
|
error.addClass('message');
|
||||||
$(button).text(i + 1);
|
|
||||||
});
|
if (element.is(':radio') || element.parents('.checkboxset').length > 0) {
|
||||||
|
error.insertAfter(element.closest('ul'));
|
||||||
// Update the actual progress bar.
|
} else if (element.parents('.checkbox').length > 0) {
|
||||||
self.$el.find('.progress-bar').attr('aria-valuemax', $visibleButtons.length);
|
error.insertAfter(element.next('label'));
|
||||||
|
} else {
|
||||||
// Update any text that uses the total number of steps.
|
error.insertAfter(element);
|
||||||
self.$el.find('.total-step-number').text($visibleButtons.length);
|
}
|
||||||
});
|
},
|
||||||
|
invalidHandler: (event, validator) => {
|
||||||
// Spaces out the steps below progress bar evenly
|
// setTimeout 0 so it runs after errorPlacement
|
||||||
this.$jsAlign.each(function (index, button) {
|
setTimeout(() => {
|
||||||
var $button = $(button),
|
validator.currentElements.filter('.error').first().focus();
|
||||||
leftPercent = (100 / (self.$jsAlign.length - 1) * index + '%'),
|
}, 0);
|
||||||
buttonOffset = -1 * ($button.innerWidth() / 2);
|
},
|
||||||
|
// Callback for handling the actual submit when the form is valid.
|
||||||
$button.css({left: leftPercent, marginLeft: buttonOffset});
|
// 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.
|
||||||
// First and last buttons are kept within userform-progress container
|
submitHandler: (form) => {
|
||||||
if (index === self.$jsAlign.length - 1) {
|
let isValid = true;
|
||||||
$button.css({marginLeft: buttonOffset * 2});
|
|
||||||
} else if (index === 0) {
|
// Validate the current step
|
||||||
$button.css({marginLeft: 0});
|
if (userform.currentStep) {
|
||||||
}
|
userform.currentStep.valid = $(form).valid();
|
||||||
});
|
}
|
||||||
|
|
||||||
this.update(0);
|
// Check for invalid previous steps.
|
||||||
|
$.each(userform.steps, (i, step) => {
|
||||||
return this;
|
if (!step.valid && !step.conditionallyHidden()) {
|
||||||
}
|
isValid = false;
|
||||||
|
userform.errorContainer.addStepLink(step);
|
||||||
/**
|
}
|
||||||
* @func ProgressBar.update
|
});
|
||||||
* @param {number} stepID - Zero based index of the new step.
|
|
||||||
* @desc Update the progress element to show a new step.
|
if (isValid) {
|
||||||
*/
|
// When using the "are you sure?" plugin, ensure the form immediately submits.
|
||||||
ProgressBar.prototype.update = function (stepID) {
|
$(form).removeClass('dirty');
|
||||||
var $newStepElement = $($('.form-step')[stepID]),
|
|
||||||
stepNumber = 0,
|
form.submit();
|
||||||
barWidth = stepID / (this.$buttons.length - 1) * 100;
|
} else {
|
||||||
|
userform.errorContainer.show();
|
||||||
// Set the current step number.
|
}
|
||||||
this.$buttons.each(function (i, button) {
|
},
|
||||||
if (i > stepID) {
|
// When a field becomes valid.
|
||||||
return false; // break the loop
|
success: (error) => {
|
||||||
}
|
const errorId = $(error).attr('id');
|
||||||
|
const fieldId = errorId.substr(0, errorId.indexOf('-error')).replace(/[\\[\\]]/, '');
|
||||||
if ($(button).is(':visible')) {
|
|
||||||
stepNumber += 1;
|
// Remove square brackets since jQuery.validate.js uses idOrName,
|
||||||
}
|
// which breaks further on when using a selector that end with
|
||||||
});
|
// square brackets.
|
||||||
|
|
||||||
// Update elements that contain the current step number.
|
error.remove();
|
||||||
this.$el.find('.current-step-number').each(function (i, element) {
|
|
||||||
$(element).text(stepNumber);
|
// Pass the field's ID with the event.
|
||||||
});
|
userform.$el.trigger('userform.form.valid', [fieldId]);
|
||||||
|
},
|
||||||
// Update aria attributes.
|
};
|
||||||
this.$el.find('[aria-valuenow]').each(function (i, element) {
|
|
||||||
$(element).attr('aria-valuenow', stepNumber);
|
/**
|
||||||
});
|
* @func UserForm.addStep
|
||||||
|
* @param {object} step - An instance of FormStep.
|
||||||
// Update the CSS classes on step buttons.
|
* @desc Adds a step to the UserForm.
|
||||||
this.$buttons.each(function (i, element) {
|
*/
|
||||||
var $element = $(element),
|
UserForm.prototype.addStep = (step) => {
|
||||||
$item = $element.parent();
|
// Make sure we're dealing with a form step.
|
||||||
|
if (!step instanceof FormStep) {
|
||||||
if (parseInt($element.data('step'), 10) === stepNumber && $element.is(':visible')) {
|
return;
|
||||||
$item.addClass('current viewed');
|
}
|
||||||
$element.removeAttr('disabled');
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
return;
|
step.id = this.steps.length;
|
||||||
}
|
|
||||||
|
this.steps.push(step);
|
||||||
$item.removeClass('current');
|
};
|
||||||
});
|
|
||||||
|
/**
|
||||||
// Update the progress bar's title with the new step's title.
|
* @func UserForm.setCurrentStep
|
||||||
this.$el.siblings('.progress-title').text($newStepElement.data('title'));
|
* @param {object} step - An instance of FormStep.
|
||||||
|
* @desc Sets the step the user is currently on.
|
||||||
// Update the width of the progress bar.
|
*/
|
||||||
barWidth = barWidth ? barWidth + '%' : '';
|
UserForm.prototype.setCurrentStep = (step) => {
|
||||||
this.$el.find('.progress-bar').width(barWidth);
|
// Make sure we're dealing with a form step.
|
||||||
};
|
if (!(step instanceof FormStep)) {
|
||||||
|
return;
|
||||||
/**
|
}
|
||||||
* @func FormActions
|
|
||||||
* @constructor
|
this.currentStep = step;
|
||||||
* @param {object} element
|
this.currentStep.show();
|
||||||
* @desc Creates the navigation and actions (Prev, Next, Submit buttons).
|
|
||||||
*/
|
// Record the user has viewed the step.
|
||||||
function FormActions (element) {
|
this.currentStep.viewed = true;
|
||||||
var self = this;
|
this.currentStep.$el.addClass('viewed');
|
||||||
|
};
|
||||||
this.$el = element instanceof jQuery ? element : $(element);
|
|
||||||
|
/**
|
||||||
this.$prevButton = this.$el.find('.step-button-prev');
|
* @func UserForm.jumpToStep
|
||||||
this.$nextButton = this.$el.find('.step-button-next');
|
* @param {number} stepNumber
|
||||||
|
* @param {boolean} [direction] - Defaults to forward (true).
|
||||||
// Show the buttons.
|
* @desc Jumps to a specific form step.
|
||||||
this.$prevButton.parent().attr('aria-hidden', false).show();
|
*/
|
||||||
this.$nextButton.parent().attr('aria-hidden', false).show();
|
UserForm.prototype.jumpToStep = (stepNumber, direction) => {
|
||||||
|
const targetStep = this.steps[stepNumber];
|
||||||
// Bind the step navigation event listeners.
|
let isValid = false;
|
||||||
this.$prevButton.on('click', function (e) {
|
const forward = direction === void 0 ? true : direction;
|
||||||
e.preventDefault();
|
|
||||||
self.$el.trigger('userform.action.prev');
|
// Make sure the target step exists.
|
||||||
});
|
if (targetStep === void 0) {
|
||||||
this.$nextButton.on('click', function (e) {
|
return;
|
||||||
e.preventDefault();
|
}
|
||||||
self.$el.trigger('userform.action.next');
|
|
||||||
});
|
// 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.
|
||||||
// Listen for changes to the current form step, or conditional pages,
|
if (targetStep.conditionallyHidden()) {
|
||||||
// so we can show hide buttons appropriatly.
|
if (forward) {
|
||||||
userform.$el.on('userform.form.changestep userform.form.conditionalstep', function () {
|
this.jumpToStep(stepNumber + 1);
|
||||||
self.update();
|
} else {
|
||||||
});
|
this.jumpToStep(stepNumber - 1);
|
||||||
|
}
|
||||||
this.update();
|
|
||||||
|
return;
|
||||||
return this;
|
}
|
||||||
}
|
|
||||||
|
// Validate the form.
|
||||||
/**
|
// This well effectivly validate the current step and not the entire form.
|
||||||
* @func FormAcrions.update
|
// This is because hidden fields are excluded from validation, and all fields
|
||||||
* @param {number} stepID - Zero based ID of the current step.
|
// on all other steps, are currently hidden.
|
||||||
* @desc Updates the form actions element to reflect the current state of the page.
|
isValid = this.$el.valid();
|
||||||
*/
|
|
||||||
FormActions.prototype.update = function () {
|
// Set the 'valid' property on the current step.
|
||||||
var numberOfSteps = userform.steps.length,
|
this.currentStep.valid = isValid;
|
||||||
stepID = userform.currentStep ? userform.currentStep.id : 0,
|
|
||||||
i, lastStep;
|
// Users can navigate to step's they've already viewed even if the current step is invalid.
|
||||||
|
if (isValid === false && targetStep.viewed === false) {
|
||||||
// Update the "Prev" button.
|
return;
|
||||||
this.$el.find('.step-button-prev')[stepID === 0 ? 'hide' : 'show']();
|
}
|
||||||
|
|
||||||
// Find last step, skipping hidden ones
|
this.currentStep.hide();
|
||||||
for(i = numberOfSteps - 1; i >= 0; i--) {
|
this.setCurrentStep(targetStep);
|
||||||
lastStep = userform.steps[i];
|
|
||||||
|
this.$el.trigger('userform.form.changestep', [targetStep.id]);
|
||||||
// Skip if step is hidden
|
};
|
||||||
if(lastStep.conditionallyHidden()) {
|
|
||||||
continue;
|
/**
|
||||||
}
|
* @func UserForm.nextStep
|
||||||
|
* @desc Advances the form to the next step.
|
||||||
// Update the "Next" button.
|
*/
|
||||||
this.$el.find('.step-button-next')[stepID >= i ? 'hide' : 'show']();
|
UserForm.prototype.nextStep = () => {
|
||||||
|
this.jumpToStep(this.steps.indexOf(this.currentStep) + 1, true);
|
||||||
// Update the "Actions".
|
};
|
||||||
this.$el.find('.Actions')[stepID >= i ? 'show' : 'hide']();
|
|
||||||
|
/**
|
||||||
// Stop processing last step
|
* @func UserForm.prevStep
|
||||||
break;
|
* @desc Goes back one step (not bound to browser history).
|
||||||
}
|
*/
|
||||||
};
|
UserForm.prototype.prevStep = () => {
|
||||||
|
this.jumpToStep(this.steps.indexOf(this.currentStep) - 1, false);
|
||||||
/**
|
};
|
||||||
* @func main
|
|
||||||
* @desc Bootstraps the front-end.
|
/**
|
||||||
*/
|
* @func main
|
||||||
function main() {
|
* @desc Bootstraps the front-end.
|
||||||
var progressBar = null,
|
*/
|
||||||
formActions = null,
|
function main() {
|
||||||
$userform = $('.userform');
|
const $userform = $('.userform');
|
||||||
|
|
||||||
// If there's no userform, do nothing.
|
// If there's no userform, do nothing.
|
||||||
if ($userform.length === 0) {
|
if ($userform.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CONSTANTS.ENABLE_LIVE_VALIDATION = $userform.data('livevalidation') !== void 0;
|
CONSTANTS.ENABLE_LIVE_VALIDATION = $userform.data('livevalidation') !== void 0;
|
||||||
CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP = $userform.data('toperrors') !== void 0;
|
CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP = $userform.data('toperrors') !== void 0;
|
||||||
|
|
||||||
// Extend the default validation options with conditional options
|
// Extend the default validation options with conditional options
|
||||||
// that are set by the user in the CMS.
|
// that are set by the user in the CMS.
|
||||||
if (CONSTANTS.ENABLE_LIVE_VALIDATION === false) {
|
if (CONSTANTS.ENABLE_LIVE_VALIDATION === false) {
|
||||||
$.extend(UserForm.prototype.validationOptions, {
|
$.extend(UserForm.prototype.validationOptions, {
|
||||||
onfocusout: false
|
onfocusout: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP) {
|
if (CONSTANTS.DISPLAY_ERROR_MESSAGES_AT_TOP) {
|
||||||
$.extend(UserForm.prototype.validationOptions, {
|
$.extend(UserForm.prototype.validationOptions, {
|
||||||
// Callback for custom code when an invalid form / step is submitted.
|
// Callback for custom code when an invalid form / step is submitted.
|
||||||
invalidHandler: function (event, validator) {
|
invalidHandler: (event, validator) => {
|
||||||
$userform.trigger('userform.form.error', [validator]);
|
$userform.trigger('userform.form.error', [validator]);
|
||||||
},
|
},
|
||||||
onfocusout: false
|
onfocusout: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display all the things that are hidden when JavaScript is disabled.
|
// Display all the things that are hidden when JavaScript is disabled.
|
||||||
$('.userform-progress, .step-navigation').attr('aria-hidden', false).show();
|
$('.userform-progress, .step-navigation').attr('aria-hidden', false).show();
|
||||||
|
|
||||||
// Extend classes with common functionality.
|
// Extend classes with common functionality.
|
||||||
$.extend(FormStep.prototype, commonMixin);
|
$.extend(FormStep.prototype, commonMixin);
|
||||||
$.extend(ErrorContainer.prototype, commonMixin);
|
$.extend(ErrorContainer.prototype, commonMixin);
|
||||||
|
|
||||||
userform = new UserForm($userform);
|
userform = new UserForm($userform);
|
||||||
|
|
||||||
// Conditionally hide field labels and use HTML5 placeholder instead.
|
// Conditionally hide field labels and use HTML5 placeholder instead.
|
||||||
if (CONSTANTS.HIDE_FIELD_LABELS) {
|
if (CONSTANTS.HIDE_FIELD_LABELS) {
|
||||||
$userform.find('label.left').each(function () {
|
$userform.find('label.left').each(() => {
|
||||||
var $label = $(this);
|
const $label = $(this);
|
||||||
|
|
||||||
$('[name="' + $label.attr('for') + '"]').attr('placeholder', $label.text());
|
$(`[name="${$label.attr('for')}"]`).attr('placeholder', $label.text());
|
||||||
$label.remove();
|
$label.remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the form steps.
|
// Initialise the form steps.
|
||||||
userform.$el.find('.form-step').each(function (i, element) {
|
userform.$el.find('.form-step').each((i, element) => {
|
||||||
var step = new FormStep(element);
|
const step = new FormStep(element);
|
||||||
|
|
||||||
userform.addStep(step);
|
userform.addStep(step);
|
||||||
});
|
});
|
||||||
|
|
||||||
userform.setCurrentStep(userform.steps[0]);
|
userform.setCurrentStep(userform.steps[0]);
|
||||||
|
|
||||||
// Initialise actions and progressbar
|
// Initialise actions and progressbar
|
||||||
progressBar = new ProgressBar($('#userform-progress'));
|
// @todo Commented out because they appear unused - are they expected to be exported to the
|
||||||
formActions = new FormActions($('#step-navigation'));
|
// global scope? Check this works on the frontend
|
||||||
|
// const progressBar = new ProgressBar($('#userform-progress'));
|
||||||
// Enable jQuery UI datepickers
|
// const formActions = new FormActions($('#step-navigation'));
|
||||||
$(document).on('click', 'input.text[data-showcalendar]', function() {
|
|
||||||
var $element = $(this);
|
// Enable jQuery UI datepickers
|
||||||
|
$(document).on('click', 'input.text[data-showcalendar]', () => {
|
||||||
$element.ssDatepicker();
|
const $element = $(this);
|
||||||
|
|
||||||
if($element.data('datepicker')) {
|
$element.ssDatepicker();
|
||||||
$element.datepicker('show');
|
|
||||||
}
|
if ($element.data('datepicker')) {
|
||||||
});
|
$element.datepicker('show');
|
||||||
|
}
|
||||||
// Make sure the form doesn't expire on the user. Pings every 3 mins.
|
});
|
||||||
setInterval(function () {
|
|
||||||
$.ajax({ url: 'UserDefinedForm_Controller/ping' });
|
// Make sure the form doesn't expire on the user. Pings every 3 mins.
|
||||||
}, 180 * 1000);
|
setInterval(() => {
|
||||||
|
$.ajax({ url: 'UserDefinedForm_Controller/ping' });
|
||||||
// Bind a confirmation message when navigating away from a partially completed form.
|
}, 180 * 1000);
|
||||||
var form = $('form.userform');
|
|
||||||
if(typeof form.areYouSure != 'undefined') {
|
// Bind a confirmation message when navigating away from a partially completed form.
|
||||||
form.areYouSure({
|
const form = $('form.userform');
|
||||||
message: ss.i18n._t('UserForms.LEAVE_CONFIRMATION', 'You have unsaved changes!')
|
if (typeof form.areYouSure !== 'undefined') {
|
||||||
});
|
form.areYouSure({
|
||||||
}
|
message: window.ss.i18n._t('UserForms.LEAVE_CONFIRMATION', 'You have unsaved changes!'),
|
||||||
}
|
});
|
||||||
|
}
|
||||||
main();
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
});
|
});
|
||||||
|
3
client/src/styles/bundle-cms.scss
Normal file
3
client/src/styles/bundle-cms.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// CMS SASS bundle
|
||||||
|
@import "variables";
|
||||||
|
@import "userforms-cms";
|
3
client/src/styles/bundle.scss
Normal file
3
client/src/styles/bundle.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// Frontend SASS bundle
|
||||||
|
@import "variables";
|
||||||
|
@import "userforms";
|
@ -1,156 +1,151 @@
|
|||||||
/**
|
// Animations
|
||||||
* Animations
|
|
||||||
*/
|
|
||||||
|
|
||||||
@keyframes flashBackground {
|
@keyframes flash-background {
|
||||||
0% {background-color: white;}
|
0% {background-color: $body-bg;}
|
||||||
10% {background-color: #dcfedd;}
|
10% {background-color: $green-bg;}
|
||||||
70% {background-color: #dcfedd;}
|
70% {background-color: $green-bg;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
.uf-field-editor {
|
||||||
* Styles for cms
|
padding-bottom: 0;
|
||||||
*/
|
|
||||||
|
|
||||||
.cms {
|
// Row styles
|
||||||
.uf-field-editor {
|
table.ss-gridfield-table {
|
||||||
padding-bottom: 0;
|
// Standard rows
|
||||||
|
.ss-gridfield-item {
|
||||||
|
height: $height-base;
|
||||||
|
|
||||||
// Row styles
|
&,
|
||||||
table.ss-gridfield-table {
|
&:hover {
|
||||||
// Standard rows
|
background: $body-bg;
|
||||||
.ss-gridfield-item {
|
}
|
||||||
height: 46px;
|
|
||||||
|
|
||||||
&, &:hover {
|
td {
|
||||||
background: white;
|
border-right-width: 0;
|
||||||
}
|
border-top: 1px solid $gray-light;
|
||||||
|
|
||||||
td {
|
&:last-child {
|
||||||
border-right-width: 0;
|
border-right-width: 1px;
|
||||||
border-top: 1px solid #EEE;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:last-child {
|
.handle {
|
||||||
border-right-width: 1px;
|
min-height: $height-base;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.handle {
|
&.flash-background {
|
||||||
min-height: 46px;
|
animation: flash-background 2s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.flashBackground {
|
&.ui-sortable-placeholder {
|
||||||
animation: flashBackground 2s linear;
|
height: $placeholder-height;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.ui-sortable-placeholder {
|
.ss-gridfield-item.infieldgroup {
|
||||||
height: 50px;
|
&,
|
||||||
}
|
&:hover {
|
||||||
}
|
background: $blue-light;
|
||||||
|
}
|
||||||
|
|
||||||
.ss-gridfield-item.inFieldGroup {
|
td {
|
||||||
&, &:hover {
|
border-bottom: 0;
|
||||||
background: #f2f9fd;
|
border-top: 1px solid $gray-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
.col-reorder,
|
||||||
border-bottom: 0;
|
.handle {
|
||||||
border-top: 1px solid #eee;
|
background: $blue;
|
||||||
}
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.col-reorder, .handle {
|
&.infieldgroup-level-2 {
|
||||||
background: #BEE0F8;
|
.col-reorder,
|
||||||
border-top: 0;
|
.handle {
|
||||||
}
|
background: $blue-dark;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.inFieldGroup-level-2 {
|
&.infieldgroup-level-3 {
|
||||||
.col-reorder, .handle {
|
.col-reorder,
|
||||||
background: #99CEF4;
|
.handle {
|
||||||
border-top: 0;
|
background: $blue-darker;
|
||||||
}
|
border-top: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.inFieldGroup-level-3 {
|
.ss-gridfield-item[data-class="EditableFormStep"] {
|
||||||
.col-reorder, .handle {
|
&,
|
||||||
background: #89BEF4;
|
&:hover {
|
||||||
border-top: 0;
|
background: $gray-bg;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ss-gridfield-item[data-class='EditableFormStep'] {
|
label {
|
||||||
&, &:hover {
|
font-weight: bold;
|
||||||
background: #dae2e7;
|
color: $gray-base;
|
||||||
}
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
td {
|
||||||
font-weight: bold;
|
border-top: 1px solid $gray;
|
||||||
color: black;
|
}
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
+ .ss-gridfield-item td {
|
||||||
border-top: 1px solid #a6b6c1;
|
border-top: 1px solid $gray-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ .ss-gridfield-item td {
|
+ .ss-gridfield-item[data-class="EditableFieldGroup"] td {
|
||||||
border-top: 1px solid #dae2e7;
|
border-top: 1px solid $blue-base;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ .ss-gridfield-item[data-class='EditableFieldGroup'] td {
|
.ss-gridfield-item[data-class="EditableFieldGroup"] {
|
||||||
border-top: 1px solid #a8d7f5;
|
td {
|
||||||
}
|
border-top: 1px solid $blue-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ss-gridfield-item[data-class='EditableFieldGroup'] {
|
label {
|
||||||
td {
|
font-weight: bold;
|
||||||
border-top: 1px solid #a8d7f5;
|
color: $gray-darker;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
.ss-gridfield-item[data-class="EditableFieldGroupEnd"] {
|
||||||
font-weight: bold;
|
td {
|
||||||
color: #444;
|
border-bottom: 1px solid $blue-base;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.ss-gridfield-item[data-class='EditableFieldGroupEnd'] {
|
+ .ss-gridfield-item[data-class="EditableFieldGroupEnd"] {
|
||||||
td {
|
border-top: 0;
|
||||||
border-bottom: 1px solid #a8d7f5;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
+ .ss-gridfield-item[data-class='EditableFieldGroupEnd'] {
|
.col-buttons .action {
|
||||||
border-top: 0;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-buttons .action{
|
label {
|
||||||
display: none;
|
color: $gray-dark;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
.sticky-buttons {
|
||||||
color: #777;
|
position: fixed;
|
||||||
}
|
top: $height-top;
|
||||||
}
|
z-index: 2;
|
||||||
}
|
background: $gray-light;
|
||||||
|
box-shadow: 0 $padding-base $padding-xs -$padding-base-horizontal $gray-light;
|
||||||
|
padding: $padding-base;
|
||||||
|
margin-left: -$padding-base;
|
||||||
|
|
||||||
.stickyButtons {
|
& button.action {
|
||||||
position: fixed;
|
margin-bottom: 0;
|
||||||
top: 40px;
|
}
|
||||||
z-index: 2;
|
|
||||||
background: #E6EAED;
|
|
||||||
box-shadow: 0 12px 4px -8px #999;
|
|
||||||
padding: 12px;
|
|
||||||
margin-left: -12px;
|
|
||||||
|
|
||||||
& button.action {
|
~ .ss-gridfield-table {
|
||||||
margin-bottom: 0;
|
margin-top: $height-top;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
~ .ss-gridfield-table {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,87 +1,85 @@
|
|||||||
/**
|
// Lightweight base styles for the front-end form.
|
||||||
* Lightweight base styles for the front-end form.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.userform-progress {
|
.userform-progress {
|
||||||
.progress {
|
.progress {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
background: #eee;
|
background: $gray-lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
background: #666;
|
background: $gray-progress-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-buttons {
|
.step-buttons {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-button-wrapper {
|
.step-button-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
|
||||||
&.viewed .step-button-jump {
|
&.viewed .step-button-jump {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-button-jump {
|
.step-button-jump {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-navigation {
|
.step-navigation {
|
||||||
.step-buttons {
|
.step-buttons {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-button-wrapper {
|
.step-button-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.userform {
|
.userform {
|
||||||
clear: both;
|
clear: both;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
.field label.right {
|
.field label.right {
|
||||||
color: #555;
|
color: $gray-dark-label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.userformsgroup {
|
.userformsgroup {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid $gray-light-border;
|
||||||
border-radius: 4px;
|
border-radius: $padding-xs;
|
||||||
padding: 8px;
|
padding: $padding-base-horizontal;
|
||||||
margin-top: 12px;
|
margin-top: $padding-base;
|
||||||
margin-bottom: 12px;
|
margin-bottom: $padding-base;
|
||||||
|
|
||||||
> legend {
|
> legend {
|
||||||
padding-left: 4px;
|
padding-left: $padding-xs;
|
||||||
padding-right: 4px;
|
padding-right: $padding-xs;
|
||||||
border: 0;
|
border: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-title {
|
.right-title {
|
||||||
clear: both;
|
clear: both;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox .right-title {
|
.checkbox .right-title {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.userform .left {
|
.userform .left {
|
||||||
margin-bottom: 5px;
|
margin-bottom: $padding-sm;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
51
client/src/styles/variables.scss
Normal file
51
client/src/styles/variables.scss
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//== Colors
|
||||||
|
|
||||||
|
$gray-base: #000;
|
||||||
|
$gray-dark: #777;
|
||||||
|
$gray-darker: #444;
|
||||||
|
$gray: #a6b6c1;
|
||||||
|
$gray-light: #999;
|
||||||
|
$gray-lighter: #eee;
|
||||||
|
|
||||||
|
//== Custom colors
|
||||||
|
|
||||||
|
$gray-bg: #dae2e7;
|
||||||
|
$gray-progress-bg: #666;
|
||||||
|
$gray-dark-label: #555;
|
||||||
|
$gray-light-border: #ccc;
|
||||||
|
|
||||||
|
$blue-base: #a8d7f5;
|
||||||
|
$blue-dark: #99cef4;
|
||||||
|
$blue-darker: #89bef4;
|
||||||
|
$blue: #bee0f8;
|
||||||
|
$blue-light: #f2f9fd;
|
||||||
|
|
||||||
|
$green-bg: #dcfedd;
|
||||||
|
|
||||||
|
//== Scaffolding
|
||||||
|
//
|
||||||
|
//## Settings for some of the most global styles.
|
||||||
|
|
||||||
|
$body-bg: #fff;
|
||||||
|
|
||||||
|
//== Components
|
||||||
|
//
|
||||||
|
//## Define common padding and border radius sizes and more.
|
||||||
|
|
||||||
|
$padding-base-horizontal: 8px;
|
||||||
|
|
||||||
|
|
||||||
|
//== Custom Components
|
||||||
|
|
||||||
|
$padding-base: 12px;
|
||||||
|
$padding-xs: 4px;
|
||||||
|
$padding-sm: 5px;
|
||||||
|
|
||||||
|
$height-base: 46px;
|
||||||
|
$height-top: 40px;
|
||||||
|
$placeholder-height: 50px;
|
@ -6,7 +6,7 @@
|
|||||||
"build": "yarn && NODE_ENV=production webpack -p --bail --progress",
|
"build": "yarn && NODE_ENV=production webpack -p --bail --progress",
|
||||||
"watch": "yarn && NODE_ENV=development webpack --watch --progress",
|
"watch": "yarn && NODE_ENV=development webpack --watch --progress",
|
||||||
"css": "WEBPACK_CHILD=css npm run build",
|
"css": "WEBPACK_CHILD=css npm run build",
|
||||||
"lint": "eslint client/src && sass-lint -v"
|
"lint": "eslint client/src; sass-lint -v"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -54,8 +54,8 @@ const config = [
|
|||||||
{
|
{
|
||||||
name: 'css',
|
name: 'css',
|
||||||
entry: {
|
entry: {
|
||||||
userforms: `${PATHS.SRC}/styles/userforms.scss`,
|
userforms: `${PATHS.SRC}/styles/bundle.scss`,
|
||||||
'userforms-cms': `${PATHS.SRC}/styles/userforms-cms.scss`,
|
'userforms-cms': `${PATHS.SRC}/styles/bundle-cms.scss`,
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: PATHS.DIST,
|
path: PATHS.DIST,
|
||||||
|
Loading…
Reference in New Issue
Block a user