├── .editorconfig ├── .eslintrc ├── .gitignore ├── Changelog.md ├── LICENSE.txt ├── README.md ├── bower.json ├── css └── ngFormBuilder.css ├── dist ├── ngFormBuilder-complete.css ├── ngFormBuilder-complete.js ├── ngFormBuilder-complete.min.css ├── ngFormBuilder-complete.min.js ├── ngFormBuilder-full.css ├── ngFormBuilder-full.js ├── ngFormBuilder-full.min.css ├── ngFormBuilder-full.min.js ├── ngFormBuilder.css ├── ngFormBuilder.js ├── ngFormBuilder.min.css └── ngFormBuilder.min.js ├── gulp ├── eslint.js ├── scripts-complete.js ├── scripts-full.js ├── scripts.js ├── styles-basic.js ├── styles-complete.js ├── styles-full.js └── watch.js ├── gulpfile.js ├── index.html ├── package-lock.json ├── package.json └── src ├── components ├── address.js ├── button.js ├── checkbox.js ├── columns.js ├── components.js ├── container.js ├── content.js ├── currency.js ├── custom.js ├── datagrid.js ├── datetime.js ├── day.js ├── editgrid.js ├── email.js ├── fieldset.js ├── file.js ├── form.js ├── hidden.js ├── htmlelement.js ├── index.js ├── number.js ├── page.js ├── panel.js ├── password.js ├── phonenumber.js ├── radio.js ├── resource.js ├── select.js ├── selectboxes.js ├── signature.js ├── survey.js ├── table.js ├── textarea.js ├── textfield.js ├── time.js └── well.js ├── constants ├── commonOptions.js └── formOptions.js ├── directives ├── formBuilder.js ├── formBuilderComponent.js ├── formBuilderConditional.js ├── formBuilderDnd.js ├── formBuilderElement.js ├── formBuilderList.js ├── formBuilderOption.js ├── formBuilderOptionCustomValidation.js ├── formBuilderOptionInputFormat.js ├── formBuilderOptionInputsLabelPosition.js ├── formBuilderOptionKey.js ├── formBuilderOptionLabelPosition.js ├── formBuilderOptionOptionsLabelPosition.js ├── formBuilderOptionShortcut.js ├── formBuilderOptionTags.js ├── formBuilderRow.js ├── formBuilderTable.js ├── formBuilderTooltip.js ├── headersBuilder.js ├── jsonInput.js ├── labelValidator.js ├── multiMaskInput.js ├── objectBuilder.js ├── textMask.js ├── validApiKey.js ├── valueBuilder.js └── valueBuilderWithShortcuts.js ├── factories ├── BuilderUtils.js └── debounce.js ├── ngFormBuilder-complete.js ├── ngFormBuilder-full.js ├── ngFormBuilder.js └── templates ├── builder.html ├── component.html ├── confirm-remove.html ├── datagrid.html ├── editbuttons.html ├── form.html ├── list.html └── row.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [{package,bower}.json] 24 | indent_style = space 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "formio", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "globals": { 8 | "angular": true, 9 | "_": true 10 | }, 11 | "rules": { 12 | "new-cap": [2, {"capIsNewExceptions": ["FormioPlugins"]}] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bower.json 2 | .idea 3 | bower_components 4 | node_modules 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Form.io 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in the 6 | Software without restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 8 | Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 19 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## This repository is now considered legacy and no longer supported. It has been replaced with our latest Form Builder and Renderer @ https://github.com/formio/formio.js and Angular libraries @ https://github.com/formio/angular. 2 | 3 | ## Please take a look at our recent repositories and help documentation at the following links. 4 | - https://help.form.io 5 | - https://github.com/formio/formio.js 6 | - https://github.com/formio/formio 7 | - https://github.com/formio/react 8 | - https://github.com/formio/angular 9 | - https://github.com/formio/vue 10 | 11 | The [Form.io](https://form.io) Form Builder 12 | -------------------------------- 13 | This library provides form building capabilities to an Angular.js application. This form builder's purpose is to 14 | construct a JSON object reporesentation of a form, which could then be handed off to a Form Renderer such as the one 15 | found @ [https://github.com/formio/ngFormio](https://github.com/formio/ngFormio). The following landing page should 16 | provide a good example of how this form builder works. 17 | 18 | [See Working Example](http://codepen.io/travist/full/xVyMjo/) 19 | 20 | The form builder can be embedded within your application using the following embed code. 21 | 22 | ``` 23 | 24 | ``` 25 | 26 | Where ```myform``` would be a form object that is placed on the scope of the controller containing the form builder. 27 | 28 | Installation 29 | ================ 30 | To install this within your application, you will first need to include the following 31 | 32 | 33 | Adding Components 34 | ================= 35 | To add a component, add it in the config phase. 36 | 37 | ``` 38 | angular 39 | .module('myApp') 40 | .config([ 41 | 'formioComponentsProvider', 42 | function (formioComponentsProvider) { 43 | formioComponentsProvider.register('myfield', { 44 | title: 'My Field', 45 | template: 'formio/components/icons.html', 46 | controller: ['$scope', function($scope) { 47 | }], 48 | group: 'custom', 49 | icon: 'fa fa-heart-o', 50 | settings: {}, 51 | views: [] 52 | }); 53 | ``` 54 | Removing Components 55 | =================== 56 | To remove default components or groups from the form builder, set them as disabled in the run phase. 57 | 58 | ``` 59 | angular.module('myApp') 60 | .run(['formioComponents', function(formioComponents) { 61 | formioComponents.components.textfield.disabled = true; 62 | formioComponents.groups.layout.disabled = true; 63 | }]); 64 | ``` 65 | 66 | Form.io 67 | ============== 68 | This project is provided by [Form.io](https://form.io), which is a combined form and API platform for Developers. 69 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-formio-builder", 3 | "main": [ 4 | "dist/ngFormBuilder.js", 5 | "css/ngFormBuilder.css" 6 | ], 7 | "version": "2.39.0", 8 | "authors": [ 9 | "Travis Tidwell " 10 | ], 11 | "description": "The Angular.JS form builder.", 12 | "license": "MIT", 13 | "ignore": [ 14 | "**/.*", 15 | "node_modules", 16 | "bower_components", 17 | "test", 18 | "tests" 19 | ], 20 | "dependencies": { 21 | "angular-drag-and-drop-lists": "^2.1.0", 22 | "angular-bootstrap": "^2.5.0", 23 | "ng-dialog": "^1.4.0", 24 | "ng-formio": "^2.41.0", 25 | "ng-tags-input": "^3.2.0", 26 | "angular-ckeditor-legacy": "^1.0.3" 27 | }, 28 | "devDependencies": { 29 | "font-awesome": "^4.7.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /css/ngFormBuilder.css: -------------------------------------------------------------------------------- 1 | .ngdialog-close { 2 | -webkit-appearance: none; 3 | background: none; 4 | border: none; 5 | width: 40px; 6 | height: 30px; 7 | z-index: 200; 8 | } 9 | 10 | .form-builder-premium { 11 | display: none; 12 | } 13 | 14 | .component-form-group { 15 | position: relative; 16 | } 17 | 18 | .component-btn-group { 19 | position: absolute; 20 | right: 0; 21 | z-index: 1000; 22 | } 23 | 24 | .component-form-group.component-type-hidden.form-builder-component, 25 | .component-form-group.component-type-form.form-builder-component { 26 | height: 3em; 27 | border: 2px dashed #ddd; 28 | } 29 | 30 | .component-form-group.component-type-hidden.form-builder-component .form-group, 31 | .component-form-group.component-type-form.form-builder-component .form-group { 32 | text-align: center; 33 | color: #aaa; 34 | padding-top: 0.5em; 35 | } 36 | 37 | .component-btn-group .component-settings-button { 38 | float: right; 39 | z-index: 1001; 40 | margin: 4px 4px 0 0; 41 | } 42 | 43 | .component-form-group.col-xs-6 { 44 | clear: right; 45 | } 46 | 47 | li .component-btn-group .component-settings-button { 48 | z-index: 1001; 49 | -webkit-box-shadow: 0px 0px 10px 1px rgba(48,113,169,0.6); 50 | -moz-box-shadow: 0px 0px 10px 1px rgba(48,113,169,0.6); 51 | box-shadow: 0px 0px 10px 1px rgba(48,113,169,0.6); 52 | } 53 | 54 | li:not(:hover) .component-btn-group .component-settings-button { 55 | display: none; 56 | } 57 | 58 | .formbuilder .nav-tabs { 59 | margin-bottom: 0; 60 | } 61 | 62 | .form-builder-panel .panel-body { 63 | padding: 5px; 64 | } 65 | 66 | .form-component-list { 67 | list-style: none; 68 | margin: 0; 69 | padding: 0; 70 | } 71 | 72 | .form-component-list li { 73 | margin-bottom: 10px; 74 | } 75 | 76 | .btn-xxs, .btn-group-xxs > .btn, .component-btn-group .component-settings-button { 77 | padding: 2px 2px; 78 | font-size: 10px; 79 | line-height: 1.2em; 80 | border-radius: 0; 81 | width: 18px; 82 | height: 18px; 83 | } 84 | 85 | .ngdialog.ngdialog-theme-default.component-settings .ngdialog-content { 86 | width: 65%; 87 | } 88 | 89 | #component-settings .tab-pane { 90 | padding: 10px; 91 | } 92 | 93 | #component-settings .nav-tabs { 94 | font-size: 12px; 95 | } 96 | 97 | .component-settings-key { 98 | margin: -1em 1em 1em 1em; 99 | } 100 | 101 | /***************************** Required styles *****************************/ 102 | 103 | /** 104 | * For the correct positioning of the placeholder element, the dnd-list and 105 | * it's children must have position: relative 106 | */ 107 | ul[dnd-list], 108 | ul[dnd-list] > li { 109 | position: relative; 110 | } 111 | 112 | tr[dnd-list], 113 | tr[dnd-list] > th { 114 | position: relative; 115 | } 116 | 117 | /***************************** Dropzone Styling *****************************/ 118 | 119 | /** 120 | * The dnd-list should always have a min-height, 121 | * otherwise you can't drop to it once it's empty 122 | */ 123 | ul.component-list { 124 | min-height: 42px; 125 | margin: 0px; 126 | padding-left: 0px; 127 | } 128 | 129 | /** 130 | * The dnd-lists's child elements currently MUST have 131 | * position: relative. Otherwise we can not determine 132 | * whether the mouse pointer is in the upper or lower 133 | * half of the element we are dragging over. In other 134 | * browsers we can use event.offsetY for this. 135 | */ 136 | ul.component-list li { 137 | display: block; 138 | padding: 0px; 139 | } 140 | 141 | .dropzone { 142 | min-height: 150px; 143 | min-width: 150px; 144 | } 145 | 146 | /** 147 | * Reduce opacity of elements during the drag operation. This allows the user 148 | * to see where he is dropping his element, even if the element is huge. The 149 | * .dndDragging class is automatically set during the drag operation. 150 | */ 151 | .dropzone .dndDragging { 152 | opacity: 0.7; 153 | } 154 | 155 | /** 156 | * The dndDraggingSource class will be applied to the source element of a drag 157 | * operation. It makes sense to hide it to give the user the feeling that he's 158 | * actually moving it. Note that the source element has also .dndDragging class. 159 | */ 160 | .dropzone .dndDraggingSource { 161 | display: none; 162 | } 163 | 164 | /** 165 | * An element with .dndPlaceholder class will be added as child of the dnd-list 166 | * while the user is dragging over it. 167 | */ 168 | .dropzone .dndPlaceholder { 169 | background-color: #ddd; 170 | min-height: 50px; 171 | min-width: 50px; 172 | position: relative; 173 | } 174 | 175 | /** 176 | * An overlay that is shown while dragging. This way, elements like iframes in 177 | * a content component do not interfere with dragging. 178 | */ 179 | .dropzone .dndOverlay { 180 | top: 0; 181 | bottom: 0; 182 | left: 0; 183 | right: 0; 184 | z-index: 99999; 185 | opacity: 0; 186 | } 187 | 188 | /***************************** Element Selection *****************************/ 189 | 190 | .dropzone .selected .item { 191 | color: #3c763d; 192 | background-color: #dff0d8; 193 | } 194 | 195 | .dropzone .selected .box { 196 | border-color: #d6e9c6; 197 | } 198 | 199 | .dropzone .selected .box > h3 { 200 | color: #3c763d; 201 | background-color: #dff0d8; 202 | background-image: linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%); 203 | border-color: #d6e9c6; 204 | } 205 | 206 | /***************************** Element type specific styles *****************************/ 207 | 208 | .dropzone .item { 209 | padding: 20px; 210 | } 211 | 212 | .dropzone .container-element { 213 | margin: 10px; 214 | } 215 | 216 | .dropzone .container-element .column { 217 | float: left; 218 | width: 50%; 219 | } 220 | 221 | .dropzone .component-list { 222 | padding-bottom: 5px; 223 | } 224 | 225 | /***************************** Toolbox *****************************/ 226 | 227 | .toolbox ul { 228 | list-style: none; 229 | padding-left: 0px; 230 | cursor: move; 231 | } 232 | 233 | .toolbox button { 234 | margin: 5px; 235 | width: 123px; 236 | opacity: 1.0; 237 | } 238 | 239 | .toolbox .dndDragging { 240 | opacity: 0.5; 241 | } 242 | 243 | .toolbox .dndDraggingSource { 244 | opacity: 1.0; 245 | } 246 | 247 | /***************************** Trashcan *****************************/ 248 | 249 | .trashcan ul { 250 | list-style: none; 251 | padding-left: 0px; 252 | } 253 | 254 | .trashcan img { 255 | width: 100%; 256 | -webkit-filter: grayscale(100%); 257 | -moz-filter: grayscale(100%); 258 | filter: grayscale(100%); 259 | } 260 | 261 | .trashcan .dndDragover img { 262 | width: 100%; 263 | -webkit-filter: none; 264 | -moz-filter: none; 265 | filter: none; 266 | } 267 | 268 | .trashcan .dndPlaceholder { 269 | display: none; 270 | } 271 | 272 | .ui-select-toggle.btn { 273 | text-align: left; 274 | } 275 | 276 | /***************************** Layout Styling *****************************/ 277 | 278 | .form-builder-component .form-field-type-fieldset fieldset, 279 | .form-builder-component .form-field-type-editgrid fieldset, 280 | .form-builder-component .form-field-type-container fieldset { 281 | padding: 5px; 282 | margin-left: -5px; 283 | margin-right: -5px; 284 | border: dotted 2px #e8e8e8; 285 | } 286 | 287 | .form-builder-component .form-field-type-columns .formio-column { 288 | padding: 10px; 289 | border: dotted 2px #e8e8e8; 290 | } 291 | 292 | /****************************** Data Grid Styling *************************/ 293 | 294 | .datagrid-dnd { 295 | padding: 5px; 296 | border: dotted 2px #e8e8e8; 297 | min-height: inherit; 298 | } 299 | 300 | /***************************** Form Component Buttons *********************/ 301 | 302 | .formcomponents { 303 | overflow: auto; 304 | min-height: 200px; 305 | } 306 | 307 | .formcomponents .formcomponentcontainer { 308 | margin: 0 2px 2px 0; 309 | } 310 | 311 | .formcomponents .formcomponent { 312 | text-align: left; 313 | padding-left: 15px; 314 | } 315 | 316 | /********* Multi-mask component styles for default value ******************/ 317 | 318 | .form-control.formio-multiple-mask-select { 319 | width: 70px; 320 | z-index: 4; 321 | } 322 | 323 | .form-control.formio-multiple-mask-input { 324 | width: 100%; 325 | margin-left: -70px; 326 | padding-left: 80px; 327 | } 328 | 329 | .input-group.formio-multiple-mask-container { 330 | width: 100%; 331 | } 332 | 333 | .formio-drop-zone { 334 | display: none; 335 | position: absolute; 336 | z-index:10; 337 | background-color: #0d87e9; 338 | opacity: 0.1; 339 | } 340 | 341 | .formio-drop-zone.enabled { 342 | display: inherit; 343 | } 344 | -------------------------------------------------------------------------------- /dist/ngFormBuilder.css: -------------------------------------------------------------------------------- 1 | .ngdialog-close { 2 | -webkit-appearance: none; 3 | background: none; 4 | border: none; 5 | width: 40px; 6 | height: 30px; 7 | z-index: 200; 8 | } 9 | 10 | .form-builder-premium { 11 | display: none; 12 | } 13 | 14 | .component-form-group { 15 | position: relative; 16 | } 17 | 18 | .component-btn-group { 19 | position: absolute; 20 | right: 0; 21 | z-index: 1000; 22 | } 23 | 24 | .component-form-group.component-type-hidden.form-builder-component, 25 | .component-form-group.component-type-form.form-builder-component { 26 | height: 3em; 27 | border: 2px dashed #ddd; 28 | } 29 | 30 | .component-form-group.component-type-hidden.form-builder-component .form-group, 31 | .component-form-group.component-type-form.form-builder-component .form-group { 32 | text-align: center; 33 | color: #aaa; 34 | padding-top: 0.5em; 35 | } 36 | 37 | .component-btn-group .component-settings-button { 38 | float: right; 39 | z-index: 1001; 40 | margin: 4px 4px 0 0; 41 | } 42 | 43 | .component-form-group.col-xs-6 { 44 | clear: right; 45 | } 46 | 47 | li .component-btn-group .component-settings-button { 48 | z-index: 1001; 49 | -webkit-box-shadow: 0px 0px 10px 1px rgba(48,113,169,0.6); 50 | -moz-box-shadow: 0px 0px 10px 1px rgba(48,113,169,0.6); 51 | box-shadow: 0px 0px 10px 1px rgba(48,113,169,0.6); 52 | } 53 | 54 | li:not(:hover) .component-btn-group .component-settings-button { 55 | display: none; 56 | } 57 | 58 | .formbuilder .nav-tabs { 59 | margin-bottom: 0; 60 | } 61 | 62 | .form-builder-panel .panel-body { 63 | padding: 5px; 64 | } 65 | 66 | .form-component-list { 67 | list-style: none; 68 | margin: 0; 69 | padding: 0; 70 | } 71 | 72 | .form-component-list li { 73 | margin-bottom: 10px; 74 | } 75 | 76 | .btn-xxs, .btn-group-xxs > .btn, .component-btn-group .component-settings-button { 77 | padding: 2px 2px; 78 | font-size: 10px; 79 | line-height: 1.2em; 80 | border-radius: 0; 81 | width: 18px; 82 | height: 18px; 83 | } 84 | 85 | .ngdialog.ngdialog-theme-default.component-settings .ngdialog-content { 86 | width: 65%; 87 | } 88 | 89 | #component-settings .tab-pane { 90 | padding: 10px; 91 | } 92 | 93 | #component-settings .nav-tabs { 94 | font-size: 12px; 95 | } 96 | 97 | .component-settings-key { 98 | margin: -1em 1em 1em 1em; 99 | } 100 | 101 | /***************************** Required styles *****************************/ 102 | 103 | /** 104 | * For the correct positioning of the placeholder element, the dnd-list and 105 | * it's children must have position: relative 106 | */ 107 | ul[dnd-list], 108 | ul[dnd-list] > li { 109 | position: relative; 110 | } 111 | 112 | tr[dnd-list], 113 | tr[dnd-list] > th { 114 | position: relative; 115 | } 116 | 117 | /***************************** Dropzone Styling *****************************/ 118 | 119 | /** 120 | * The dnd-list should always have a min-height, 121 | * otherwise you can't drop to it once it's empty 122 | */ 123 | ul.component-list { 124 | min-height: 42px; 125 | margin: 0px; 126 | padding-left: 0px; 127 | } 128 | 129 | /** 130 | * The dnd-lists's child elements currently MUST have 131 | * position: relative. Otherwise we can not determine 132 | * whether the mouse pointer is in the upper or lower 133 | * half of the element we are dragging over. In other 134 | * browsers we can use event.offsetY for this. 135 | */ 136 | ul.component-list li { 137 | display: block; 138 | padding: 0px; 139 | } 140 | 141 | .dropzone { 142 | min-height: 150px; 143 | min-width: 150px; 144 | } 145 | 146 | /** 147 | * Reduce opacity of elements during the drag operation. This allows the user 148 | * to see where he is dropping his element, even if the element is huge. The 149 | * .dndDragging class is automatically set during the drag operation. 150 | */ 151 | .dropzone .dndDragging { 152 | opacity: 0.7; 153 | } 154 | 155 | /** 156 | * The dndDraggingSource class will be applied to the source element of a drag 157 | * operation. It makes sense to hide it to give the user the feeling that he's 158 | * actually moving it. Note that the source element has also .dndDragging class. 159 | */ 160 | .dropzone .dndDraggingSource { 161 | display: none; 162 | } 163 | 164 | /** 165 | * An element with .dndPlaceholder class will be added as child of the dnd-list 166 | * while the user is dragging over it. 167 | */ 168 | .dropzone .dndPlaceholder { 169 | background-color: #ddd; 170 | min-height: 50px; 171 | min-width: 50px; 172 | position: relative; 173 | } 174 | 175 | /** 176 | * An overlay that is shown while dragging. This way, elements like iframes in 177 | * a content component do not interfere with dragging. 178 | */ 179 | .dropzone .dndOverlay { 180 | top: 0; 181 | bottom: 0; 182 | left: 0; 183 | right: 0; 184 | z-index: 99999; 185 | opacity: 0; 186 | } 187 | 188 | /***************************** Element Selection *****************************/ 189 | 190 | .dropzone .selected .item { 191 | color: #3c763d; 192 | background-color: #dff0d8; 193 | } 194 | 195 | .dropzone .selected .box { 196 | border-color: #d6e9c6; 197 | } 198 | 199 | .dropzone .selected .box > h3 { 200 | color: #3c763d; 201 | background-color: #dff0d8; 202 | background-image: linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%); 203 | border-color: #d6e9c6; 204 | } 205 | 206 | /***************************** Element type specific styles *****************************/ 207 | 208 | .dropzone .item { 209 | padding: 20px; 210 | } 211 | 212 | .dropzone .container-element { 213 | margin: 10px; 214 | } 215 | 216 | .dropzone .container-element .column { 217 | float: left; 218 | width: 50%; 219 | } 220 | 221 | .dropzone .component-list { 222 | padding-bottom: 5px; 223 | } 224 | 225 | /***************************** Toolbox *****************************/ 226 | 227 | .toolbox ul { 228 | list-style: none; 229 | padding-left: 0px; 230 | cursor: move; 231 | } 232 | 233 | .toolbox button { 234 | margin: 5px; 235 | width: 123px; 236 | opacity: 1.0; 237 | } 238 | 239 | .toolbox .dndDragging { 240 | opacity: 0.5; 241 | } 242 | 243 | .toolbox .dndDraggingSource { 244 | opacity: 1.0; 245 | } 246 | 247 | /***************************** Trashcan *****************************/ 248 | 249 | .trashcan ul { 250 | list-style: none; 251 | padding-left: 0px; 252 | } 253 | 254 | .trashcan img { 255 | width: 100%; 256 | -webkit-filter: grayscale(100%); 257 | -moz-filter: grayscale(100%); 258 | filter: grayscale(100%); 259 | } 260 | 261 | .trashcan .dndDragover img { 262 | width: 100%; 263 | -webkit-filter: none; 264 | -moz-filter: none; 265 | filter: none; 266 | } 267 | 268 | .trashcan .dndPlaceholder { 269 | display: none; 270 | } 271 | 272 | .ui-select-toggle.btn { 273 | text-align: left; 274 | } 275 | 276 | /***************************** Layout Styling *****************************/ 277 | 278 | .form-builder-component .form-field-type-fieldset fieldset, 279 | .form-builder-component .form-field-type-editgrid fieldset, 280 | .form-builder-component .form-field-type-container fieldset { 281 | padding: 5px; 282 | margin-left: -5px; 283 | margin-right: -5px; 284 | border: dotted 2px #e8e8e8; 285 | } 286 | 287 | .form-builder-component .form-field-type-columns .formio-column { 288 | padding: 10px; 289 | border: dotted 2px #e8e8e8; 290 | } 291 | 292 | /****************************** Data Grid Styling *************************/ 293 | 294 | .datagrid-dnd { 295 | padding: 5px; 296 | border: dotted 2px #e8e8e8; 297 | min-height: inherit; 298 | } 299 | 300 | /***************************** Form Component Buttons *********************/ 301 | 302 | .formcomponents { 303 | overflow: auto; 304 | min-height: 200px; 305 | } 306 | 307 | .formcomponents .formcomponentcontainer { 308 | margin: 0 2px 2px 0; 309 | } 310 | 311 | .formcomponents .formcomponent { 312 | text-align: left; 313 | padding-left: 15px; 314 | } 315 | 316 | /********* Multi-mask component styles for default value ******************/ 317 | 318 | .form-control.formio-multiple-mask-select { 319 | width: 70px; 320 | z-index: 4; 321 | } 322 | 323 | .form-control.formio-multiple-mask-input { 324 | width: 100%; 325 | margin-left: -70px; 326 | padding-left: 80px; 327 | } 328 | 329 | .input-group.formio-multiple-mask-container { 330 | width: 100%; 331 | } 332 | 333 | .formio-drop-zone { 334 | display: none; 335 | position: absolute; 336 | z-index:10; 337 | background-color: #0d87e9; 338 | opacity: 0.1; 339 | } 340 | 341 | .formio-drop-zone.enabled { 342 | display: inherit; 343 | } 344 | -------------------------------------------------------------------------------- /dist/ngFormBuilder.min.css: -------------------------------------------------------------------------------- 1 | .ngdialog-close{-webkit-appearance:none;background:none;border:none;width:40px;height:30px;z-index:200}.form-builder-premium{display:none}.component-form-group{position:relative}.component-btn-group{position:absolute;right:0;z-index:1000}.component-form-group.component-type-form.form-builder-component,.component-form-group.component-type-hidden.form-builder-component{height:3em;border:2px dashed #ddd}.component-form-group.component-type-form.form-builder-component .form-group,.component-form-group.component-type-hidden.form-builder-component .form-group{text-align:center;color:#aaa;padding-top:.5em}.component-btn-group .component-settings-button{float:right;z-index:1001;margin:4px 4px 0 0}.component-form-group.col-xs-6{clear:right}li .component-btn-group .component-settings-button{z-index:1001;box-shadow:0 0 10px 1px rgba(48,113,169,.6)}li:not(:hover) .component-btn-group .component-settings-button{display:none}.formbuilder .nav-tabs{margin-bottom:0}.form-builder-panel .panel-body{padding:5px}.form-component-list{list-style:none;margin:0;padding:0}.form-component-list li{margin-bottom:10px}.btn-group-xxs>.btn,.btn-xxs,.component-btn-group .component-settings-button{padding:2px;font-size:10px;line-height:1.2em;border-radius:0;width:18px;height:18px}.ngdialog.ngdialog-theme-default.component-settings .ngdialog-content{width:65%}#component-settings .tab-pane{padding:10px}#component-settings .nav-tabs{font-size:12px}.component-settings-key{margin:-1em 1em 1em}tr[dnd-list],tr[dnd-list]>th,ul[dnd-list],ul[dnd-list]>li{position:relative}ul.component-list{min-height:42px;margin:0;padding-left:0}ul.component-list li{display:block;padding:0}.dropzone{min-height:150px;min-width:150px}.dropzone .dndDragging{opacity:.7}.dropzone .dndDraggingSource{display:none}.dropzone .dndPlaceholder{background-color:#ddd;min-height:50px;min-width:50px;position:relative}.dropzone .dndOverlay{top:0;bottom:0;left:0;right:0;z-index:99999;opacity:0}.dropzone .selected .item{color:#3c763d;background-color:#dff0d8}.dropzone .selected .box{border-color:#d6e9c6}.dropzone .selected .box>h3{color:#3c763d;background-color:#dff0d8;background-image:linear-gradient(180deg,#dff0d8 0,#d0e9c6);border-color:#d6e9c6}.dropzone .item{padding:20px}.dropzone .container-element{margin:10px}.dropzone .container-element .column{float:left;width:50%}.dropzone .component-list{padding-bottom:5px}.toolbox ul{list-style:none;padding-left:0;cursor:move}.toolbox button{margin:5px;width:123px;opacity:1}.toolbox .dndDragging{opacity:.5}.toolbox .dndDraggingSource{opacity:1}.trashcan ul{list-style:none;padding-left:0}.trashcan img{width:100%;-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%);filter:grayscale(100%)}.trashcan .dndDragover img{width:100%;-webkit-filter:none;-moz-filter:none;filter:none}.trashcan .dndPlaceholder{display:none}.ui-select-toggle.btn{text-align:left}.form-builder-component .form-field-type-container fieldset,.form-builder-component .form-field-type-editgrid fieldset,.form-builder-component .form-field-type-fieldset fieldset{padding:5px;margin-left:-5px;margin-right:-5px;border:2px dotted #e8e8e8}.form-builder-component .form-field-type-columns .formio-column{padding:10px;border:2px dotted #e8e8e8}.datagrid-dnd{padding:5px;border:2px dotted #e8e8e8;min-height:inherit}.formcomponents{overflow:auto;min-height:200px}.formcomponents .formcomponentcontainer{margin:0 2px 2px 0}.formcomponents .formcomponent{text-align:left;padding-left:15px}.form-control.formio-multiple-mask-select{width:70px;z-index:4}.form-control.formio-multiple-mask-input{width:100%;margin-left:-70px;padding-left:80px}.input-group.formio-multiple-mask-container{width:100%}.formio-drop-zone{display:none;position:absolute;z-index:10;background-color:#0d87e9;opacity:.1}.formio-drop-zone.enabled{display:inherit} -------------------------------------------------------------------------------- /gulp/eslint.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp, plugins) { 2 | return function () { 3 | return gulp.src(['src/**/*.js']) 4 | .pipe(plugins.eslint({ 5 | rules: { 6 | 'max-len': 0 7 | } 8 | })) 9 | .pipe(plugins.eslint.format()) 10 | .pipe(plugins.eslint.failAfterError()); 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /gulp/scripts-complete.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp, plugins) { 2 | return function() { 3 | var bundle = plugins.browserify({ 4 | entries: './src/ngFormBuilder-complete.js', 5 | debug: false, 6 | standalone: 'formio-builder' 7 | }); 8 | 9 | return bundle 10 | .bundle() 11 | .pipe(plugins.source('ngFormBuilder-complete.js')) 12 | .pipe(plugins.replace('<%=version%>', plugins.packageJson.version)) 13 | .pipe(plugins.derequire()) 14 | .pipe(gulp.dest('dist/')) 15 | .pipe(plugins.rename('ngFormBuilder-complete.min.js')) 16 | .pipe(plugins.streamify(plugins.uglify({output: {comments: '/^!/'}}))) 17 | .pipe(gulp.dest('dist/')) 18 | .on('error', function(err){ 19 | console.log(err); 20 | this.emit('end'); 21 | }); 22 | }; 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /gulp/scripts-full.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp, plugins) { 2 | return function() { 3 | var bundle = plugins.browserify({ 4 | entries: './src/ngFormBuilder-full.js', 5 | debug: false, 6 | standalone: 'formio-builder' 7 | }); 8 | 9 | return bundle 10 | .bundle() 11 | .pipe(plugins.source('ngFormBuilder-full.js')) 12 | .pipe(plugins.replace('<%=version%>', plugins.packageJson.version)) 13 | .pipe(plugins.derequire()) 14 | .pipe(gulp.dest('dist/')) 15 | .pipe(plugins.rename('ngFormBuilder-full.min.js')) 16 | .pipe(plugins.streamify(plugins.uglify({output: {comments: '/^!/'}}))) 17 | .pipe(gulp.dest('dist/')) 18 | .on('error', function(err){ 19 | console.log(err); 20 | this.emit('end'); 21 | }); 22 | }; 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /gulp/scripts.js: -------------------------------------------------------------------------------- 1 | var livereload = require('gulp-livereload'); 2 | 3 | module.exports = function(gulp, plugins, bundle) { 4 | return function() { 5 | bundle = bundle || plugins.browserify({ 6 | entries: './src/ngFormBuilder.js', 7 | debug: false, 8 | standalone: 'formio-builder' 9 | }); 10 | 11 | return bundle 12 | .bundle() 13 | .pipe(plugins.source('ngFormBuilder.js')) 14 | .pipe(plugins.replace('<%=version%>', plugins.packageJson.version)) 15 | .pipe(plugins.derequire()) 16 | .pipe(gulp.dest('dist/')) 17 | .pipe(plugins.rename('ngFormBuilder.min.js')) 18 | .pipe(plugins.streamify(plugins.uglify({output: {comments: '/^!/'}}))) 19 | .pipe(gulp.dest('dist/')) 20 | .pipe(livereload()) 21 | .on('error', function(err) { 22 | console.log(err); 23 | this.emit('end'); 24 | }); 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /gulp/styles-basic.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp, plugins) { 2 | return function () { 3 | return gulp.src('css/ngFormBuilder.css') 4 | .pipe(gulp.dest('dist')) 5 | .pipe(plugins.cssnano({zindex: false})) 6 | .pipe(plugins.rename('ngFormBuilder.min.css')) 7 | .pipe(gulp.dest('dist')); 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /gulp/styles-complete.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp, plugins) { 2 | return function () { 3 | return gulp.src(plugins.bowerFiles().concat('css/ngFormBuilder.css')) 4 | .pipe(plugins.filter('**/*.css')) 5 | .pipe(plugins.concat('ngFormBuilder-complete.css')) 6 | .pipe(gulp.dest('dist')) 7 | .pipe(plugins.cssnano({zindex: false})) 8 | .pipe(plugins.rename('ngFormBuilder-complete.min.css')) 9 | .pipe(gulp.dest('dist')); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /gulp/styles-full.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp, plugins) { 2 | return function () { 3 | return gulp.src(plugins.bowerFiles().concat('css/ngFormBuilder.css')) 4 | .pipe(plugins.filter('**/*.css')) 5 | .pipe(plugins.concat('ngFormBuilder-full.css')) 6 | .pipe(gulp.dest('dist')) 7 | .pipe(plugins.cssnano({zindex: false})) 8 | .pipe(plugins.rename('ngFormBuilder-full.min.css')) 9 | .pipe(gulp.dest('dist')); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var livereload = require('gulp-livereload'); 5 | 6 | module.exports = function(gulp, plugins) { 7 | return function() { 8 | var bundle = plugins.browserify({ 9 | entries: './src/ngFormBuilder.js', 10 | debug: true 11 | }); 12 | 13 | var build = require('./scripts')(gulp, plugins, bundle); 14 | livereload.listen(); 15 | bundle = plugins.watchify(bundle); 16 | bundle.on('update', function(files) { 17 | console.log('Changed files: ', files.map(path.relative.bind(path, process.cwd())).join(', ')); 18 | console.log('Rebuilding dist/ngFormBuilder.js...'); 19 | build(); 20 | }); 21 | bundle.on('log', function(msg) { 22 | console.log(msg); 23 | }); 24 | 25 | return build(); 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var plugins = require('gulp-load-plugins')(); 5 | plugins.source = require('vinyl-source-stream'); 6 | plugins.browserify = require('browserify'); 7 | plugins.watchify = require('watchify'); 8 | plugins.runSeq = require('run-sequence'); 9 | plugins.bowerFiles = require('main-bower-files'); 10 | plugins.packageJson = require('./package.json'); 11 | 12 | gulp.task('clean', require('del').bind(null, ['dist'])); 13 | gulp.task('eslint', require('./gulp/eslint')(gulp, plugins)); 14 | gulp.task('styles:basic', require('./gulp/styles-basic')(gulp, plugins)); 15 | gulp.task('styles:full', require('./gulp/styles-full')(gulp, plugins)); 16 | gulp.task('styles:complete', require('./gulp/styles-complete')(gulp, plugins)); 17 | gulp.task('styles', gulp.parallel('styles:basic', 'styles:complete', 'styles:full')); 18 | gulp.task('scripts:basic', require('./gulp/scripts')(gulp, plugins)); 19 | gulp.task('scripts:full', require('./gulp/scripts-full')(gulp, plugins)); 20 | gulp.task('scripts:complete', require('./gulp/scripts-complete')(gulp, plugins)); 21 | gulp.task('scripts', gulp.parallel('scripts:basic', 'scripts:complete', 'scripts:full')); 22 | gulp.task('build', gulp.series('clean', gulp.parallel('scripts', 'styles'))); 23 | gulp.task('watch', require('./gulp/watch')(gulp, plugins)); 24 | gulp.task('default', gulp.series('build', 'watch')); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-formio-builder", 3 | "version": "2.39.0", 4 | "description": "The Angular.js form builder component.", 5 | "main": "dist/ngFormBuilder.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:formioapp/ngFormBuilder.git" 12 | }, 13 | "author": "Travis Tidwell ", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/formioapp/ngFormBuilder/issues" 17 | }, 18 | "homepage": "https://github.com/formioapp/ngFormBuilder", 19 | "devDependencies": { 20 | "babel-core": "^6.26.3", 21 | "babel-preset-env": "^1.7.0", 22 | "babelify": "^10.0.0", 23 | "brfs": "^2.0.2", 24 | "browserify": "^16.5.0", 25 | "del": "^5.1.0", 26 | "eslint-config-formio": "^1.1.0", 27 | "gulp": "^4.0.2", 28 | "gulp-concat": "^2.6.0", 29 | "gulp-cssnano": "^2.1.3", 30 | "gulp-derequire": "^2.1.0", 31 | "gulp-eslint": "^6.0.0", 32 | "gulp-filter": "^6.0.0", 33 | "gulp-livereload": "^4.0.2", 34 | "gulp-load-plugins": "^2.0.2", 35 | "gulp-rename": "^1.4.0", 36 | "gulp-replace": "^1.0.0", 37 | "gulp-streamify": "^1.0.2", 38 | "gulp-uglify": "^3.0.2", 39 | "main-bower-files": "^2.13.3", 40 | "natives": "^1.1.6", 41 | "run-sequence": "^2.2.0", 42 | "shallow-copy": "0.0.1", 43 | "strictify": "^0.2.0", 44 | "uglifyify": "^5.0.2", 45 | "vinyl-source-stream": "^2.0.0", 46 | "watchify": "^3.11.1" 47 | }, 48 | "browserify": { 49 | "transform": [ 50 | "strictify", 51 | "brfs" 52 | ] 53 | }, 54 | "dependencies": { 55 | "angular": "^1.7.9", 56 | "angular-ckeditor-legacy": "^1.0.3", 57 | "angular-drag-and-drop-lists": "^2.1.0", 58 | "angular-ui-bootstrap": "^2.5.6", 59 | "formiojs": "^3.28.1", 60 | "lodash": "^4.17.15", 61 | "ng-dialog": "^1.4.0", 62 | "ng-formio": "^2.41.0", 63 | "ng-tags-input": "^3.2.0", 64 | "vanilla-text-mask": "^5.1.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/address.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('address', { 6 | icon: 'fa fa-home', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/address/display.html' 11 | }, 12 | { 13 | name: 'Validation', 14 | template: 'formio/components/address/validate.html' 15 | }, 16 | { 17 | name: 'API', 18 | template: 'formio/components/common/api.html' 19 | }, 20 | { 21 | name: 'Layout', 22 | template: 'formio/components/common/layout.html' 23 | }, 24 | { 25 | name: 'Conditional', 26 | template: 'formio/components/common/conditional.html' 27 | } 28 | ], 29 | documentation: 'http://help.form.io/userguide/#address' 30 | }); 31 | } 32 | ]); 33 | app.run([ 34 | '$templateCache', 35 | function($templateCache) { 36 | // Create the settings markup. 37 | $templateCache.put('formio/components/address/display.html', 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '
' + 48 | '' + 49 | '' + 50 | '
' + 51 | '
' + 52 | '' + 53 | '' + 54 | '
' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '
' 66 | ); 67 | 68 | $templateCache.put('formio/components/address/validate.html', 69 | '' + 70 | '' + 71 | '' + 72 | '' + 73 | '' 74 | ); 75 | } 76 | ]); 77 | }; 78 | -------------------------------------------------------------------------------- /src/components/button.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | 'FORM_OPTIONS', 5 | function( 6 | formioComponentsProvider, 7 | FORM_OPTIONS 8 | ) { 9 | formioComponentsProvider.register('button', { 10 | onEdit: ['$scope', function($scope) { 11 | $scope.actions = FORM_OPTIONS.actions; 12 | $scope.sizes = FORM_OPTIONS.sizes; 13 | $scope.themes = FORM_OPTIONS.themes; 14 | }], 15 | icon: 'fa fa-stop', 16 | views: [ 17 | { 18 | name: 'Display', 19 | template: 'formio/components/button/display.html' 20 | }, 21 | { 22 | name: 'API', 23 | template: 'formio/components/common/api.html' 24 | }, 25 | { 26 | name: 'Layout', 27 | template: 'formio/components/common/layout.html' 28 | }, 29 | { 30 | name: 'Conditional', 31 | template: 'formio/components/common/conditional.html' 32 | } 33 | ], 34 | documentation: 'http://help.form.io/userguide/#button' 35 | }); 36 | } 37 | ]); 38 | app.run([ 39 | '$templateCache', 40 | function($templateCache) { 41 | // Create the settings markup. 42 | $templateCache.put('formio/components/button/display.html', 43 | '' + 44 | '' + 45 | '
' + 46 | '' + 47 | '' + 48 | '
' + 49 | '
' + 50 | ' ' + 51 | ' ' + 52 | '
' + 53 | '
' + 54 | ' ' + 55 | ' ' + 56 | '
' + 57 | '
' + 58 | ' ' + 60 | ' ' + 62 | '
' + 63 | '' + 66 | '
' + 67 | ' ' + 68 | ' ' + 69 | '
' + 70 | '
' + 71 | '' + 72 | '' + 73 | '
' + 74 | '
' + 75 | '' + 76 | '' + 77 | '
' + 78 | '' + 79 | '' + 80 | '' + 81 | '' + 82 | '' + 83 | '' + 84 | '' + 85 | '' + 86 | '' + 87 | '
' 88 | ); 89 | } 90 | ]); 91 | }; 92 | -------------------------------------------------------------------------------- /src/components/checkbox.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('checkbox', { 6 | icon: 'fa fa-check-square', 7 | onEdit: ['$scope', function($scope) { 8 | $scope.inputTypes = [ 9 | { 10 | name: 'checkbox', 11 | title: 'Checkbox' 12 | }, 13 | { 14 | name: 'radio', 15 | title: 'Radio' 16 | } 17 | ]; 18 | 19 | $scope.labelPositions = [ 20 | { 21 | value: 'top', 22 | title: 'Top' 23 | }, 24 | { 25 | value: 'left', 26 | title: 'Left' 27 | }, 28 | { 29 | value: 'right', 30 | title: 'Right' 31 | }, 32 | { 33 | value: 'bottom', 34 | title: 'Bottom' 35 | } 36 | ]; 37 | 38 | if (!$scope.component.labelPosition) { 39 | $scope.component.labelPosition = 'right'; 40 | } 41 | }], 42 | views: [ 43 | { 44 | name: 'Display', 45 | template: 'formio/components/checkbox/display.html' 46 | }, 47 | { 48 | name: 'Data', 49 | template: 'formio/components/common/data.html' 50 | }, 51 | { 52 | name: 'Validation', 53 | template: 'formio/components/checkbox/validate.html' 54 | }, 55 | { 56 | name: 'API', 57 | template: 'formio/components/common/api.html' 58 | }, 59 | { 60 | name: 'Layout', 61 | template: 'formio/components/common/layout.html' 62 | }, 63 | { 64 | name: 'Conditional', 65 | template: 'formio/components/common/conditional.html' 66 | } 67 | ], 68 | documentation: 'http://help.form.io/userguide/#checkbox' 69 | }); 70 | } 71 | ]); 72 | app.run([ 73 | '$templateCache', 74 | function($templateCache) { 75 | // Create the settings markup. 76 | $templateCache.put('formio/components/checkbox/display.html', 77 | '' + 78 | '' + 79 | '' + 80 | '
' + 81 | '' + 82 | '' + 83 | '
' + 84 | '' + 85 | '' + 86 | '
' + 87 | '' + 88 | '' + 89 | '
' + 90 | '
' + 91 | ' ' + 92 | ' ' + 93 | '
' + 94 | '
' + 95 | ' ' + 96 | ' ' + 97 | '
' + 98 | '' + 99 | '' + 100 | '' + 101 | '' + 102 | '' + 103 | '' + 104 | '' + 105 | '' + 106 | '' + 107 | '' + 108 | '' + 109 | '' + 110 | '
' 111 | ); 112 | 113 | $templateCache.put('formio/components/checkbox/validate.html', 114 | '' + 115 | '' + 116 | '' + 117 | '' + 118 | '' 119 | ); 120 | } 121 | ]); 122 | }; 123 | -------------------------------------------------------------------------------- /src/components/columns.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('columns', { 6 | onEdit: ['$scope', function($scope) { 7 | $scope.removeColumn = function(index) { 8 | $scope.component.columns.splice(index, 1); 9 | }; 10 | $scope.addColumn = function() { 11 | $scope.component.columns.push({components: [], width: 1, offset: 0, push: 0, pull: 0}); 12 | }; 13 | }], 14 | fbtemplate: 'formio/formbuilder/columns.html', 15 | icon: 'fa fa-columns', 16 | documentation: 'http://help.form.io/userguide/#columns', 17 | noDndOverlay: true, 18 | confirmRemove: true, 19 | views: [ 20 | { 21 | name: 'Display', 22 | template: 'formio/components/columns/display.html' 23 | }, 24 | { 25 | name: 'API', 26 | template: 'formio/components/common/api.html' 27 | }, 28 | { 29 | name: 'Conditional', 30 | template: 'formio/components/common/conditional.html' 31 | } 32 | ] 33 | }); 34 | } 35 | ]); 36 | app.run([ 37 | '$templateCache', 38 | function($templateCache) { 39 | $templateCache.put('formio/formbuilder/columns.html', 40 | '
' + 41 | '
' + 42 | '' + 43 | '
' + 44 | '
' 45 | ); 46 | $templateCache.put('formio/components/columns/display.html', 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '
' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' + 67 | '' + 68 | '' + 69 | '' + 70 | '' + 71 | '' + 72 | '' + 73 | '' + 74 | '
{{\'Column\' | formioTranslate}}{{\'Width\' | formioTranslate}}{{\'Offset\' | formioTranslate}}{{\'Push\' | formioTranslate}}{{\'Pull\' | formioTranslate}}
' + 75 | '' + 76 | '
' + 77 | '' + 78 | '
' 79 | ); 80 | } 81 | ]); 82 | }; 83 | -------------------------------------------------------------------------------- /src/components/container.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('container', { 6 | fbtemplate: 'formio/formbuilder/container.html', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/container/display.html' 11 | }, { 12 | name: 'API', 13 | template: 'formio/components/common/api.html' 14 | }, 15 | { 16 | name: 'Conditional', 17 | template: 'formio/components/common/conditional.html' 18 | } 19 | ], 20 | documentation: 'http://help.form.io/userguide/#container', 21 | noDndOverlay: true, 22 | confirmRemove: true 23 | }); 24 | } 25 | ]); 26 | 27 | app.run([ 28 | '$templateCache', 29 | function($templateCache) { 30 | $templateCache.put('formio/components/container/display.html', 31 | '' + 32 | '' + 33 | '' + 34 | '' + 35 | '' + 36 | '' + 37 | '' + 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '' 44 | ); 45 | 46 | $templateCache.put('formio/formbuilder/container.html', 47 | '
' + 48 | '' + 52 | '' + 53 | '' + 57 | '
' 58 | ); 59 | } 60 | ]); 61 | }; 62 | -------------------------------------------------------------------------------- /src/components/content.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('content', { 6 | fbtemplate: 'formio/formbuilder/content.html', 7 | icon: 'fa fa-html5', 8 | documentation: 'http://help.form.io/userguide/#content-component', 9 | controller: function(settings, $scope) { 10 | $scope.ckeditorOptions = { 11 | allowedContent: true, 12 | toolbarGroups: [ 13 | {name: 'basicstyles', groups: ['basicstyles', 'cleanup']}, 14 | {name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi', 'paragraph', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock']}, 15 | {name: 'links', groups: ['links']}, 16 | {name: 'insert', groups: ['insert']}, 17 | '/', 18 | {name: 'styles', groups: ['Styles', 'Format', 'Font', 'FontSize']}, 19 | {name: 'colors', groups: ['colors']}, 20 | {name: 'clipboard', groups: ['clipboard', 'undo']}, 21 | {name: 'editing', groups: ['find', 'selection', 'spellchecker', 'editing']}, 22 | {name: 'document', groups: ['mode', 'document', 'doctools']}, 23 | {name: 'others', groups: ['others']}, 24 | {name: 'tools', groups: ['tools']} 25 | ], 26 | extraPlugins: 'justify,font', 27 | removeButtons: 'Cut,Copy,Paste,Underline,Subscript,Superscript,Scayt,About', 28 | uiColor: '#eeeeee', 29 | height: '400px', 30 | width: '100%' 31 | }; 32 | $scope.$watch('component.html', function() { 33 | $scope.$emit('formBuilder:update', $scope.component); 34 | }); 35 | }, 36 | views: [ 37 | { 38 | name: 'Display', 39 | template: 'formio/components/common/display.html' 40 | }, 41 | { 42 | name: 'API', 43 | template: 'formio/components/common/api.html' 44 | }, 45 | { 46 | name: 'Conditional', 47 | template: 'formio/components/common/conditional.html' 48 | } 49 | ] 50 | }); 51 | } 52 | ]); 53 | app.run([ 54 | '$templateCache', 55 | function($templateCache) { 56 | $templateCache.put('formio/formbuilder/content.html', 57 | '
' + 58 | '' + 58 | '
' + 59 | '' 60 | ); 61 | } 62 | ]); 63 | }; 64 | -------------------------------------------------------------------------------- /src/components/datagrid.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | 'FORM_OPTIONS', 5 | function( 6 | formioComponentsProvider, 7 | FORM_OPTIONS 8 | ) { 9 | formioComponentsProvider.register('datagrid', { 10 | fbtemplate: 'formio/formbuilder/datagrid.html', 11 | icon: 'fa fa-th', 12 | onEdit: ['$scope', function($scope) { 13 | $scope.themes = FORM_OPTIONS.themes; 14 | if (!$scope.component.addAnotherPosition) { 15 | $scope.component.addAnotherPosition = 'bottom'; 16 | } 17 | $scope.addAnotherPosition = [ 18 | { 19 | value: 'top', 20 | title: 'Top' 21 | }, 22 | { 23 | value: 'bottom', 24 | title: 'Bottom' 25 | }, 26 | { 27 | value: 'both', 28 | title: 'Both' 29 | } 30 | ]; 31 | }], 32 | views: [ 33 | { 34 | name: 'Display', 35 | template: 'formio/components/datagrid/display.html' 36 | }, 37 | { 38 | name: 'Validation', 39 | template: 'formio/components/datagrid/validate.html' 40 | }, 41 | { 42 | name: 'API', 43 | template: 'formio/components/common/api.html' 44 | }, 45 | { 46 | name: 'Conditional', 47 | template: 'formio/components/common/conditional.html' 48 | } 49 | ], 50 | documentation: 'http://help.form.io/userguide/#datagrid', 51 | noDndOverlay: true, 52 | confirmRemove: true 53 | }); 54 | } 55 | ]); 56 | 57 | app.run([ 58 | '$templateCache', 59 | function($templateCache) { 60 | $templateCache.put('formio/components/datagrid/display.html', 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' + 67 | '
' + 68 | '' + 69 | '' + 70 | '
' + 71 | '' + 72 | '' + 73 | '' + 74 | '' + 75 | '' + 76 | '' + 77 | '' + 78 | '' + 79 | '' + 80 | '' + 81 | '' + 82 | '' + 83 | '
' 84 | ); 85 | 86 | $templateCache.put('formio/components/datagrid/validate.html', 87 | '' + 88 | '' + 89 | '' + 90 | '' + 91 | '' + 92 | '' 93 | ); 94 | } 95 | ]); 96 | }; 97 | -------------------------------------------------------------------------------- /src/components/day.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('day', { 6 | icon: 'fa fa-calendar', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/day/display.html' 11 | }, 12 | { 13 | name: 'Data', 14 | template: 'formio/components/common/data.html' 15 | }, 16 | { 17 | name: 'Validation', 18 | template: 'formio/components/day/validate.html' 19 | }, 20 | { 21 | name: 'API', 22 | template: 'formio/components/common/api.html' 23 | }, 24 | { 25 | name: 'Layout', 26 | template: 'formio/components/common/layout.html' 27 | }, 28 | { 29 | name: 'Conditional', 30 | template: 'formio/components/common/conditional.html' 31 | } 32 | ], 33 | documentation: 'http://help.form.io/userguide/#day' 34 | }); 35 | } 36 | ]); 37 | app.run([ 38 | '$templateCache', 39 | function($templateCache) { 40 | // Create the settings markup. 41 | $templateCache.put('formio/components/day/display.html', 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' + 67 | '' + 68 | '' 69 | ); 70 | 71 | $templateCache.put('formio/components/day/validate.html', 72 | '' + 73 | '' + 74 | '' + 75 | '' + 76 | '' + 77 | '' + 78 | '' 79 | ); 80 | } 81 | ]); 82 | }; 83 | -------------------------------------------------------------------------------- /src/components/editgrid.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('editgrid', { 6 | fbtemplate: 'formio/formbuilder/editgrid.html', 7 | icon: 'fa fa-tasks', 8 | views: [ 9 | { 10 | name: 'Display', 11 | template: 'formio/components/editgrid/display.html' 12 | }, 13 | { 14 | name: 'Templates', 15 | template: 'formio/components/editgrid/templates.html' 16 | }, 17 | { 18 | name: 'Validation', 19 | template: 'formio/components/editgrid/validate.html' 20 | }, 21 | { 22 | name: 'API', 23 | template: 'formio/components/common/api.html' 24 | }, 25 | { 26 | name: 'Conditional', 27 | template: 'formio/components/common/conditional.html' 28 | } 29 | ], 30 | documentation: 'http://help.form.io/userguide/#editgrid', 31 | noDndOverlay: true, 32 | confirmRemove: true 33 | }); 34 | } 35 | ]); 36 | 37 | app.run([ 38 | '$templateCache', 39 | function($templateCache) { 40 | $templateCache.put('formio/components/editgrid/display.html', 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' 53 | ); 54 | 55 | $templateCache.put('formio/components/editgrid/templates.html', 56 | '' + 57 | '
' + 58 | ' ' + 59 | ' ' + 60 | '

Two available variables. "value" is the array of row data and "components" is the array of components in the grid.

' + 61 | '
' + 62 | '
' + 63 | ' ' + 64 | ' ' + 65 | '

Two available variables. "row" is an object of one row\'s data and "components" is the array of components in the grid. To add click events, add the classes "editRow" and "removeRow" to elements.

' + 66 | '
' + 67 | '
' + 68 | ' ' + 69 | ' ' + 70 | '

Two available variables. "value" is the array of row data and "components" is the array of components in the grid.

' + 71 | '
' + 72 | '' + 73 | '' + 74 | '' + 75 | '' + 76 | '' + 77 | '
' 78 | ); 79 | 80 | $templateCache.put('formio/components/editgrid/validate.html', 81 | '' + 82 | ' ' + 83 | ' ' + 84 | ' ' + 85 | '

Normal validation does not run when a row is in "View" mode. This validation allows running custom view validation and returning an error per row.

' + 86 | '

You must assign the valid variable as either true or an error message if validation fails.

' + 87 | '

The variables row, component, and valid are provided.

' + 88 | '
' + 89 | ' ' + 90 | ' ' + 91 | '
' 92 | ); 93 | 94 | $templateCache.put('formio/formbuilder/editgrid.html', 95 | '
' + 96 | '' + 100 | '' + 101 | '
' 102 | ); 103 | 104 | } 105 | ]); 106 | }; 107 | -------------------------------------------------------------------------------- /src/components/email.js: -------------------------------------------------------------------------------- 1 | var _cloneDeep = require('lodash/cloneDeep'); 2 | var _each = require('lodash/each'); 3 | module.exports = function(app) { 4 | app.config([ 5 | 'formioComponentsProvider', 6 | function(formioComponentsProvider) { 7 | var views = _cloneDeep(formioComponentsProvider.$get().components.textfield.views); 8 | _each(views, function(view) { 9 | if (view.name === 'Validation') { 10 | view.template = 'formio/components/email/validate.html'; 11 | } 12 | }); 13 | formioComponentsProvider.register('email', { 14 | icon: 'fa fa-at', 15 | views: views, 16 | documentation: 'http://help.form.io/userguide/#email' 17 | }); 18 | } 19 | ]); 20 | app.run([ 21 | '$templateCache', 22 | function($templateCache) { 23 | $templateCache.put('formio/components/email/validate.html', 24 | '' + 25 | '' + 26 | '' + 27 | '
' + 28 | '

{{\'Kickbox\' | formioTranslate}}

' + 29 | '
' + 30 | '

{{\'Validate this email using the Kickbox email validation service.\' | formioTranslate}}

' + 31 | '
' + 32 | '' + 35 | '
' + 36 | '
' + 37 | '
' + 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '
' 44 | ); 45 | } 46 | ]); 47 | }; 48 | -------------------------------------------------------------------------------- /src/components/fieldset.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('fieldset', { 6 | fbtemplate: 'formio/formbuilder/fieldset.html', 7 | icon: 'fa fa-th-large', 8 | views: [ 9 | { 10 | name: 'Display', 11 | template: 'formio/components/fieldset/display.html' 12 | }, 13 | { 14 | name: 'Layout', 15 | template: 'formio/components/common/layout.html' 16 | }, 17 | { 18 | name: 'API', 19 | template: 'formio/components/common/api.html' 20 | }, 21 | { 22 | name: 'Conditional', 23 | template: 'formio/components/common/conditional.html' 24 | } 25 | ], 26 | documentation: 'http://help.form.io/userguide/#fieldset', 27 | keepChildrenOnRemove: true, 28 | noDndOverlay: true, 29 | confirmRemove: true 30 | }); 31 | } 32 | ]); 33 | app.run([ 34 | '$templateCache', 35 | function($templateCache) { 36 | $templateCache.put('formio/formbuilder/fieldset.html', 37 | '
' + 38 | '' + 39 | '{{ component.legend }} ' + 40 | '' + 41 | '' + 42 | '' + 43 | '
' 44 | ); 45 | 46 | // Create the settings markup. 47 | $templateCache.put('formio/components/fieldset/display.html', 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' 57 | ); 58 | } 59 | ]); 60 | }; 61 | -------------------------------------------------------------------------------- /src/components/file.js: -------------------------------------------------------------------------------- 1 | var _map = require('lodash/map'); 2 | module.exports = function(app) { 3 | app.config([ 4 | 'formioComponentsProvider', 5 | function( 6 | formioComponentsProvider 7 | ) { 8 | formioComponentsProvider.register('file', { 9 | onEdit: [ 10 | '$scope', 11 | 'Formio', 12 | function($scope, Formio) { 13 | // Pull out title and name from the list of storage plugins. 14 | $scope.storage = _map(Formio.providers.storage, function(storage, key) { 15 | return { 16 | title: storage.title, 17 | name: key 18 | }; 19 | }); 20 | } 21 | ], 22 | icon: 'fa fa-file', 23 | views: [ 24 | { 25 | name: 'Display', 26 | template: 'formio/components/file/display.html' 27 | }, 28 | { 29 | name: 'Validation', 30 | template: 'formio/components/file/validate.html' 31 | }, 32 | { 33 | name: 'API', 34 | template: 'formio/components/common/api.html' 35 | }, 36 | { 37 | name: 'Layout', 38 | template: 'formio/components/common/layout.html' 39 | }, 40 | { 41 | name: 'Conditional', 42 | template: 'formio/components/common/conditional.html' 43 | } 44 | ], 45 | documentation: 'http://help.form.io/userguide/#file' 46 | }); 47 | } 48 | ]); 49 | app.run([ 50 | '$templateCache', 51 | function($templateCache) { 52 | // Create the settings markup. 53 | $templateCache.put('formio/components/file/display.html', 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '
' + 60 | '' + 61 | '' + 62 | '
' + 63 | '' + 64 | '' + 65 | '' + 66 | '' + 67 | '' + 68 | '' + 69 | '' + 70 | '' + 71 | '' + 72 | '' + 73 | '' + 74 | '' + 75 | '' + 76 | '' + 77 | '' + 78 | '' + 79 | '' + 80 | '' + 81 | '
' 82 | ); 83 | 84 | $templateCache.put('formio/components/file/validate.html', 85 | '' + 86 | '' + 87 | '' + 88 | '' + 89 | '' + 90 | '' 91 | ); 92 | } 93 | ]); 94 | }; 95 | -------------------------------------------------------------------------------- /src/components/form.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('form', { 6 | fbtemplate: 'formio/formbuilder/form.html', 7 | icon: 'fa fa-wpforms', 8 | views: [ 9 | { 10 | name: 'Display', 11 | template: 'formio/components/form/display.html' 12 | }, 13 | { 14 | name: 'Data', 15 | template: 'formio/components/common/data.html' 16 | }, 17 | { 18 | name: 'API', 19 | template: 'formio/components/common/api.html' 20 | }, 21 | { 22 | name: 'Conditional', 23 | template: 'formio/components/common/conditional.html' 24 | } 25 | ], 26 | documentation: 'http://help.form.io/userguide/#form', 27 | onEdit: ['$scope', function($scope) { 28 | $scope.forms = []; 29 | $scope.component.project = $scope.formio.projectId; 30 | $scope.formio.loadForms({params: { 31 | limit: 4294967295, 32 | select: '_id,title,type' 33 | }}).then(function(forms) { 34 | var data = []; 35 | if ($scope.form._id) { 36 | angular.forEach(forms, function(form) { 37 | if (form._id !== $scope.form._id) { 38 | data.push(form); 39 | } 40 | }); 41 | $scope.forms = data; 42 | } 43 | else { 44 | $scope.forms = forms; 45 | } 46 | 47 | if (!$scope.component.form) { 48 | $scope.component.form = forms[0]._id; 49 | } 50 | }); 51 | }] 52 | }); 53 | 54 | // Override the controller for form building. 55 | var formComponent = formioComponentsProvider.$get().components.form; 56 | var formController = formComponent.controller; 57 | formComponent.controller = [ 58 | '$scope', 59 | '$controller', 60 | function( 61 | $scope, 62 | $controller 63 | ) { 64 | if (!$scope.builder) { 65 | return $controller(formController, {$scope: $scope}); 66 | } 67 | 68 | var forms = {}; 69 | $scope.form = {title: 'Unknown form'}; 70 | $scope.formio.loadForms({params: { 71 | limit: 4294967295, 72 | select: '_id,title,type' 73 | }}).then(function(formioForms) { 74 | angular.forEach(formioForms, function(form) { 75 | forms[form._id] = form; 76 | }); 77 | 78 | if ( 79 | $scope.component.form && 80 | ($scope.form._id !== $scope.component.form) && 81 | forms.hasOwnProperty($scope.component.form) 82 | ) { 83 | $scope.form = forms[$scope.component.form]; 84 | } 85 | }); 86 | 87 | $scope.$watch('component.form', function(formId) { 88 | if (!formId || !forms.hasOwnProperty(formId)) { 89 | return; 90 | } 91 | $scope.form = forms[formId]; 92 | }); 93 | } 94 | ]; 95 | } 96 | ]); 97 | app.run([ 98 | '$templateCache', 99 | function($templateCache) { 100 | $templateCache.put('formio/formbuilder/form.html', '{{ form.title }} {{ form.type }}'); 101 | 102 | // Create the settings markup. 103 | $templateCache.put('formio/components/form/display.html', 104 | '' + 105 | '' + 106 | '' + 107 | '' + 108 | '
' + 109 | '' + 110 | '' + 111 | '
' + 112 | '' + 113 | '' + 114 | '' + 115 | '' + 116 | '' + 117 | '' + 118 | '' + 119 | '
' 120 | ); 121 | } 122 | ]); 123 | }; 124 | -------------------------------------------------------------------------------- /src/components/hidden.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('hidden', { 6 | fbtemplate: 'formio/formbuilder/hidden.html', 7 | icon: 'fa fa-user-secret', 8 | views: [ 9 | { 10 | name: 'Display', 11 | template: 'formio/components/hidden/display.html' 12 | }, 13 | { 14 | name: 'Data', 15 | template: 'formio/components/common/data.html' 16 | }, 17 | { 18 | name: 'Validation', 19 | template: 'formio/components/hidden/validation.html' 20 | }, 21 | { 22 | name: 'API', 23 | template: 'formio/components/common/api.html' 24 | }, 25 | { 26 | name: 'Conditional', 27 | template: 'formio/components/common/conditional.html' 28 | } 29 | ], 30 | documentation: 'http://help.form.io/userguide/#hidden' 31 | }); 32 | } 33 | ]); 34 | app.run([ 35 | '$templateCache', 36 | function($templateCache) { 37 | $templateCache.put('formio/formbuilder/hidden.html', '{{ component.label }}'); 38 | 39 | // Create the settings markup. 40 | $templateCache.put('formio/components/hidden/display.html', 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' 49 | ); 50 | 51 | $templateCache.put('formio/components/hidden/validation.html', 52 | '' + 53 | '' + 54 | '' 55 | ); 56 | } 57 | ]); 58 | }; 59 | -------------------------------------------------------------------------------- /src/components/htmlelement.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('htmlelement', { 6 | fbtemplate: 'formio/formbuilder/htmlelement.html', 7 | icon: 'fa fa-code', 8 | views: [ 9 | { 10 | name: 'Display', 11 | template: 'formio/components/htmlelement/display.html' 12 | }, 13 | { 14 | name: 'API', 15 | template: 'formio/components/common/api.html' 16 | }, 17 | { 18 | name: 'Conditional', 19 | template: 'formio/components/common/conditional.html' 20 | } 21 | ], 22 | documentation: 'http://help.form.io/userguide/#html-element-component' 23 | }); 24 | } 25 | ]); 26 | app.run([ 27 | '$templateCache', 28 | function($templateCache) { 29 | $templateCache.put('formio/formbuilder/htmlelement.html', 30 | '

{{ \'HTML Element with no content\' | formioTranslate }}

' 31 | ); 32 | 33 | // Create the settings markup. 34 | $templateCache.put('formio/components/htmlelement/display.html', 35 | '' + 36 | '' + 37 | '' + 38 | '' + 39 | '' + 40 | '' + 41 | '' + 51 | '
' + 52 | '' + 53 | '' + 54 | '
' + 55 | '
' 56 | ); 57 | } 58 | ]); 59 | }; 60 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | var app = angular.module('ngFormBuilder'); 2 | 3 | // Basic 4 | require('./components')(app); 5 | require('./textfield')(app); 6 | require('./number')(app); 7 | require('./password')(app); 8 | require('./textarea')(app); 9 | require('./checkbox')(app); 10 | require('./selectboxes')(app); 11 | require('./select')(app); 12 | require('./radio')(app); 13 | require('./htmlelement')(app); 14 | require('./content')(app); 15 | require('./button')(app); 16 | 17 | // Special 18 | require('./email')(app); 19 | require('./phonenumber')(app); 20 | require('./address')(app); 21 | require('./datetime')(app); 22 | require('./day')(app); 23 | require('./time')(app); 24 | require('./currency')(app); 25 | require('./hidden')(app); 26 | require('./resource')(app); 27 | require('./file')(app); 28 | require('./form')(app); 29 | require('./signature')(app); 30 | require('./custom')(app); 31 | require('./datagrid')(app); 32 | require('./editgrid')(app); 33 | require('./survey')(app); 34 | 35 | // Layout 36 | require('./columns')(app); 37 | require('./fieldset')(app); 38 | require('./container')(app); 39 | require('./page')(app); 40 | require('./panel')(app); 41 | require('./table')(app); 42 | require('./well')(app); 43 | -------------------------------------------------------------------------------- /src/components/page.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('page', { 6 | fbtemplate: 'formio/formbuilder/page.html' 7 | }); 8 | } 9 | ]); 10 | app.run([ 11 | '$templateCache', 12 | function($templateCache) { 13 | $templateCache.put('formio/formbuilder/page.html', 14 | '' 15 | ); 16 | } 17 | ]); 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/panel.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | 'FORM_OPTIONS', 5 | function( 6 | formioComponentsProvider, 7 | FORM_OPTIONS 8 | ) { 9 | formioComponentsProvider.register('panel', { 10 | fbtemplate: 'formio/formbuilder/panel.html', 11 | icon: 'fa fa-list-alt', 12 | onEdit: ['$scope', function($scope) { 13 | $scope.themes = FORM_OPTIONS.themes; 14 | if (!$scope.component.breadcrumb) { 15 | $scope.component.breadcrumb = 'default'; 16 | } 17 | $scope.breadcrumbs = [ 18 | { 19 | name: 'default', 20 | title: 'Yes' 21 | }, 22 | { 23 | name: 'none', 24 | title: 'No' 25 | } 26 | ]; 27 | }], 28 | views: [ 29 | { 30 | name: 'Display', 31 | template: 'formio/components/panel/display.html' 32 | }, 33 | { 34 | name: 'Layout', 35 | template: 'formio/components/common/layout.html' 36 | }, 37 | { 38 | name: 'API', 39 | template: 'formio/components/common/api.html' 40 | }, 41 | { 42 | name: 'Conditional', 43 | template: 'formio/components/panel/conditional.html' 44 | } 45 | ], 46 | documentation: 'http://help.form.io/userguide/#panels', 47 | noDndOverlay: true, 48 | confirmRemove: true 49 | }); 50 | } 51 | ]); 52 | app.run([ 53 | '$templateCache', 54 | function($templateCache) { 55 | $templateCache.put('formio/formbuilder/panel.html', 56 | '
' + 57 | '

' + 58 | '{{ component.title }} ' + 59 | '' + 60 | '

' + 61 | '
' + 62 | '' + 63 | '
' + 64 | '
' 65 | ); 66 | 67 | // Create the settings markup. 68 | $templateCache.put('formio/components/panel/display.html', 69 | '' + 70 | '' + 71 | '' + 72 | '
' + 73 | '' + 74 | '' + 75 | '
' + 76 | '
' + 77 | '' + 78 | '' + 79 | '
' + 80 | '' + 81 | '' + 82 | '' + 83 | '' + 84 | '' + 85 | '
' 86 | ); 87 | 88 | $templateCache.put('formio/components/panel/conditional.html', 89 | '' + 90 | '' + 91 | '
' + 92 | '' + 93 | '' + 94 | '

Enter custom conditional code.

' + 95 | '

You must assign the next variable with the API key of the next page.

' + 96 | '

The global variable data is provided, and allows you to access the data of any form component, by using its API key.

' + 97 | '

Also moment library is available, and allows you to manipulate dates in a convenient way.

' + 98 | '
' + 99 | '
' + 100 | '
' + 101 | '' + 102 | '

Execute custom next page with JSON and JsonLogic.

' + 103 | '

Submission data is available as JsonLogic variables, with the same api key as your components.

' + 104 | '

Click here for an example

' + 105 | '
' + 106 | '' + 107 | '
' + 108 | '
' 109 | ); 110 | } 111 | ]); 112 | }; 113 | -------------------------------------------------------------------------------- /src/components/password.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('password', { 6 | icon: 'fa fa-asterisk', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/password/display.html' 11 | }, 12 | { 13 | name: 'Validation', 14 | template: 'formio/components/textfield/validate.html' 15 | }, 16 | { 17 | name: 'API', 18 | template: 'formio/components/common/api.html' 19 | }, 20 | { 21 | name: 'Layout', 22 | template: 'formio/components/common/layout.html' 23 | }, 24 | { 25 | name: 'Conditional', 26 | template: 'formio/components/common/conditional.html' 27 | } 28 | ], 29 | documentation: 'http://help.form.io/userguide/#password', 30 | template: 'formio/components/password.html' 31 | }); 32 | } 33 | ]); 34 | app.run([ 35 | '$templateCache', 36 | function( 37 | $templateCache 38 | ) { 39 | // Disable dragging on password inputs because it breaks dndLists 40 | var textFieldTmpl = $templateCache.get('formio/components/textfield.html'); 41 | var passwordTmpl = textFieldTmpl.replace( 42 | /' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' + 67 | '' + 68 | '' + 69 | '' 70 | ); 71 | } 72 | ]); 73 | }; 74 | -------------------------------------------------------------------------------- /src/components/phonenumber.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('phoneNumber', { 6 | icon: 'fa fa-phone-square', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/phoneNumber/display.html' 11 | }, 12 | { 13 | name: 'Data', 14 | template: 'formio/components/textfield/data.html' 15 | }, 16 | { 17 | name: 'Validation', 18 | template: 'formio/components/phoneNumber/validate.html' 19 | }, 20 | { 21 | name: 'API', 22 | template: 'formio/components/common/api.html' 23 | }, 24 | { 25 | name: 'Layout', 26 | template: 'formio/components/common/layout.html' 27 | }, 28 | { 29 | name: 'Conditional', 30 | template: 'formio/components/common/conditional.html' 31 | } 32 | ], 33 | documentation: 'http://help.form.io/userguide/#phonenumber' 34 | }); 35 | } 36 | ]); 37 | app.run([ 38 | '$templateCache', 39 | function($templateCache) { 40 | // Create the settings markup. 41 | $templateCache.put('formio/components/phoneNumber/display.html', 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' + 67 | '' 68 | ); 69 | 70 | // Create the Validation markup. 71 | $templateCache.put('formio/components/phoneNumber/validate.html', 72 | '' + 73 | '' + 74 | '' + 75 | '' + 76 | '' 77 | ); 78 | } 79 | ]); 80 | }; 81 | -------------------------------------------------------------------------------- /src/components/radio.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('radio', { 6 | icon: 'fa fa-dot-circle-o', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/radio/display.html' 11 | }, 12 | { 13 | name: 'Data', 14 | template: 'formio/components/common/data.html' 15 | }, 16 | { 17 | name: 'Validation', 18 | template: 'formio/components/radio/validate.html' 19 | }, 20 | { 21 | name: 'API', 22 | template: 'formio/components/common/api.html' 23 | }, 24 | { 25 | name: 'Layout', 26 | template: 'formio/components/common/layout.html' 27 | }, 28 | { 29 | name: 'Conditional', 30 | template: 'formio/components/common/conditional.html' 31 | } 32 | ], 33 | documentation: 'http://help.form.io/userguide/#radio' 34 | }); 35 | } 36 | ]); 37 | app.run([ 38 | '$templateCache', 39 | function($templateCache) { 40 | // Create the settings markup. 41 | $templateCache.put('formio/components/radio/display.html', 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' 65 | ); 66 | // Create the API markup. 67 | $templateCache.put('formio/components/radio/validate.html', 68 | '' + 69 | '' + 70 | '' + 71 | '' + 72 | '' 73 | ); 74 | } 75 | ]); 76 | }; 77 | -------------------------------------------------------------------------------- /src/components/resource.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('resource', { 6 | onEdit: ['$scope', function($scope) { 7 | $scope.resources = []; 8 | $scope.component.project = $scope.formio.projectId; 9 | $scope.formio.loadForms({params: { 10 | type: 'resource', 11 | limit: 4294967295, 12 | select: '_id,title' 13 | }}).then(function(resources) { 14 | $scope.resources = resources; 15 | if (!$scope.component.resource) { 16 | $scope.component.resource = resources[0]._id; 17 | } 18 | }); 19 | }], 20 | icon: 'fa fa-files-o', 21 | views: [ 22 | { 23 | name: 'Display', 24 | template: 'formio/components/resource/display.html' 25 | }, 26 | { 27 | name: 'Validation', 28 | template: 'formio/components/resource/validate.html' 29 | }, 30 | { 31 | name: 'API', 32 | template: 'formio/components/common/api.html' 33 | }, 34 | { 35 | name: 'Layout', 36 | template: 'formio/components/common/layout.html' 37 | }, 38 | { 39 | name: 'Conditional', 40 | template: 'formio/components/common/conditional.html' 41 | } 42 | ], 43 | documentation: 'http://help.form.io/userguide/#resource' 44 | }); 45 | } 46 | ]); 47 | app.run([ 48 | '$templateCache', 49 | function($templateCache) { 50 | // Create the settings markup. 51 | $templateCache.put('formio/components/resource/display.html', 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '
' + 59 | '' + 60 | '' + 61 | '
' + 62 | '
' + 63 | '' + 64 | '' + 65 | '
' + 66 | '
' + 67 | '' + 68 | '' + 69 | '
' + 70 | '
' + 71 | '' + 72 | '' + 73 | '
' + 74 | '' + 75 | '' + 76 | '' + 77 | '' + 78 | '' + 79 | '' + 80 | '' + 81 | '' + 82 | '' + 83 | '' + 84 | '' + 85 | '' + 86 | '' + 87 | '' + 88 | '' + 89 | '
' 90 | ); 91 | 92 | // Create the API markup. 93 | $templateCache.put('formio/components/resource/validate.html', 94 | '' + 95 | '' + 96 | '' + 97 | '' 98 | ); 99 | } 100 | ]); 101 | }; 102 | -------------------------------------------------------------------------------- /src/components/selectboxes.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('selectboxes', { 6 | icon: 'fa fa-plus-square', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/selectboxes/display.html' 11 | }, 12 | { 13 | name: 'Validation', 14 | template: 'formio/components/selectboxes/validate.html' 15 | }, 16 | { 17 | name: 'API', 18 | template: 'formio/components/selectboxes/api.html' 19 | }, 20 | { 21 | name: 'Layout', 22 | template: 'formio/components/common/layout.html' 23 | }, 24 | { 25 | name: 'Conditional', 26 | template: 'formio/components/common/conditional.html' 27 | } 28 | ], 29 | documentation: 'http://help.form.io/userguide/#selectboxes' 30 | }); 31 | } 32 | ]); 33 | app.run([ 34 | '$templateCache', 35 | function($templateCache) { 36 | // Create the settings markup. 37 | $templateCache.put('formio/components/selectboxes/display.html', 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' + 59 | '' 60 | ); 61 | 62 | // Create the API markup. 63 | $templateCache.put('formio/components/selectboxes/api.html', 64 | '' + 65 | '' + 66 | '' + 67 | '
' + 68 | '' + 69 | '
' + 70 | '
' + 71 | '
' 72 | ); 73 | 74 | // Create the API markup. 75 | $templateCache.put('formio/components/selectboxes/validate.html', 76 | '' + 77 | '' + 78 | '' + 79 | '' + 80 | '' 81 | ); 82 | } 83 | ]); 84 | }; 85 | -------------------------------------------------------------------------------- /src/components/signature.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('signature', { 6 | icon: 'fa fa-pencil', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/signature/display.html' 11 | }, 12 | { 13 | name: 'Validation', 14 | template: 'formio/components/signature/validate.html' 15 | }, 16 | { 17 | name: 'API', 18 | template: 'formio/components/common/api.html' 19 | }, 20 | { 21 | name: 'Layout', 22 | template: 'formio/components/common/layout.html' 23 | }, 24 | { 25 | name: 'Conditional', 26 | template: 'formio/components/common/conditional.html' 27 | } 28 | ], 29 | documentation: 'http://help.form.io/userguide/#signature' 30 | }); 31 | } 32 | ]); 33 | app.run([ 34 | '$templateCache', 35 | function($templateCache) { 36 | // Create the settings markup. 37 | $templateCache.put('formio/components/signature/display.html', 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' 54 | ); 55 | 56 | // Create the Validation markup. 57 | $templateCache.put('formio/components/signature/validate.html', 58 | '' + 59 | '' + 60 | '' + 61 | '' 62 | ); 63 | } 64 | ]); 65 | }; 66 | -------------------------------------------------------------------------------- /src/components/survey.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('survey', { 6 | icon: 'fa fa-list', 7 | views: [ 8 | { 9 | name: 'Display', 10 | template: 'formio/components/survey/display.html' 11 | }, 12 | { 13 | name: 'Validation', 14 | template: 'formio/components/survey/validate.html' 15 | }, 16 | { 17 | name: 'API', 18 | template: 'formio/components/common/api.html' 19 | }, 20 | { 21 | name: 'Layout', 22 | template: 'formio/components/common/layout.html' 23 | }, 24 | { 25 | name: 'Conditional', 26 | template: 'formio/components/common/conditional.html' 27 | } 28 | ], 29 | documentation: 'http://help.form.io/userguide/#survey' 30 | }); 31 | } 32 | ]); 33 | app.run([ 34 | '$templateCache', 35 | function($templateCache) { 36 | // Create the settings markup. 37 | $templateCache.put('formio/components/survey/display.html', 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 48 | '' + 49 | '' + 50 | '' + 51 | '' + 52 | '' + 53 | '' + 54 | '' + 55 | '' + 56 | '' + 57 | '' + 58 | '' 59 | ); 60 | // Create the API markup. 61 | $templateCache.put('formio/components/survey/validate.html', 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' 67 | ); 68 | } 69 | ]); 70 | }; 71 | -------------------------------------------------------------------------------- /src/components/table.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('table', { 6 | fbtemplate: 'formio/formbuilder/table.html', 7 | documentation: 'http://help.form.io/userguide/#table', 8 | noDndOverlay: true, 9 | confirmRemove: true, 10 | icon: 'fa fa-table', 11 | views: [ 12 | { 13 | name: 'Display', 14 | template: 'formio/components/table/display.html' 15 | }, 16 | { 17 | name: 'Layout', 18 | template: 'formio/components/common/layout.html' 19 | }, 20 | { 21 | name: 'API', 22 | template: 'formio/components/common/api.html' 23 | }, 24 | { 25 | name: 'Conditional', 26 | template: 'formio/components/common/conditional.html' 27 | } 28 | ] 29 | }); 30 | } 31 | ]); 32 | app.run([ 33 | '$templateCache', 34 | function($templateCache) { 35 | var tableClasses = "{'table-striped': component.striped, "; 36 | tableClasses += "'table-bordered': component.bordered, "; 37 | tableClasses += "'table-hover': component.hover, "; 38 | tableClasses += "'table-condensed': component.condensed}"; 39 | $templateCache.put('formio/formbuilder/table.html', 40 | '
' + 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' + 47 | '' + 50 | '' + 51 | '' + 52 | '
{{ header }}
' + 48 | '' + 49 | '
' + 53 | '
' 54 | ); 55 | 56 | $templateCache.put('formio/components/table/display.html', 57 | '' + 58 | '' + 59 | '' + 60 | '' + 61 | '' + 62 | '' + 63 | '' + 64 | '' + 65 | '' + 66 | '' 67 | ); 68 | } 69 | ]); 70 | }; 71 | -------------------------------------------------------------------------------- /src/components/time.js: -------------------------------------------------------------------------------- 1 | var _cloneDeep = require('lodash/cloneDeep'); 2 | var _each = require('lodash/each'); 3 | 4 | module.exports = function(app) { 5 | app.config([ 6 | 'formioComponentsProvider', 7 | function(formioComponentsProvider) { 8 | var views = _cloneDeep(formioComponentsProvider.$get().components.textfield.views); 9 | _each(views, function(view) { 10 | if (view.name === 'Display') { 11 | view.template = 'formio/components/time/display.html'; 12 | } 13 | }); 14 | formioComponentsProvider.register('time', { 15 | icon: 'fa fa-clock-o', 16 | views: views, 17 | documentation: 'http://help.form.io/userguide/#time' 18 | }); 19 | } 20 | ]); 21 | app.run([ 22 | '$templateCache', 23 | function($templateCache) { 24 | $templateCache.put('formio/components/time/display.html', 25 | '' + 26 | '' + 27 | '' + 28 | '' + 29 | '' + 30 | '' + 31 | '' + 32 | '' + 33 | '' + 34 | '' + 35 | '' + 36 | '' + 37 | '' + 38 | '' + 39 | '' + 40 | '' + 41 | '' + 42 | '' + 43 | '' + 44 | '' + 45 | '' + 46 | '' 47 | ); 48 | } 49 | ]); 50 | }; 51 | -------------------------------------------------------------------------------- /src/components/well.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | app.config([ 3 | 'formioComponentsProvider', 4 | function(formioComponentsProvider) { 5 | formioComponentsProvider.register('well', { 6 | fbtemplate: 'formio/formbuilder/well.html', 7 | icon: 'fa fa-square-o', 8 | documentation: 'http://help.form.io/userguide/#well', 9 | noDndOverlay: true, 10 | confirmRemove: true, 11 | views: [ 12 | { 13 | name: 'Display', 14 | template: 'formio/components/well/display.html' 15 | }, 16 | { 17 | name: 'API', 18 | template: 'formio/components/common/api.html' 19 | }, 20 | { 21 | name: 'Conditional', 22 | template: 'formio/components/common/conditional.html' 23 | } 24 | ] 25 | }); 26 | } 27 | ]); 28 | app.run([ 29 | '$templateCache', 30 | function($templateCache) { 31 | $templateCache.put('formio/formbuilder/well.html', 32 | '
' + 33 | '' + 34 | '
' 35 | ); 36 | $templateCache.put('formio/components/well/display.html', 37 | '' + 38 | '' + 39 | '' + 40 | '' + 41 | '' 42 | ); 43 | } 44 | ]); 45 | }; 46 | -------------------------------------------------------------------------------- /src/constants/formOptions.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | actions: [ 3 | { 4 | name: 'submit', 5 | title: 'Submit' 6 | }, 7 | { 8 | name: 'saveState', 9 | title: 'Save in state' 10 | }, 11 | { 12 | name: 'event', 13 | title: 'Event' 14 | }, 15 | { 16 | name: 'custom', 17 | title: 'Custom' 18 | }, 19 | { 20 | name: 'reset', 21 | title: 'Reset' 22 | }, 23 | { 24 | name: 'delete', 25 | title: 'Delete' 26 | }, 27 | { 28 | name: 'url', 29 | title: 'POST to URL' 30 | }, 31 | { 32 | name: 'oauth', 33 | title: 'OAuth' 34 | } 35 | ], 36 | themes: [ 37 | { 38 | name: 'default', 39 | title: 'Default' 40 | }, 41 | { 42 | name: 'primary', 43 | title: 'Primary' 44 | }, 45 | { 46 | name: 'info', 47 | title: 'Info' 48 | }, 49 | { 50 | name: 'success', 51 | title: 'Success' 52 | }, 53 | { 54 | name: 'danger', 55 | title: 'Danger' 56 | }, 57 | { 58 | name: 'warning', 59 | title: 'Warning' 60 | } 61 | ], 62 | sizes: [ 63 | { 64 | name: 'xs', 65 | title: 'Extra Small' 66 | }, 67 | { 68 | name: 'sm', 69 | title: 'Small' 70 | }, 71 | { 72 | name: 'md', 73 | title: 'Medium' 74 | }, 75 | { 76 | name: 'lg', 77 | title: 'Large' 78 | } 79 | ] 80 | }; 81 | -------------------------------------------------------------------------------- /src/directives/formBuilderComponent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create the form-builder-component directive. 3 | * Extend the formio-component directive and change the template. 4 | */ 5 | module.exports = [ 6 | 'formioComponentDirective', 7 | function(formioComponentDirective) { 8 | return angular.extend({}, formioComponentDirective[0], { 9 | scope: false, 10 | templateUrl: 'formio/formbuilder/component.html' 11 | }); 12 | } 13 | ]; 14 | -------------------------------------------------------------------------------- /src/directives/formBuilderConditional.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var utils = require('formiojs/utils').default; 3 | var _get = require('lodash/get'); 4 | var _reject = require('lodash/reject'); 5 | module.exports = [ 6 | function() { 7 | return { 8 | restrict: 'E', 9 | scope: true, 10 | template: '' + 11 | '' + 12 | '
' + 13 | 'This component should Display:' + 14 | '' + 17 | '
When the form component:' + 18 | '' + 21 | '
Has the value:' + 22 | '' + 23 | '
' + 24 | '
' + 25 | '' + 26 | '' + 27 | '

Enter custom conditional code.

' + 28 | '

You must assign the show variable as either true or false.

' + 29 | '

The global variable data is provided, and allows you to access the data of any form component, by using its API key.

' + 30 | '

Also moment library is available, and allows you to manipulate dates in a convenient way.

' + 31 | '

Note: Advanced Conditional logic will override the results of the Simple Conditional logic.

' + 32 | '
' + 33 | '
' + 34 | '
' + 35 | '' + 36 | '

Execute custom validation logic with JSON and JsonLogic.

' + 37 | '

Submission data is available as JsonLogic variables, with the same api key as your components.

' + 38 | '

Click here for an example

' + 39 | '
' + 40 | '' + 41 | '
' + 42 | '
', 43 | controller: [ 44 | '$scope', 45 | function( 46 | $scope) { 47 | // Default the current components conditional logic. 48 | $scope.component = $scope.component || {}; 49 | $scope.component.conditional = $scope.component.conditional || {}; 50 | 51 | // The available logic functions. 52 | $scope._booleans = ['', 'true', 'false']; 53 | 54 | // Filter the list of available form components for conditional logic. 55 | $scope._components = _get($scope, 'form.components') || []; 56 | $scope._components = utils.flattenComponents($scope._components); 57 | // Remove non-input/button fields because they don't make sense. 58 | // FA-890 - Dont allow the current component to be a conditional trigger. 59 | $scope._components = _reject($scope._components, function(c) { 60 | return !c.input || (c.type === 'button') || (c.key === $scope.component.key) || (!c.label && !c.key); 61 | }); 62 | 63 | // Add default item to the components list. 64 | $scope._components.unshift(''); 65 | 66 | // Default and watch the show logic. 67 | $scope.component.conditional.show = $scope.component.conditional.show || ''; 68 | // Coerce show var to supported value. 69 | var _booleanMap = { 70 | '': '', 71 | 'true': 'true', 72 | 'false': 'false' 73 | }; 74 | $scope.component.conditional.show = _booleanMap.hasOwnProperty($scope.component.conditional.show) 75 | ? _booleanMap[$scope.component.conditional.show] 76 | : ''; 77 | 78 | // Default and watch the when logic. 79 | $scope.component.conditional.when = $scope.component.conditional.when || null; 80 | 81 | // Default and watch the search logic. 82 | $scope.component.conditional.eq = $scope.component.conditional.eq || ''; 83 | 84 | // Track the status of the accordion panels open state. 85 | $scope.status = { 86 | simple: !$scope.component.customConditional, 87 | advanced: !!$scope.component.customConditional 88 | }; 89 | } 90 | ] 91 | }; 92 | } 93 | ]; 94 | -------------------------------------------------------------------------------- /src/directives/formBuilderElement.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'formioElementDirective', 3 | function(formioElementDirective) { 4 | return angular.extend({}, formioElementDirective[0], { 5 | scope: false, 6 | controller: [ 7 | '$scope', 8 | 'formioComponents', 9 | function( 10 | $scope, 11 | formioComponents 12 | ) { 13 | $scope.builder = true; 14 | $scope.formComponent = formioComponents.components[$scope.component.type] || formioComponents.components.custom; 15 | if ($scope.formComponent.fbtemplate) { 16 | $scope.template = $scope.formComponent.fbtemplate; 17 | } 18 | } 19 | ] 20 | }); 21 | } 22 | ]; 23 | -------------------------------------------------------------------------------- /src/directives/formBuilderList.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | function() { 3 | return { 4 | scope: { 5 | component: '=', 6 | formio: '=', 7 | form: '=', 8 | parent: '=?', 9 | path: '=?', 10 | // # of items needed in the list before hiding the 11 | // drag and drop prompt div 12 | hideDndBoxCount: '=', 13 | rootList: '=', 14 | options: '=', 15 | data:'=?' 16 | }, 17 | restrict: 'E', 18 | replace: true, 19 | controller: 'formBuilderDnd', 20 | templateUrl: 'formio/formbuilder/list.html' 21 | }; 22 | } 23 | ]; 24 | -------------------------------------------------------------------------------- /src/directives/formBuilderOption.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This directive creates a field for tweaking component options. 3 | * This needs at least a property attribute specifying what property 4 | * of the component to bind to. 5 | * 6 | * If the property is defined in COMMON_OPTIONS above, it will automatically 7 | * populate its label, placeholder, input type, and tooltip. If not, you may specify 8 | * those via attributes (except for tooltip, which you can specify with the title attribute). 9 | * The generated input will also carry over any other properties you specify on this directive. 10 | */ 11 | module.exports = ['COMMON_OPTIONS', '$filter', function(COMMON_OPTIONS, $filter) { 12 | return { 13 | restrict: 'E', 14 | require: 'property', 15 | priority: 2, 16 | replace: true, 17 | template: function(el, attrs) { 18 | var formioTranslate = $filter('formioTranslate'); 19 | 20 | var property = attrs.property; 21 | var label = attrs.label || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].label); 22 | var placeholder = attrs.placeholder || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].placeholder) || null; 23 | var type = attrs.type || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].type) || 'text'; 24 | var tooltip = attrs.tooltip || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].tooltip) || ''; 25 | var step = attrs.step || (COMMON_OPTIONS[property] && COMMON_OPTIONS[property].step) || ''; 26 | 27 | var input = type === 'textarea' ? angular.element('') : angular.element(''); 28 | 29 | var inputAttrs = { 30 | id: property, 31 | name: property, 32 | type: type, 33 | 'ng-model': 'component.' + property, 34 | placeholder: formioTranslate(placeholder) 35 | }; 36 | 37 | if (step) { 38 | inputAttrs.step = step; 39 | } 40 | 41 | // Pass through attributes from the directive to the input element 42 | angular.forEach(attrs.$attr, function(key) { 43 | inputAttrs[key] = attrs[attrs.$normalize(key)]; 44 | // Allow specifying tooltip via title attr 45 | if (key.toLowerCase() === 'title') { 46 | tooltip = attrs[key]; 47 | } 48 | }); 49 | 50 | if(property === 'label') { 51 | inputAttrs['label-validator'] = ""; 52 | inputAttrs.required = ""; 53 | inputAttrs.autofocus = true; 54 | } 55 | // Add min/max value floor values for validation. 56 | if (property === 'validate.minLength' || property === 'validate.maxLength') { 57 | inputAttrs.min = 0; 58 | } 59 | 60 | input.attr(inputAttrs); 61 | 62 | // Checkboxes have a slightly different layout 63 | if (inputAttrs.type && inputAttrs.type.toLowerCase() === 'checkbox') { 64 | return '
' + 65 | '' + 68 | '
'; 69 | } 70 | 71 | var helpMessage = ''; 72 | switch (property) { 73 | case 'label': 74 | helpMessage = 'You must provide a label for this component.'; 75 | break; 76 | default: 77 | break; 78 | } 79 | 80 | input.addClass('form-control'); 81 | return '
' + 82 | '
' + 83 | input.prop('outerHTML') + 84 | helpMessage + 85 | '
'; 86 | } 87 | }; 88 | }]; 89 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionCustomValidation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for editing a component's custom validation. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: '' + 9 | '
' + 10 | '' + 11 | '
' + 12 | ' ' + 13 | ' ' + 14 | '

Enter custom validation code.

' + 15 | '

You must assign the valid variable as either true or an error message if validation fails.

' + 16 | '

The global variables input, component, and valid are provided.

' + 17 | '
' + 18 | '
' + 19 | '
' + 20 | ' ' + 23 | '
' + 24 | '

Check this if you wish to perform the validation ONLY on the server side. This keeps your validation logic private and secret.

' + 25 | '
' + 26 | '
' + 27 | '
' + 28 | ' ' + 29 | '

Execute custom validation logic with JSON and JsonLogic.

' + 30 | '

Submission data is available as JsonLogic variables, with the same api key as your components.

' + 31 | '

Click here for an example

' + 32 | '
' + 33 | ' ' + 34 | '
' + 35 | '
' + 36 | '
' 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionInputFormat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component input format. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: function() { 9 | return '
' + 10 | '' + 11 | '' + 12 | '
'; 13 | }, 14 | controller: ['$scope', function($scope) { 15 | $scope.formats = [ 16 | { 17 | value: 'plain', 18 | title: 'Plain' 19 | }, 20 | { 21 | value: 'html', 22 | title: 'HTML' 23 | }, 24 | { 25 | value: 'raw', 26 | title: 'Raw (Insecure)' 27 | } 28 | ]; 29 | 30 | if (!$scope.component.inputFormat) { 31 | if ($scope.component.type === 'textarea') { 32 | $scope.$watch('component.wysiwyg', function(wysiwyg) { 33 | $scope.component.inputFormat = wysiwyg ? 'html' : 'plain'; 34 | }); 35 | } 36 | 37 | $scope.component.inputFormat = 'plain'; 38 | } 39 | }] 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionInputsLabelPosition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component inputs' label position. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: function() { 9 | return '
' + 10 | '' + 11 | '' + 12 | '
'; 13 | }, 14 | controller: ['$scope', function($scope) { 15 | $scope.inputsLabelPosition = [ 16 | { 17 | value: 'top', 18 | title: 'Top' 19 | }, 20 | { 21 | value: 'left', 22 | title: 'Left' 23 | }, 24 | { 25 | value: 'right', 26 | title: 'Right' 27 | }, 28 | { 29 | value: 'bottom', 30 | title: 'Bottom' 31 | } 32 | ]; 33 | 34 | if (!$scope.component.inputsLabelPosition) { 35 | $scope.component.inputsLabelPosition = 'top'; 36 | } 37 | }] 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionKey.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component's key. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: function() { 9 | return '
' + 10 | '' + 13 | '' + 14 | '' + 16 | '

' + 17 | 'Using a dot in your Property Name will link this field to a field from a Resource. Doing this manually is not recommended because you will experience unexpected behavior if the Resource field is not found. If you wish to embed a Resource field in your form, use a component from the corresponding Resource Components category on the left.' + 18 | '

' + 19 | '
'; 20 | }, 21 | controller: ['$scope', 'BuilderUtils', function($scope, BuilderUtils) { 22 | BuilderUtils.uniquify($scope.form, $scope.component); 23 | 24 | $scope.onBlur = function() { 25 | $scope.component.lockKey = true; 26 | 27 | // If they try to input an empty key, refill it with default and let uniquify make it unique. 28 | if (!$scope.component.key && $scope.formComponents[$scope.component.type].settings.key) { 29 | $scope.component.key = $scope.formComponents[$scope.component.type].settings.key; 30 | $scope.component.lockKey = false; // Also unlock key 31 | BuilderUtils.uniquify($scope.form, $scope.component); 32 | } 33 | }; 34 | 35 | $scope.shouldWarnAboutEmbedding = function() { 36 | if (!$scope.component || !$scope.component.key) { 37 | return false; 38 | } 39 | return !$scope.component.source && $scope.component.key.indexOf('.') !== -1; 40 | }; 41 | }] 42 | }; 43 | }; 44 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionLabelPosition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component's label position. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: function() { 9 | return '
' + 10 | '
' + 11 | '' + 12 | '' + 13 | '
' + 14 | '
' + 15 | ' ' + 16 | ' ' + 17 | '
' + 18 | '
' + 19 | ' ' + 20 | ' ' + 21 | '
' + 22 | '
'; 23 | }, 24 | controller: ['$scope', function($scope) { 25 | $scope.labelPositions = [ 26 | { 27 | value: 'top', 28 | title: 'Top' 29 | }, 30 | { 31 | value: 'left-left', 32 | title: 'Left (Left-aligned)' 33 | }, 34 | { 35 | value: 'left-right', 36 | title: 'Left (Right-aligned)' 37 | }, 38 | { 39 | value: 'right-left', 40 | title: 'Right (Left-aligned)' 41 | }, 42 | { 43 | value: 'right-right', 44 | title: 'Right (Right-aligned)' 45 | }, 46 | { 47 | value: 'bottom', 48 | title: 'Bottom' 49 | } 50 | ]; 51 | 52 | $scope.labelAtTheTopOrBottom = function() { 53 | return ['top', 'bottom'].indexOf($scope.component.labelPosition) === -1; 54 | }; 55 | 56 | if (!$scope.component.labelPosition) { 57 | $scope.component.labelPosition = 'top'; 58 | } 59 | }] 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionOptionsLabelPosition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component options' label position. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: function() { 9 | return '
' + 10 | '' + 11 | '' + 12 | '
'; 13 | }, 14 | controller: ['$scope', function($scope) { 15 | $scope.optionsLabelPositions = [ 16 | { 17 | value: 'top', 18 | title: 'Top' 19 | }, 20 | { 21 | value: 'left', 22 | title: 'Left' 23 | }, 24 | { 25 | value: 'right', 26 | title: 'Right' 27 | }, 28 | { 29 | value: 'bottom', 30 | title: 'Bottom' 31 | } 32 | ]; 33 | 34 | if (!$scope.component.optionsLabelPosition) { 35 | $scope.component.optionsLabelPosition = 'right'; 36 | } 37 | }] 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionShortcut.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component's shortcut. 3 | */ 4 | module.exports = function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | template: function() { 9 | return '' + 10 | '
' + 11 | ' ' + 12 | ' ' + 13 | '
'; 14 | }, 15 | controller: ['$scope', 'BuilderUtils', function($scope, BuilderUtils) { 16 | $scope.shortcuts = BuilderUtils.getAvailableShortcuts($scope.form, $scope.component); 17 | }] 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /src/directives/formBuilderOptionTags.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a field to edit a component's tags. 3 | */ 4 | var _map = require('lodash/map'); 5 | module.exports = function() { 6 | return { 7 | restrict: 'E', 8 | replace: true, 9 | template: function() { 10 | return '' + 11 | '
' + 12 | ' ' + 13 | ' ' + 14 | '
'; 15 | }, 16 | controller: ['$scope', function($scope) { 17 | $scope.component.tags = $scope.component.tags || []; 18 | $scope.tags = _map($scope.component.tags, function(tag) { 19 | return {text: tag}; 20 | }); 21 | 22 | $scope.addTag = function(tag) { 23 | if (!$scope.component) { 24 | return; 25 | } 26 | if (!$scope.component.tags) { 27 | $scope.component.tags = []; 28 | } 29 | $scope.component.tags.push(tag.text); 30 | }; 31 | $scope.removeTag = function(tag) { 32 | if ($scope.component.tags && $scope.component.tags.length) { 33 | var tagIndex = $scope.component.tags.indexOf(tag.text); 34 | if (tagIndex !== -1) { 35 | $scope.component.tags.splice(tagIndex, 1); 36 | } 37 | } 38 | }; 39 | }] 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/directives/formBuilderRow.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | function() { 3 | return { 4 | scope: { 5 | component: '=', 6 | formio: '=', 7 | form: '=', 8 | // # of items needed in the list before hiding the 9 | // drag and drop prompt div 10 | hideDndBoxCount: '=', 11 | options: '=' 12 | }, 13 | restrict: 'E', 14 | replace: true, 15 | controller: 'formBuilderDnd', 16 | templateUrl: 'formio/formbuilder/row.html' 17 | }; 18 | } 19 | ]; 20 | -------------------------------------------------------------------------------- /src/directives/formBuilderTable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for a table builder 3 | */ 4 | var _merge = require('lodash/merge'); 5 | module.exports = function() { 6 | return { 7 | restrict: 'E', 8 | replace: true, 9 | template: function() { 10 | return '
' + 11 | '
' + 12 | ' ' + 13 | ' ' + 14 | '
' + 15 | '
' + 16 | ' ' + 17 | ' ' + 18 | '
' + 19 | '
'; 20 | }, 21 | controller: [ 22 | '$scope', 23 | function($scope) { 24 | $scope.builder = true; 25 | var changeTable = function() { 26 | /*eslint-disable max-depth */ 27 | if ($scope.component.numRows && $scope.component.numCols) { 28 | var tmpTable = []; 29 | $scope.component.rows.splice($scope.component.numRows); 30 | for (var row = 0; row < $scope.component.numRows; row++) { 31 | if ($scope.component.rows[row]) { 32 | $scope.component.rows[row].splice($scope.component.numCols); 33 | } 34 | for (var col = 0; col < $scope.component.numCols; col++) { 35 | if (!tmpTable[row]) { 36 | tmpTable[row] = []; 37 | } 38 | tmpTable[row][col] = {components:[]}; 39 | } 40 | } 41 | $scope.component.rows = _merge(tmpTable, $scope.component.rows); 42 | /*eslint-enable max-depth */ 43 | } 44 | }; 45 | 46 | $scope.$watch('component.numRows', changeTable); 47 | $scope.$watch('component.numCols', changeTable); 48 | } 49 | ] 50 | }; 51 | }; 52 | -------------------------------------------------------------------------------- /src/directives/formBuilderTooltip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invokes Bootstrap's popover jquery plugin on an element 3 | * Tooltip text can be provided via title attribute or 4 | * as the value for this directive. 5 | */ 6 | module.exports = ['$filter', function($filter) { 7 | return { 8 | restrict: 'A', 9 | replace: false, 10 | link: function($scope, el, attrs) { 11 | var formioTranslate = $filter('formioTranslate'); 12 | 13 | if (attrs.formBuilderTooltip || attrs.title) { 14 | var tooltip = el; 15 | if (attrs.popoverAppend !== 'false') { 16 | tooltip = angular.element(''); 17 | el.append(' ').append(tooltip); 18 | } 19 | tooltip.popover({ 20 | html: true, 21 | trigger: 'manual', 22 | placement: attrs.popoverPlacement || 'right', 23 | content: formioTranslate(attrs.title || attrs.formBuilderTooltip) 24 | }).on('mouseenter', function() { 25 | var $self = angular.element(this); 26 | $self.popover('show'); 27 | $self.siblings('.popover').on('mouseleave', function() { 28 | $self.popover('hide'); 29 | }); 30 | }).on('mouseleave', function() { 31 | var $self = angular.element(this); 32 | setTimeout(function() { 33 | if (!angular.element('.popover:hover').length) { 34 | $self.popover('hide'); 35 | } 36 | }, 100); 37 | }); 38 | el.append(' ').append(tooltip); 39 | } 40 | } 41 | }; 42 | }]; 43 | -------------------------------------------------------------------------------- /src/directives/headersBuilder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive that provides a UI to add {value, label} objects to an array. 3 | */ 4 | var _map = require('lodash/map'); 5 | var _camelCase = require('lodash/camelCase'); 6 | module.exports = function() { 7 | return { 8 | scope: { 9 | data: '=', 10 | label: '@', 11 | tooltipText: '@', 12 | valueLabel: '@', 13 | labelHeader: '@', 14 | valueProperty: '@', 15 | headerProperty: '@' 16 | }, 17 | restrict: 'E', 18 | template: '
' + 19 | '' + 20 | '' + 21 | '' + 22 | '' + 23 | '' + 24 | '' + 25 | '' + 26 | '' + 27 | '' + 28 | '' + 29 | '' + 30 | '' + 31 | '' + 32 | '' + 33 | '' + 34 | '' + 35 | '
{{ labelHeader | formioTranslate }}{{ valueLabel | formioTranslate }}
' + 36 | '' + 39 | '
', 40 | replace: true, 41 | link: function($scope, el, attrs) { 42 | $scope.valueProperty = $scope.valueProperty || 'value'; 43 | $scope.headerProperty = $scope.headerProperty || 'header'; 44 | $scope.valueLabel = $scope.valueLabel || 'Value'; 45 | $scope.labelHeader = $scope.labelHeader || 'Header'; 46 | $scope.data = $scope.data || []; 47 | 48 | $scope.addValue = function() { 49 | var obj = {}; 50 | obj[$scope.valueProperty] = ''; 51 | obj[$scope.headerProperty] = ''; 52 | $scope.data.push(obj); 53 | }; 54 | 55 | $scope.removeValue = function(index) { 56 | $scope.data.splice(index, 1); 57 | }; 58 | } 59 | }; 60 | }; 61 | -------------------------------------------------------------------------------- /src/directives/jsonInput.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return { 3 | restrict: 'A', 4 | require: 'ngModel', 5 | link: function(scope, elem, attr, ctrl) { 6 | ctrl.$parsers.push(function(input) { 7 | try { 8 | var obj = JSON.parse(input); 9 | ctrl.$setValidity('jsonInput', true); 10 | return obj; 11 | } 12 | catch (e) { 13 | ctrl.$setValidity('jsonInput', false); 14 | return undefined; 15 | } 16 | }); 17 | ctrl.$formatters.push(function(data) { 18 | if (data === null) { 19 | ctrl.$setValidity('jsonInput', false); 20 | return ''; 21 | } 22 | try { 23 | var str = angular.toJson(data, true); 24 | ctrl.$setValidity('jsonInput', true); 25 | return str; 26 | } 27 | catch (e) { 28 | ctrl.$setValidity('jsonInput', false); 29 | return ''; 30 | } 31 | }); 32 | } 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /src/directives/labelValidator.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | restrict: 'A', 4 | require: 'ngModel', 5 | link: function (scope, element, attrs, ctrl) { 6 | 7 | scope.$watch('component.label', function () { 8 | if(ctrl.$invalid) { 9 | element[0].parentNode.classList.add('has-warning'); 10 | ctrl.$validate(); 11 | } 12 | else { 13 | element[0].parentNode.classList.remove('has-warning'); 14 | ctrl.$validate(); 15 | } 16 | }, true); 17 | 18 | } 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/directives/multiMaskInput.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive that provides a UI for multiple masks input. 3 | */ 4 | module.exports = ['COMMON_OPTIONS', function (COMMON_OPTIONS) { 5 | return { 6 | scope: { 7 | component: '=', 8 | property: '@' 9 | }, 10 | restrict: 'E', 11 | template: '
' + 12 | '' + 13 | '
' + 14 | '' + 15 | '' + 16 | '
' + 17 | '
', 18 | replace: true, 19 | link: function ($scope, el, attrs) { 20 | if (!$scope.property) { 21 | return; 22 | } 23 | $scope.label = (COMMON_OPTIONS[$scope.property] && COMMON_OPTIONS[$scope.property].label) || ''; 24 | $scope.tooltip = (COMMON_OPTIONS[$scope.property] && COMMON_OPTIONS[$scope.property].tooltip) || ''; 25 | if ($scope.property) { 26 | $scope.component[$scope.property] = {}; 27 | } 28 | $scope.$watch('mask', function (newMask) { 29 | $scope.component[$scope.property].maskName = newMask.label || undefined; 30 | $scope.component.inputMask = newMask.mask || undefined; 31 | }); 32 | 33 | $scope.$watch('value', function (newValue) { 34 | $scope.component[$scope.property].value = newValue; 35 | }); 36 | } 37 | }; 38 | }]; 39 | -------------------------------------------------------------------------------- /src/directives/objectBuilder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive that provides a UI to add key-value pair object. 3 | */ 4 | module.exports = function() { 5 | return { 6 | scope: { 7 | data: '=', 8 | label: '@', 9 | tooltipText: '@' 10 | }, 11 | restrict: 'E', 12 | template: '
' + 13 | '' + 14 | '' + 15 | '' + 16 | '' + 17 | '' + 18 | '' + 19 | '' + 20 | '' + 21 | '' + 22 | '' + 23 | '' + 24 | '' + 25 | '' + 26 | '' + 27 | '' + 28 | '' + 29 | '
{{ "Key" | formioTranslate }}{{ "Value" | formioTranslate }}
' + 30 | '' + 31 | '
', 32 | replace: true, 33 | link: function($scope) { 34 | init(); 35 | 36 | $scope.addValue = function() { 37 | $scope.dataArray.push({key: '', value: ''}); 38 | }; 39 | 40 | $scope.removeValue = function(index) { 41 | $scope.dataArray.splice(index, 1); 42 | }; 43 | 44 | if ($scope.dataArray.length === 0) { 45 | $scope.addValue(); 46 | } 47 | 48 | $scope.$watch('data', init); 49 | 50 | $scope.$watch('dataArray', function(newValue) { 51 | $scope.data = {}; 52 | for (var i in newValue) { 53 | var item = newValue[i]; 54 | $scope.data[item.key] = item.value; 55 | } 56 | }, true); 57 | 58 | function init() { 59 | $scope.data = $scope.data || {}; 60 | $scope.dataArray = []; 61 | for (var key in $scope.data) { 62 | $scope.dataArray.push({ 63 | key: key, 64 | value: $scope.data[key] 65 | }); 66 | } 67 | } 68 | } 69 | }; 70 | }; 71 | -------------------------------------------------------------------------------- /src/directives/textMask.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive for an input mask for default value. 3 | */ 4 | var maskInput = require('vanilla-text-mask').default; 5 | var formioUtils = require('formiojs/utils').default; 6 | module.exports = function() { 7 | return { 8 | restrict: 'A', 9 | replace: true, 10 | link: function(scope, element) { 11 | var input = null; 12 | 13 | if (element[0].tagName === 'INPUT') { 14 | // `textMask` directive is used directly on an input element 15 | input = element[0]; 16 | } 17 | else { 18 | // `textMask` directive is used on an abstracted input element 19 | input = element[0].getElementsByTagName('INPUT')[0]; 20 | } 21 | 22 | var maskedElement = null; 23 | 24 | scope.$watch('component.inputMask', function(mask) { 25 | if (!mask) { 26 | return; 27 | } 28 | 29 | var inputMask = formioUtils.getInputMask(mask); 30 | // var defaultValue = scope.component.defaultValue; 31 | 32 | if (maskedElement) { 33 | maskedElement.destroy(); 34 | } 35 | 36 | maskedElement = maskInput({ 37 | inputElement: input, 38 | mask: inputMask, 39 | showMask: true, 40 | keepCharPositions: false, 41 | guide: true, 42 | placeholderChar: '_' 43 | }); 44 | }); 45 | } 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /src/directives/validApiKey.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Prevents user inputting invalid api key characters. 3 | * Valid characters for an api key are alphanumeric and hyphens 4 | */ 5 | module.exports = function() { 6 | return { 7 | require: 'ngModel', 8 | link: function(scope, element, attrs, ngModel) { 9 | var invalidRegex = /[^\w\.-]/g; 10 | ngModel.$parsers.push(function(inputValue) { 11 | var transformedInput = inputValue.replace(invalidRegex, ''); 12 | if (transformedInput !== inputValue) { 13 | ngModel.$setViewValue(transformedInput); 14 | ngModel.$render(); 15 | } 16 | return transformedInput; 17 | }); 18 | } 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /src/directives/valueBuilder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive that provides a UI to add {value, label} objects to an array. 3 | */ 4 | var _map = require('lodash/map'); 5 | var _camelCase = require('lodash/camelCase'); 6 | module.exports = function() { 7 | return { 8 | scope: { 9 | data: '=', 10 | label: '@', 11 | tooltipText: '@', 12 | valueLabel: '@', 13 | labelLabel: '@', 14 | valueProperty: '@', 15 | labelProperty: '@' 16 | }, 17 | restrict: 'E', 18 | template: '
' + 19 | '' + 20 | '' + 21 | '' + 22 | '' + 23 | '' + 24 | '' + 25 | '' + 26 | '' + 27 | '' + 28 | '' + 29 | '' + 30 | '' + 31 | '' + 32 | '' + 33 | '' + 34 | '' + 35 | '
{{ labelLabel | formioTranslate }}{{ valueLabel | formioTranslate }}
' + 36 | '' + 37 | '
', 38 | replace: true, 39 | link: function($scope, el, attrs) { 40 | $scope.valueProperty = $scope.valueProperty || 'value'; 41 | $scope.labelProperty = $scope.labelProperty || 'label'; 42 | $scope.valueLabel = $scope.valueLabel || 'Value'; 43 | $scope.labelLabel = $scope.labelLabel || 'Label'; 44 | $scope.data = $scope.data || []; 45 | 46 | $scope.addValue = function() { 47 | var obj = {}; 48 | obj[$scope.valueProperty] = ''; 49 | obj[$scope.labelProperty] = ''; 50 | $scope.data.push(obj); 51 | }; 52 | 53 | $scope.removeValue = function(index) { 54 | $scope.data.splice(index, 1); 55 | }; 56 | 57 | if ($scope.data.length === 0) { 58 | $scope.addValue(); 59 | } 60 | 61 | if (!attrs.noAutocompleteValue) { 62 | $scope.$watch('data', function(newValue, oldValue) { 63 | // Ignore array addition/deletion changes 64 | if (newValue.length !== oldValue.length) { 65 | return; 66 | } 67 | 68 | _map(newValue, function(entry, i) { 69 | if (entry[$scope.labelProperty] !== oldValue[i][$scope.labelProperty]) {// label changed 70 | if (entry[$scope.valueProperty] === '' || entry[$scope.valueProperty] === _camelCase(oldValue[i][$scope.labelProperty])) { 71 | entry[$scope.valueProperty] = _camelCase(entry[$scope.labelProperty]); 72 | } 73 | } 74 | }); 75 | }, true); 76 | } 77 | } 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /src/directives/valueBuilderWithShortcuts.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A directive that provides a UI to add {value, label} objects to an array. 3 | */ 4 | var _difference = require('lodash/difference'); 5 | var _without = require('lodash/without'); 6 | var _map = require('lodash/map'); 7 | var _camelCase = require('lodash/camelCase'); 8 | module.exports = ['BuilderUtils', function(BuilderUtils) { 9 | return { 10 | scope: { 11 | form: '=', 12 | component: '=', 13 | data: '=', 14 | label: '@', 15 | tooltipText: '@', 16 | valueLabel: '@', 17 | labelLabel: '@', 18 | valueProperty: '@', 19 | labelProperty: '@' 20 | }, 21 | restrict: 'E', 22 | template: '
' + 23 | '' + 24 | '' + 25 | '' + 26 | '' + 27 | '' + 28 | '' + 29 | '' + 30 | '' + 31 | '' + 32 | '' + 33 | '' + 34 | '' + 35 | '' + 36 | '' + 37 | '' + 38 | '' + 39 | '' + 40 | '' + 41 | '
{{ labelLabel | formioTranslate }}{{ valueLabel | formioTranslate }}{{ \'Shortcut\' | formioTranslate }}
' + 42 | '' + 43 | '
', 44 | replace: true, 45 | link: function($scope, el, attrs) { 46 | $scope.valueProperty = $scope.valueProperty || 'value'; 47 | $scope.labelProperty = $scope.labelProperty || 'label'; 48 | $scope.valueLabel = $scope.valueLabel || 'Value'; 49 | $scope.labelLabel = $scope.labelLabel || 'Label'; 50 | 51 | var shortcuts = BuilderUtils.getAvailableShortcuts($scope.form, $scope.component); 52 | $scope.shortcuts = []; 53 | 54 | $scope.data = $scope.data || []; 55 | 56 | if ($scope.data.length) { 57 | updateShortcuts($scope.data); 58 | } 59 | 60 | $scope.addValue = function() { 61 | var obj = {}; 62 | obj[$scope.valueProperty] = ''; 63 | obj[$scope.labelProperty] = ''; 64 | obj.shortcut = ''; 65 | $scope.data.push(obj); 66 | }; 67 | 68 | $scope.removeValue = function(index) { 69 | $scope.data.splice(index, 1); 70 | }; 71 | 72 | if ($scope.data.length === 0) { 73 | $scope.addValue(); 74 | } 75 | 76 | if (!attrs.noAutocompleteValue) { 77 | $scope.$watch('data', function(newValue, oldValue) { 78 | if (newValue.length !== oldValue.length) { 79 | updateShortcuts(newValue); 80 | return; 81 | } 82 | 83 | var shortcutChanged = false; 84 | _map(newValue, function(entry, i) { 85 | var oldEntry = oldValue[i]; 86 | 87 | if (entry.shortcut !== oldEntry.shortcut) { 88 | shortcutChanged = true; 89 | } 90 | 91 | if (entry[$scope.labelProperty] !== oldEntry[$scope.labelProperty]) {// label changed 92 | if (entry[$scope.valueProperty] === '' || entry[$scope.valueProperty] === _camelCase(oldEntry[$scope.labelProperty])) { 93 | entry[$scope.valueProperty] = _camelCase(entry[$scope.labelProperty]); 94 | } 95 | } 96 | }); 97 | 98 | if (shortcutChanged) { 99 | updateShortcuts(newValue); 100 | } 101 | }, true); 102 | } 103 | 104 | function updateShortcuts(entries) { 105 | var bindedShortcuts = []; 106 | entries.forEach(function(entry) { 107 | if (entry.shortcut) { 108 | bindedShortcuts.push(entry.shortcut); 109 | } 110 | }); 111 | $scope.shortcuts = entries.map(function(entry) { 112 | var shortcutsToOmit = _without(bindedShortcuts, entry.shortcut); 113 | return _difference(shortcuts, shortcutsToOmit); 114 | }); 115 | } 116 | } 117 | }; 118 | } 119 | ]; 120 | -------------------------------------------------------------------------------- /src/factories/BuilderUtils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _range = require('lodash/range'); 4 | var _difference = require('lodash/difference'); 5 | 6 | module.exports = ['FormioUtils', function(FormioUtils) { 7 | var suffixRegex = /(\d+)$/; 8 | 9 | /** 10 | * Memoize the given form components in a map, using the component keys. 11 | * 12 | * @param {Array} components 13 | * An array of the form components. 14 | * @param {Object} input 15 | * The input component we're trying to uniquify. 16 | * 17 | * @returns {Object} 18 | * The memoized form components. 19 | */ 20 | var findExistingComponents = function(components, input) { 21 | // Prebuild a list of existing components. 22 | var existingComponents = {}; 23 | FormioUtils.eachComponent(components, function(component) { 24 | // If theres no key, we cant compare components. 25 | if (!component.key) return; 26 | 27 | // A component is pre-existing if the key is unique, or the key is a duplicate and its not flagged as the new component. 28 | if ( 29 | (component.key !== input.key) || 30 | ((component.key === input.key) && (!!component.isNew !== !!input.isNew)) 31 | ) { 32 | existingComponents[component.key] = component; 33 | } 34 | }, true); 35 | 36 | return existingComponents; 37 | }; 38 | 39 | /** 40 | * Determine if the given component key already exists in the memoization. 41 | * 42 | * @param {Object} memoization 43 | * The form components map. 44 | * @param component 45 | * The component to uniquify. 46 | * 47 | * @returns {boolean} 48 | * Whether or not the key exists. 49 | */ 50 | var keyExists = function(memoization, key) { 51 | if (memoization.hasOwnProperty(key)) { 52 | return true; 53 | } 54 | return false; 55 | }; 56 | 57 | /** 58 | * Iterate the given key to make it unique. 59 | * 60 | * @param {String} key 61 | * Modify the component key to be unique. 62 | * 63 | * @returns {String} 64 | * The new component key. 65 | */ 66 | var iterateKey = function(key) { 67 | if (!key.match(suffixRegex)) { 68 | return key + '2'; 69 | } 70 | 71 | return key.replace(suffixRegex, function(suffix) { 72 | return Number(suffix) + 1; 73 | }); 74 | }; 75 | 76 | /** 77 | * Appends a number to a component.key to keep it unique 78 | * 79 | * @param {Object} form 80 | * The components parent form. 81 | * @param {Object} component 82 | * The component to uniquify 83 | */ 84 | var uniquify = function(form, component) { 85 | var isNew = component.isNew || false; 86 | 87 | // Recurse into all child components. 88 | FormioUtils.eachComponent([component], function(component) { 89 | // Force the component isNew to be the same as the parent. 90 | component.isNew = isNew; 91 | 92 | // Skip key uniquification if this component doesn't have a key. 93 | if (!component.key) { 94 | return; 95 | } 96 | 97 | var memoization = findExistingComponents(form.components, component); 98 | while (keyExists(memoization, component.key)) { 99 | component.key = iterateKey(component.key); 100 | } 101 | }, true); 102 | 103 | return component; 104 | }; 105 | 106 | function getAlphaShortcuts() { 107 | return _range('A'.charCodeAt(), 'Z'.charCodeAt() + 1).map(function(charCode) { 108 | return String.fromCharCode(charCode); 109 | }); 110 | } 111 | 112 | var additionalShortcuts = { 113 | button: [ 114 | 'Enter', 115 | 'Esc' 116 | ] 117 | } 118 | 119 | function getAdditionalShortcuts(type) { 120 | return additionalShortcuts[type] || []; 121 | } 122 | 123 | function getBindedShortcuts(components, input) { 124 | var result = []; 125 | 126 | FormioUtils.eachComponent(components, function(component) { 127 | if (component === input) { 128 | return; 129 | } 130 | 131 | if (component.shortcut) { 132 | result.push(component.shortcut); 133 | } 134 | if (component.values) { 135 | component.values.forEach(function(value) { 136 | if (value.shortcut) { 137 | result.push(value.shortcut); 138 | } 139 | }); 140 | } 141 | }, true); 142 | 143 | return result; 144 | } 145 | 146 | function getAvailableShortcuts(form, component) { 147 | return _difference( 148 | getAlphaShortcuts().concat(getAdditionalShortcuts(component.type)), 149 | getBindedShortcuts(form.components, component)); 150 | } 151 | 152 | return { 153 | getAvailableShortcuts: getAvailableShortcuts, 154 | uniquify: uniquify 155 | }; 156 | }]; 157 | -------------------------------------------------------------------------------- /src/factories/debounce.js: -------------------------------------------------------------------------------- 1 | // Create an AngularJS service called debounce 2 | module.exports = ['$timeout','$q', function($timeout, $q) { 3 | // The service is actually this function, which we call with the func 4 | // that should be debounced and how long to wait in between calls 5 | return function debounce(func, wait, immediate) { 6 | var timeout; 7 | // Create a deferred object that will be resolved when we need to 8 | // actually call the func 9 | var deferred = $q.defer(); 10 | return function() { 11 | var context = this, args = arguments; 12 | var later = function() { 13 | timeout = null; 14 | if (!immediate) { 15 | deferred.resolve(func.apply(context, args)); 16 | deferred = $q.defer(); 17 | } 18 | }; 19 | var callNow = immediate && !timeout; 20 | if ( timeout ) { 21 | $timeout.cancel(timeout); 22 | } 23 | timeout = $timeout(later, wait); 24 | if (callNow) { 25 | deferred.resolve(func.apply(context,args)); 26 | deferred = $q.defer(); 27 | } 28 | return deferred.promise; 29 | }; 30 | }; 31 | }]; 32 | -------------------------------------------------------------------------------- /src/ngFormBuilder-complete.js: -------------------------------------------------------------------------------- 1 | require('ng-formio/src/formio-complete.js'); 2 | require('angular-drag-and-drop-lists'); 3 | require('ng-dialog'); 4 | require('./ngFormBuilder.js'); 5 | -------------------------------------------------------------------------------- /src/ngFormBuilder-full.js: -------------------------------------------------------------------------------- 1 | require('ng-formio/src/formio-full.js'); 2 | require('angular-drag-and-drop-lists'); 3 | require('ng-dialog'); 4 | require('./ngFormBuilder.js'); 5 | -------------------------------------------------------------------------------- /src/ngFormBuilder.js: -------------------------------------------------------------------------------- 1 | /*! ng-formio-builder v<%=version%> | https://unpkg.com/ng-formio-builder@<%=version%>/LICENSE.txt */ 2 | /*global window: false, console: false, jQuery: false */ 3 | /*jshint browser: true */ 4 | var fs = require('fs'); 5 | var utils = require('formiojs/utils').default; 6 | 7 | var app = angular.module('ngFormBuilder', [ 8 | 'formio', 9 | 'dndLists', 10 | 'ngDialog', 11 | 'ui.bootstrap.accordion', 12 | 'ui.bootstrap.tooltip', 13 | 'ckeditor' 14 | ]); 15 | 16 | app.constant('FORM_OPTIONS', require('./constants/formOptions')); 17 | 18 | app.constant('COMMON_OPTIONS', require('./constants/commonOptions')); 19 | 20 | app.factory('debounce', require('./factories/debounce')); 21 | 22 | app.directive('formBuilderDraggable', function() { 23 | return { 24 | restrict: 'A', 25 | scope: { 26 | 'formBuilderDraggable': '=' 27 | }, 28 | link: function(scope, element) { 29 | var el = element[0]; 30 | el.draggable = true; 31 | var formBuilder = null; 32 | var dropZone = null; 33 | 34 | // Drag over event handler. 35 | var dragOver = function(event) { 36 | if (event.preventDefault) { 37 | event.preventDefault(); 38 | } 39 | return false; 40 | }; 41 | 42 | // Drag end event handler. 43 | var dragEnd = function() { 44 | jQuery(dropZone).removeClass('enabled'); 45 | dropZone.removeEventListener('dragover', dragOver, false); 46 | dropZone.removeEventListener('drop', dragDrop, false); 47 | }; 48 | 49 | // Drag drop event handler. 50 | var dragDrop = function(event) { 51 | if (event.preventDefault) { 52 | event.preventDefault(); 53 | } 54 | if (event.stopPropagation) { 55 | event.stopPropagation(); 56 | } 57 | var dropOffset = jQuery(dropZone).offset(); 58 | var dragData = angular.copy(scope.formBuilderDraggable); 59 | dragData.fbDropX = event.pageX - dropOffset.left; 60 | dragData.fbDropY = event.pageY - dropOffset.top; 61 | angular.element(dropZone).scope().$emit('fbDragDrop', dragData); 62 | dragEnd(); 63 | return false; 64 | }; 65 | 66 | el.addEventListener('dragstart', function(event) { 67 | event.stopPropagation(); 68 | event.dataTransfer.setData('text', 'true'); 69 | if (!dropZone) { 70 | dropZone = document.getElementById('fb-drop-zone'); 71 | } 72 | if (!dropZone) { 73 | return console.warn('Cannot find fb-drop-zone'); 74 | } 75 | if (!formBuilder) { 76 | formBuilder = document.getElementById('fb-pdf-builder'); 77 | } 78 | if (!formBuilder) { 79 | return console.warn('Cannot find fb-pdf-builder'); 80 | } 81 | 82 | var builderRect = utils.getElementRect(formBuilder); 83 | dropZone.style.width = builderRect && builderRect.width ? builderRect.width + 'px' : '100%'; 84 | dropZone.style.height = builderRect && builderRect.height ? builderRect.height + 'px' : '1000px'; 85 | jQuery(dropZone).addClass('enabled'); 86 | dropZone.addEventListener('dragover', dragOver, false); 87 | dropZone.addEventListener('drop', dragDrop, false); 88 | return false; 89 | }, false); 90 | el.addEventListener('dragend', function(event) { 91 | dragEnd(); 92 | return false; 93 | }, false); 94 | } 95 | }; 96 | }); 97 | 98 | app.factory('BuilderUtils', require('./factories/BuilderUtils')); 99 | 100 | app.directive('formBuilder', require('./directives/formBuilder')); 101 | 102 | app.directive('formBuilderComponent', require('./directives/formBuilderComponent')); 103 | 104 | app.directive('formBuilderElement', require('./directives/formBuilderElement')); 105 | 106 | app.controller('formBuilderDnd', require('./directives/formBuilderDnd')); 107 | 108 | app.directive('formBuilderList', require('./directives/formBuilderList')); 109 | 110 | app.directive('formBuilderRow', require('./directives/formBuilderRow')); 111 | 112 | app.directive('jsonInput', require('./directives/jsonInput')); 113 | 114 | app.directive('formBuilderOption', require('./directives/formBuilderOption')); 115 | 116 | app.directive('labelValidator', require('./directives/labelValidator')); 117 | 118 | app.directive('formBuilderTable', require('./directives/formBuilderTable')); 119 | 120 | app.directive('formBuilderOptionInputFormat', require('./directives/formBuilderOptionInputFormat')); 121 | 122 | app.directive('formBuilderOptionInputsLabelPosition', require('./directives/formBuilderOptionInputsLabelPosition')); 123 | 124 | app.directive('formBuilderOptionKey', require('./directives/formBuilderOptionKey')); 125 | 126 | app.directive('formBuilderOptionLabelPosition', require('./directives/formBuilderOptionLabelPosition')); 127 | 128 | app.directive('formBuilderOptionOptionsLabelPosition', require('./directives/formBuilderOptionOptionsLabelPosition')); 129 | 130 | app.directive('formBuilderOptionShortcut', require('./directives/formBuilderOptionShortcut')); 131 | 132 | app.directive('formBuilderOptionTags', require('./directives/formBuilderOptionTags')); 133 | 134 | app.directive('textMask', require('./directives/textMask')); 135 | 136 | app.directive('validApiKey', require('./directives/validApiKey')); 137 | 138 | app.directive('formBuilderOptionCustomValidation', require('./directives/formBuilderOptionCustomValidation')); 139 | 140 | app.directive('formBuilderTooltip', require('./directives/formBuilderTooltip')); 141 | 142 | app.directive('valueBuilder', require('./directives/valueBuilder')); 143 | 144 | app.directive('headersBuilder', require('./directives/headersBuilder')); 145 | 146 | app.directive('valueBuilderWithShortcuts', require('./directives/valueBuilderWithShortcuts')); 147 | 148 | app.directive('objectBuilder', require('./directives/objectBuilder')); 149 | 150 | app.directive('formBuilderConditional', require('./directives/formBuilderConditional')); 151 | 152 | app.directive('multiMaskInput', require('./directives/multiMaskInput')); 153 | 154 | /** 155 | * This workaround handles the fact that iframes capture mouse drag 156 | * events. This interferes with dragging over components like the 157 | * Content component. As a workaround, we keep track of the isDragging 158 | * flag here to overlay iframes with a div while dragging. 159 | */ 160 | app.value('dndDragIframeWorkaround', { 161 | isDragging: false 162 | }); 163 | 164 | app.run([ 165 | '$templateCache', 166 | '$rootScope', 167 | 'ngDialog', 168 | function( 169 | $templateCache, 170 | $rootScope, 171 | ngDialog 172 | ) { 173 | // Close all open dialogs on state change. 174 | $rootScope.$on('$stateChangeStart', function() { 175 | ngDialog.closeAll(false); 176 | }); 177 | 178 | $templateCache.put('formio/formbuilder/editbuttons.html', 179 | fs.readFileSync(__dirname + '/templates/editbuttons.html', 'utf8') 180 | ); 181 | 182 | $templateCache.put('formio/formbuilder/component.html', 183 | fs.readFileSync(__dirname + '/templates/component.html', 'utf8') 184 | ); 185 | 186 | $templateCache.put('formio/formbuilder/list.html', 187 | fs.readFileSync(__dirname + '/templates/list.html', 'utf8') 188 | ); 189 | 190 | $templateCache.put('formio/formbuilder/row.html', 191 | fs.readFileSync(__dirname + '/templates/row.html', 'utf8') 192 | ); 193 | 194 | $templateCache.put('formio/formbuilder/builder.html', 195 | fs.readFileSync(__dirname + '/templates/builder.html', 'utf8') 196 | ); 197 | 198 | $templateCache.put('formio/formbuilder/datagrid.html', 199 | fs.readFileSync(__dirname + '/templates/datagrid.html', 'utf8') 200 | ); 201 | 202 | $templateCache.put('formio/components/confirm-remove.html', 203 | fs.readFileSync(__dirname + '/templates/confirm-remove.html', 'utf8') 204 | ); 205 | } 206 | ]); 207 | 208 | require('./components'); 209 | -------------------------------------------------------------------------------- /src/templates/builder.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 |
13 | 14 | {{ component.title | formioTranslate }} 15 | 16 |
17 |
18 |
19 |
25 | 26 | {{ component.title | formioTranslate }} 27 | 28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 | {{ pdftype.title | formioTranslate }} 36 | 37 |
38 |
39 |
40 |
41 |
42 | 46 |
47 |
48 |
49 | 50 |
51 | 62 |
63 |
64 |
65 | -------------------------------------------------------------------------------- /src/templates/component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /src/templates/confirm-remove.html: -------------------------------------------------------------------------------- 1 |
2 |

Removing this component will also remove all of its children! Are you sure you want to do this?

3 |
4 |
5 |   6 |   7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /src/templates/datagrid.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 21 | 38 | 43 | 44 | 45 |
10 | {{ (component.label || '') | formioTranslate:null:builder }} 11 |
12 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
39 | 42 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /src/templates/editbuttons.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /src/templates/form.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formio/ngFormBuilder/fda85e3e26c6ef06bfcecc0a86e5931d9422a432/src/templates/form.html -------------------------------------------------------------------------------- /src/templates/list.html: -------------------------------------------------------------------------------- 1 |
    4 |
  • 5 | 8 |
  • 9 | 10 |
  • 17 | 18 |
    19 |
  • 20 |
21 | -------------------------------------------------------------------------------- /src/templates/row.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
    7 |
  • 14 | 15 |
    16 |
  • 17 |
  • 18 | 21 |
  • 22 |
23 |
24 |
25 | --------------------------------------------------------------------------------