├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── api.html ├── babel.config.json ├── css ├── awesome-bootstrap-checkbox.css ├── bootstrap.css ├── bootstrap.min.css ├── demo-stackslider.css ├── demo.css ├── doc.css ├── font-awesome.css ├── prism.css └── stackSlider.css ├── demos.html ├── demos ├── demo-basic-extended.html ├── demo-basic-lite.html ├── demo-basic.html ├── demo-stackslider-1.html └── demo-stackslider-2.html ├── dist ├── lite │ ├── surveyjs-esm.js │ ├── surveyjs-esm.min.js │ ├── surveyjs-esm.min.js.map │ ├── surveyjs-systemjs.js │ ├── surveyjs-systemjs.min.js │ ├── surveyjs-systemjs.min.js.map │ ├── surveyjs.js │ ├── surveyjs.min.js │ └── surveyjs.min.js.map ├── surveyjs-esm.js ├── surveyjs-esm.min.js ├── surveyjs-esm.min.js.map ├── surveyjs-systemjs.js ├── surveyjs-systemjs.min.js ├── surveyjs-systemjs.min.js.map ├── surveyjs.js ├── surveyjs.min.js └── surveyjs.min.js.map ├── fonts ├── FontAwesome.otf ├── fontawesome-webfont.eot ├── fontawesome-webfont.svg ├── fontawesome-webfont.ttf ├── fontawesome-webfont.woff └── fontawesome-webfont.woff2 ├── get-started.html ├── index.d.ts ├── index.html ├── js ├── demo.js ├── demos │ ├── demo-basic-extended.js │ ├── demo-basic-lite.js │ ├── demo-basic.js │ ├── demo-stackslider-1.js │ ├── demo-stackslider-2.js │ └── doc.js ├── include.js ├── prism.js └── vendors │ ├── bootstrap.bundle.min.js │ ├── formjs.js │ ├── formjs.min.js │ ├── formjs.min.js.map │ ├── jquery-1.12.4.min.js │ ├── jquery_stackslider.js │ └── modernizr_custom_63321.js ├── json ├── survey-simple.json └── survey.json ├── package-lock.json ├── package.json ├── rollup.config.js ├── rollup.config.lite.js ├── rollup.config.server.js └── src ├── index-lite.js ├── index.js ├── modules-lite └── options.js └── modules ├── buildSurvey ├── buildSurvey.js ├── generateQAcode.js ├── generateQAcodeUtils │ ├── generateAnswers.js │ ├── generateOptionTags.js │ ├── getAttributesStringHTML.js │ └── getTemplates.js └── populateAnswers.js ├── destroy.js ├── helpers.js ├── helpers ├── ajaxCall.js ├── arrayMove.js ├── checkFormEl.js ├── customEvents.js ├── deepFreeze.js ├── dispatchCustomEvent.js ├── fieldsStringSelectorSurvey.js ├── getQuestionId.js ├── isDOMNode.js ├── isEmptyObject.js ├── isNodeList.js ├── isPlainObject.js ├── mergeObjects.js ├── replaceObjectKeysInString.js ├── sortList.js ├── toKebabCase.js └── webStorage.js ├── internals.js ├── listenerCallbacks.js ├── listenerCallbacks ├── submit.js └── validationEnd.js ├── options.js ├── optionsUtils.js ├── utils ├── getAnswerIndex.js └── getQuestionObject.js └── version.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "overrides": [ 8 | ], 9 | "parserOptions": { 10 | "ecmaVersion": "latest", 11 | "sourceType": "module" 12 | }, 13 | "ignorePatterns": ["js", "dist", "node_modules"], 14 | "rules": { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | *.html linguist-documentation 4 | css/* linguist-documentation 5 | demos/* linguist-documentation 6 | fonts/* linguist-documentation 7 | img/* linguist-documentation 8 | json/* linguist-documentation 9 | js/demo.js linguist-documentation 10 | js/include.js linguist-documentation 11 | js/prism.js linguist-documentation 12 | js/demos/* linguist-vendored 13 | js/vendors/* linguist-vendored 14 | dist/* linguist-generated=true 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.zip 3 | .DS_Store 4 | **/.DS_Store 5 | Thumbs.db 6 | **/Thumbs.db 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | css 2 | demos 3 | fonts 4 | js 5 | json 6 | *.html 7 | *.config.js 8 | *.config.*.js 9 | *.zip 10 | .gitattributes 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 Valerio Di Punzio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | surveyJS is available on 4 | NPM | 5 | jsDelivr | 6 | UNPKG 7 |

8 | 9 | # surveyJS 10 | 11 | Visit the [Plugin Documentation Page](https://www.valeriodipunzio.com/plugins/surveyJS/) for more info. 12 | 13 | 14 | 15 | ## Changelog 16 | 17 | See the [Changelog Page](https://www.valeriodipunzio.com/plugins/surveyJS/#changelog) for details. 18 | 19 | 20 | 21 | ## Releases 22 | 23 | See the [Releases Page](https://github.com/SimplySayHi/surveyJS/releases) to download provious versions. 24 | 25 | 26 | 27 | ## License 28 | 29 | MIT 30 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "build": { 4 | "exclude": "node_modules/**", 5 | "presets": [ 6 | [ "@babel/env", {"modules": false} ] 7 | ] 8 | }, 9 | "test": { 10 | "presets": [ 11 | [ "@babel/env", {"targets": {"node": "current"}} ] 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /css/awesome-bootstrap-checkbox.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | .abc-checkbox { 3 | cursor: default; 4 | padding-left: 4px; } 5 | .abc-checkbox label { 6 | cursor: pointer; 7 | display: inline; 8 | vertical-align: top; 9 | position: relative; 10 | padding-left: 5px; } 11 | .abc-checkbox label::before { 12 | cursor: pointer; 13 | content: ""; 14 | display: inline-block; 15 | position: absolute; 16 | width: 17px; 17 | height: 17px; 18 | top: 2px; 19 | left: 0; 20 | margin-left: -1.25rem; 21 | border: 1px solid rgba(0, 0, 0, 0.15); 22 | border-radius: 3px; 23 | background-color: #fff; 24 | transition: border 0.15s ease-in-out, color 0.15s ease-in-out; } 25 | .abc-checkbox label::after { 26 | cursor: pointer; 27 | display: inline-block; 28 | position: absolute; 29 | width: 16px; 30 | height: 16px; 31 | left: 0; 32 | top: 2px; 33 | margin-left: -1.25rem; 34 | padding-left: 3px; 35 | padding-top: 1px; 36 | font-size: 11px; 37 | color: #495057; } 38 | .abc-checkbox input[type="checkbox"], 39 | .abc-checkbox input[type="radio"] { 40 | position: static; 41 | margin-left: 0; 42 | cursor: pointer; 43 | opacity: 0; 44 | z-index: 1; } 45 | .abc-checkbox input[type="checkbox"]:focus + label::before, 46 | .abc-checkbox input[type="radio"]:focus + label::before { 47 | outline: thin dotted; 48 | outline: 5px auto -webkit-focus-ring-color; 49 | outline-offset: -2px; } 50 | .abc-checkbox input[type="checkbox"]:checked + label::after, 51 | .abc-checkbox input[type="radio"]:checked + label::after { 52 | font-family: "FontAwesome"; 53 | content: ""; } 54 | .abc-checkbox input[type="checkbox"]:indeterminate + label::after, 55 | .abc-checkbox input[type="radio"]:indeterminate + label::after { 56 | display: block; 57 | content: ""; 58 | width: 10px; 59 | height: 3px; 60 | background-color: #555555; 61 | border-radius: 2px; 62 | margin-left: -16.5px; 63 | margin-top: 7px; } 64 | .abc-checkbox input[type="checkbox"]:disabled + label, 65 | .abc-checkbox input[type="radio"]:disabled + label { 66 | opacity: 0.65; } 67 | .abc-checkbox input[type="checkbox"]:disabled + label::before, 68 | .abc-checkbox input[type="radio"]:disabled + label::before { 69 | background-color: #e9ecef; 70 | cursor: not-allowed; } 71 | .abc-checkbox input[type="checkbox"]:disabled + label::after, 72 | .abc-checkbox input[type="radio"]:disabled + label::after { 73 | cursor: not-allowed; } 74 | .abc-checkbox.abc-checkbox-circle label::before { 75 | border-radius: 50%; } 76 | .abc-checkbox.checkbox-inline { 77 | margin-top: 0; } 78 | 79 | .abc-checkbox-primary input[type="checkbox"]:checked + label::before, 80 | .abc-checkbox-primary input[type="radio"]:checked + label::before { 81 | background-color: #007bff; 82 | border-color: #007bff; } 83 | .abc-checkbox-primary input[type="checkbox"]:checked + label::after, 84 | .abc-checkbox-primary input[type="radio"]:checked + label::after { 85 | color: #fff; } 86 | 87 | .abc-checkbox-danger input[type="checkbox"]:checked + label::before, 88 | .abc-checkbox-danger input[type="radio"]:checked + label::before { 89 | background-color: #dc3545; 90 | border-color: #dc3545; } 91 | .abc-checkbox-danger input[type="checkbox"]:checked + label::after, 92 | .abc-checkbox-danger input[type="radio"]:checked + label::after { 93 | color: #fff; } 94 | 95 | .abc-checkbox-info input[type="checkbox"]:checked + label::before, 96 | .abc-checkbox-info input[type="radio"]:checked + label::before { 97 | background-color: #17a2b8; 98 | border-color: #17a2b8; } 99 | .abc-checkbox-info input[type="checkbox"]:checked + label::after, 100 | .abc-checkbox-info input[type="radio"]:checked + label::after { 101 | color: #fff; } 102 | 103 | .abc-checkbox-warning input[type="checkbox"]:checked + label::before, 104 | .abc-checkbox-warning input[type="radio"]:checked + label::before { 105 | background-color: #ffc107; 106 | border-color: #ffc107; } 107 | .abc-checkbox-warning input[type="checkbox"]:checked + label::after, 108 | .abc-checkbox-warning input[type="radio"]:checked + label::after { 109 | color: #fff; } 110 | 111 | .abc-checkbox-success input[type="checkbox"]:checked + label::before, 112 | .abc-checkbox-success input[type="radio"]:checked + label::before { 113 | background-color: #28a745; 114 | border-color: #28a745; } 115 | .abc-checkbox-success input[type="checkbox"]:checked + label::after, 116 | .abc-checkbox-success input[type="radio"]:checked + label::after { 117 | color: #fff; } 118 | 119 | .abc-checkbox-primary input[type="checkbox"]:indeterminate + label::before, 120 | .abc-checkbox-primary input[type="radio"]:indeterminate + label::before { 121 | background-color: #007bff; 122 | border-color: #007bff; } 123 | .abc-checkbox-primary input[type="checkbox"]:indeterminate + label::after, 124 | .abc-checkbox-primary input[type="radio"]:indeterminate + label::after { 125 | background-color: #fff; } 126 | 127 | .abc-checkbox-danger input[type="checkbox"]:indeterminate + label::before, 128 | .abc-checkbox-danger input[type="radio"]:indeterminate + label::before { 129 | background-color: #dc3545; 130 | border-color: #dc3545; } 131 | .abc-checkbox-danger input[type="checkbox"]:indeterminate + label::after, 132 | .abc-checkbox-danger input[type="radio"]:indeterminate + label::after { 133 | background-color: #fff; } 134 | 135 | .abc-checkbox-info input[type="checkbox"]:indeterminate + label::before, 136 | .abc-checkbox-info input[type="radio"]:indeterminate + label::before { 137 | background-color: #17a2b8; 138 | border-color: #17a2b8; } 139 | .abc-checkbox-info input[type="checkbox"]:indeterminate + label::after, 140 | .abc-checkbox-info input[type="radio"]:indeterminate + label::after { 141 | background-color: #fff; } 142 | 143 | .abc-checkbox-warning input[type="checkbox"]:indeterminate + label::before, 144 | .abc-checkbox-warning input[type="radio"]:indeterminate + label::before { 145 | background-color: #ffc107; 146 | border-color: #ffc107; } 147 | .abc-checkbox-warning input[type="checkbox"]:indeterminate + label::after, 148 | .abc-checkbox-warning input[type="radio"]:indeterminate + label::after { 149 | background-color: #fff; } 150 | 151 | .abc-checkbox-success input[type="checkbox"]:indeterminate + label::before, 152 | .abc-checkbox-success input[type="radio"]:indeterminate + label::before { 153 | background-color: #28a745; 154 | border-color: #28a745; } 155 | .abc-checkbox-success input[type="checkbox"]:indeterminate + label::after, 156 | .abc-checkbox-success input[type="radio"]:indeterminate + label::after { 157 | background-color: #fff; } 158 | 159 | .abc-radio { 160 | cursor: default; 161 | padding-left: 4px; } 162 | .abc-radio label { 163 | cursor: pointer; 164 | display: inline; 165 | vertical-align: top; 166 | position: relative; 167 | padding-left: 5px; } 168 | .abc-radio label::before { 169 | cursor: pointer; 170 | content: ""; 171 | display: inline-block; 172 | position: absolute; 173 | width: 17px; 174 | height: 17px; 175 | top: 2px; 176 | left: 0; 177 | margin-left: -20px; 178 | border: 1px solid rgba(0, 0, 0, 0.15); 179 | border-radius: 50%; 180 | background-color: #fff; 181 | transition: border 0.15s ease-in-out; } 182 | .abc-radio label::after { 183 | cursor: pointer; 184 | display: inline-block; 185 | position: absolute; 186 | content: " "; 187 | width: 11px; 188 | height: 11px; 189 | left: 3px; 190 | top: 5px; 191 | margin-left: -20px; 192 | border-radius: 50%; 193 | background-color: #495057; 194 | transform: scale(0, 0); 195 | transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); } 196 | .abc-radio input[type="radio"] { 197 | position: static; 198 | margin-left: 0; 199 | cursor: pointer; 200 | opacity: 0; 201 | z-index: 1; } 202 | .abc-radio input[type="radio"]:focus + label::before { 203 | outline: thin dotted; 204 | outline: 5px auto -webkit-focus-ring-color; 205 | outline-offset: -2px; } 206 | .abc-radio input[type="radio"]:checked + label::after { 207 | transform: scale(1, 1); } 208 | .abc-radio input[type="radio"]:disabled + label { 209 | opacity: 0.65; } 210 | .abc-radio input[type="radio"]:disabled + label::before { 211 | cursor: not-allowed; } 212 | .abc-radio input[type="radio"]:disabled + label::after { 213 | cursor: not-allowed; } 214 | .abc-radio.radio-inline { 215 | margin-top: 0; } 216 | 217 | .abc-radio-primary input[type="radio"] + label::after { 218 | background-color: #007bff; } 219 | .abc-radio-primary input[type="radio"]:checked + label::before { 220 | border-color: #007bff; } 221 | .abc-radio-primary input[type="radio"]:checked + label::after { 222 | background-color: #007bff; } 223 | 224 | .abc-radio-danger input[type="radio"] + label::after { 225 | background-color: #dc3545; } 226 | .abc-radio-danger input[type="radio"]:checked + label::before { 227 | border-color: #dc3545; } 228 | .abc-radio-danger input[type="radio"]:checked + label::after { 229 | background-color: #dc3545; } 230 | 231 | .abc-radio-info input[type="radio"] + label::after { 232 | background-color: #17a2b8; } 233 | .abc-radio-info input[type="radio"]:checked + label::before { 234 | border-color: #17a2b8; } 235 | .abc-radio-info input[type="radio"]:checked + label::after { 236 | background-color: #17a2b8; } 237 | 238 | .abc-radio-warning input[type="radio"] + label::after { 239 | background-color: #ffc107; } 240 | .abc-radio-warning input[type="radio"]:checked + label::before { 241 | border-color: #ffc107; } 242 | .abc-radio-warning input[type="radio"]:checked + label::after { 243 | background-color: #ffc107; } 244 | 245 | .abc-radio-success input[type="radio"] + label::after { 246 | background-color: #28a745; } 247 | .abc-radio-success input[type="radio"]:checked + label::before { 248 | border-color: #28a745; } 249 | .abc-radio-success input[type="radio"]:checked + label::after { 250 | background-color: #28a745; } 251 | 252 | label .was-validated .form-check-input:invalid .abc-checkbox:before, label 253 | .was-validated .form-check-input:invalid .abc-radio:before, label .form-check-input.is-invalid .abc-checkbox:before, label 254 | .form-check-input.is-invalid .abc-radio:before { 255 | border-color: #dc3545; } 256 | -------------------------------------------------------------------------------- /css/demo-stackslider.css: -------------------------------------------------------------------------------- 1 | html, body, .input-group-addon, .input-group-prepend, .form-control { 2 | font-size: 16px; 3 | } 4 | 5 | .btn { 6 | border: 0 none; 7 | font-weight: bold; 8 | } 9 | 10 | .btn-red { 11 | background-color: #ef476f; 12 | color: #fff; 13 | } 14 | 15 | .btn-red:hover { 16 | color: #ffd166; 17 | } 18 | 19 | .form-control { 20 | color: #073b4c; 21 | } 22 | 23 | .st-wrapper { 24 | overflow: visible; 25 | } 26 | 27 | .st-wrapper nav .st-arrow:before { 28 | content: '' !important; 29 | } 30 | 31 | .st-wrapper nav .st-arrow:after { 32 | content: ''; 33 | position: absolute; 34 | top: 50%; 35 | left: 50%; 36 | width: 0; 37 | height: 0; 38 | border-style: solid; 39 | } 40 | 41 | .st-wrapper nav .st-arrow.st-prev:after { 42 | transform: translate(-75%, -50%); 43 | border-width: 7px 7px 7px 0; 44 | border-color: transparent white transparent transparent; 45 | } 46 | 47 | .st-wrapper nav .st-arrow.st-prev:hover:after, 48 | .st-wrapper nav .st-arrow.st-prev:focus:after { 49 | border-color: transparent #ffd166 transparent transparent; 50 | } 51 | 52 | .st-wrapper nav .st-arrow.st-next:after { 53 | transform: translate(-25%, -50%); 54 | border-width: 7px 0 7px 7px; 55 | border-color: transparent transparent transparent white; 56 | } 57 | 58 | .st-wrapper nav .st-arrow.st-next:hover:after, 59 | .st-wrapper nav .st-arrow.st-next:focus:after { 60 | border-color: transparent transparent transparent #ffd166; 61 | } 62 | 63 | .st-wrapper nav .st-arrow.st-disabled, 64 | .st-wrapper nav .st-arrow.st-disabled:before { 65 | cursor: auto; 66 | } 67 | 68 | .st-wrapper nav .st-arrow.st-disabled:before { 69 | background-color: #fff; 70 | } 71 | 72 | .st-wrapper nav .st-arrow.st-prev.st-disabled:after { 73 | border-color: transparent #eee transparent transparent; 74 | } 75 | 76 | .st-wrapper nav .st-arrow.st-next.st-disabled:after { 77 | border-color: transparent transparent transparent #eee; 78 | } 79 | 80 | .surveyjs-wrapper { 81 | background-color: transparent; 82 | color: #fff; 83 | border-radius: 8px; 84 | border: 0 none; 85 | } 86 | 87 | .surveyjs-title { 88 | text-transform: uppercase; 89 | } 90 | 91 | .surveyjs-description { 92 | margin: 0; 93 | } 94 | 95 | .surveyjs-loading p { 96 | margin: 0; 97 | } 98 | 99 | .surveyjs-form { 100 | color: #073b4c; 101 | } 102 | 103 | .surveyjs-loading, 104 | .surveyjs-message { 105 | text-align: center; 106 | color: #fff; 107 | } 108 | 109 | .surveyjs-form .surveyjs-body [data-formjs-question], 110 | .surveyjs-form .surveyjs-body .surveyjs-question-wrapper { 111 | background-color: #fff; 112 | color: #073b4c; 113 | border-radius: 8px 8px 0 0; 114 | } 115 | 116 | .surveyjs-form .surveyjs-body .surveyjs-question-wrapper { 117 | padding: 60px 30px 20px; 118 | } 119 | 120 | .surveyjs-form .surveyjs-question-text { 121 | text-transform: inherit; 122 | background-color: inherit; 123 | color: inherit; 124 | border-radius: 0; 125 | } 126 | 127 | .surveyjs-form .surveyjs-question-text, 128 | .surveyjs-form .surveyjs-answers-wrapper, 129 | .surveyjs-form .surveyjs-question-wrapper { 130 | padding: 0; 131 | } 132 | 133 | .surveyjs-footer { 134 | border-top: 4px dashed #073b4c; 135 | padding: 30px; 136 | background-color: #fff; 137 | border-radius: 0 0 8px 8px; 138 | width: 100%; 139 | margin: -1px auto; 140 | max-width: 600px; 141 | } 142 | 143 | .surveyjs-wrapper .alert { 144 | margin-bottom: 0; 145 | margin-top: 15px; 146 | } 147 | 148 | .modal-body h3 { 149 | margin: 0; 150 | } 151 | 152 | .modal-body p { 153 | margin-bottom: 0; 154 | } 155 | -------------------------------------------------------------------------------- /css/demo.css: -------------------------------------------------------------------------------- 1 | 2 | /* SURVEY */ 3 | .surveyjs-wrapper { 4 | background-color: #fff; 5 | color: #073B4C; 6 | border-radius: 8px; 7 | border: 0 none; 8 | } 9 | 10 | .surveyjs-wrapper .card-header-inner { 11 | padding-bottom: 1rem; 12 | border-bottom: 4px dotted #06d6a0; 13 | } 14 | 15 | .surveyjs-title { 16 | text-transform: uppercase; 17 | } 18 | 19 | .surveyjs-description { 20 | margin: 0; 21 | } 22 | 23 | .surveyjs-loading p { 24 | margin: 0; 25 | } 26 | 27 | .surveyjs-form .surveyjs-question-wrapper { 28 | padding-bottom: 30px; 29 | } 30 | 31 | .surveyjs-form .surveyjs-question-text, 32 | .surveyjs-form .surveyjs-answers-wrapper { 33 | padding: 15px; 34 | } 35 | .surveyjs-form .surveyjs-question-text { 36 | background-color: #06d6a0; 37 | color: #fff; 38 | border-radius: 8px; 39 | } 40 | 41 | .surveyjs-form .input-group .form-control, 42 | .surveyjs-form .input-group .surveyjs-select:not([size]):not([multiple]) { 43 | height: auto; 44 | } 45 | 46 | .surveyjs-form .surveyjs-submit-btn.surveyjs-submit-sending .surveyjs-submit-text { 47 | display: none; 48 | } 49 | 50 | .surveyjs-form .surveyjs-submit-btn.surveyjs-submit-sending:before { 51 | content: 'Sending data...'; 52 | } 53 | 54 | .surveyjs-footer { 55 | border-top: 4px dotted #06d6a0; 56 | padding-top: 15px; 57 | } 58 | 59 | .surveyjs-wrapper .alert { 60 | margin-bottom: 0; 61 | margin-top: 15px; 62 | } 63 | 64 | .surveyjs-wrapper .surveyjs-nested-inner { 65 | padding-left: 20px; 66 | } 67 | 68 | .surveyjs-wrapper .input-group { 69 | margin-left: -0.75em; 70 | margin-top: 0.3125em; 71 | margin-bottom: 0.3125em; 72 | width: auto; 73 | } 74 | 75 | .surveyjs-wrapper .input-group .form-check-input { 76 | position: static; 77 | margin: 0; 78 | } 79 | 80 | .surveyjs-wrapper .input-group .surveyjs-label { 81 | padding-left: .3125rem; 82 | } 83 | 84 | .surveyjs-wrapper .surveyjs-errors-wrapper, 85 | .surveyjs-wrapper .surveyjs-footer { 86 | display: none; 87 | } 88 | 89 | .surveyjs-wrapper .has-error .surveyjs-errors-wrapper, 90 | .surveyjs-wrapper.surveyjs-init-success .surveyjs-footer { 91 | display: block; 92 | } 93 | 94 | .surveyjs-wrapper .surveyjs-errors-wrapper { 95 | padding: 0 15px; 96 | } 97 | 98 | /* SURVEY WITH CUSTOM INPUTS */ 99 | .surveyjs-wrapper.surveyjs-custom-inputs .form-check.abc-checkbox, 100 | .surveyjs-wrapper.surveyjs-custom-inputs .form-check.abc-radio { 101 | padding-left: 0; 102 | } 103 | 104 | .surveyjs-wrapper.surveyjs-custom-inputs .form-check .surveyjs-input[type="checkbox"], 105 | .surveyjs-wrapper.surveyjs-custom-inputs .form-check .surveyjs-input[type="radio"] { 106 | width: 17px; 107 | margin: 0; 108 | padding: 0; 109 | } 110 | 111 | /* INHERIT THESE PROPS VALUES IS USEFUL DUE TO BOOTSTRAP INCONSISTENCY USAGE OF CSS CLASS custom-select */ 112 | .surveyjs-wrapper.surveyjs-custom-inputs .surveyjs-field-container.custom-select { 113 | height: inherit; 114 | padding: inherit; 115 | background: inherit; 116 | border: inherit; 117 | } 118 | 119 | .surveyjs-wrapper.surveyjs-custom-inputs .surveyjs-label:before, 120 | .surveyjs-wrapper.surveyjs-custom-inputs .surveyjs-label:after { 121 | margin-left: -17px; 122 | } 123 | 124 | .surveyjs-wrapper.surveyjs-custom-inputs .surveyjs-nested-wrapper > .surveyjs-label.custom-control-label:before, 125 | .surveyjs-wrapper.surveyjs-custom-inputs .surveyjs-nested-wrapper > .surveyjs-label.custom-control-label:after { 126 | display: none; 127 | } 128 | 129 | .surveyjs-wrapper.surveyjs-custom-inputs .input-group .input-group-prepend { 130 | padding: 0; 131 | } 132 | 133 | .surveyjs-wrapper.surveyjs-custom-inputs .input-group .custom-control { 134 | padding-left: 2rem; 135 | } 136 | 137 | .surveyjs-wrapper.surveyjs-custom-inputs .input-group .custom-control-label:before, 138 | .surveyjs-wrapper.surveyjs-custom-inputs .input-group .custom-control-label:after { 139 | left: auto; 140 | right: 100%; 141 | margin-right: 5px; 142 | } 143 | 144 | .surveyjs-wrapper.surveyjs-custom-inputs .input-group .custom-control .surveyjs-label { 145 | position: relative; 146 | } 147 | 148 | .surveyjs-wrapper.surveyjs-custom-inputs .custom-control .surveyjs-label:before, 149 | .surveyjs-wrapper.surveyjs-custom-inputs .custom-control .surveyjs-label:after { 150 | margin-left: 0; 151 | } 152 | 153 | 154 | 155 | /* MODAL */ 156 | .modal-body h3 { 157 | margin: 0; 158 | } 159 | 160 | .modal-body p { 161 | margin-bottom: 0; 162 | } 163 | 164 | 165 | 166 | /* GENERIC */ 167 | .text-white { 168 | color: #fff; 169 | } 170 | 171 | .margin-lg { 172 | margin-top: 30px; 173 | margin-bottom: 30px; 174 | } 175 | 176 | 177 | 178 | /* FIELD ERROR */ 179 | .has-error .help-block, 180 | .has-error .control-label, 181 | .has-error .radio, 182 | .has-error .checkbox, 183 | .has-error .radio-inline, 184 | .has-error .checkbox-inline, 185 | .has-error .form-check, 186 | .has-error .form-check-inline, 187 | .has-error.radio label, 188 | .has-error.checkbox label, 189 | .has-error.radio-inline label, 190 | .has-error.checkbox-inline label, 191 | .has-error.form-check label, 192 | .has-error.form-check-inline label 193 | { 194 | color: #ef476f; 195 | } 196 | 197 | .has-error .custom-select, 198 | .has-error .custom-select:focus, 199 | .has-error .form-control, 200 | .has-error .form-control:focus { 201 | border-color: #ef476f; 202 | border-width: 2px; 203 | -webkit-box-shadow: none; 204 | box-shadow: none; 205 | } 206 | 207 | .has-error .input-group-addon, 208 | .has-error .input-group-prepend .input-group-text { 209 | color: #ef476f; 210 | border-width: 2px; 211 | border-color: #ef476f; 212 | border-right-color: #ef476f; 213 | background-color: #fcdde4; 214 | } 215 | 216 | 217 | 218 | /* TOGGABLE CONTENT */ 219 | .toggable-content-outer .fake-checkbox.btn-toggable-content, 220 | .toggable-content-outer .fake-checkbox.btn-toggable-content ~ .toggable-label span, 221 | .toggable-content-outer .toggable-content { 222 | display: none; 223 | } 224 | 225 | .toggable-content-outer .toggable-label { 226 | position: relative; 227 | } 228 | 229 | .toggable-content-outer .toggable-label span { 230 | cursor: pointer; 231 | font-size: 1rem; 232 | } 233 | 234 | .toggable-content-outer .toggable-label span:after { 235 | display: inline-block; 236 | margin-left: .255em; 237 | vertical-align: .255em; 238 | content: ""; 239 | border-right: .3em solid transparent; 240 | border-bottom: 0; 241 | border-left: .3em solid transparent; 242 | } 243 | 244 | .toggable-content-outer .toggable-label span:first-child:after { 245 | border-top: .3em solid; 246 | border-top-color: #ef476f; 247 | } 248 | 249 | .toggable-content-outer .toggable-label span:last-child:after { 250 | border-bottom: .3em solid; 251 | border-bottom-color: #ef476f; 252 | } 253 | 254 | .toggable-content-outer .fake-checkbox.btn-toggable-content:not(:checked) ~ .toggable-label span:first-child { 255 | display: block; 256 | } 257 | 258 | .toggable-content-outer .fake-checkbox.btn-toggable-content:checked ~ .toggable-label span:last-child, 259 | .toggable-content-outer .fake-checkbox.btn-toggable-content:checked ~ .toggable-content { 260 | display: block; 261 | } 262 | -------------------------------------------------------------------------------- /css/doc.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-size: 16px; 3 | font-family: 'Raleway', sans-serif; 4 | } 5 | 6 | body { 7 | background-color: #073b4c; 8 | color: #06d6a0; 9 | } 10 | 11 | ul, ol { 12 | padding-left: 1em; 13 | } 14 | 15 | .card-header p { 16 | margin: 0; 17 | } 18 | 19 | code{display: inline-block;padding: 8px;color: #ccc;background-color: rgba(0,0,0,0.1);border: 2px solid rgba(0,0,0,0.15);border-radius: 4px;} 20 | pre{display: block;padding: 9.5px;margin: 0 0 10px;font-size: 14px;line-height: 1.5;word-break: break-all;word-wrap: break-word;color: #ccc;background-color: rgba(0,0,0,0.1);border: 2px solid rgba(0,0,0,0.15);border-radius: 4px;} 21 | pre code{padding: 0;font-size: inherit;color: inherit;white-space: pre-wrap;background-color: rgba(0,0,0,0.1);border-radius: 0;} 22 | 23 | p code, 24 | li code { 25 | padding: 0 4px; 26 | } 27 | 28 | .btn { 29 | cursor: pointer; 30 | border: 0 none; 31 | border-radius: 8px; 32 | padding: 0.75em 3em; 33 | } 34 | 35 | .overflow-auto { 36 | -webkit-overflow-scrolling: touch; 37 | } 38 | 39 | .container-fluid { max-width: 1400px; } 40 | 41 | body > .container-fluid > div { position: relative; z-index: 0; } 42 | #menu { top: 0; right: 0; z-index: 10; } 43 | #menu a { text-decoration: none !important; } 44 | #menu a.github-logo { border-radius: 100px; border: 2px solid #073b4c; background-color: #073b4c; } 45 | #menu .dropdown, #menu .nav-desktop { top: 0; right: 0; } 46 | /* #menu .nav-desktop, */ 47 | #menu .dropdown-toggle { background-color: #073b4c; } 48 | #menu .dropdown-menu, 49 | #hero .dropdown-menu { 50 | left: auto !important; right: 0 !important; 51 | transform: none !important; top: 100% !important; 52 | } 53 | 54 | #hero { min-height: calc(100vh - 120px); z-index: 5; overflow: hidden; } 55 | 56 | a { transition: all 0.15s linear; } 57 | h1, h2, h3 { font-family: 'Expletus Sans', sans-serif; } 58 | h2, h3 { color: #ffd166; margin-top: 2em; } 59 | h1 { font-size: 6em; line-height: 1; display: inline-block; border-bottom: 2px solid rgba(0,0,0,0.15); padding: 0.1em 0.05em; } 60 | h2 { font-size: 3em; border-bottom: 2px solid rgba(0,0,0,0.15); padding: 0.25em 0.0625em; } 61 | h3 { font-size: 2em; } 62 | h1 .small { font-family: 'Raleway', sans-serif; font-size: 0.5em; color: inherit; } 63 | h3 .small { color: inherit; } 64 | .small-title { font-size: 1.25em; } 65 | .claim { font-size: 2rem; } 66 | .logo { 67 | font-family: 'Expletus Sans', sans-serif; 68 | font-size: 32px; 69 | position: absolute; 70 | top: 10px; 71 | left: 0; 72 | width: 40px; 73 | height: 40px; 74 | text-align: center; 75 | border-radius: 1000px; 76 | background-color:#fff; 77 | } 78 | .sticky-title { 79 | position: -webkit-sticky; position: sticky; margin-bottom: 0; 80 | top: 0; z-index: 10; background: #073B4C; border-bottom: 2px solid rgba(0,0,0,0.15); 81 | padding: 0.45em 0.05em 0.33em 52px; 82 | height: 60px; 83 | } 84 | .sticky-title + * { margin-top: 1rem !important; } 85 | .sticky-title + p, .sticky-title + ul { margin-top: 0.5rem !important; } 86 | .sticky-title ~ .panel .sticky-header { 87 | position: -webkit-sticky; position: sticky; top: 98px; z-index: 5; 88 | } 89 | .interline-normal { line-height: 1.2; } 90 | .interline-sm { line-height: 1; } 91 | hr { border-top: 1px solid rgba(0, 0, 0, 0.2); } 92 | .mt-0 { margin-top: 0; } 93 | .ml-4em { margin-left: 4em; } 94 | .title-min { line-height: 0.75; } 95 | .text-yellow { color: #ffd166; } 96 | .text-red { color: #ef476f; } 97 | .text-green { color: #06d6a0; } 98 | .border-red { border-color: #ef476f !important; } 99 | .border-green { border-color: #06d6a0 !important; } 100 | .badge-yellow { background-color: #ffd166; color: #073b4c; } 101 | .text-opacity { opacity: 0.5; } 102 | ul { padding-left: 1em; } 103 | a { color: #ef476f; } 104 | a:hover, a:focus { color: inherit; } 105 | pre { max-height: 355px; } 106 | u { text-decoration: none; border-bottom: 1px solid #06d6a0; } 107 | .panel { background-color: transparent; border-width: 2px; border-radius: 8px; /*color: #ccc;*/ } 108 | .card-header { border: 0 none; border-top-right-radius: 6px; border-top-left-radius: 6px; } 109 | .panel-transparent { color: #ccc; } 110 | .no-bg { background: none; } 111 | .padding-tb-md { padding-top: 1em; padding-bottom: 1em; } 112 | .row-list-separator { border-top: 2px solid rgba(204, 204, 204, 0.2); } 113 | .row-list-separator:first-child { border-top: 0 none; } 114 | .dropdown-menu { min-width: auto; } 115 | .dropdown-toggle.dropdown-red-outline { border: 1px solid #ef476f; color: #ef476f; } 116 | .dropdown-toggle.dropdown-red-outline:after { border-top-color: #ef476f; } 117 | .dropdown-toggle.dropdown-red-outline[aria-expanded="true"] { background-color: #ef476f !important; color: #fff; } 118 | .dropdown-toggle.dropdown-red-outline[aria-expanded="true"]:after { border-top-color: #fff; } 119 | .version-num { min-width: 32px; } 120 | .bg-white { 121 | background-color: #fff; 122 | } 123 | .no-bg { 124 | background-color: transparent !important; 125 | } 126 | 127 | .sticky-nav-2 { 128 | top: 60px; 129 | z-index: 100; 130 | background:#073b4c; 131 | height: 40px; 132 | } 133 | .sticky-nav-2 a { 134 | display: block; 135 | padding: 5px; 136 | white-space: nowrap; 137 | } 138 | 139 | /* PANELS */ 140 | .panel { 141 | border: 2px solid #fff; 142 | } 143 | .panel-collapsible .card-header, 144 | .panel-collapsible .panel-heading { 145 | cursor: pointer; 146 | position: relative; 147 | } 148 | .panel-collapsible .panel-heading:after { 149 | content: '\e114'; 150 | font-family:'Glyphicons Halflings'; 151 | position: absolute; 152 | top: 50%; 153 | right: 15px; 154 | -webkit-transform: translateY(-50%); 155 | transform: translateY(-50%); 156 | } 157 | .panel-collapsible .panel-heading.active:after { 158 | content: '\e113'; 159 | } 160 | .panel-collapsible .card-body, 161 | .panel-collapsible .panel-body { 162 | display: none; 163 | } 164 | 165 | .panel-collapsible .card-header > div { 166 | position: relative; 167 | } 168 | 169 | .panel-collapsible .card-header > div:after { 170 | content: ''; 171 | position: absolute; 172 | top: 50%; 173 | right: 0; 174 | transform: translateY(-50%); 175 | width: 0; 176 | height: 0; 177 | border-style: solid; 178 | border-width: 7px 7px 0 7px; 179 | border-color: black transparent transparent transparent; 180 | } 181 | 182 | .panel-collapsible .card-header.active > div:after { 183 | border-width: 0 7px 7px 7px; 184 | border-color: transparent transparent black transparent; 185 | } 186 | 187 | .toggable-content-outer .fake-checkbox.btn-toggable-content, 188 | .toggable-content-outer .fake-checkbox.btn-toggable-content ~ .toggable-label span, 189 | .toggable-content-outer .toggable-content { 190 | display: none; 191 | } 192 | 193 | .toggable-content-outer .toggable-label { 194 | position: relative; 195 | } 196 | 197 | .toggable-content-outer .toggable-label.btn { 198 | background-color: #fff; 199 | border: 2px solid #fff; 200 | } 201 | 202 | .toggable-content-outer .toggable-label.btn span:after { 203 | display: none !important; 204 | } 205 | 206 | .toggable-content-outer .toggable-label span { 207 | cursor: pointer; 208 | font-size: 1rem; 209 | } 210 | 211 | .toggable-content-outer .toggable-label span:after { 212 | display: inline-block; 213 | margin-left: .255em; 214 | vertical-align: .255em; 215 | content: ""; 216 | border-right: .3em solid transparent; 217 | border-bottom: 0; 218 | border-left: .3em solid transparent; 219 | } 220 | 221 | .toggable-content-outer .toggable-label span:first-child:after { 222 | border-top: .3em solid; 223 | border-top-color: #ef476f; 224 | } 225 | 226 | .toggable-content-outer .toggable-label span:last-child:after { 227 | border-bottom: .3em solid; 228 | border-bottom-color: #ef476f; 229 | } 230 | 231 | .toggable-content-outer .fake-checkbox.btn-toggable-content:checked ~ .toggable-label.btn { 232 | background-color: transparent; 233 | border: 2px solid #06d6a0; 234 | color: #fff; 235 | } 236 | 237 | .toggable-content-outer .fake-checkbox.btn-toggable-content:not(:checked) ~ .toggable-label span:first-child { 238 | display: block; 239 | } 240 | 241 | .toggable-content-outer .fake-checkbox.btn-toggable-content:checked ~ .toggable-label span:last-child, 242 | .toggable-content-outer .fake-checkbox.btn-toggable-content:checked ~ .toggable-content { 243 | display: block; 244 | } 245 | 246 | .toggable-content-outer .fake-checkbox.btn-toggable-content:not(:checked) ~ .panel .validation-list .additional-validation, 247 | .toggable-content-outer .fake-checkbox.btn-toggable-content:not(:checked) ~ .panel .errors-list .additional-error { 248 | display: none !important; 249 | } 250 | 251 | .demos-list > a { 252 | -ms-flex: 0 0 246px; 253 | flex: 0 0 246px; 254 | height: 100px; 255 | margin: 14px; 256 | padding: 14px; 257 | background-color: transparent; 258 | color: #fff; 259 | border: 1px solid #ef476f; 260 | text-decoration: none !important; 261 | transition: all 0.15s linear; 262 | } 263 | 264 | .demos-list > a:hover { 265 | background-color: #ef476f; 266 | color: #fff; 267 | } 268 | 269 | [class*="language-"] { 270 | border: 0 none; 271 | } 272 | 273 | :not(pre) > code[class*="language-"], pre[class*="language-"] { 274 | border: 2px solid rgba(0,0,0,0.15); 275 | } 276 | 277 | footer hr { 278 | border-top: 2px solid rgba(0,0,0,0.15); 279 | } 280 | 281 | @media (max-width: 767px){ 282 | h1 { font-size: 4em; } 283 | h2 { font-size: 2.25em; } 284 | h3 { font-size: 1.75em; } 285 | .logo { 286 | font-size: 26px; 287 | top: 10px; 288 | left: 0; 289 | width: 32px; 290 | height: 32px; 291 | } 292 | #menu .dropdown { top: 13px; } 293 | .dropdown-item { 294 | font-size: 20px; 295 | padding-top: 0.5rem; 296 | padding-bottom: 0.5rem; 297 | } 298 | .sticky-title { height: 55px; padding-left: 40px; } 299 | .sticky-nav-2 { top: 55px; } 300 | } 301 | 302 | @media (max-width: 580px){ 303 | .demos-list > a { 304 | -ms-flex: 0 0 100%; 305 | flex: 0 0 100%; 306 | margin-left: 0; 307 | margin-right: 0; 308 | } 309 | } 310 | 311 | @media (max-width: 413px){ 312 | h1 { font-size: 3em; } 313 | h2 { font-size: 1.75em; } 314 | h3 { font-size: 1.375em; } 315 | .logo { top: 4px; } 316 | #menu .dropdown { top: 7px; } 317 | .sticky-title { height: 43px; } 318 | .sticky-nav-2 { top: 43px; } 319 | } -------------------------------------------------------------------------------- /css/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.19.0 2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript&plugins=line-highlight+file-highlight */ 3 | /** 4 | * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML 5 | * Based on https://github.com/chriskempson/tomorrow-theme 6 | * @author Rose Pritchard 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: #ccc; 12 | background: none; 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | font-size: 1em; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | 31 | } 32 | 33 | /* Code blocks */ 34 | pre[class*="language-"] { 35 | padding: 1em; 36 | margin: .5em 0; 37 | overflow: auto; 38 | } 39 | 40 | :not(pre) > code[class*="language-"], 41 | pre[class*="language-"] { 42 | background: #2d2d2d; 43 | } 44 | 45 | /* Inline code */ 46 | :not(pre) > code[class*="language-"] { 47 | padding: .1em; 48 | border-radius: .3em; 49 | white-space: normal; 50 | } 51 | 52 | .token.comment, 53 | .token.block-comment, 54 | .token.prolog, 55 | .token.doctype, 56 | .token.cdata { 57 | color: #999; 58 | } 59 | 60 | .token.punctuation { 61 | color: #ccc; 62 | } 63 | 64 | .token.tag, 65 | .token.attr-name, 66 | .token.namespace, 67 | .token.deleted { 68 | color: #e2777a; 69 | } 70 | 71 | .token.function-name { 72 | color: #6196cc; 73 | } 74 | 75 | .token.boolean, 76 | .token.number, 77 | .token.function { 78 | color: #f08d49; 79 | } 80 | 81 | .token.property, 82 | .token.class-name, 83 | .token.constant, 84 | .token.symbol { 85 | color: #f8c555; 86 | } 87 | 88 | .token.selector, 89 | .token.important, 90 | .token.atrule, 91 | .token.keyword, 92 | .token.builtin { 93 | color: #cc99cd; 94 | } 95 | 96 | .token.string, 97 | .token.char, 98 | .token.attr-value, 99 | .token.regex, 100 | .token.variable { 101 | color: #7ec699; 102 | } 103 | 104 | .token.operator, 105 | .token.entity, 106 | .token.url { 107 | color: #67cdcc; 108 | } 109 | 110 | .token.important, 111 | .token.bold { 112 | font-weight: bold; 113 | } 114 | .token.italic { 115 | font-style: italic; 116 | } 117 | 118 | .token.entity { 119 | cursor: help; 120 | } 121 | 122 | .token.inserted { 123 | color: green; 124 | } 125 | 126 | pre[data-line] { 127 | position: relative; 128 | padding: 1em 0 1em 3em; 129 | } 130 | 131 | .line-highlight { 132 | position: absolute; 133 | left: 0; 134 | right: 0; 135 | padding: inherit 0; 136 | margin-top: 1em; /* Same as .prism’s padding-top */ 137 | 138 | background: hsla(24, 20%, 50%,.08); 139 | background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); 140 | 141 | pointer-events: none; 142 | 143 | line-height: inherit; 144 | white-space: pre; 145 | } 146 | 147 | .line-highlight:before, 148 | .line-highlight[data-end]:after { 149 | content: attr(data-start); 150 | position: absolute; 151 | top: .4em; 152 | left: .6em; 153 | min-width: 1em; 154 | padding: 0 .5em; 155 | background-color: hsla(24, 20%, 50%,.4); 156 | color: hsl(24, 20%, 95%); 157 | font: bold 65%/1.5 sans-serif; 158 | text-align: center; 159 | vertical-align: .3em; 160 | border-radius: 999px; 161 | text-shadow: none; 162 | box-shadow: 0 1px white; 163 | } 164 | 165 | .line-highlight[data-end]:after { 166 | content: attr(data-end); 167 | top: auto; 168 | bottom: .4em; 169 | } 170 | 171 | .line-numbers .line-highlight:before, 172 | .line-numbers .line-highlight:after { 173 | content: none; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /css/stackSlider.css: -------------------------------------------------------------------------------- 1 | .js .st-stack-raw { 2 | display: none; 3 | } 4 | 5 | .st-wrapper { 6 | width: 100%; 7 | height: auto; 8 | position: relative; 9 | margin: 0 auto; 10 | padding: 40px 0 0; 11 | overflow: hidden; 12 | } 13 | 14 | .st-stack { 15 | position: absolute; 16 | height: 10px; 17 | bottom: 0px; 18 | background-image: linear-gradient(to bottom, #fff 50%, #e7ae38 50%); 19 | background-size: 5px 5px; 20 | background-position: bottom center; 21 | } 22 | 23 | .st-stack:before { 24 | content: ''; 25 | position: absolute; 26 | width: 140%; 27 | left: -20%; 28 | bottom: -10px; 29 | height: 20px; 30 | z-index: -1; 31 | background: radial-gradient(center, ellipse cover, rgba(0,0,0,0.1) 0%,rgba(0,0,0,0) 60%); 32 | } 33 | 34 | .st-stack-left { 35 | left: 0px; 36 | } 37 | 38 | .st-stack-right { 39 | right: 0px; 40 | } 41 | 42 | .st-wrapper .st-title { 43 | color: #fff; 44 | position: absolute; 45 | top: 0; 46 | left: 50%; 47 | margin-left: -40px; 48 | padding: 0; 49 | width: 80px; 50 | height: 80px; 51 | line-height: 80px; 52 | border-radius: 1000px; 53 | text-align: center; 54 | background-color: #06d6a0; 55 | z-index: 2; 56 | } 57 | 58 | .st-wrapper nav { 59 | position: absolute; 60 | width: 100%; 61 | top: 20px; 62 | left: 0; 63 | text-align: center; 64 | -webkit-touch-callout: none; 65 | -webkit-user-select: none; 66 | -khtml-user-select: none; 67 | -moz-user-select: none; 68 | -ms-user-select: none; 69 | user-select: none; 70 | z-index: 3; 71 | } 72 | 73 | .st-wrapper .st-container { 74 | position: relative; 75 | transition: all 0.4s linear; 76 | z-index: 1; 77 | } 78 | 79 | .st-wrapper nav span { 80 | color: transparent; 81 | position: absolute; 82 | width: 40px; 83 | height: 40px; 84 | left: 50%; 85 | top: 0; 86 | cursor: pointer; 87 | } 88 | 89 | .st-wrapper nav span:first-child { 90 | margin-left: -90px; 91 | } 92 | 93 | .st-wrapper nav span:last-child { 94 | margin-left: 50px; 95 | } 96 | 97 | .st-wrapper nav span:before { 98 | font-family: 'Glyphicons Halflings'; 99 | font-size: 20px; 100 | font-style: normal; 101 | speak: none; 102 | font-weight: normal; 103 | line-height: 40px; 104 | text-align: center; 105 | -webkit-font-smoothing: antialiased; 106 | position: absolute; 107 | width: 100%; 108 | height: 100%; 109 | left: 0; 110 | color: #fff; 111 | background-color: #ef476f; 112 | border-radius: 50%; 113 | cursor: pointer; 114 | } 115 | 116 | .st-wrapper nav span:first-child:before { 117 | content: "\e079"; 118 | } 119 | 120 | .st-wrapper nav span:last-child:before { 121 | content: "\e080"; 122 | } 123 | 124 | .st-wrapper nav span:hover:before { 125 | color: #ffd166; 126 | } 127 | 128 | .st-wrapper .st-item { 129 | transform: rotate(-90deg) translateX(-50%) rotateX(90deg); 130 | transform-origin: 50% 0; 131 | transform-style : preserve-3d; 132 | backface-visibility: hidden; 133 | transition: all 0.4s linear; 134 | 135 | position: absolute; 136 | top: 0; 137 | left: 50%; 138 | width: 100%; 139 | margin: 0 auto; 140 | max-width: 600px; 141 | opacity: 0; 142 | z-index: -1; 143 | } 144 | 145 | .st-wrapper .st-item.st-center { 146 | opacity: 1; 147 | transform: rotate(0deg) translateX(-50%) rotateX(0deg); 148 | z-index: 10; 149 | } 150 | 151 | .st-wrapper .st-item.st-leftflow-in { 152 | transform: rotate(-90deg) translateX(-50%) rotateX(0deg); 153 | pointer-events: none; 154 | opacity: 0; 155 | } 156 | 157 | .st-wrapper .st-item.st-rightflow-in { 158 | transform: rotate(90deg) translateX(-50%) rotateX(0deg); 159 | pointer-events: none; 160 | opacity: 0; 161 | } 162 | 163 | .st-wrapper .st-item.st-left, 164 | .st-wrapper .st-item.st-leftflow { 165 | transform: rotate(90deg) translateX(-50%) rotateX(90deg); 166 | pointer-events: none; 167 | opacity: 0; 168 | } 169 | 170 | .st-wrapper .st-item.st-right, 171 | .st-wrapper .st-item.st-rightflow { 172 | transform: rotate(-90deg) translateX(-50%) rotateX(90deg); 173 | pointer-events: none; 174 | opacity: 0; 175 | } 176 | 177 | .st-wrapper .st-item.st-leftflow-in, 178 | .st-wrapper .st-item.st-rightflow-in { 179 | transition-duration: 0.001s !important; 180 | } 181 | 182 | .st-wrapper .st-item.st-center { 183 | opacity: 1; 184 | } 185 | 186 | .surveyjs-cards .st-wrapper .st-item { 187 | transform: translateX(10%) rotate(7deg) rotateY(90deg); 188 | transition: opacity 0.45s linear, transform 0.3s linear; 189 | } 190 | 191 | .surveyjs-cards .st-wrapper .st-item.st-center { 192 | transition-delay: 0.15s; 193 | opacity: 1; 194 | transform: translateX(-50%) rotate(0deg) rotateY(0deg); 195 | } 196 | 197 | .surveyjs-cards .st-wrapper .st-item.st-leftflow-in { 198 | transform: translateX(10%) rotate(7deg) rotateY(0deg); 199 | pointer-events: none; 200 | opacity: 0; 201 | } 202 | 203 | .surveyjs-cards .st-wrapper .st-item.st-rightflow-in { 204 | transform: translateX(-110%) rotate(-7deg) rotateY(0deg); 205 | pointer-events: none; 206 | opacity: 0; 207 | } 208 | 209 | .surveyjs-cards .st-wrapper .st-item.st-leftflow { 210 | transform: translateX(-110%) rotate(-7deg) rotateY(0deg); 211 | pointer-events: none; 212 | opacity: 0; 213 | } 214 | 215 | .surveyjs-cards .st-wrapper .st-item.st-left { 216 | transition-duration: 0.15s; 217 | transform: translateX(-110%) rotate(-7deg) rotateY(90deg); 218 | pointer-events: none; 219 | opacity: 0; 220 | } 221 | 222 | .surveyjs-cards .st-wrapper .st-item.st-rightflow { 223 | transform: translateX(10%) rotate(7deg) rotateY(0deg); 224 | pointer-events: none; 225 | opacity: 0; 226 | } 227 | 228 | .surveyjs-cards .st-wrapper .st-item.st-right { 229 | transition-duration: 0.15s; 230 | transform: translateX(10%) rotate(7deg) rotateY(90deg); 231 | pointer-events: none; 232 | opacity: 0; 233 | } 234 | 235 | .surveyjs-cards .st-wrapper .st-item.st-leftflow-in, 236 | .surveyjs-cards .st-wrapper .st-item.st-rightflow-in { 237 | transition-duration: 0.001s !important; 238 | } 239 | 240 | .surveyjs-cards .st-wrapper .st-item.st-center { 241 | opacity: 1; 242 | } -------------------------------------------------------------------------------- /demos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demos | surveyJS - JavaScript Survey Creation & Management. Made Easy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 59 | 60 |
61 |

surveyJS

62 |

Demos

63 | 86 |
87 | 88 | 94 | 95 |
96 | 97 | 98 | -------------------------------------------------------------------------------- /demos/demo-basic-lite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo Basic Lite | surveyJS - JavaScript Survey Creation & Management. Made Easy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 67 | 68 |
69 | 70 |
71 |

surveyJS

72 | / 73 |

Demos

74 |
75 | 76 |

Demo Basic Lite

77 | 78 |
79 |
80 |
81 |
82 |
83 |
84 |

HTML

85 |
86 |
87 |
88 |
 89 | <div class="surveyjs-wrapper card panel-primary mb-4 pt-2" data-surveyjs-wrapper>
 90 |     <div class="card-header no-bg">
 91 |         <div class="card-header-inner">
 92 |             <h3 class="surveyjs-title panel-title text-green mt-0">My Survey</h3>
 93 |             <p class="surveyjs-description">Answer the questions</p>
 94 |         </div>
 95 |     </div>
 96 |     <div class="card-body">
 97 |         <form action="../json/survey.json" name="surveyjs-form" class="surveyjs-form" data-surveyjs-form novalidate>
 98 |             <div class="surveyjs-body questionsList" data-surveyjs-body></div>
 99 |             <div class="surveyjs-footer">
100 |                 <button class="btn btn-primary d-block mx-auto" type="submit">SEND</button>
101 |             </div>
102 |         </form>
103 |     </div>
104 | </div>
105 | 
106 | 
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |

JS

115 |
116 |
117 |
118 |
119 | // FULL CODE: /js/demos/demo-basic-lite.js
120 | const $form = document.querySelector('[data-surveyjs-form]');
121 | const options = { url: '../json/survey.json' };
122 | 
123 | $form.addEventListener('submit', event => {
124 |     event.preventDefault();
125 |     console.log('FORM SUBMIT');
126 |     // FORM VALIDATION IS UP TO YOU :)
127 | });
128 | 
129 | const mySurvey = new Survey( $form, options );
130 | 
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |

My Survey

140 |

Answer the questions

141 |
142 |
143 |
144 |
145 |
146 | 149 |
150 |
151 |
152 |
153 |
154 | 155 |
156 | 157 | 163 |
164 | 165 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /demos/demo-basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo Basic | surveyJS - JavaScript Survey Creation & Management. Made Easy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 69 | 70 |
71 | 72 |
73 |

surveyJS

74 | / 75 |

Demos

76 |
77 | 78 |

Demo Basic

79 | 80 |
81 |
82 |
83 |
84 |
85 |
86 |

HTML

87 |
88 |
89 |
90 |
 91 | <div class="surveyjs-wrapper card panel-primary mb-4 pt-2" data-surveyjs-wrapper>
 92 |     <div class="card-header no-bg">
 93 |         <div class="card-header-inner">
 94 |             <h3 class="surveyjs-title panel-title text-green mt-0">My Survey</h3>
 95 |             <p class="surveyjs-description">Answer the questions</p>
 96 |         </div>
 97 |     </div>
 98 |     <div class="card-body">
 99 |         <form action="../json/survey.json" name="surveyjs-form" class="surveyjs-form" data-surveyjs-form novalidate>
100 |             <div class="surveyjs-body questionsList" data-surveyjs-body></div>
101 |             <div class="surveyjs-footer">
102 |                 <button class="btn btn-primary d-block mx-auto" type="submit">SEND</button>
103 |             </div>
104 |         </form>
105 |     </div>
106 | </div>
107 | 
108 | 
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |

JS

117 |
118 |
119 |
120 |
121 | // FULL CODE: /js/demos/demo-basic.js
122 | const $form = document.querySelector('[data-surveyjs-form]');
123 | const options = { url: '../json/survey.json' };
124 | 
125 | $form.addEventListener('fjs.form:submit', event => {
126 |     event.detail
127 |         .then(response => {...})
128 |         .catch(error => {...})
129 |         .finally(() => {...});
130 | });
131 | 
132 | const mySurvey = new Survey( $form, options );
133 | 
134 | 
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |

My Survey

144 |

Answer the questions

145 |
146 |
147 |
148 |
149 |
150 | 153 |
154 |
155 |
156 |
157 |
158 | 159 |
160 | 161 | 167 |
168 | 169 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /dist/lite/surveyjs-esm.min.js: -------------------------------------------------------------------------------- 1 | /* surveyJS Lite v4.0.2 | Valerio Di Punzio (@SimplySayHi) | https://www.valeriodipunzio.com/plugins/surveyJS/ | https://github.com/SimplySayHi/surveyJS | MIT license */ 2 | const e=e=>Element.prototype.isPrototypeOf(e),s="sjs:destroy",t="sjs:init",r=e=>(Object.getOwnPropertyNames(e).forEach((s=>{const t=e[s];"object"==typeof t&&null!==t&&r(t)})),Object.freeze(e)),a=e=>"[object Object]"===Object.prototype.toString.call(e),o=function(e={}){return Array.from(arguments).slice(1).filter((e=>!!e)).forEach((s=>{Object.keys(s).forEach((t=>{Array.isArray(s[t])?e[t]=(e[t]||[]).concat(s[t].slice(0)):a(s[t])?e[t]=o(e[t]||{},s[t]):Array.isArray(e[t])?e[t].push(s[t]):e[t]=s[t]}))})),e},i=(e,s,t)=>{t=o({},{bubbles:!0},t);const r=new CustomEvent(s,t);e.dispatchEvent(r)},l=(e,s)=>Object.keys(e).reduce(((s,t)=>{const r=new RegExp("{{"+t+"}}","g");return s.replace(r,e[t])}),s),n=e=>(e[0].sort&&e.sort(((e,s)=>e.sort>s.sort)),e),d=(e=[])=>n(e).reduce(((e,s)=>e+``),""),c=(e,s,t)=>{const r=["data","id","label","nested","related","sort"];/^(option|textarea)$/.test(e.type)&&r.push("type","value");let a="";return Object.keys(e).filter((e=>-1===r.indexOf(e))).forEach((s=>{a+=` ${s}="${e[s]}"`})),e.data&&Object.keys(e.data).forEach((s=>{a+=` data-${((e="",s=!1)=>{let t=e.trim().replace(/(([_ ])([a-z]))|(([a-z])?([A-Z]))/g,((e,s,t,r,a,o,i)=>(r?"-"+r:(o||"")+"-"+i).toLowerCase()));return s?t.toUpperCase():t})(s)}="${e.data[s]}"`})),t&&(a+=" required"),e.related&&(a+=" data-require-more"),a+=` id="${s}"`,a.trim()},u=(e,s,t)=>{let r="",a="";return n(e).forEach(((i,n)=>{let p="";const y="option"===i.type?"select":i.type;if("select"===y&&a===y)return;a=y,s.question.checks&&(i=o({},i,{data:{checks:s.question.checks}}));const m=`${y}-${s.surveyId}-${s.question.id}-${"select"===y?n+1:i.id}`,f={questionNumber:s.question.index+1,wrapperClasses:t.cssClasses.wrapper[y]||t.cssClasses.wrapper.field,fieldAttributes:c(i,m,s.question.isRequired),fieldClasses:t.cssClasses[y]||t.cssClasses.field,answerType:y,answerCode:m,addMoreName:"",labelString:i.label||"",labelClasses:t.cssClasses.label};let v="";if(i.related){const e=i.related.type||"select",s="select"===e,r=s?o({},i):i.related;r.type=s?"option":e,r.id="",r.data=o({},r.data,{requiredFrom:"#"+m}),delete r.related;const a={fieldAttributes:c(r,"",!1),answerType:e,addMoreName:"-more",fieldClasses:s?t.cssClasses.select:t.cssClasses[e]||t.cssClasses.field};if(v=t.templates[e]||t.templates.input,s){const e=d(i.related);v=v.replace("{{optionsHtml}}",e)}v=l(a,v)}const w=((e,s)=>({field:s[e]||s.input,label:/^(checkbox|nested|radio|related)$/.test(e)?s.label:"",wrapper:s.wrapper[e]||s.wrapper.field}))(i.related?"related":i.nested?"nested":y,t.templates);let h="";i.nested&&(h=u(i.nested,s,t));let b="";"select"===y&&(b=d(e)),p=w.wrapper.replace("{{relatedFieldHTML}}",v).replace("{{fieldTemplate}}",w.field).replace("{{optionsHtml}}",b).replace("{{labelTemplate}}",w.label).replace("{{nestedFieldsHTML}}",h),r+=l(f,p)})),r},p=(e,s,t)=>{const r=((e,s,t)=>n(e).reduce(((e,r,o)=>{if(r.external)return e;let i=t.templates.wrapper.question;const n=r.id,d=o+1,c={surveyId:s,question:{id:n,index:o,isRequired:!!r.required}};r.checks&&(c.question.checks=r.checks);const p=u(r.answers,c,t),y=r.checks?JSON.parse(r.checks):"",m=y[0]||"",f=y[1]||"",v=y&&t.messages.maxChoice?" ("+f+" "+t.messages.maxChoice+")":"",w={questionId:n,questionNumber:d,questionText:r.question+v,answersHTML:p};if(i=l(w,i),t.showErrorMessage){let e=""!==y?t.messages.errorMultiChoice:r.errorMessage||t.messages.error;a(e)&&(e=""),i=i.replace(/{{errorTemplates}}/g,e)}return e+l({checksMin:m,checksMax:f},i)}),""))(e.questions,e.id,t);s.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforeend",r);const o=e.questions.filter((e=>e.external));if(o.length>0){const t=s.closest("[data-surveyjs-wrapper]");o.forEach(((s,r)=>{const a=t.querySelector('[data-surveyjs-external="'+(r+1)+'"]');a.setAttribute("data-question-id",s.id),s.answers.forEach(((t,r)=>{const o=a.querySelectorAll("[data-field]")[r],i={id:`${t.type}-${e.id}-${s.id}-${t.id}`,type:t.type,value:t.value,required:!!s.required};Object.keys(i).forEach((e=>{o[e]=i[e]}));const l=o.closest("[data-answer]");l.querySelector("label").setAttribute("for",i.id),l.querySelector("[data-label]").innerHTML=t.label,a.querySelector("[data-question]").innerHTML=s.question}))}))}};class y{constructor(s,a={}){const l=arguments.length,n=(s=>{const t=typeof s,r="string"===t&&e(document.querySelector(s))&&"form"===document.querySelector(s).tagName.toLowerCase();return{result:e(s)||r,element:"string"===t?document.querySelector(s):s}})(s);if(0===l||l>0&&!s)throw new Error('First argument "$form" is missing or falsy!');if(d=s,NodeList.prototype.isPrototypeOf(d))throw new Error('First argument "$form" must be a single DOM node or a form CSS selector, not a NodeList!');var d;if(!n.result)throw new Error('First argument "$form" is not a DOM node nor a form CSS selector!');if(!a.url||"string"!=typeof a.url)throw new Error('"options.url" is missing or not a string!');const c=this;c.$form=n.element,c.options=o({},y.prototype.options,a),s=c.$form,a=c.options,s.surveyjs=c,s.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforebegin",a.templates.loading);const u=((e=location.href,s={})=>{let t;if(s.headers=new Headers(s.headers),s.timeout>0){const e=new AbortController,r=e.signal;s.signal=r,t=window.setTimeout((()=>{e.abort()}),s.timeout)}return fetch(e,s).then((e=>{if(!e.ok)throw new Error(e.statusText);return e.json()})).catch((e=>{throw new Error(e.message)})).finally((()=>{t&&window.clearTimeout(t)}))})(a.url,a.initAjaxOptions).then((e=>"success"!==e.status.toLowerCase()?Promise.reject(e):(e.data.questions&&e.data.questions.length>0&&(p(e.data,s,a),Object.defineProperty(c,"data",{value:r(e.data)}),c.isInitialized=!0,s.closest("[data-surveyjs-wrapper]").classList.add("surveyjs-init-success")),e))).finally((()=>{const e=s.querySelector("[data-surveyjs-loading]");e&&e.parentNode.removeChild(e)}));i(s,t,{detail:u})}destroy(){delete this.$form.surveyjs,i(this.$form,s)}static setOptions(e){y.prototype.options=o({},y.prototype.options,e)}}y.prototype.isInitialized=!1,y.prototype.options={cssClasses:{checkbox:"form-check-input",field:"form-control",file:"form-control-file",label:"form-check-label",radio:"form-check-input",wrapper:{checkbox:"form-check",field:"",radio:"form-check"}},initAjaxOptions:{cache:"no-store",credentials:"same-origin",headers:{"Content-Type":"application/json",Accept:"application/json"},method:"GET",mode:"same-origin",redirect:"follow",timeout:0},messages:{maxChoice:"answers max",error:"Answer is necessary.",errorMultiChoice:"You must choose from {{checksMin}} to {{checksMax}} answers."},showErrorMessage:!0,templates:{error:'
{{errorMessage}}
',input:'',label:'',loading:'
Loading...
',select:'',textarea:'',wrapper:{field:'
{{fieldTemplate}}{{labelTemplate}}
',nested:'
{{labelTemplate}}
{{nestedFieldsHTML}}
',question:'
{{questionText}}
{{answersHTML}}
{{errorTemplates}}
',related:''}}},y.prototype.version="4.0.2";export{y as default}; 3 | //# sourceMappingURL=surveyjs-esm.min.js.map 4 | -------------------------------------------------------------------------------- /dist/lite/surveyjs-systemjs.min.js: -------------------------------------------------------------------------------- 1 | /* surveyJS Lite v4.0.2 | Valerio Di Punzio (@SimplySayHi) | https://www.valeriodipunzio.com/plugins/surveyJS/ | https://github.com/SimplySayHi/surveyJS | MIT license */ 2 | System.register([],(function(e){"use strict";return{execute:function(){function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}function t(e,r){if(!(e instanceof r))throw new TypeError("Cannot call a class as a function")}function s(e,r){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:location.href,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t.headers=new Headers(t.headers),t.timeout>0){var s=new AbortController,a=s.signal;t.signal=a,e=window.setTimeout((function(){s.abort()}),t.timeout)}return fetch(r,t).then((function(e){if(!e.ok)throw new Error(e.statusText);return e.json()})).catch((function(e){throw new Error(e.message)})).finally((function(){e&&window.clearTimeout(e)}))},o=function(e){return Element.prototype.isPrototypeOf(e)},n=function(e){var t=r(e),s="string"===t&&o(document.querySelector(e))&&"form"===document.querySelector(e).tagName.toLowerCase();return{result:o(e)||s,element:"string"===t?document.querySelector(e):e}},i="sjs:destroy",l="sjs:init",c=function e(t){return Object.getOwnPropertyNames(t).forEach((function(s){var a=t[s];"object"===r(a)&&null!==a&&e(a)})),Object.freeze(t)},u=function(e){return"[object Object]"===Object.prototype.toString.call(e)},d=function e(){var r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Array.from(arguments).slice(1).filter((function(e){return!!e})).forEach((function(t){Object.keys(t).forEach((function(s){Array.isArray(t[s])?r[s]=(r[s]||[]).concat(t[s].slice(0)):u(t[s])?r[s]=e(r[s]||{},t[s]):Array.isArray(r[s])?r[s].push(t[s]):r[s]=t[s]}))})),r},p=function(e,r,t){t=d({},{bubbles:!0},t);var s=new CustomEvent(r,t);e.dispatchEvent(s)},f=function(e){return NodeList.prototype.isPrototypeOf(e)},v=function(e,r){return Object.keys(e).reduce((function(r,t){var s=new RegExp("{{"+t+"}}","g");return r.replace(s,e[t])}),r)},y=function(e){return e[0].sort&&e.sort((function(e,r){return e.sort>r.sort})),e},m=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return y(e).reduce((function(e,r){return e+'")}),"")},b=function(e,r,t){var s=["data","id","label","nested","related","sort"];/^(option|textarea)$/.test(e.type)&&s.push("type","value");var a="";return Object.keys(e).filter((function(e){return-1===s.indexOf(e)})).forEach((function(r){a+=" ".concat(r,'="').concat(e[r],'"')})),e.data&&Object.keys(e.data).forEach((function(r){a+=" data-".concat(function(){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").trim().replace(/(([_ ])([a-z]))|(([a-z])?([A-Z]))/g,(function(e,r,t,s,a,o,n){return(s?"-"+s:(o||"")+"-"+n).toLowerCase()}));return e?r.toUpperCase():r}(r),'="').concat(e.data[r],'"')})),t&&(a+=" required"),e.related&&(a+=" data-require-more"),(a+=' id="'.concat(r,'"')).trim()},h=function e(r,t,s){var a="",o="";return y(r).forEach((function(n,i){var l,c="option"===n.type?"select":n.type;if("select"!==c||o!==c){o=c,t.question.checks&&(n=d({},n,{data:{checks:t.question.checks}}));var u="".concat(c,"-").concat(t.surveyId,"-").concat(t.question.id,"-").concat("select"===c?i+1:n.id),p={questionNumber:t.question.index+1,wrapperClasses:s.cssClasses.wrapper[c]||s.cssClasses.wrapper.field,fieldAttributes:b(n,u,t.question.isRequired),fieldClasses:s.cssClasses[c]||s.cssClasses.field,answerType:c,answerCode:u,addMoreName:"",labelString:n.label||"",labelClasses:s.cssClasses.label},f="";if(n.related){var y=n.related.type||"select",h="select"===y,w=h?d({},n):n.related;w.type=h?"option":y,w.id="",w.data=d({},w.data,{requiredFrom:"#"+u}),delete w.related;var g={fieldAttributes:b(w,"",!1),answerType:y,addMoreName:"-more",fieldClasses:h?s.cssClasses.select:s.cssClasses[y]||s.cssClasses.field};if(f=s.templates[y]||s.templates.input,h){var j=m(n.related);f=f.replace("{{optionsHtml}}",j)}f=v(g,f)}var q=function(e,r){return{field:r[e]||r.input,label:/^(checkbox|nested|radio|related)$/.test(e)?r.label:"",wrapper:r.wrapper[e]||r.wrapper.field}}(n.related?"related":n.nested?"nested":c,s.templates),C="";n.nested&&(C=e(n.nested,t,s));var T="";"select"===c&&(T=m(r)),l=q.wrapper.replace("{{relatedFieldHTML}}",f).replace("{{fieldTemplate}}",q.field).replace("{{optionsHtml}}",T).replace("{{labelTemplate}}",q.label).replace("{{nestedFieldsHTML}}",C),a+=v(p,l)}})),a},w=function(e,r,t){return y(e).reduce((function(e,s,a){if(s.external)return e;var o=t.templates.wrapper.question,n=s.id,i=a+1,l={surveyId:r,question:{id:n,index:a,isRequired:!!s.required}};s.checks&&(l.question.checks=s.checks);var c=h(s.answers,l,t),d=s.checks?JSON.parse(s.checks):"",p=d[0]||"",f=d[1]||"",y=d&&t.messages.maxChoice?" ("+f+" "+t.messages.maxChoice+")":"",m={questionId:n,questionNumber:i,questionText:s.question+y,answersHTML:c};if(o=v(m,o),t.showErrorMessage){var b=""!==d?t.messages.errorMultiChoice:s.errorMessage||t.messages.error;u(b)&&(b=""),o=o.replace(/{{errorTemplates}}/g,b)}return e+v({checksMin:p,checksMax:f},o)}),"")},g=function(e,r,t){var s=w(e.questions,e.id,t);r.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforeend",s);var a=e.questions.filter((function(e){return e.external}));if(a.length>0){var o=r.closest("[data-surveyjs-wrapper]");a.forEach((function(r,t){var s=o.querySelector('[data-surveyjs-external="'+(t+1)+'"]');s.setAttribute("data-question-id",r.id),r.answers.forEach((function(t,a){var o=s.querySelectorAll("[data-field]")[a],n={id:"".concat(t.type,"-").concat(e.id,"-").concat(r.id,"-").concat(t.id),type:t.type,value:t.value,required:!!r.required};Object.keys(n).forEach((function(e){o[e]=n[e]}));var i=o.closest("[data-answer]");i.querySelector("label").setAttribute("for",n.id),i.querySelector("[data-label]").innerHTML=t.label,s.querySelector("[data-question]").innerHTML=r.question}))}))}},j=e("default",function(){function e(r){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};t(this,e);var o=arguments.length,i=n(r);if(0===o||o>0&&!r)throw new Error('First argument "$form" is missing or falsy!');if(f(r))throw new Error('First argument "$form" must be a single DOM node or a form CSS selector, not a NodeList!');if(!i.result)throw new Error('First argument "$form" is not a DOM node nor a form CSS selector!');if(!s.url||"string"!=typeof s.url)throw new Error('"options.url" is missing or not a string!');var u=this;u.$form=i.element,u.options=d({},e.prototype.options,s),r=u.$form,s=u.options,r.surveyjs=u,r.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforebegin",s.templates.loading);var v=a(s.url,s.initAjaxOptions).then((function(e){return"success"!==e.status.toLowerCase()?Promise.reject(e):(e.data.questions&&e.data.questions.length>0&&(g(e.data,r,s),Object.defineProperty(u,"data",{value:c(e.data)}),u.isInitialized=!0,r.closest("[data-surveyjs-wrapper]").classList.add("surveyjs-init-success")),e)})).finally((function(){var e=r.querySelector("[data-surveyjs-loading]");e&&e.parentNode.removeChild(e)}));p(r,l,{detail:v})}var r,o,u;return r=e,u=[{key:"setOptions",value:function(r){e.prototype.options=d({},e.prototype.options,r)}}],(o=[{key:"destroy",value:function(){delete this.$form.surveyjs,p(this.$form,i)}}])&&s(r.prototype,o),u&&s(r,u),Object.defineProperty(r,"prototype",{writable:!1}),e}());j.prototype.isInitialized=!1,j.prototype.options={cssClasses:{checkbox:"form-check-input",field:"form-control",file:"form-control-file",label:"form-check-label",radio:"form-check-input",wrapper:{checkbox:"form-check",field:"",radio:"form-check"}},initAjaxOptions:{cache:"no-store",credentials:"same-origin",headers:{"Content-Type":"application/json",Accept:"application/json"},method:"GET",mode:"same-origin",redirect:"follow",timeout:0},messages:{maxChoice:"answers max",error:"Answer is necessary.",errorMultiChoice:"You must choose from {{checksMin}} to {{checksMax}} answers."},showErrorMessage:!0,templates:{error:'
{{errorMessage}}
',input:'',label:'',loading:'
Loading...
',select:'',textarea:'',wrapper:{field:'
{{fieldTemplate}}{{labelTemplate}}
',nested:'
{{labelTemplate}}
{{nestedFieldsHTML}}
',question:'
{{questionText}}
{{answersHTML}}
{{errorTemplates}}
',related:''}}},j.prototype.version="4.0.2"}}})); 3 | //# sourceMappingURL=surveyjs-systemjs.min.js.map 4 | -------------------------------------------------------------------------------- /dist/lite/surveyjs.min.js: -------------------------------------------------------------------------------- 1 | /* surveyJS Lite v4.0.2 | Valerio Di Punzio (@SimplySayHi) | https://www.valeriodipunzio.com/plugins/surveyJS/ | https://github.com/SimplySayHi/surveyJS | MIT license */ 2 | !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).Survey=r()}(this,(function(){"use strict";function e(r){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(r)}function r(e,r){if(!(e instanceof r))throw new TypeError("Cannot call a class as a function")}function t(e,r){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:location.href,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t.headers=new Headers(t.headers),t.timeout>0){var s=new AbortController,a=s.signal;t.signal=a,e=window.setTimeout((function(){s.abort()}),t.timeout)}return fetch(r,t).then((function(e){if(!e.ok)throw new Error(e.statusText);return e.json()})).catch((function(e){throw new Error(e.message)})).finally((function(){e&&window.clearTimeout(e)}))},a=function(e){return Element.prototype.isPrototypeOf(e)},o=function(r){var t=e(r),s="string"===t&&a(document.querySelector(r))&&"form"===document.querySelector(r).tagName.toLowerCase();return{result:a(r)||s,element:"string"===t?document.querySelector(r):r}},n="sjs:destroy",i="sjs:init",l=function r(t){return Object.getOwnPropertyNames(t).forEach((function(s){var a=t[s];"object"===e(a)&&null!==a&&r(a)})),Object.freeze(t)},c=function(e){return"[object Object]"===Object.prototype.toString.call(e)},u=function e(){var r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Array.from(arguments).slice(1).filter((function(e){return!!e})).forEach((function(t){Object.keys(t).forEach((function(s){Array.isArray(t[s])?r[s]=(r[s]||[]).concat(t[s].slice(0)):c(t[s])?r[s]=e(r[s]||{},t[s]):Array.isArray(r[s])?r[s].push(t[s]):r[s]=t[s]}))})),r},d=function(e,r,t){t=u({},{bubbles:!0},t);var s=new CustomEvent(r,t);e.dispatchEvent(s)},p=function(e){return NodeList.prototype.isPrototypeOf(e)},f=function(e,r){return Object.keys(e).reduce((function(r,t){var s=new RegExp("{{"+t+"}}","g");return r.replace(s,e[t])}),r)},y=function(e){return e[0].sort&&e.sort((function(e,r){return e.sort>r.sort})),e},v=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return y(e).reduce((function(e,r){return e+'")}),"")},m=function(e,r,t){var s=["data","id","label","nested","related","sort"];/^(option|textarea)$/.test(e.type)&&s.push("type","value");var a="";return Object.keys(e).filter((function(e){return-1===s.indexOf(e)})).forEach((function(r){a+=" ".concat(r,'="').concat(e[r],'"')})),e.data&&Object.keys(e.data).forEach((function(r){a+=" data-".concat(function(){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").trim().replace(/(([_ ])([a-z]))|(([a-z])?([A-Z]))/g,(function(e,r,t,s,a,o,n){return(s?"-"+s:(o||"")+"-"+n).toLowerCase()}));return e?r.toUpperCase():r}(r),'="').concat(e.data[r],'"')})),t&&(a+=" required"),e.related&&(a+=" data-require-more"),(a+=' id="'.concat(r,'"')).trim()},b=function e(r,t,s){var a="",o="";return y(r).forEach((function(n,i){var l,c="option"===n.type?"select":n.type;if("select"!==c||o!==c){o=c,t.question.checks&&(n=u({},n,{data:{checks:t.question.checks}}));var d="".concat(c,"-").concat(t.surveyId,"-").concat(t.question.id,"-").concat("select"===c?i+1:n.id),p={questionNumber:t.question.index+1,wrapperClasses:s.cssClasses.wrapper[c]||s.cssClasses.wrapper.field,fieldAttributes:m(n,d,t.question.isRequired),fieldClasses:s.cssClasses[c]||s.cssClasses.field,answerType:c,answerCode:d,addMoreName:"",labelString:n.label||"",labelClasses:s.cssClasses.label},y="";if(n.related){var b=n.related.type||"select",h="select"===b,w=h?u({},n):n.related;w.type=h?"option":b,w.id="",w.data=u({},w.data,{requiredFrom:"#"+d}),delete w.related;var g={fieldAttributes:m(w,"",!1),answerType:b,addMoreName:"-more",fieldClasses:h?s.cssClasses.select:s.cssClasses[b]||s.cssClasses.field};if(y=s.templates[b]||s.templates.input,h){var j=v(n.related);y=y.replace("{{optionsHtml}}",j)}y=f(g,y)}var q=function(e,r){return{field:r[e]||r.input,label:/^(checkbox|nested|radio|related)$/.test(e)?r.label:"",wrapper:r.wrapper[e]||r.wrapper.field}}(n.related?"related":n.nested?"nested":c,s.templates),C="";n.nested&&(C=e(n.nested,t,s));var T="";"select"===c&&(T=v(r)),l=q.wrapper.replace("{{relatedFieldHTML}}",y).replace("{{fieldTemplate}}",q.field).replace("{{optionsHtml}}",T).replace("{{labelTemplate}}",q.label).replace("{{nestedFieldsHTML}}",C),a+=f(p,l)}})),a},h=function(e,r,t){return y(e).reduce((function(e,s,a){if(s.external)return e;var o=t.templates.wrapper.question,n=s.id,i=a+1,l={surveyId:r,question:{id:n,index:a,isRequired:!!s.required}};s.checks&&(l.question.checks=s.checks);var u=b(s.answers,l,t),d=s.checks?JSON.parse(s.checks):"",p=d[0]||"",y=d[1]||"",v=d&&t.messages.maxChoice?" ("+y+" "+t.messages.maxChoice+")":"",m={questionId:n,questionNumber:i,questionText:s.question+v,answersHTML:u};if(o=f(m,o),t.showErrorMessage){var h=""!==d?t.messages.errorMultiChoice:s.errorMessage||t.messages.error;c(h)&&(h=""),o=o.replace(/{{errorTemplates}}/g,h)}return e+f({checksMin:p,checksMax:y},o)}),"")},w=function(e,r,t){var s=h(e.questions,e.id,t);r.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforeend",s);var a=e.questions.filter((function(e){return e.external}));if(a.length>0){var o=r.closest("[data-surveyjs-wrapper]");a.forEach((function(r,t){var s=o.querySelector('[data-surveyjs-external="'+(t+1)+'"]');s.setAttribute("data-question-id",r.id),r.answers.forEach((function(t,a){var o=s.querySelectorAll("[data-field]")[a],n={id:"".concat(t.type,"-").concat(e.id,"-").concat(r.id,"-").concat(t.id),type:t.type,value:t.value,required:!!r.required};Object.keys(n).forEach((function(e){o[e]=n[e]}));var i=o.closest("[data-answer]");i.querySelector("label").setAttribute("for",n.id),i.querySelector("[data-label]").innerHTML=t.label,s.querySelector("[data-question]").innerHTML=r.question}))}))}},g=function(){function e(t){var a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r(this,e);var n=arguments.length,c=o(t);if(0===n||n>0&&!t)throw new Error('First argument "$form" is missing or falsy!');if(p(t))throw new Error('First argument "$form" must be a single DOM node or a form CSS selector, not a NodeList!');if(!c.result)throw new Error('First argument "$form" is not a DOM node nor a form CSS selector!');if(!a.url||"string"!=typeof a.url)throw new Error('"options.url" is missing or not a string!');var f=this;f.$form=c.element,f.options=u({},e.prototype.options,a),t=f.$form,a=f.options,t.surveyjs=f,t.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforebegin",a.templates.loading);var y=s(a.url,a.initAjaxOptions).then((function(e){return"success"!==e.status.toLowerCase()?Promise.reject(e):(e.data.questions&&e.data.questions.length>0&&(w(e.data,t,a),Object.defineProperty(f,"data",{value:l(e.data)}),f.isInitialized=!0,t.closest("[data-surveyjs-wrapper]").classList.add("surveyjs-init-success")),e)})).finally((function(){var e=t.querySelector("[data-surveyjs-loading]");e&&e.parentNode.removeChild(e)}));d(t,i,{detail:y})}var a,c,f;return a=e,f=[{key:"setOptions",value:function(r){e.prototype.options=u({},e.prototype.options,r)}}],(c=[{key:"destroy",value:function(){delete this.$form.surveyjs,d(this.$form,n)}}])&&t(a.prototype,c),f&&t(a,f),Object.defineProperty(a,"prototype",{writable:!1}),e}();return g.prototype.isInitialized=!1,g.prototype.options={cssClasses:{checkbox:"form-check-input",field:"form-control",file:"form-control-file",label:"form-check-label",radio:"form-check-input",wrapper:{checkbox:"form-check",field:"",radio:"form-check"}},initAjaxOptions:{cache:"no-store",credentials:"same-origin",headers:{"Content-Type":"application/json",Accept:"application/json"},method:"GET",mode:"same-origin",redirect:"follow",timeout:0},messages:{maxChoice:"answers max",error:"Answer is necessary.",errorMultiChoice:"You must choose from {{checksMin}} to {{checksMax}} answers."},showErrorMessage:!0,templates:{error:'
{{errorMessage}}
',input:'',label:'',loading:'
Loading...
',select:'',textarea:'',wrapper:{field:'
{{fieldTemplate}}{{labelTemplate}}
',nested:'
{{labelTemplate}}
{{nestedFieldsHTML}}
',question:'
{{questionText}}
{{answersHTML}}
{{errorTemplates}}
',related:''}}},g.prototype.version="4.0.2",g})); 3 | //# sourceMappingURL=surveyjs.min.js.map 4 | -------------------------------------------------------------------------------- /dist/surveyjs-esm.min.js: -------------------------------------------------------------------------------- 1 | /* surveyJS v4.0.2 | Valerio Di Punzio (@SimplySayHi) | https://www.valeriodipunzio.com/plugins/surveyJS/ | https://github.com/SimplySayHi/surveyJS | MIT license */ 2 | import e from"formjs-plugin";const s="sjs:destroy",t="sjs:init",r=e=>(Object.getOwnPropertyNames(e).forEach((s=>{const t=e[s];"object"==typeof t&&null!==t&&r(t)})),Object.freeze(e)),a=e=>"[object Object]"===Object.prototype.toString.call(e),o=function(e={}){return Array.from(arguments).slice(1).filter((e=>!!e)).forEach((s=>{Object.keys(s).forEach((t=>{Array.isArray(s[t])?e[t]=(e[t]||[]).concat(s[t].slice(0)):a(s[t])?e[t]=o(e[t]||{},s[t]):Array.isArray(e[t])?e[t].push(s[t]):e[t]=s[t]}))})),e},i=(e,s,t)=>{t=o({},{bubbles:!0},t);const r=new CustomEvent(s,t);e.dispatchEvent(r)},n=e=>{const s=e.closest("[data-question-id]");return s&&s.getAttribute("data-question-id")||""},l=e=>a(e)&&0===Object.getOwnPropertyNames(e).length,c=(e,s)=>Object.keys(e).reduce(((s,t)=>{const r=new RegExp("{{"+t+"}}","g");return s.replace(r,e[t])}),s),d=e=>(e[0].sort&&e.sort(((e,s)=>e.sort>s.sort)),e),u=()=>{const e=(()=>{const e="check_storage";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}})();return e&&(Storage.prototype.setObject=function(e,s){this.setItem(e,JSON.stringify(s))},Storage.prototype.getObject=function(e){const s=this.getItem(e);return s&&JSON.parse(s)}),{isAvailable:e}},p=(e,s)=>{const t=e.length;let r={};for(let a=0;a{const a=e.type,d=e.name;if(d===i&&a===c)return;e.matches("[data-required-from]")||(i=d,c=a);const u=n(e),m={question:u,answer:{value:s?e.value.trim():e.value||""}};if(!e.matches("[data-required-from]")&&""!==u&&!l(p(t.data.questions,u))){if("radio"===a){const s=(e.closest("form")?r:e.closest(t.options.fieldOptions.questionContainer)).querySelector('[name="'+d+'"]:checked');m.answer.value=s&&s.value||"",s&&s.matches("[data-require-more]")&&(m.answer.related=r.querySelector('[data-required-from="#'+s.id+'"]').value)}"checkbox"===a&&e.matches("[data-checks]")&&(m.answer.value=[],Array.from(r.querySelectorAll('[name="'+d+'"]:checked')).forEach((e=>{m.answer.value.push(e.value)}))),o.answers.push(m)}})),o}}}.formOptions.getFormData},initAjaxOptions:{cache:"no-store",credentials:"same-origin",headers:{"Content-Type":"application/json",Accept:"application/json"},method:"GET",mode:"same-origin",redirect:"follow",timeout:0},messages:{maxChoice:"answers max",error:"Answer is necessary.",errorMultiChoice:"You must choose from {{checksMin}} to {{checksMax}} answers."},showErrorMessage:!0,templates:{error:'
{{errorMessage}}
',input:'',label:'',loading:'
Loading...
',select:'',textarea:'',wrapper:{field:'
{{fieldTemplate}}{{labelTemplate}}
',nested:'
{{labelTemplate}}
{{nestedFieldsHTML}}
',question:'
{{questionText}}
{{answersHTML}}
{{errorTemplates}}
',related:''}},useWebStorage:!0},f={storageName:"Survey_"+location.href+"_{{surveyFormName}}_surveyId[{{surveyId}}]"};function y(e){const s=e.target.surveyjs;e.detail.then((()=>{s.options.useWebStorage&&sessionStorage.removeItem(s.internals.storageName)}))}const v=(e,s,t="")=>{const r=e.length;for(let a=0;a{const t=d.errorMessage[s]||"";return e+(t?o.templates.error.replace("{{errorMessage}}",t):"")}),"");i.innerHTML=s}var u,m,f;if(!e.detail.isCheckingForm&&o.useWebStorage&&!s.matches("[data-exclude-storage]")){const e=r.internals.storageName;let t=sessionStorage.getObject(e)||[];const a=s.name,o=s.value,i=s.matches("[data-required-from]"),n=s.matches("[data-checks]"),l=s.matches("[data-require-more]"),c=i?document.querySelector(s.getAttribute("data-required-from")):null,d=v(t,a+"-more");!l&&!i&&d>=0&&t.splice(d,1);const u=v(t,a,!!n&&o);if(u>=0)t.splice(u,1),(n&&s.checked||!n&&""!==o)&&t.push({name:a,value:o});else if(""!==o){if(i){const e=v(t,c.name);e>=0&&t.splice(e,1),t.push({name:c.name,value:c.value})}t.push({name:a,value:o})}sessionStorage.setObject(e,t)}!d.required||s.required||s.matches("[data-required-from]")||(s.required=!0,r.validateField(s))}const b=(e=[])=>d(e).reduce(((e,s)=>e+``),""),g=(e,s,t)=>{const r=["data","id","label","nested","related","sort"];/^(option|textarea)$/.test(e.type)&&r.push("type","value");let a="";return Object.keys(e).filter((e=>-1===r.indexOf(e))).forEach((s=>{a+=` ${s}="${e[s]}"`})),e.data&&Object.keys(e.data).forEach((s=>{a+=` data-${((e="",s=!1)=>{let t=e.trim().replace(/(([_ ])([a-z]))|(([a-z])?([A-Z]))/g,((e,s,t,r,a,o,i)=>(r?"-"+r:(o||"")+"-"+i).toLowerCase()));return s?t.toUpperCase():t})(s)}="${e.data[s]}"`})),t&&(a+=" required"),e.related&&(a+=" data-require-more"),a+=` id="${s}"`,a.trim()},j=(e,s,t)=>{let r="",a="";return d(e).forEach(((i,n)=>{let l="";const d="option"===i.type?"select":i.type;if("select"===d&&a===d)return;a=d,s.question.checks&&(i=o({},i,{data:{checks:s.question.checks}}));const u=`${d}-${s.surveyId}-${s.question.id}-${"select"===d?n+1:i.id}`,p={questionNumber:s.question.index+1,wrapperClasses:t.cssClasses.wrapper[d]||t.cssClasses.wrapper.field,fieldAttributes:g(i,u,s.question.isRequired),fieldClasses:t.cssClasses[d]||t.cssClasses.field,answerType:d,answerCode:u,addMoreName:"",labelString:i.label||"",labelClasses:t.cssClasses.label};let m="";if(i.related){const e=i.related.type||"select",s="select"===e,r=s?o({},i):i.related;r.type=s?"option":e,r.id="",r.data=o({},r.data,{requiredFrom:"#"+u}),delete r.related;const a={fieldAttributes:g(r,"",!1),answerType:e,addMoreName:"-more",fieldClasses:s?t.cssClasses.select:t.cssClasses[e]||t.cssClasses.field};if(m=t.templates[e]||t.templates.input,s){const e=b(i.related);m=m.replace("{{optionsHtml}}",e)}m=c(a,m)}const f=((e,s)=>({field:s[e]||s.input,label:/^(checkbox|nested|radio|related)$/.test(e)?s.label:"",wrapper:s.wrapper[e]||s.wrapper.field}))(i.related?"related":i.nested?"nested":d,t.templates);let y="";i.nested&&(y=j(i.nested,s,t));let v="";"select"===d&&(v=b(e)),l=f.wrapper.replace("{{relatedFieldHTML}}",m).replace("{{fieldTemplate}}",f.field).replace("{{optionsHtml}}",v).replace("{{labelTemplate}}",f.label).replace("{{nestedFieldsHTML}}",y),r+=c(p,l)})),r},w=(e,s,t)=>{const r=((e,s,t)=>d(e).reduce(((e,r,o)=>{if(r.external)return e;let i=t.templates.wrapper.question;const n=r.id,l=o+1,d={surveyId:s,question:{id:n,index:o,isRequired:!!r.required}};r.checks&&(d.question.checks=r.checks);const u=j(r.answers,d,t),p=r.checks?JSON.parse(r.checks):"",m=p[0]||"",f=p[1]||"",y=p&&t.messages.maxChoice?" ("+f+" "+t.messages.maxChoice+")":"",v={questionId:n,questionNumber:l,questionText:r.question+y,answersHTML:u};if(i=c(v,i),t.showErrorMessage){let e=""!==p?t.messages.errorMultiChoice:r.errorMessage||t.messages.error;a(e)&&(e=""),i=i.replace(/{{errorTemplates}}/g,e)}return e+c({checksMin:m,checksMax:f},i)}),""))(e.questions,e.id,t);s.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforeend",r);const o=e.questions.filter((e=>e.external));if(o.length>0){const t=s.closest("[data-surveyjs-wrapper]");o.forEach(((s,r)=>{const a=t.querySelector('[data-surveyjs-external="'+(r+1)+'"]');a.setAttribute("data-question-id",s.id),s.answers.forEach(((t,r)=>{const o=a.querySelectorAll("[data-field]")[r],i={id:`${t.type}-${e.id}-${s.id}-${t.id}`,type:t.type,value:t.value,required:!!s.required};Object.keys(i).forEach((e=>{o[e]=i[e]}));const n=o.closest("[data-answer]");n.querySelector("label").setAttribute("for",i.id),n.querySelector("[data-label]").innerHTML=t.label,a.querySelector("[data-question]").innerHTML=s.question}))}))}};class q extends e{constructor(e,s={}){if(!s.url||"string"!=typeof s.url)throw new Error('"options.url" is missing or not a string!');s=o({},q.prototype.options,s),u().isAvailable||(s.useWebStorage=!1),super(e,s);const a=this;a.internals=f;const n=a.$form;s=a.options;const l=a.internals;n.surveyjs=a,n.querySelector("[data-surveyjs-body]").insertAdjacentHTML("beforebegin",s.templates.loading);const c=((e=location.href,s={})=>{let t;if(s.headers=new Headers(s.headers),s.timeout>0){const e=new AbortController,r=e.signal;s.signal=r,t=window.setTimeout((()=>{e.abort()}),s.timeout)}return fetch(e,s).then((e=>{if(!e.ok)throw new Error(e.statusText);return e.json()})).catch((e=>{throw new Error(e.message)})).finally((()=>{t&&window.clearTimeout(t)}))})(s.url,s.initAjaxOptions).then((e=>"success"!==e.status.toLowerCase()?Promise.reject(e):e.data.questions&&e.data.questions.length>0?(l.storageName=l.storageName.replace(/{{surveyId}}/,e.data.id),l.storageName=l.storageName.replace(/{{surveyFormName}}/,n.getAttribute("name")||""),w(e.data,n,s),s.useWebStorage&&((e,s)=>{const t=sessionStorage.getObject(s.storageName);if(t){const s=e.closest("[data-surveyjs-wrapper]");t.forEach((e=>{const t=s.querySelector('[name="'+e.name+'"]'),r=t.matches('[type="radio"], [type="checkbox"]'),a=r?s.querySelector('[name="'+e.name+'"][value="'+e.value+'"]'):t;r?a.checked=!0:a.value=e.value}))}})(n,l),Object.defineProperty(a,"data",{value:r(e.data)}),n.addEventListener("fjs.field:validation",h),n.addEventListener("fjs.form:submit",y),s.formOptions.onInitCheckFilled?a._&&"function"==typeof a._.asyncInitEnd?a._.asyncInitEnd().then((()=>(a.isInitialized=!0,n.closest("[data-surveyjs-wrapper]").classList.add("surveyjs-init-success"),e))):super.validateFilledFields().then((()=>(a.isInitialized=!0,n.closest("[data-surveyjs-wrapper]").classList.add("surveyjs-init-success"),e))):(a.isInitialized=!0,n.closest("[data-surveyjs-wrapper]").classList.add("surveyjs-init-success"),e)):e)).finally((()=>{const e=n.querySelector("[data-surveyjs-loading]");e&&e.parentNode.removeChild(e)}));i(n,t,{detail:c})}destroy(){var e;super.destroy(),(e=this.$form).removeEventListener("fjs.field:validation",h),e.removeEventListener("fjs.form:submit",y),delete e.surveyjs,i(this.$form,s)}static setOptions(e){q.prototype.options=o({},q.prototype.options,e)}}q.prototype.isInitialized=!1,q.prototype.options=m,q.prototype.version="4.0.2";export{q as default}; 3 | //# sourceMappingURL=surveyjs-esm.min.js.map 4 | -------------------------------------------------------------------------------- /fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySayHi/surveyJS/d87ef89e7e698e39b0ecd9c2797595b46b5fce7c/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySayHi/surveyJS/d87ef89e7e698e39b0ecd9c2797595b46b5fce7c/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySayHi/surveyJS/d87ef89e7e698e39b0ecd9c2797595b46b5fce7c/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySayHi/surveyJS/d87ef89e7e698e39b0ecd9c2797595b46b5fce7c/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySayHi/surveyJS/d87ef89e7e698e39b0ecd9c2797595b46b5fce7c/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare module 'surveyjs'; 3 | -------------------------------------------------------------------------------- /js/demo.js: -------------------------------------------------------------------------------- 1 | 2 | var validationRules = { 3 | 4 | alphabetic: function( string ){ 5 | var regex = new RegExp(/^[a-z]+$/i), 6 | obj = { 7 | result: regex.test( string ) 8 | }; 9 | 10 | return obj; 11 | }, 12 | 13 | alphabeticExtended: function( string ){ 14 | var regex = new RegExp(/^[-'A-ZÀ-ÖØ-öø-ÿ]+$/i), 15 | obj = { 16 | result: regex.test( string ) 17 | }; 18 | 19 | return obj; 20 | }, 21 | 22 | alphanumeric: function( string ){ 23 | var regex = new RegExp(/^[\w]+$/i), // OR [a-z0-9_] 24 | obj = { 25 | result: regex.test( string ) 26 | }; 27 | 28 | return obj; 29 | } 30 | 31 | }; 32 | 33 | Form.addValidationRules( validationRules ); 34 | -------------------------------------------------------------------------------- /js/demos/demo-basic-extended.js: -------------------------------------------------------------------------------- 1 | 2 | var $surveyCont = $('[data-surveyjs-wrapper]'); 3 | var $form = document.querySelector('[data-surveyjs-form]'); 4 | var options = { 5 | url: '../json/survey.json', 6 | cssClasses: { 7 | select: 'custom-select' 8 | }, 9 | formOptions: { 10 | beforeSend: function beforeSend_surveyDemo_1( data ){ 11 | console.log('Survey beforeSend_surveyDemo_1', data); 12 | 13 | var surveyContEl = this.$form.closest('[data-surveyjs-wrapper]'); 14 | var surveyBtn = this.$form.querySelector('button[type="submit"]'); 15 | 16 | if( !data.stopExecution ){ 17 | surveyBtn.classList.add('surveyjs-submit-sending'); 18 | var elemToRemove = surveyContEl.querySelector('.alert'); 19 | if(elemToRemove){ 20 | elemToRemove.parentNode.removeChild(elemToRemove); 21 | } 22 | } 23 | 24 | return data; 25 | } 26 | } 27 | }; 28 | 29 | var onInitSuccess = function( response ){ 30 | if( response.status !== 'success' ){ 31 | onInitError.call(mySurvey, response); 32 | } 33 | }, 34 | onInitError = function( error ){ 35 | var $surveyForm = this.$form; 36 | $surveyForm.querySelector('.surveyjs-body').innerHTML = '
Loading Error. Please, reload the page.
'; 37 | }, 38 | onValidation = function( fields ){ 39 | console.log( 'onValidation', fields ); 40 | if( fields.length > 1 ){ 41 | var isFormSubmitting = $form.classList.contains('is-submitting'); 42 | var submitDisabled = $form.querySelector('[type="submit"]').disabled; 43 | 44 | if( (submitDisabled && !isFormSubmitting) || !isFormSubmitting ){ 45 | return; 46 | } 47 | 48 | var unanswered = fields.filter(function(obj){ 49 | return !obj.result 50 | }); 51 | if( unanswered.length > 0 ){ 52 | var contEl = unanswered[0].$field.closest('[data-formjs-question]'); 53 | scrollToElement(contEl); 54 | } 55 | 56 | } else { 57 | var fieldObj = fields[0]; 58 | if( fieldObj.$field.name === 'prova-00' ){ 59 | var btn = fieldObj.$field.closest('form').querySelector('[type="submit"]'), 60 | isValidValue = fieldObj.$field.value.trim().length > 0; 61 | 62 | btn.disabled = !isValidValue; 63 | } 64 | } 65 | } 66 | ; 67 | 68 | $form.addEventListener('fjs.field:validation', function(event){ 69 | console.log(event.type); 70 | onValidation([event.detail]); 71 | }); 72 | 73 | $form.addEventListener('fjs.form:validation', function(event){ 74 | console.log(event.type); 75 | onValidation(event.detail.fields); 76 | }); 77 | 78 | $form.addEventListener('fjs.form:submit', function(event){ 79 | console.log(event.type); 80 | event.detail 81 | .then(function(response){ 82 | console.log('then', response); 83 | if( response.status !== 'success' ){ 84 | return Promise.reject(response); 85 | } 86 | // REMOVE THE SURVEY FROM THE PAGE 87 | $surveyCont.remove(); 88 | // OPEN THE BOOTSTRAP MODAL TO SHOW A CONGRATULATION MESSAGE 89 | $('#modal-notification').modal('show'); 90 | }) 91 | .catch(function(error){ 92 | console.log('catch', error); 93 | // PRINT THE ERROR MESSAGE AFTER THE FORM 94 | var surveyContEl = $form.closest('[data-surveyjs-wrapper]'); 95 | surveyContEl.innerHTML = surveyContEl.innerHTML + ''; 96 | }) 97 | .finally(function(){ 98 | console.log('finally'); 99 | $form.querySelector('button[type="submit"]').classList.remove('surveyjs-submit-sending'); 100 | }); 101 | }); 102 | 103 | $form.addEventListener('sjs:init', function(event){ 104 | console.log(event.type); 105 | event.detail 106 | .then(function( data ){ 107 | console.log('Survey init then'); 108 | console.log(data); 109 | onInitSuccess.call(mySurvey, data); 110 | }) 111 | .catch(function( error ){ 112 | console.log('Survey init catch'); 113 | console.log(error); 114 | onInitError.call(mySurvey, error); 115 | }); 116 | }); 117 | 118 | var mySurvey = new Survey( $form, options ); 119 | -------------------------------------------------------------------------------- /js/demos/demo-basic-lite.js: -------------------------------------------------------------------------------- 1 | 2 | var $form = document.querySelector('[data-surveyjs-form]'); 3 | var options = { url: '../json/survey-simple.json' }; 4 | 5 | $form.addEventListener('submit', function( event ){ 6 | event.preventDefault(); 7 | console.log('FORM SUBMIT'); 8 | // FORM VALIDATION IS UP TO YOU :) 9 | }); 10 | 11 | var mySurvey = new Survey( $form, options ); 12 | -------------------------------------------------------------------------------- /js/demos/demo-basic.js: -------------------------------------------------------------------------------- 1 | 2 | var $form = document.querySelector('[data-surveyjs-form]'); 3 | var options = { url: '../json/survey-simple.json' }; 4 | 5 | $form.addEventListener('fjs.form:submit', function(event){ 6 | console.log(event.type); 7 | event.detail 8 | .then(function(response){ 9 | console.log('then', response); 10 | if( response.status !== 'success' ){ 11 | return Promise.reject(response); 12 | } 13 | $('#modal-notification').modal('show'); 14 | }) 15 | .catch(function(error){ 16 | console.log('catch', error); 17 | var surveyContEl = $form.closest('[data-surveyjs-wrapper]'); 18 | surveyContEl.innerHTML = surveyContEl.innerHTML + ''; 19 | }) 20 | .finally(function(){ 21 | console.log('finally'); 22 | }); 23 | }); 24 | 25 | var mySurvey = new Survey( $form, options ); 26 | -------------------------------------------------------------------------------- /js/demos/demo-stackslider-1.js: -------------------------------------------------------------------------------- 1 | var $surveyCont = $('[data-surveyjs-wrapper]'), 2 | $surveyForm = $surveyCont.find('[data-surveyjs-form]'), 3 | $surveyBtn = $surveyForm.find('.surveyjs-submit-btn'); 4 | 5 | var $form = document.querySelector('[data-surveyjs-form]'); 6 | var options = { 7 | url: '../json/survey.json', 8 | cssClasses: { 9 | checkbox: 'custom-control-input', 10 | radio: 'custom-control-input', 11 | label: 'custom-control-label', 12 | select: 'custom-select', 13 | wrapper: { 14 | checkbox: 'custom-control form-check', 15 | radio: 'custom-control form-check' 16 | } 17 | }, 18 | templates: { 19 | wrapper: { 20 | field: '
'+ 21 | '{{fieldTemplate}}'+ 22 | '{{labelTemplate}}'+ 23 | '
', 24 | 25 | question: '
'+ 26 | '
'+ 27 | '
{{questionText}}
'+ 28 | '
'+ 29 | '{{answersHTML}}'+ 30 | '
'+ 31 | '
'+ 32 | '
', 33 | 34 | related: '' 43 | } 44 | }, 45 | formOptions: { 46 | beforeSend: function beforeSend_doc( data ){ 47 | console.log('Survey formOptions.beforeSend call...', data); 48 | 49 | if( !data.stopExecution ){ 50 | $surveyBtn.addClass('surveyjs-submit-sending'); 51 | $surveyCont.find('.alert').remove(); 52 | } 53 | 54 | return data; 55 | } 56 | } 57 | }; 58 | 59 | var onInitSuccess = function( ajaxData ){ 60 | console.log('onInitSuccess', ajaxData); 61 | 62 | var surveyFormEl = this.$form, 63 | surveyBody = surveyFormEl.querySelector('.surveyjs-body'), 64 | initStatus = ajaxData.status; 65 | 66 | if( initStatus === 'success' ){ 67 | $('.stackSlider').stackslider({ piles : false }); 68 | } else { 69 | var elemToRemove = surveyFormEl.querySelector('.surveyjs-footer'); 70 | elemToRemove.parentNode.removeChild(elemToRemove); 71 | surveyBody.innerHTML = '
Loading Error. Please, reload the page.
'; 72 | } 73 | }, 74 | onInitError = function( error ){ 75 | var surveyFormEl = this.$form; 76 | 77 | console.log('onInitError', error); 78 | console.log('SURVEY init(\''+ surveyFormEl.getAttribute('action') +'\') RETURNED AN ERROR:'); 79 | 80 | surveyFormEl.querySelector('.surveyjs-body').innerHTML = '
Loading Error. Please, reload the page.
'; 81 | }, 82 | onValidation = function( fields ){ 83 | console.log( 'onValidation', fields ); 84 | if( fields.length > 1 ){ 85 | if( !$form.querySelector('[type="submit"]').disabled ){ 86 | return; 87 | } 88 | // GO TO THE FIRST UNANSWERED QUESTION 89 | var $stWrapper = $('.surveyjs-form .st-wrapper'), 90 | activeIndex = $stWrapper.find('.st-center').index(), 91 | $invalidField = (function(){ 92 | for( var f=0; f invalidIndex ? 'prev' : 'next' ), 105 | $btn = ( clickDirection === 'prev' ? $stWrapper.find('nav > span:first-child') : $stWrapper.find('nav > span:last-child') ), 106 | clicksLength = ( clickDirection === 'prev' ? activeIndex - invalidIndex : invalidIndex - activeIndex ); 107 | 108 | for(var i=0; i

Generic error, please retry.

' ); 151 | } 152 | } 153 | }) 154 | .catch(function(error){ 155 | console.log('catch', error); 156 | // PRINT THE ERROR MESSAGE AFTER THE FORM 157 | var surveyContEl = $form.closest('[data-surveyjs-wrapper]'); 158 | surveyContEl.innerHTML = surveyContEl.innerHTML + ''; 159 | }) 160 | .finally(function(){ 161 | console.log('finally'); 162 | $form.querySelector('button[type="submit"]').classList.remove('surveyjs-submit-sending'); 163 | }); 164 | }); 165 | 166 | $form.addEventListener('sjs:init', function(event){ 167 | console.log(event.type); 168 | event.detail 169 | .then(function( data ){ 170 | console.log('Survey init then'); 171 | console.log(data); 172 | onInitSuccess.call(mySurvey, data); 173 | }) 174 | .catch(function( error ){ 175 | console.log('Survey init catch'); 176 | console.log(error); 177 | onInitError.call(mySurvey, error); 178 | }); 179 | }); 180 | 181 | var mySurvey = new Survey( $form, options ); 182 | -------------------------------------------------------------------------------- /js/demos/demo-stackslider-2.js: -------------------------------------------------------------------------------- 1 | var $surveyCont = $('[data-surveyjs-wrapper]'), 2 | $surveyForm = $surveyCont.find('[data-surveyjs-form]'), 3 | $surveyBtn = $surveyForm.find('.surveyjs-submit-btn'); 4 | 5 | var $form = document.querySelector('[data-surveyjs-form]'); 6 | var options = { 7 | url: '../json/survey.json', 8 | cssClasses: { 9 | select: 'custom-select' 10 | }, 11 | templates: { 12 | wrapper: { 13 | field: '
'+ 14 | '{{fieldTemplate}}'+ 15 | '{{labelTemplate}}'+ 16 | '
', 17 | 18 | question: '
'+ 19 | '
'+ 20 | '
{{questionText}}
'+ 21 | '
'+ 22 | '{{answersHTML}}'+ 23 | '
'+ 24 | '
'+ 25 | '
', 26 | 27 | related: '' 36 | } 37 | }, 38 | formOptions: { 39 | beforeSend: function beforeSend_doc( data ){ 40 | console.log('Survey formOptions.beforeSend call...', data); 41 | 42 | if( !data.stopExecution ){ 43 | $surveyBtn.addClass('surveyjs-submit-sending'); 44 | $surveyCont.find('.alert').remove(); 45 | } 46 | 47 | return data; 48 | } 49 | } 50 | }; 51 | 52 | var onInitSuccess = function( ajaxData ){ 53 | console.log('onInitSuccess', ajaxData); 54 | 55 | var $surveyForm = this.$form, 56 | surveyBody = $surveyForm.querySelector('.surveyjs-body'), 57 | initStatus = ajaxData.status; 58 | 59 | if( initStatus === 'success' ){ 60 | $('.stackSlider').stackslider({ piles : false }); 61 | } else { 62 | var elemToRemove = $surveyForm.querySelector('.surveyjs-footer'); 63 | elemToRemove.parentNode.removeChild(elemToRemove); 64 | surveyBody.innerHTML = '
Loading Error. Please, reload the page.
'; 65 | } 66 | }, 67 | onInitError = function( error ){ 68 | var $surveyForm = this.$form; 69 | 70 | console.log('onInitError', error); 71 | console.log('SURVEY init(\''+ $surveyForm.getAttribute('action') +'\') RETURNED AN ERROR:'); 72 | 73 | $surveyForm.querySelector('.surveyjs-body').innerHTML = '
Loading Error. Please, reload the page.
'; 74 | }, 75 | onValidation = function( fields ){ 76 | if( fields.length > 1 ){ 77 | if( !$form.querySelector('[type="submit"]').disabled ){ 78 | return; 79 | } 80 | // GO TO THE FIRST UNANSWERED QUESTION 81 | var $stWrapper = $('.surveyjs-form .st-wrapper'), 82 | activeIndex = $stWrapper.find('.st-center').index(), 83 | $invalidField = (function(){ 84 | for( var f=0; f invalidIndex ? 'prev' : 'next' ), 97 | $btn = ( clickDirection === 'prev' ? $stWrapper.find('nav > span:first-child') : $stWrapper.find('nav > span:last-child') ), 98 | clicksLength = ( clickDirection === 'prev' ? activeIndex - invalidIndex : invalidIndex - activeIndex ); 99 | 100 | for(var i=0; i

Generic error, please retry.

' ); 143 | } 144 | } 145 | }) 146 | .catch(function(error){ 147 | console.log('catch', error); 148 | // PRINT THE ERROR MESSAGE AFTER THE FORM 149 | var surveyContEl = $form.closest('[data-surveyjs-wrapper]'); 150 | surveyContEl.innerHTML = surveyContEl.innerHTML + ''; 151 | }) 152 | .finally(function(){ 153 | console.log('finally'); 154 | $form.querySelector('button[type="submit"]').classList.remove('surveyjs-submit-sending'); 155 | }); 156 | }); 157 | 158 | $form.addEventListener('sjs:init', function(event){ 159 | console.log(event.type); 160 | event.detail 161 | .then(function( data ){ 162 | console.log('Survey init then'); 163 | console.log(data); 164 | onInitSuccess.call(mySurvey, data); 165 | }) 166 | .catch(function( error ){ 167 | console.log('Survey init catch'); 168 | console.log(error); 169 | onInitError.call(mySurvey, error); 170 | }); 171 | }); 172 | 173 | var mySurvey = new Survey( $form, options ); 174 | -------------------------------------------------------------------------------- /js/demos/doc.js: -------------------------------------------------------------------------------- 1 | 2 | var $surveyCont = $('[data-surveyjs-wrapper]'), 3 | $surveyForm = $surveyCont.find('[data-surveyjs-form]'), 4 | $surveyBtn = $surveyForm.find('.surveyjs-submit-btn'); 5 | 6 | var $form = document.querySelector('[data-surveyjs-form]'); 7 | var options = { 8 | url: 'json/survey.json', 9 | cssClasses: { 10 | select: 'custom-select' 11 | }, 12 | templates: { 13 | wrapper: { 14 | field: '
'+ 15 | '{{fieldTemplate}}'+ 16 | '{{labelTemplate}}'+ 17 | '
', 18 | 19 | question: '
'+ 20 | '
'+ 21 | '
{{questionText}}
'+ 22 | '
'+ 23 | '{{answersHTML}}'+ 24 | '
'+ 25 | '
'+ 26 | '
', 27 | 28 | related: '' 37 | } 38 | }, 39 | formOptions: { 40 | beforeSend: function beforeSend_doc( data ){ 41 | console.log('Survey formOptions.beforeSend call...', data); 42 | 43 | if( !data.stopExecution ){ 44 | $surveyBtn.addClass('surveyjs-submit-sending'); 45 | $surveyCont.find('.alert').remove(); 46 | } 47 | 48 | return data; 49 | } 50 | } 51 | }; 52 | 53 | var onInitSuccess = function( ajaxData ){ 54 | if( ajaxData.status === 'success' ){ 55 | console.log('init slider'); 56 | $('.stackSlider').stackslider({ piles : false }); 57 | } else { 58 | onInitError.call(this); 59 | } 60 | }, 61 | onInitError = function( error ){ 62 | var survey$form = this.$form; 63 | survey$form.querySelector('.surveyjs-body').innerHTML = '
Loading Error. Please, reload the page.
'; 64 | }, 65 | onValidation = function( fields ){ 66 | console.log( 'onValidation', fields ); 67 | if( fields.length > 1 ){ 68 | if( !$form.querySelector('[type="submit"]').disabled ){ 69 | return; 70 | } 71 | // GO TO THE FIRST UNANSWERED QUESTION 72 | var $stWrapper = $('.surveyjs-form .st-wrapper'), 73 | activeIndex = $stWrapper.find('.st-center').index(), 74 | $invalidField = (function(){ 75 | for( var f=0; f invalidIndex ? 'prev' : 'next' ), 88 | $btn = ( clickDirection === 'prev' ? $stWrapper.find('nav > span:first-child') : $stWrapper.find('nav > span:last-child') ), 89 | clicksLength = ( clickDirection === 'prev' ? activeIndex - invalidIndex : invalidIndex - activeIndex ); 90 | 91 | for(var i=0; i

Generic error, please retry.

' ); 134 | } 135 | } 136 | }) 137 | .catch(function(error){ 138 | console.log('catch', error); 139 | // PRINT THE ERROR MESSAGE AFTER THE FORM 140 | $surveyForm.closest('.surveyjs-wrapper').append( '' ); 141 | }) 142 | .finally(function(){ 143 | console.log('finally'); 144 | $surveyBtn.removeClass('surveyjs-submit-sending'); 145 | }); 146 | }); 147 | 148 | $form.addEventListener('sjs:init', function(event){ 149 | console.log(event.type); 150 | event.detail 151 | .then(function( data ){ 152 | console.log('Survey init then'); 153 | console.log(data); 154 | onInitSuccess.call(mySurvey, data); 155 | }) 156 | .catch(function( error ){ 157 | console.log('Survey init catch'); 158 | console.log(error); 159 | onInitError.call(mySurvey, error); 160 | }); 161 | }); 162 | 163 | var mySurvey = new Survey( $form, options ); 164 | -------------------------------------------------------------------------------- /js/include.js: -------------------------------------------------------------------------------- 1 | 2 | function isPlainObject( object ){ 3 | return Object.prototype.toString.call( object ) === '[object Object]'; 4 | } 5 | 6 | function scrollToElement( element ){ 7 | setTimeout(function(){ 8 | element.scrollIntoView({ behavior: 'smooth' }); 9 | }, 50); 10 | } 11 | 12 | var isLocalEnv = location.protocol.indexOf('http') === -1 || location.host.indexOf('127.0.0.1') > -1; 13 | 14 | document.addEventListener('click', function(e){ 15 | var key = e.which || e.keyCode; 16 | 17 | if( key === 1 ){ 18 | var elem = e.target, 19 | cardHeaderSelector = '.panel-collapsible .card-header', 20 | dropDownSelector = '[data-toggle="dropdown"]', 21 | checkElement = function( cssSelector ){ 22 | return (elem.matches(cssSelector) ? elem : (elem.closest(cssSelector) || null)); 23 | }; 24 | 25 | // CLOSE ALL OPEN DROPDOWNS 26 | /* if( 27 | !checkElement(dropDownSelector) || 28 | elem.matches(dropDownSelector+'[aria-expanded="false"]') || 29 | elem.matches(dropDownSelector+':not([aria-expanded])') 30 | ){ 31 | var dropdownsOpen = document.querySelectorAll(dropDownSelector); 32 | if( dropdownsOpen.length > 0 ){ 33 | Array.from(dropdownsOpen).forEach(function(dropdownEl){ 34 | dropdownEl.setAttribute('aria-expanded', false); 35 | dropdownEl.nextElementSibling.classList.remove('show'); 36 | }); 37 | } 38 | } */ 39 | 40 | if( checkElement(cardHeaderSelector) ){ 41 | 42 | // OPEN PANEL 43 | e.preventDefault(); 44 | 45 | var cardHeader = checkElement(cardHeaderSelector), 46 | panelEl = elem.closest('.panel').querySelector('.card-body'), 47 | panelDisplay = panelEl.style.display; 48 | 49 | cardHeader.classList.toggle('active'); 50 | panelEl.style.display = (panelDisplay === '' || panelDisplay === 'none' ? 'block' : 'none'); 51 | 52 | } else if( checkElement(dropDownSelector) ){ 53 | 54 | // OPEN DROPDOWN 55 | /* e.preventDefault(); 56 | 57 | var dropDown = checkElement(dropDownSelector), 58 | dropDownList = dropDown.nextElementSibling, 59 | dropDownAriaExpanded = dropDown.getAttribute('aria-expanded'), 60 | ariaExpValue = ( !dropDownAriaExpanded || dropDownAriaExpanded === 'false' ? 'true' : 'false' ); 61 | 62 | dropDown.setAttribute('aria-expanded', ariaExpValue); 63 | dropDownList.classList.toggle('show'); */ 64 | 65 | } 66 | } 67 | }, false); 68 | 69 | document.addEventListener('DOMContentLoaded', function(){ 70 | if( window.Survey ){ 71 | var version = Survey.prototype.version; 72 | Array.from( document.querySelectorAll('[data-print-current-version]') ).forEach(function( elem ){ 73 | elem.innerHTML = version; 74 | }); 75 | } 76 | }); 77 | 78 | if( document.querySelector('[data-panel="html"] .card-header') ){ 79 | document.querySelector('[data-panel="html"] .card-header').click(); 80 | } 81 | 82 | if( document.querySelector('[data-panel="js"] .card-header') ){ 83 | document.querySelector('[data-panel="js"] .card-header').click(); 84 | } 85 | -------------------------------------------------------------------------------- /js/vendors/modernizr_custom_63321.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.6.2 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-csstransforms3d-csstransitions-shiv-cssclasses-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function z(a){j.cssText=a}function A(a,b){return z(m.join(a+";")+(b||""))}function B(a,b){return typeof a===b}function C(a,b){return!!~(""+a).indexOf(b)}function D(a,b){for(var d in a){var e=a[d];if(!C(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function E(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:B(f,"function")?f.bind(d||b):f}return!1}function F(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+o.join(d+" ")+d).split(" ");return B(b,"string")||B(b,"undefined")?D(e,b):(e=(a+" "+p.join(d+" ")+d).split(" "),E(e,b,c))}var d="2.6.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n="Webkit Moz O ms",o=n.split(" "),p=n.toLowerCase().split(" "),q={},r={},s={},t=[],u=t.slice,v,w=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["­",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},x={}.hasOwnProperty,y;!B(x,"undefined")&&!B(x.call,"undefined")?y=function(a,b){return x.call(a,b)}:y=function(a,b){return b in a&&B(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=u.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(u.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(u.call(arguments)))};return e}),q.csstransforms3d=function(){var a=!!F("perspective");return a&&"webkitPerspective"in g.style&&w("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},q.csstransitions=function(){return F("transition")};for(var G in q)y(q,G)&&(v=G.toLowerCase(),e[v]=q[G](),t.push((e[v]?"":"no-")+v));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)y(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},z(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.testProp=function(a){return D([a])},e.testAllProps=F,e.testStyles=w,e.prefixed=function(a,b,c){return b?F(a,b,c):F(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+t.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f 0 && !$form) ){ 14 | throw new Error('First argument "$form" is missing or falsy!'); 15 | } 16 | if( isNodeList($form) ){ 17 | throw new Error('First argument "$form" must be a single DOM node or a form CSS selector, not a NodeList!'); 18 | } 19 | if( !checkFormElem.result ){ 20 | throw new Error('First argument "$form" is not a DOM node nor a form CSS selector!'); 21 | } 22 | if( !optionsObj.url || typeof optionsObj.url !== 'string' ){ 23 | throw new Error('"options.url" is missing or not a string!'); 24 | } 25 | 26 | const self = this; 27 | self.$form = checkFormElem.element; 28 | self.options = mergeObjects( {}, Survey.prototype.options, optionsObj ); 29 | $form = self.$form; 30 | optionsObj = self.options; 31 | 32 | $form.surveyjs = self; 33 | $form.querySelector('[data-surveyjs-body]').insertAdjacentHTML( 'beforebegin', optionsObj.templates.loading ); 34 | 35 | // CREATE SURVEY 36 | const retrieveSurvey = ajaxCall(optionsObj.url, optionsObj.initAjaxOptions) 37 | .then(response => { 38 | if( response.status.toLowerCase() !== 'success' ){ 39 | return Promise.reject(response); 40 | } 41 | if( response.data.questions && response.data.questions.length > 0 ){ 42 | buildSurvey(response.data, $form, optionsObj); 43 | Object.defineProperty(self, 'data', { 44 | value: deepFreeze(response.data) 45 | }); 46 | self.isInitialized = true; 47 | $form.closest('[data-surveyjs-wrapper]').classList.add('surveyjs-init-success'); 48 | } 49 | return response; 50 | }) 51 | .finally(() => { 52 | const $loadingBox = $form.querySelector('[data-surveyjs-loading]'); 53 | if( $loadingBox ){ 54 | $loadingBox.parentNode.removeChild($loadingBox); 55 | } 56 | }); 57 | 58 | dispatchCustomEvent( $form, customEvents.init, { detail: retrieveSurvey } ); 59 | } 60 | 61 | destroy(){ 62 | delete this.$form.surveyjs; 63 | dispatchCustomEvent( this.$form, customEvents.destroy ); 64 | } 65 | 66 | static setOptions( optionsObj ){ 67 | Survey.prototype.options = mergeObjects({}, Survey.prototype.options, optionsObj); 68 | } 69 | 70 | } 71 | 72 | Survey.prototype.isInitialized = false; 73 | Survey.prototype.options = options; 74 | Survey.prototype.version = version; 75 | 76 | export default Survey; 77 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { version } from '../package.json'; 3 | import { ajaxCall, customEvents, deepFreeze, dispatchCustomEvent, mergeObjects, webStorage } from './modules/helpers'; 4 | import { options } from './modules/options'; 5 | import { internals } from './modules/internals'; 6 | import { submit, validationEnd } from './modules/listenerCallbacks'; 7 | import { buildSurvey } from './modules/buildSurvey/buildSurvey'; 8 | import { populateAnswers } from './modules/buildSurvey/populateAnswers'; 9 | import { destroy } from './modules/destroy'; 10 | 11 | import Form from 'formjs-plugin'; 12 | 13 | class Survey extends Form { 14 | 15 | constructor( form, optionsObj = {} ){ 16 | if( !optionsObj.url || typeof optionsObj.url !== 'string' ){ 17 | throw new Error('"options.url" is missing or not a string!'); 18 | } 19 | 20 | optionsObj = mergeObjects( {}, Survey.prototype.options, optionsObj ); 21 | 22 | if( !webStorage().isAvailable ){ 23 | optionsObj.useWebStorage = false; 24 | } 25 | 26 | // CREATE FORM INSTANCE FOR SURVEY 27 | super( form, optionsObj ); 28 | const self = this; 29 | self.internals = internals; 30 | const $form = self.$form; 31 | optionsObj = self.options; 32 | const selfInternals = self.internals; 33 | 34 | $form.surveyjs = self; 35 | $form.querySelector('[data-surveyjs-body]').insertAdjacentHTML( 'beforebegin', optionsObj.templates.loading ); 36 | 37 | // CREATE SURVEY 38 | const retrieveSurvey = ajaxCall(optionsObj.url, optionsObj.initAjaxOptions) 39 | .then(response => { 40 | if( response.status.toLowerCase() !== 'success' ){ 41 | return Promise.reject(response); 42 | } 43 | 44 | if( response.data.questions && response.data.questions.length > 0 ){ 45 | // REPLACE SURVEY ID AND FORM NAME IN WEB STORAGE NAME 46 | selfInternals.storageName = selfInternals.storageName.replace( /{{surveyId}}/, response.data.id ); 47 | selfInternals.storageName = selfInternals.storageName.replace( /{{surveyFormName}}/, ($form.getAttribute('name') || '') ); 48 | 49 | buildSurvey(response.data, $form, optionsObj); 50 | 51 | if( optionsObj.useWebStorage ){ 52 | populateAnswers($form, selfInternals); 53 | } 54 | 55 | Object.defineProperty(self, 'data', { 56 | value: deepFreeze(response.data) 57 | }); 58 | 59 | $form.addEventListener('fjs.field:validation', validationEnd); 60 | $form.addEventListener('fjs.form:submit', submit); 61 | 62 | if( optionsObj.formOptions.onInitCheckFilled ){ 63 | if( self._ && typeof self._.asyncInitEnd === 'function' ){ 64 | return self._.asyncInitEnd() 65 | .then(() => { 66 | self.isInitialized = true; 67 | $form.closest('[data-surveyjs-wrapper]').classList.add('surveyjs-init-success'); 68 | return response 69 | }); 70 | } 71 | 72 | return super.validateFilledFields().then(() => { 73 | self.isInitialized = true; 74 | $form.closest('[data-surveyjs-wrapper]').classList.add('surveyjs-init-success'); 75 | return response 76 | }); 77 | } 78 | 79 | self.isInitialized = true; 80 | $form.closest('[data-surveyjs-wrapper]').classList.add('surveyjs-init-success'); 81 | return response 82 | } 83 | 84 | return response; 85 | }) 86 | .finally(() => { 87 | const $loadingBox = $form.querySelector('[data-surveyjs-loading]'); 88 | if( $loadingBox ){ 89 | $loadingBox.parentNode.removeChild($loadingBox); 90 | } 91 | }); 92 | 93 | dispatchCustomEvent( $form, customEvents.init, { detail: retrieveSurvey } ); 94 | } 95 | 96 | destroy(){ 97 | super.destroy(); 98 | destroy(this.$form); 99 | dispatchCustomEvent( this.$form, customEvents.destroy ); 100 | } 101 | 102 | static setOptions( optionsObj ){ 103 | Survey.prototype.options = mergeObjects({}, Survey.prototype.options, optionsObj); 104 | } 105 | 106 | } 107 | 108 | Survey.prototype.isInitialized = false; 109 | Survey.prototype.options = options; 110 | Survey.prototype.version = version; 111 | 112 | export default Survey; 113 | -------------------------------------------------------------------------------- /src/modules-lite/options.js: -------------------------------------------------------------------------------- 1 | 2 | export const options = { 3 | cssClasses: { 4 | checkbox: 'form-check-input', 5 | field: 'form-control', 6 | file: 'form-control-file', 7 | label: 'form-check-label', 8 | radio: 'form-check-input', 9 | wrapper: { 10 | checkbox: 'form-check', 11 | field: '', 12 | radio: 'form-check' 13 | } 14 | }, 15 | initAjaxOptions: { 16 | cache: 'no-store', 17 | credentials: 'same-origin', 18 | headers: { 19 | 'Content-Type': 'application/json', 20 | 'Accept': 'application/json' 21 | }, 22 | method: 'GET', 23 | mode: 'same-origin', 24 | redirect: 'follow', 25 | timeout: 0 26 | }, 27 | messages:{ 28 | maxChoice: 'answers max', 29 | error: 'Answer is necessary.', 30 | errorMultiChoice: 'You must choose from {{checksMin}} to {{checksMax}} answers.' 31 | }, 32 | showErrorMessage: true, 33 | templates: { 34 | error: '
{{errorMessage}}
', 35 | 36 | input: '', 37 | 38 | label: '', 39 | 40 | loading: '
Loading...
', 41 | 42 | select: '', 45 | 46 | textarea: '', 47 | 48 | wrapper: { 49 | field: '
'+ 50 | '{{fieldTemplate}}'+ 51 | '{{labelTemplate}}'+ 52 | '
', 53 | 54 | nested: '
'+ 55 | '{{labelTemplate}}'+ 56 | '
'+ 57 | '{{nestedFieldsHTML}}'+ 58 | '
'+ 59 | '
', 60 | 61 | question: '
'+ 62 | '
{{questionText}}
'+ 63 | '
'+ 64 | '{{answersHTML}}'+ 65 | '
'+ 66 | '
{{errorTemplates}}
'+ 67 | '
', 68 | 69 | related: '' 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/modules/buildSurvey/buildSurvey.js: -------------------------------------------------------------------------------- 1 | 2 | import { generateQAcode } from './generateQAcode'; 3 | 4 | export const buildSurvey = ( data, $form, options ) => { 5 | 6 | const qaHtmlAll = generateQAcode( data.questions, data.id, options ); 7 | $form.querySelector('[data-surveyjs-body]').insertAdjacentHTML( 'beforeend', qaHtmlAll ); 8 | 9 | // MANAGE EXTERNAL QUESTION 10 | const extQuestions = data.questions.filter(obj => obj.external); 11 | if( extQuestions.length > 0 ){ 12 | const $surveyWrapper = $form.closest('[data-surveyjs-wrapper]'); 13 | extQuestions.forEach((question, qIndex) => { 14 | 15 | const $externalCont = $surveyWrapper.querySelector('[data-surveyjs-external="'+ (qIndex+1) +'"]'); 16 | 17 | $externalCont.setAttribute('data-question-id', question.id); 18 | 19 | question.answers.forEach((answer, aIndex) => { 20 | const $externalField = $externalCont.querySelectorAll('[data-field]')[aIndex]; 21 | const fieldProps = { 22 | id: `${answer.type}-${data.id}-${question.id}-${answer.id}`, 23 | type: answer.type, 24 | value: answer.value, 25 | required: !!question.required 26 | }; 27 | 28 | Object.keys(fieldProps).forEach(name => { 29 | $externalField[name] = fieldProps[name]; 30 | }); 31 | 32 | const $answerCont = $externalField.closest('[data-answer]'); 33 | $answerCont.querySelector('label').setAttribute('for', fieldProps.id); 34 | $answerCont.querySelector('[data-label]').innerHTML = answer.label; 35 | $externalCont.querySelector('[data-question]').innerHTML = question.question; 36 | }); 37 | 38 | }); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/modules/buildSurvey/generateQAcode.js: -------------------------------------------------------------------------------- 1 | 2 | import { isPlainObject, replaceObjectKeysInString, sortList } from '../helpers'; 3 | import { generateAnswers } from './generateQAcodeUtils/generateAnswers'; 4 | 5 | export const generateQAcode = ( questions, surveyId, options ) => { 6 | 7 | return sortList( questions ).reduce((accCode, questionObj, index) => { 8 | if( questionObj.external ){ return accCode; } 9 | 10 | let questionHTML = options.templates.wrapper.question; 11 | const questionId = questionObj.id; 12 | const questionNumber = index + 1; 13 | const extraData = { 14 | surveyId, 15 | question: { 16 | id: questionId, 17 | index, 18 | isRequired: !!questionObj.required 19 | } 20 | }; 21 | 22 | if( questionObj.checks ){ 23 | extraData.question.checks = questionObj.checks; 24 | } 25 | 26 | const answersHTML = generateAnswers( questionObj.answers, extraData, options ); 27 | 28 | const maxChoice = questionObj.checks ? JSON.parse(questionObj.checks) : ''; 29 | const checksMin = maxChoice[0] || ''; 30 | const checksMax = maxChoice[1] || ''; 31 | const maxChoiceText = maxChoice && options.messages.maxChoice ? ' ('+ checksMax +' '+ options.messages.maxChoice +')' : ''; 32 | 33 | const questionData = { 34 | questionId, 35 | questionNumber, 36 | questionText: questionObj.question + maxChoiceText, 37 | answersHTML 38 | }; 39 | questionHTML = replaceObjectKeysInString(questionData, questionHTML); 40 | 41 | if( options.showErrorMessage ){ 42 | let errorMessage = maxChoice !== '' ? options.messages.errorMultiChoice : (questionObj.errorMessage || options.messages.error); 43 | 44 | // CASE OF MULTIPLE ERROR MESSAGES FROM JSON DATA => DYNAMICALLY MANAGED VIA EVENT LISTENER IN CONSTRUCTOR 45 | if( isPlainObject(errorMessage) ){ 46 | errorMessage = ''; 47 | } 48 | 49 | questionHTML = questionHTML.replace( /{{errorTemplates}}/g, errorMessage ); 50 | } 51 | 52 | return accCode += replaceObjectKeysInString({checksMin, checksMax}, questionHTML); 53 | }, ''); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/modules/buildSurvey/generateQAcodeUtils/generateAnswers.js: -------------------------------------------------------------------------------- 1 | 2 | import { mergeObjects, replaceObjectKeysInString, sortList } from '../../helpers'; 3 | import { generateOptionTags } from './generateOptionTags'; 4 | import { getAttributesStringHTML } from './getAttributesStringHTML'; 5 | import { getTemplates } from './getTemplates'; 6 | 7 | export const generateAnswers = ( answersList, extraData, options ) => { 8 | 9 | let allAnswersHTML = ''; 10 | let previousType = ''; 11 | 12 | sortList( answersList ).forEach((answer, index) => { 13 | 14 | let answerHTML = ''; 15 | 16 | // COLLECT USEFUL DATA 17 | // answerType => checkbox, date, email, radio, select, text, textarea, etc... 18 | const answerType = answer.type === 'option' ? 'select' : answer.type; 19 | 20 | if( answerType === 'select' && previousType === answerType ){ return; } 21 | 22 | previousType = answerType; 23 | 24 | if( extraData.question.checks ){ 25 | answer = mergeObjects({}, answer, {data:{checks:extraData.question.checks}}); 26 | } 27 | 28 | const answerCode = `${answerType}-${extraData.surveyId}-${extraData.question.id}-${answerType === 'select' ? (index + 1) : answer.id}`; 29 | const answerData = { 30 | questionNumber: extraData.question.index + 1, 31 | wrapperClasses: options.cssClasses.wrapper[answerType] || options.cssClasses.wrapper.field, 32 | fieldAttributes: getAttributesStringHTML( answer, answerCode, extraData.question.isRequired ), 33 | fieldClasses: options.cssClasses[answerType] || options.cssClasses.field, 34 | 35 | answerType, 36 | answerCode, 37 | addMoreName: '', 38 | 39 | labelString: answer.label || '', 40 | labelClasses: options.cssClasses.label 41 | }; 42 | 43 | let relatedFieldHTML = ''; 44 | if( answer.related ){ 45 | const relatedType = answer.related.type || 'select'; 46 | const relatedIsSelect = relatedType === 'select'; 47 | const relatedObj = relatedIsSelect ? mergeObjects({}, answer) : answer.related; 48 | 49 | relatedObj.type = relatedIsSelect ? 'option' : relatedType; 50 | relatedObj.id = ''; 51 | relatedObj.data = mergeObjects({}, relatedObj.data, {requiredFrom:'#'+answerCode}); 52 | delete relatedObj.related; 53 | 54 | const answerDataRelated = { 55 | fieldAttributes: getAttributesStringHTML(relatedObj, '', false), 56 | answerType: relatedType, 57 | addMoreName: '-more', 58 | fieldClasses: relatedIsSelect ? options.cssClasses.select : (options.cssClasses[relatedType] || options.cssClasses.field) 59 | }; 60 | 61 | relatedFieldHTML = options.templates[relatedType] || options.templates.input; 62 | if( relatedIsSelect ){ 63 | const optionsHtml = generateOptionTags( answer.related ); 64 | relatedFieldHTML = relatedFieldHTML.replace('{{optionsHtml}}', optionsHtml); 65 | } 66 | 67 | relatedFieldHTML = replaceObjectKeysInString(answerDataRelated, relatedFieldHTML); 68 | } 69 | 70 | // TAKE RIGHT TEMPLATES ( wrapper, field and label ) AND PUT ALL TOGETHER 71 | // answerTypeForTemplate => related, input, nested, select, textarea, etc... 72 | const answerTypeForTemplate = answer.related ? 'related' : (answer.nested ? 'nested' : answerType); 73 | const templates = getTemplates( answerTypeForTemplate, options.templates ); 74 | 75 | let nestedFieldsHTML = ''; 76 | if( answer.nested ){ 77 | nestedFieldsHTML = generateAnswers( answer.nested, extraData, options ); 78 | } 79 | 80 | let optionsHtml = ''; 81 | if( answerType === 'select' ){ 82 | optionsHtml = generateOptionTags( answersList ); 83 | } 84 | 85 | answerHTML = templates.wrapper 86 | .replace('{{relatedFieldHTML}}', relatedFieldHTML) 87 | .replace('{{fieldTemplate}}', templates.field) 88 | .replace('{{optionsHtml}}', optionsHtml) 89 | .replace('{{labelTemplate}}', templates.label) 90 | .replace('{{nestedFieldsHTML}}', nestedFieldsHTML); 91 | allAnswersHTML += replaceObjectKeysInString(answerData, answerHTML); 92 | 93 | }); 94 | 95 | return allAnswersHTML; 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/modules/buildSurvey/generateQAcodeUtils/generateOptionTags.js: -------------------------------------------------------------------------------- 1 | 2 | import { sortList } from '../../helpers'; 3 | 4 | export const generateOptionTags = ( optionsList = [] ) => { 5 | 6 | return sortList( optionsList ).reduce((optionsHTML, opt) => { 7 | return optionsHTML += ``; 8 | }, ''); 9 | 10 | } -------------------------------------------------------------------------------- /src/modules/buildSurvey/generateQAcodeUtils/getAttributesStringHTML.js: -------------------------------------------------------------------------------- 1 | 2 | import { toKebabCase } from '../../helpers'; 3 | 4 | export const getAttributesStringHTML = ( answerObj, answerCode, isRequired ) => { 5 | const excludedAttrs = ['data', 'id', 'label', 'nested', 'related', 'sort']; 6 | 7 | if( /^(option|textarea)$/.test(answerObj.type) ){ 8 | excludedAttrs.push('type', 'value'); 9 | } 10 | 11 | let string = ''; 12 | 13 | Object.keys(answerObj) 14 | .filter(name => excludedAttrs.indexOf(name) === -1) 15 | .forEach(name => { 16 | string += ` ${name}="${answerObj[name]}"`; 17 | }); 18 | 19 | if( answerObj.data ){ 20 | Object.keys(answerObj.data).forEach(name => { 21 | string += ` data-${toKebabCase(name)}="${answerObj.data[name]}"`; 22 | }); 23 | } 24 | 25 | if( isRequired ){ 26 | string += ' required'; 27 | } 28 | 29 | if( answerObj.related ){ 30 | string += ' data-require-more'; 31 | } 32 | 33 | string += ` id="${answerCode}"`; 34 | 35 | return string.trim(); 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/buildSurvey/generateQAcodeUtils/getTemplates.js: -------------------------------------------------------------------------------- 1 | 2 | export const getTemplates = ( answerType, templates ) => { 3 | return { 4 | field: templates[answerType] || templates.input, 5 | label: /^(checkbox|nested|radio|related)$/.test(answerType) ? templates.label : '', 6 | wrapper: templates.wrapper[answerType] || templates.wrapper.field 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/modules/buildSurvey/populateAnswers.js: -------------------------------------------------------------------------------- 1 | 2 | export const populateAnswers = ( $form, internals ) => { 3 | 4 | const WS = sessionStorage.getObject( internals.storageName ); 5 | if( WS ){ 6 | const $surveyCont = $form.closest('[data-surveyjs-wrapper]'); 7 | WS.forEach(item => { 8 | const $fieldFirst = $surveyCont.querySelector( '[name="' + item.name + '"]' ), 9 | isRadioOrCheckbox = $fieldFirst.matches('[type="radio"], [type="checkbox"]'), 10 | $field = ( isRadioOrCheckbox ? $surveyCont.querySelector('[name="' + item.name + '"][value="' + item.value + '"]') : $fieldFirst ); 11 | 12 | if( isRadioOrCheckbox ){ 13 | $field.checked = true; 14 | } else { 15 | $field.value = item.value; 16 | } 17 | }); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/modules/destroy.js: -------------------------------------------------------------------------------- 1 | 2 | import { submit, validationEnd } from './listenerCallbacks'; 3 | 4 | export const destroy = $form => { 5 | 6 | $form.removeEventListener('fjs.field:validation', validationEnd); 7 | $form.removeEventListener('fjs.form:submit', submit); 8 | 9 | delete $form.surveyjs; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/modules/helpers.js: -------------------------------------------------------------------------------- 1 | 2 | export { ajaxCall } from './helpers/ajaxCall'; 3 | export { arrayMove } from './helpers/arrayMove'; 4 | export { checkFormEl } from './helpers/checkFormEl'; 5 | export { customEvents } from './helpers/customEvents'; 6 | export { deepFreeze } from './helpers/deepFreeze'; 7 | export { dispatchCustomEvent } from './helpers/dispatchCustomEvent'; 8 | export { fieldsStringSelectorSurvey } from './helpers/fieldsStringSelectorSurvey'; 9 | export { getQuestionId } from './helpers/getQuestionId'; 10 | export { isDOMNode } from './helpers/isDOMNode'; 11 | export { isEmptyObject } from './helpers/isEmptyObject'; 12 | export { isNodeList } from './helpers/isNodeList'; 13 | export { isPlainObject } from './helpers/isPlainObject'; 14 | export { mergeObjects } from './helpers/mergeObjects'; 15 | export { replaceObjectKeysInString } from './helpers/replaceObjectKeysInString'; 16 | export { sortList } from './helpers/sortList'; 17 | export { toKebabCase } from './helpers/toKebabCase'; 18 | export { webStorage } from './helpers/webStorage'; 19 | -------------------------------------------------------------------------------- /src/modules/helpers/ajaxCall.js: -------------------------------------------------------------------------------- 1 | 2 | export const ajaxCall = ( url = location.href, options = {} ) => { 3 | 4 | let timeoutTimer; 5 | 6 | options.headers = new Headers( options.headers ); 7 | 8 | /* SET AbortController FOR timeout */ 9 | if ( options.timeout > 0 ) { 10 | const controller = new AbortController(); 11 | const signal = controller.signal; 12 | 13 | options.signal = signal; 14 | 15 | timeoutTimer = window.setTimeout(() => { 16 | controller.abort(); 17 | }, options.timeout); 18 | } 19 | 20 | return fetch( url, options ) 21 | .then(response => { 22 | if( !response.ok ){ 23 | throw new Error(response.statusText); 24 | } 25 | return response.json(); 26 | }) 27 | .catch(error => { 28 | throw new Error(error.message); 29 | }) 30 | .finally(() => { 31 | if( timeoutTimer ){ 32 | window.clearTimeout( timeoutTimer ); 33 | } 34 | }); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/helpers/arrayMove.js: -------------------------------------------------------------------------------- 1 | 2 | export const arrayMove = (array, from, to) => { 3 | array.splice(to, 0, array.splice(from, 1)[0]); 4 | return array; 5 | } 6 | -------------------------------------------------------------------------------- /src/modules/helpers/checkFormEl.js: -------------------------------------------------------------------------------- 1 | 2 | import { isDOMNode } from './isDOMNode'; 3 | 4 | export const checkFormEl = formEl => { 5 | 6 | const isString = typeof formEl, 7 | isValidNodeSelector = isString === 'string' && isDOMNode(document.querySelector(formEl)), 8 | isFormSelector = isValidNodeSelector && document.querySelector(formEl).tagName.toLowerCase() === 'form', 9 | obj = { 10 | result: isDOMNode(formEl) || isFormSelector, 11 | element: (isString === 'string' ? document.querySelector(formEl) : formEl) 12 | }; 13 | 14 | return obj; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/modules/helpers/customEvents.js: -------------------------------------------------------------------------------- 1 | 2 | export const customEvents = { 3 | destroy: 'sjs:destroy', 4 | init: 'sjs:init' 5 | } 6 | -------------------------------------------------------------------------------- /src/modules/helpers/deepFreeze.js: -------------------------------------------------------------------------------- 1 | 2 | export const deepFreeze = obj => { 3 | 4 | Object.getOwnPropertyNames(obj).forEach(name => { 5 | const prop = obj[name]; 6 | if( typeof prop === 'object' && prop !== null ){ 7 | deepFreeze(prop); 8 | } 9 | }); 10 | return Object.freeze(obj); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/modules/helpers/dispatchCustomEvent.js: -------------------------------------------------------------------------------- 1 | 2 | import { mergeObjects } from './mergeObjects'; 3 | 4 | export const dispatchCustomEvent = ( elem, eventName, eventOptions ) => { 5 | eventOptions = mergeObjects({}, { bubbles: true }, eventOptions); 6 | const eventObj = new CustomEvent(eventName, eventOptions); 7 | elem.dispatchEvent( eventObj ); 8 | } 9 | -------------------------------------------------------------------------------- /src/modules/helpers/fieldsStringSelectorSurvey.js: -------------------------------------------------------------------------------- 1 | 2 | export const fieldsStringSelectorSurvey = '[data-surveyjs-form] input:not([type="reset"]):not([type="submit"]):not([type="button"]), [data-surveyjs-form] select, [data-surveyjs-form] textarea, [data-surveyjs-external] [data-field]' 3 | -------------------------------------------------------------------------------- /src/modules/helpers/getQuestionId.js: -------------------------------------------------------------------------------- 1 | 2 | export const getQuestionId = fieldEl => { 3 | const containerEl = fieldEl.closest('[data-question-id]'); 4 | return (containerEl && containerEl.getAttribute('data-question-id')) || ''; 5 | } 6 | -------------------------------------------------------------------------------- /src/modules/helpers/isDOMNode.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-prototype-builtins */ 2 | 3 | export const isDOMNode = node => { 4 | return Element.prototype.isPrototypeOf( node ); 5 | } 6 | -------------------------------------------------------------------------------- /src/modules/helpers/isEmptyObject.js: -------------------------------------------------------------------------------- 1 | 2 | import { isPlainObject } from './isPlainObject'; 3 | 4 | export const isEmptyObject = object => { 5 | return isPlainObject(object) && Object.getOwnPropertyNames(object).length === 0; 6 | } 7 | -------------------------------------------------------------------------------- /src/modules/helpers/isNodeList.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-prototype-builtins */ 2 | 3 | export const isNodeList = nodeList => { 4 | return NodeList.prototype.isPrototypeOf( nodeList ); 5 | } 6 | -------------------------------------------------------------------------------- /src/modules/helpers/isPlainObject.js: -------------------------------------------------------------------------------- 1 | 2 | export const isPlainObject = object => { 3 | return Object.prototype.toString.call( object ) === '[object Object]'; 4 | } 5 | -------------------------------------------------------------------------------- /src/modules/helpers/mergeObjects.js: -------------------------------------------------------------------------------- 1 | 2 | import { isPlainObject } from './isPlainObject'; 3 | 4 | export const mergeObjects = function( out = {} ){ 5 | Array.from(arguments).slice(1).filter(arg => !!arg).forEach(arg => { 6 | Object.keys(arg).forEach(key => { 7 | if( Array.isArray(arg[key]) ){ 8 | out[key] = (out[key] || []).concat( arg[key].slice(0) ); 9 | } else if( isPlainObject(arg[key]) ){ 10 | out[key] = mergeObjects((out[key] || {}), arg[key]); 11 | } else { 12 | // * STRING | NUMBER | BOOLEAN | FUNCTION 13 | if( Array.isArray(out[key]) ){ 14 | // IF THIS IS ONE OF ABOVE (*) AND THE DESTINATION OBJECT IS AN ARRAY 15 | out[key].push(arg[key]); 16 | } else { 17 | out[key] = arg[key]; 18 | } 19 | } 20 | }); 21 | }); 22 | 23 | return out; 24 | } 25 | -------------------------------------------------------------------------------- /src/modules/helpers/replaceObjectKeysInString.js: -------------------------------------------------------------------------------- 1 | 2 | export const replaceObjectKeysInString = (obj, stringHTML) => { 3 | return Object.keys(obj).reduce((accString, name) => { 4 | const regexStr = new RegExp( '{{' + name + '}}', 'g' ); 5 | return accString.replace(regexStr, obj[name]); 6 | }, stringHTML); 7 | } 8 | -------------------------------------------------------------------------------- /src/modules/helpers/sortList.js: -------------------------------------------------------------------------------- 1 | 2 | export const sortList = ( list ) => { 3 | if( list[0]['sort'] ){ 4 | list.sort((a, b) => a['sort'] > b['sort']); 5 | } 6 | return list; 7 | } 8 | -------------------------------------------------------------------------------- /src/modules/helpers/toKebabCase.js: -------------------------------------------------------------------------------- 1 | 2 | export const toKebabCase = ( string = '', useAllCaps = false ) => { 3 | let newString = string.trim().replace(/(([_ ])([a-z]))|(([a-z])?([A-Z]))/g, (match, p1, p2, p3, p4, p5, p6) => { 4 | const concatGroup = p3 ? '-' + p3 : (p5 || '') + '-' + p6; 5 | return concatGroup.toLowerCase(); 6 | } ); 7 | return useAllCaps ? newString.toUpperCase() : newString; 8 | } 9 | -------------------------------------------------------------------------------- /src/modules/helpers/webStorage.js: -------------------------------------------------------------------------------- 1 | 2 | export const webStorage = () => { 3 | 4 | const checkLocalStorage = () => { 5 | const mod = 'check_storage'; 6 | try { 7 | localStorage.setItem(mod, mod); 8 | localStorage.removeItem(mod); 9 | return true; 10 | } catch(e) { 11 | return false; 12 | } 13 | }; 14 | 15 | const isAvailable = checkLocalStorage(); 16 | 17 | if( isAvailable ){ 18 | // setObject METHOD FOR HTML STORAGE -> EG: localStorage.setObject( name, JSobj ) 19 | // TO STORE A JS OBJECT ( AS JSON STRING ) INSIDE THE STORAGE 20 | Storage.prototype.setObject = function( key, value ) { 21 | this.setItem( key, JSON.stringify(value) ); 22 | } 23 | 24 | // getObject METHOD FOR HTML STORAGE -> EG: localStorage.getObject( name ) 25 | // RETURN THE DATA ( STORED AS JSON STRING ) AS JS OBJECT 26 | Storage.prototype.getObject = function( key ) { 27 | const value = this.getItem( key ); 28 | return value && JSON.parse( value ); 29 | } 30 | } 31 | 32 | return { 33 | isAvailable: isAvailable 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/internals.js: -------------------------------------------------------------------------------- 1 | 2 | export const internals = { 3 | storageName: 'Survey_' + location.href + '_{{surveyFormName}}_surveyId[{{surveyId}}]' 4 | } 5 | -------------------------------------------------------------------------------- /src/modules/listenerCallbacks.js: -------------------------------------------------------------------------------- 1 | 2 | export { submit } from './listenerCallbacks/submit'; 3 | export { validationEnd } from './listenerCallbacks/validationEnd'; 4 | -------------------------------------------------------------------------------- /src/modules/listenerCallbacks/submit.js: -------------------------------------------------------------------------------- 1 | 2 | export function submit( event ){ 3 | const self = event.target.surveyjs; 4 | event.detail.then(() => { 5 | if( self.options.useWebStorage ){ 6 | sessionStorage.removeItem( self.internals.storageName ); 7 | } 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /src/modules/listenerCallbacks/validationEnd.js: -------------------------------------------------------------------------------- 1 | 2 | import { arrayMove, getQuestionId, isEmptyObject, isPlainObject } from '../helpers'; 3 | import { getQuestionObject } from '../utils/getQuestionObject'; 4 | import { getAnswerIndex } from '../utils/getAnswerIndex'; 5 | 6 | export function validationEnd( event ){ 7 | const $field = event.detail.$field; 8 | const errors = event.detail.errors; 9 | const instance = $field.closest('form').surveyjs; 10 | const options = instance.options; 11 | const $errorsWrapper = $field.closest( options.fieldOptions.questionContainer ).querySelector('[data-surveyjs-errors]'); 12 | 13 | const questionId = getQuestionId($field); 14 | const questionObj = getQuestionObject(instance.data.questions, questionId); 15 | 16 | // IF IT'S NOT A SURVEY QUESTION -> SKIP 17 | if( isEmptyObject(questionObj) ){ return true; } 18 | 19 | // MANAGE MULTIPLE ERROR MESSAGES 20 | if( $errorsWrapper && errors && isPlainObject(questionObj.errorMessage) ){ 21 | let errorsList = Object.keys(errors); 22 | if( errors.rule ){ 23 | // PUT ERROR "rule" AS FIRST, SO THAT A GENERIC ERROR IS SHOWN BEFORE ALL OTHERS 24 | const ruleIndex = errorsList.indexOf('rule'); 25 | errorsList = arrayMove(errorsList, ruleIndex, 0); 26 | } 27 | const errorsHTML = errorsList.reduce((accHTML, name) => { 28 | const errorMessage = questionObj.errorMessage[name] || ''; 29 | return accHTML += errorMessage ? options.templates.error.replace('{{errorMessage}}', errorMessage) : ''; 30 | }, ''); 31 | 32 | $errorsWrapper.innerHTML = errorsHTML; 33 | } 34 | 35 | // MANAGE ITEMS IN LOCAL STORAGE ( IF AVAILABLE AND ACTIVE ) 36 | if( !event.detail.isCheckingForm && options.useWebStorage && !$field.matches('[data-exclude-storage]') ){ 37 | const storageName = instance.internals.storageName; 38 | let storageArray = sessionStorage.getObject( storageName ) || []; 39 | 40 | const name = $field.name; 41 | const value = $field.value; 42 | const isRequiredFrom = $field.matches('[data-required-from]'); 43 | const isMultiChoice = $field.matches('[data-checks]'); 44 | const isRequireMore = $field.matches('[data-require-more]'); 45 | const $reqMore = isRequiredFrom ? document.querySelector($field.getAttribute('data-required-from')) : null; 46 | 47 | const inArrayRequireMorePos = getAnswerIndex( storageArray, name + '-more' ); 48 | if( !isRequireMore && !isRequiredFrom && inArrayRequireMorePos >= 0 ){ 49 | // WHEN CHECKING A RADIO WITHOUT RELATED ANSWER ( IN A LIST OF RADIOS WITH ONE REQ-MORE ) => REMOVE RELATED ANSWER FROM STORAGE 50 | storageArray.splice(inArrayRequireMorePos, 1); 51 | } 52 | 53 | const inArrayPos = getAnswerIndex( storageArray, name, (isMultiChoice ? value : false) ); 54 | if( inArrayPos >= 0 ){ 55 | // REMOVE ITEM FROM LS 56 | storageArray.splice(inArrayPos, 1); 57 | if( (isMultiChoice && $field.checked) || (!isMultiChoice && value !== '') ){ 58 | // ADD ITEM TO LS 59 | storageArray.push( { name, value } ); 60 | } 61 | } else if( value !== '' ){ 62 | if( isRequiredFrom ){ 63 | const reqMorePos = getAnswerIndex( storageArray, $reqMore.name ); 64 | if( reqMorePos >= 0 ){ 65 | storageArray.splice(reqMorePos, 1); 66 | } 67 | storageArray.push( { name: $reqMore.name, value: $reqMore.value } ); 68 | } 69 | storageArray.push( { name, value } ); 70 | } 71 | 72 | sessionStorage.setObject( storageName, storageArray ); 73 | } 74 | 75 | // BASED ON JSON DATA, FORCE REQUIRED FIELDS TO BE VALIDATED 76 | if( questionObj.required && !$field.required && !$field.matches('[data-required-from]') ){ 77 | $field.required = true; 78 | instance.validateField($field); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/modules/options.js: -------------------------------------------------------------------------------- 1 | 2 | import { optionsUtils } from './optionsUtils'; 3 | 4 | export const options = { 5 | cssClasses: { 6 | checkbox: 'form-check-input', 7 | field: 'form-control', 8 | file: 'form-control-file', 9 | label: 'form-check-label', 10 | radio: 'form-check-input', 11 | wrapper: { 12 | checkbox: 'form-check', 13 | field: '', 14 | radio: 'form-check' 15 | } 16 | }, 17 | formOptions: { 18 | getFormData: optionsUtils.formOptions.getFormData 19 | }, 20 | initAjaxOptions: { 21 | cache: 'no-store', 22 | credentials: 'same-origin', 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | 'Accept': 'application/json' 26 | }, 27 | method: 'GET', 28 | mode: 'same-origin', 29 | redirect: 'follow', 30 | timeout: 0 31 | }, 32 | messages:{ 33 | maxChoice: 'answers max', 34 | error: 'Answer is necessary.', 35 | errorMultiChoice: 'You must choose from {{checksMin}} to {{checksMax}} answers.' 36 | }, 37 | showErrorMessage: true, 38 | templates: { 39 | error: '
{{errorMessage}}
', 40 | 41 | input: '', 42 | 43 | label: '', 44 | 45 | loading: '
Loading...
', 46 | 47 | select: '', 50 | 51 | textarea: '', 52 | 53 | wrapper: { 54 | field: '
'+ 55 | '{{fieldTemplate}}'+ 56 | '{{labelTemplate}}'+ 57 | '
', 58 | 59 | nested: '
'+ 60 | '{{labelTemplate}}'+ 61 | '
'+ 62 | '{{nestedFieldsHTML}}'+ 63 | '
'+ 64 | '
', 65 | 66 | question: '
'+ 67 | '
{{questionText}}
'+ 68 | '
'+ 69 | '{{answersHTML}}'+ 70 | '
'+ 71 | '
{{errorTemplates}}
'+ 72 | '
', 73 | 74 | related: '' 83 | } 84 | }, 85 | useWebStorage: true 86 | } 87 | -------------------------------------------------------------------------------- /src/modules/optionsUtils.js: -------------------------------------------------------------------------------- 1 | 2 | import { fieldsStringSelectorSurvey, getQuestionId, isEmptyObject } from './helpers'; 3 | import { getQuestionObject } from './utils/getQuestionObject'; 4 | 5 | export const optionsUtils = { 6 | formOptions: { 7 | 8 | getFormData: function getFormData_surveyDefault( $filteredFields, trimValues ){ 9 | const instance = this; 10 | const $form = instance.$form; 11 | const fieldsList = Array.from( $form.closest('[data-surveyjs-wrapper]').querySelectorAll(fieldsStringSelectorSurvey) ); 12 | const obj = { 13 | answers: [], 14 | id: instance.data.id 15 | }; 16 | 17 | let fieldNameCheck = ''; 18 | let fieldTypeCheck = ''; 19 | 20 | fieldsList.forEach($field => { 21 | const type = $field.type; 22 | const name = $field.name; 23 | 24 | if( name === fieldNameCheck && type === fieldTypeCheck ){ return; } 25 | 26 | if( !$field.matches('[data-required-from]') ){ 27 | fieldNameCheck = name; 28 | fieldTypeCheck = type; 29 | } 30 | 31 | // EACH QUESTION HAS ITS OWN OBJECT ( qaObj ) THAT CONTAINS THE RELATED DATA: 32 | // question: THE QUESTION ID ( undefined FOR QUESTIONS WITH ATTRIBUTE data-required-form - will be skipped later ) 33 | // answer AN OBJECT THAT CONTAINS THE FOLLOWS: 34 | // value: THE ANSWER VALUE 35 | // related: IF THE ANSWER IS REQUIRED FROM ANOTHER ANSWER (SEE BELOW) 36 | const questionId = getQuestionId($field); 37 | const qaObj = { 38 | question: questionId, 39 | answer: { 40 | value: trimValues ? $field.value.trim() : ($field.value || '') 41 | } 42 | }; 43 | 44 | // A FIELD WITH ATTRIBUTE 'data-required-from' IS MANAGED TOGETHER WITH ITS RELATED FIELD ( WHICH HAS ATTRIBUTE 'data-require-more' ) 45 | // IF QUESTION ID IS EMPTY -> SKIP THE FIELD ( USEFUL FOR FORM FIELDS OUTSIDE THE SURVEY BODY ) 46 | if( 47 | $field.matches('[data-required-from]') || 48 | questionId === '' || 49 | isEmptyObject( getQuestionObject(instance.data.questions, questionId) ) 50 | ){ return; } 51 | 52 | if( type === 'radio' ){ 53 | const $container = $field.closest('form') ? $form : $field.closest(instance.options.fieldOptions.questionContainer); 54 | const $checked = $container.querySelector('[name="'+ name +'"]:checked'); 55 | 56 | qaObj.answer.value = ($checked && $checked.value) || ''; 57 | 58 | // FOR RADIO THAT REQUIRE THE USER TO GIVE ONE MORE ANSWER 59 | if( $checked && $checked.matches('[data-require-more]') ){ 60 | qaObj.answer.related = $form.querySelector('[data-required-from="#'+ $checked.id +'"]').value; 61 | } 62 | } 63 | 64 | if( type === 'checkbox' && $field.matches('[data-checks]') ){ 65 | qaObj.answer.value = []; 66 | Array.from($form.querySelectorAll('[name="'+ name +'"]:checked')).forEach($el => { 67 | qaObj.answer.value.push( $el.value ); 68 | }); 69 | } 70 | 71 | obj.answers.push( qaObj ); 72 | }); 73 | 74 | return obj; 75 | } 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/modules/utils/getAnswerIndex.js: -------------------------------------------------------------------------------- 1 | 2 | export const getAnswerIndex = ( list, fieldName, multiChoiceValue = '' ) => { 3 | 4 | const listLength = list.length; 5 | 6 | for(let item = 0; item < listLength; item++){ 7 | const lsItem = list[item]; 8 | if( lsItem.name === fieldName ){ 9 | if( multiChoiceValue ){ 10 | if( lsItem.value !== multiChoiceValue ){ 11 | continue; 12 | } 13 | } 14 | return item; 15 | } 16 | } 17 | 18 | return -1; 19 | 20 | } -------------------------------------------------------------------------------- /src/modules/utils/getQuestionObject.js: -------------------------------------------------------------------------------- 1 | 2 | export const getQuestionObject = ( questions, questionId ) => { 3 | 4 | const qLength = questions.length; 5 | 6 | let obj = {}; 7 | 8 | for(let q=0; q