diff --git a/.gitignore b/.gitignore index 2785a6d1..f720e67c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ node_modules bower_components .sass-cache -compiled \ No newline at end of file +compiled +npm-debug.log +.DS_Store +.idea \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..d16c3a34 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +10.15.3 \ No newline at end of file diff --git a/Gruntfile.coffee b/Gruntfile.coffee index abf78fb9..d4c7c6fc 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -1,4 +1,4 @@ -ALL_TASKS = ['jst:all', 'coffee:all', 'concat:all', 'stylus:all', 'clean:compiled'] +ALL_TASKS = ['jst:all', 'coffee:all', 'concat:all', 'stylus:all', 'clean:compiled', 'copy:all'] # formbuilder.js must be compiled in this order: # 1. rivets-config @@ -19,8 +19,10 @@ module.exports = (grunt) -> grunt.loadNpmTasks('grunt-contrib-uglify') grunt.loadNpmTasks('grunt-contrib-watch') grunt.loadNpmTasks('grunt-contrib-clean') + grunt.loadNpmTasks('grunt-contrib-copy') grunt.loadNpmTasks('grunt-release') grunt.loadNpmTasks('grunt-karma') + grunt.loadNpmTasks('grunt-contrib-connect') grunt.initConfig @@ -57,8 +59,9 @@ module.exports = (grunt) -> files: '<%= distFolder %>/formbuilder.js': '<%= compiledFolder %>/*.js' '<%= vendorFolder %>/js/vendor.js': [ + 'src/polyfills/ie8-node-enum.js' 'bower_components/ie8-node-enum/index.js' - 'bower_components/jquery/jquery.js' + 'bower_components/jquery/dist/jquery.js' 'bower_components/jquery-ui/ui/jquery.ui.core.js' 'bower_components/jquery-ui/ui/jquery.ui.widget.js' 'bower_components/jquery-ui/ui/jquery.ui.mouse.js' @@ -66,18 +69,38 @@ module.exports = (grunt) -> 'bower_components/jquery-ui/ui/jquery.ui.droppable.js' 'bower_components/jquery-ui/ui/jquery.ui.sortable.js' 'bower_components/jquery.scrollWindowTo/index.js' - 'bower_components/underscore/underscore-min.js' + 'bower_components/lodash/dist/lodash.min.js' 'bower_components/underscore.mixin.deepExtend/index.js' 'bower_components/rivets/dist/rivets.js' 'bower_components/backbone/backbone.js' 'bower_components/backbone-deep-model/src/deep-model.js' + 'bower_components/bootstrap/dist/js/bootstrap.js', + 'bower_components/bootstrap/js/tooltip.js', + 'bower_components/signature_pad/signature_pad.js' + 'bower_components/node-uuid/uuid.js' + 'bower_components/spectrum/spectrum.js', + 'bower_components/select2/select2/dist/js/select2.min.js' ] + '<%= vendorFolder %>/css/vendor.css': [ + 'bower_components/font-awesome/css/font-awesome.css', + 'bower_components/bootstrap/dist/css/bootstrap.css', + 'bower_components/summernote/dist/summernote.css', + 'bower_components/select2/dist/css/select2.css', + 'bower_components/spectrum/spectrum.css' + ] + + copy: + all: + expand: true, + flatten: true, + src: 'bower_components/font-awesome/fonts/*', + dest: '<%= vendorFolder %>/fonts/' cssmin: dist: files: '<%= distFolder %>/formbuilder-min.css': '<%= distFolder %>/formbuilder.css' - '<%= vendorFolder %>/css/vendor.css': 'bower_components/font-awesome/css/font-awesome.css' + stylus: all: @@ -99,6 +122,12 @@ module.exports = (grunt) -> files: ['<%= srcFolder %>/**/*.{coffee,styl,html}'] tasks: ALL_TASKS + connect: + server: + options: + port: 9001 + keepalive: true + # To test, run `grunt --no-write -v release` release: npm: false diff --git a/README.md b/README.md index a7c58bbe..e6cc8478 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Formbuilder is a graphical interface for letting users build their own webforms. ## Demo [Click here](http://dobtco.github.io/formbuilder/) to see Formbuilder in action. +## Add new icons to element +If you need to add/replace icon for form element, you can find all available icons from `icon-font-demo` folder ## Basic usage ```
@@ -38,22 +40,22 @@ Because of its modular nature, Formbuilder is easy to customize. Most of the con Keeping with the customizable nature of Formbuilder, you are also able to modify how Formbuilder structures its JSON output. The [default keypaths](https://github.com/dobtco/formbuilder/blob/master/coffee/main.coffee#L20) are: ```coffeescript -SIZE: 'field_options.size' -UNITS: 'field_options.units' +SIZE: 'options.size' +UNITS: 'options.units' LABEL: 'label' -FIELD_TYPE: 'field_type' +type: 'type' REQUIRED: 'required' ADMIN_ONLY: 'admin_only' -OPTIONS: 'field_options.options' -DESCRIPTION: 'field_options.description' -INCLUDE_OTHER: 'field_options.include_other_option' -INCLUDE_BLANK: 'field_options.include_blank_option' -INTEGER_ONLY: 'field_options.integer_only' -MIN: 'field_options.min' -MAX: 'field_options.max' -MINLENGTH: 'field_options.minlength' -MAXLENGTH: 'field_options.maxlength' -LENGTH_UNITS: 'field_options.min_max_length_units' +OPTIONS: 'options.options' +DESCRIPTION: 'options.description' +INCLUDE_OTHER: 'options.include_other_option' +INCLUDE_BLANK: 'options.include_blank_option' +INTEGER_ONLY: 'options.integer_only' +MIN: 'options.min' +MAX: 'options.max' +MINLENGTH: 'options.minlength' +MAXLENGTH: 'options.maxlength' +LENGTH_UNITS: 'options.min_max_length_units' ``` Which outputs JSON that looks something like: @@ -61,15 +63,15 @@ Which outputs JSON that looks something like: ```javascript [{ "label": "Please enter your clearance number", - "field_type": "text", + "type": "text", "required": true, - "field_options": {}, + "options": {}, "cid": "c6" }, { "label": "Security personnel #82?", - "field_type": "radio", + "type": "radio", "required": true, - "field_options": { + "options": { "options": [{ "label": "Yes", "checked": false @@ -82,9 +84,9 @@ Which outputs JSON that looks something like: "cid": "c10" }, { "label": "Medical history", - "field_type": "file", + "type": "file", "required": true, - "field_options": {}, + "options": {}, "cid": "c14" }] ``` @@ -108,10 +110,63 @@ Have a question about Formbuilder? Feel free to [open a GitHub Issue](https://gi ## Developing You'll need [node and npm](http://nodejs.org/) installed. -1. `npm install` -2. `bower install` -3. `grunt watch` -4. open `index.html` and you're all set! +1. `nvm use` +2. `npm install` +3. `bower install` +4. `grunt watch` +5. Open a new terminal and run `grunt connect` +6. open `http://localhost:9001/` and you're all set! + +## Committing your changes and migrating to integral project +1. Ensure you're running `grunt watch` while developing so that your main formbuilder.js file is up to date +2. If you have made any changes to the formbuilder css, do the same for it with `grunt cssmin` (for completeness, as above) +3. Copy the changed formbuilder.js files to integral/html/js/ext ; and formbuilder.css file to integral/html/css ## License MIT + +## Currently known issues +Last time this was worked on there were issues getting a new repo set up. +* npm install was failing to install correctly: + * running into issues with not finding xcode while trying to install gym. + * throwing lots of deprecation, no member named 'New' in 'v8::String', and NAN_THROW_ERRORs when installing gym + +Note made on the last attempt: + +If node install fails with `gyp: No Xcode or CLT version detected!` +Run `xcode-select --install` and try again. +If you have a pending or recently updated xcode you may need to open the app and accept permissions. + +You may also need to completely delete and re-install xcode with +~~~ +sudo rm -rf $(xcode-select -print-path) +xcode-select --install +~~~ + +Also, you may not be able to get node install to work because node-gym is unsupported with errors like this: +~~~ + CXX(target) Release/obj.target/fse/fsevents.o +In file included from ../fsevents.cc:6: +../../nan/nan.h:213:31: warning: 'Uint32Value' is deprecated [-Wdeprecated-declarations] + ? optionsObj->Get(opt)->Uint32Value() + ^ +/Users/paul/Library/Caches/node-gyp/10.19.0/include/node/v8.h:2477:3: note: 'Uint32Value' has been + explicitly marked deprecated here + V8_DEPRECATED("Use maybe version", uint32_t Uint32Value() const); +~~~ + +In that case you can switch to a much earlier version of node and try again, though it may not work: +~~~ +nvm install 0.8 +nvm use 0.8 +nvm ls +~~~ + +One last thing - node-gym has lots of issues. Sometimes if will completely stop after throwing all the errors, but sometimes it will continue. +If all else fails, completely uninstall it globally and nuke your node_modules folder and try again. +It worked for me last time. +~~~ +sudo npm uninstall node-gyp -g +rm -rf node_modules +npm install +~~~ diff --git a/bower.json b/bower.json index e7deea0a..1515c02d 100644 --- a/bower.json +++ b/bower.json @@ -16,15 +16,20 @@ "tests" ], "dependencies": { - "ie8-node-enum": "https://gist.github.com/adamjacobbecker/8902451/raw/b68459289526cb76c2e22416d98d0dbd0b722fa0/ie8_node_enum.js", - "jquery": "~2.0.3", + "jquery.scrollWindowTo": "https://gist.github.com/ajb/6519570/raw/cd741057495d0fb19e545a0f9a098efba3bef9c8/jquery.scrollWindowTo.js", + "jquery": "~1.11.1", "jquery-ui": "~1.10.3", - "jquery.scrollWindowTo": "https://gist.github.com/adamjacobbecker/6519570/raw/cd741057495d0fb19e545a0f9a098efba3bef9c8/jquery.scrollWindowTo.js", - "underscore": "~1.5.2", - "underscore.mixin.deepExtend": "https://gist.github.com/adamjacobbecker/6519561/raw/63682037af9b10200b05c1a3d5890903397b2103/underscore.mixin.deepExtend.js", "backbone": "~1.1.0", "backbone-deep-model": "~0.10.4", + "underscore.mixin.deepExtend": "https://gist.github.com/ajb/6519561/raw/63682037af9b10200b05c1a3d5890903397b2103/underscore.mixin.deepExtend.js", "rivets": "~0.5.13", - "font-awesome": "~4.0.0" + "signature_pad": "~1.3.2", + "bootstrap": "~3.1.1", + "summernote": "~0.6.16", + "node-uuid": "~1.4.1", + "mathjs": "~1.1.1", + "lodash": "~2.4.1", + "spectrum": "~1.7.1", + "select2": "~4.0" } -} \ No newline at end of file +} diff --git a/dist/formbuilder-min.css b/dist/formbuilder-min.css index 0247fb6d..0ca93dc1 100644 --- a/dist/formbuilder-min.css +++ b/dist/formbuilder-min.css @@ -1 +1 @@ -.fb-button{display:inline-block;margin:0;padding:.563rem .844rem;border:0 none;background:#16a085;color:#fff;text-align:center;text-decoration:none;font-size:12px;line-height:1.5;cursor:pointer;border-radius:.125rem;border:thin solid #19b394;border-bottom:2px solid #16a085}.fb-button[disabled]{background:#ddd!important;border:thin solid #ccc;color:#777!important;text-shadow:none!important;-ms-filter:"alpha(Opacity=65)";opacity:.65;cursor:default}.fb-clear{clear:both}.fb-main{max-width:1000px;margin:0 auto;padding:0 20px 0 0;position:relative;font-family:'Source Sans Pro','Open Sans',Tahoma}.fb-save-wrapper{position:absolute;right:20px;top:10px}.fb-left{width:320px;float:left;padding-top:30px}.fb-right{padding-top:70px;margin-left:320px;border-left:1px solid #ddd;padding-left:20px;min-height:100%;overflow:hidden}.fb-no-response-fields{color:#999}.fb-tabs{list-style:none;margin:0 0 20px;padding:0 0 0 20px;border-bottom:1px solid #ccc}.fb-tabs li{display:inline-block}.fb-tabs li a{display:block;padding:10px;border-radius:5px 5px 0 0;font-size:13px;cursor:pointer;border-left:1px solid transparent;border-right:1px solid transparent}.fb-tabs li.active a{border:1px solid #ccc;margin-bottom:-1px;border-bottom-color:#fff}.fb-tab-content .fb-tab-pane{padding:0 20px;display:none}.fb-tab-content .fb-tab-pane.active{display:block}.fb-add-field-types .section{padding-bottom:5px;margin-bottom:20px}.fb-add-field-types{font-size:0}.fb-add-field-types a{font-size:13px;display:inline-block;width:48.5%;background-color:#1abc9c;margin-bottom:9px;box-sizing:border-box}.fb-add-field-types a:nth-child(odd){margin-right:3%}.fb-add-field-types a .symbol{opacity:.6;margin:0 .25em 0 -1em}.fb-response-fields{padding-bottom:150px}.fb-response-fields a.sortable-placeholder{display:block;border:1px dashed #ddd;min-height:80px;height:80px;width:100%}.fb-field-wrapper{cursor:pointer;position:relative;margin-bottom:20px}.fb-field-wrapper input{border-radius:3px;border:thin solid #ddd}.fb-field-wrapper:hover .actions-wrapper,.fb-field-wrapper.editing .actions-wrapper{display:block}.fb-field-wrapper:hover .subtemplate-wrapper{border-color:#ddd;border-radius:3px}.fb-field-wrapper.editing{background-color:#ecf0f1;border-radius:3px}.fb-field-wrapper.editing .subtemplate-wrapper{border-color:#d9e1e3;border-style:solid;margin:0;border-radius:3px}.fb-field-wrapper .actions-wrapper{display:none;position:absolute;bottom:-7px;right:5px;z-index:3}.fb-field-wrapper .actions-wrapper a{display:inline-block;background-color:#ccc;padding:2px 8px}.edit-response-field input,.edit-response-field textarea,.edit-response-field select{border:thin solid #ddd;border-radius:.25em;padding:.5em;display:inline-block;height:auto;vertical-align:middle}.edit-response-field input:focus,.edit-response-field textarea:focus,.edit-response-field select:focus{outline:0;border:thin solid #1abc9c}.edit-response-field select{font-size:14px}.fb-field-wrapper .actions-wrapper a.js-duplicate,.fb-edit-field-wrapper .js-add-option{background-color:#2ecc71;border:0}.fb-field-wrapper .actions-wrapper a.js-clear,.fb-edit-field-wrapper .js-remove-option{background-color:#e74c3c;border:0}.fb-field-wrapper .subtemplate-wrapper{border:1px dashed transparent;margin-bottom:10px;padding:10px;position:relative}.fb-field-wrapper .subtemplate-wrapper .cover{position:absolute;top:0;left:0;height:100%;width:100%;z-index:2}.fb-field-wrapper .subtemplate-wrapper>label{display:block;border-bottom:thin solid #eee;padding-bottom:3px;margin-bottom:7px}.fb-field-wrapper .subtemplate-wrapper abbr{color:red}.fb-field-wrapper .input-line{clear:both;margin-bottom:10px}.fb-field-wrapper .input-line .above-line{margin-top:7px}.fb-field-wrapper .input-line>span{display:inline-block;vertical-align:top}.fb-field-wrapper .input-line>span input{width:100%}.fb-field-wrapper .input-line>span>label{display:block;font-size:13px;margin-left:3px}.fb-field-wrapper .help-block{display:block;font-size:12px;margin-top:5px}.fb-edit-field-wrapper{font-size:13px}.fb-edit-field-wrapper .fb-field-label{font-weight:400;background:#eee;padding:.75em;color:#666;font-size:1.25em}.fb-edit-field-wrapper .fb-field-label .field-type{margin-top:.5em;display:block;font-family:'Source Sans Pro',sans-serif;font-size:1em}.fb-edit-field-wrapper .fb-field-label .field-type:before{content:'Type: ';color:#999}.fb-edit-field-wrapper .fb-field-label .fa.fa-arrow-right{display:none}.fb-edit-field-wrapper .fb-edit-section-header{border-bottom:1px solid #ddd;margin-top:25px;margin-bottom:10px;padding-bottom:5px;clear:both;font-weight:700}.fb-edit-field-wrapper .js-add-option,.fb-edit-field-wrapper .js-remove-option{padding:3px 6px}.fb-edit-field-wrapper .fb-bottom-add{margin-top:8px}.fb-common-wrapper .fb-label-description{margin-bottom:10px}.fb-common-wrapper .fb-label-description input,.fb-common-wrapper .fb-label-description textarea{width:100%}.fb-common-wrapper .fb-label-description textarea{min-height:5em}.response-field-draggable-helper{border:1px dashed #ddd;background:#eee}.response-field-text input.rf-size-small{width:130px}.response-field-text input.rf-size-medium{width:300px}.response-field-text input.rf-size-large{width:100%}.response-field-paragraph textarea.rf-size-small{width:200px;min-height:60px}.response-field-paragraph textarea.rf-size-medium{width:400px;min-height:100px}.response-field-paragraph textarea.rf-size-large{width:100%;min-height:200px}.response-field-address .street{width:400px}.response-field-address .city,.response-field-address .state,.response-field-address .zip,.response-field-address .country{width:198px}.response-field-date .month,.response-field-date .day,.response-field-date .year{width:50px}.response-field-time .hours,.response-field-time .minutes,.response-field-time .seconds{width:50px}.response-field-checkboxes .fb-option,.response-field-radio .fb-option{margin-bottom:5px;display:inline-block} \ No newline at end of file +[class^=fb-icon-]:before,[class*=" fb-icon-"]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.fb-icon-date:before{content:'\f133'}.fb-icon-radio:before{content:'\f192'}.fb-icon-checkbox:before{content:'\e893'}.fb-icon-data-source:before{content:'\f1c0'}.fb-icon-dropdown:before{content:'\e854'}.fb-icon-signature:before{content:'\e830'}.fb-icon-info:before{content:'\f129'}.fb-icon-table:before{content:'\f0ce'}.fb-icon-textarea:before{content:'\f1dd'}.fb-icon-section:before{content:'\f2d1'}.fb-icon-text:before{content:'\e87d'}.fb-icon-number:before{content:'\f162'}.fb-icon-time:before{content:'\e84a'}.fb-icon-conditional:before{content:'\E824'}.fb-icon-geolocation:before{content:'\e839'}.fb-icon-approval:before{content:'\f14b'}.fb-icon-grid:before{content:'\e810'}.fb-button{text-align:left}.fb-clear{clear:both}.fb-main{padding:0 20px 0 0;position:relative}.fb-save-wrapper{position:absolute;right:20px;top:10px}.fb-left{float:left;width:320px;padding-top:30px}.fb-right{padding-top:70px;margin-left:320px;border-left:1px solid #ddd;padding-left:20px;padding-bottom:150px;min-height:100%;overflow:hidden}.fb-no-response-fields{color:#999}.fb-tabs{list-style:none;margin:0 0 20px;padding:0 0 0 20px;border-bottom:1px solid #ccc}.fb-tabs li{display:inline-block}.fb-tabs li a{display:block;padding:10px;border-radius:5px 5px 0 0;font-size:13px;cursor:pointer;border-left:1px solid transparent;border-right:1px solid transparent}.fb-tabs li.active a{border:1px solid #ccc;margin-bottom:-1px;border-bottom-color:#fff}.fb-tab-content .fb-tab-pane{padding:0 20px;display:none}.fb-tab-content .fb-tab-pane.active{display:block}.fb-add-types .section{padding-bottom:5px;margin-bottom:20px}.fb-add-types{font-size:0}.fb-add-types a{font-size:13px;display:inline-block;width:48.5%;margin-bottom:9px;box-sizing:border-box}.fb-add-types a:nth-child(odd){margin-right:3%}.fb-add-types a .symbol{opacity:.6;margin:0 .25em 0 -1em}.fb-response-fields{padding-bottom:150px}.fb-response-fields a.sortable-placeholder{display:block;border:1px dashed #ddd;min-height:80px;height:80px;width:100%}.fb-field-wrapper{cursor:pointer;position:relative;margin-bottom:20px}.fb-field-wrapper input{border-radius:3px;border:thin solid #ddd}.fb-field-wrapper:hover .actions-wrapper,.fb-field-wrapper.editing .actions-wrapper{display:block}.fb-field-wrapper:hover .subtemplate-wrapper{border-color:#ddd;border-radius:3px}.fb-field-wrapper.editing{background-color:#ecf0f1;border-radius:3px;box-shadow:inset 0 0 7px 2px rgba(100,100,100,.1);border:1px solid rgba(100,100,100,.2)}.fb-field-wrapper.parent{box-shadow:rgba(0,0,0,.3) 1px 1px 10px}.fb-field-wrapper.editing .subtemplate-wrapper{border-color:#d9e1e3;border-style:solid;margin:0;border-radius:3px}.fb-field-wrapper .actions-wrapper{display:none;position:absolute;bottom:-7px;right:5px;z-index:3}.fb-field-wrapper .actions-wrapper a{display:inline-block;background-color:#ccc;padding:2px 8px}.edit-response-field .options{background-color:#eee;max-height:600px;overflow-y:auto;padding:3px;border-radius:3px;border:thin solid #ddd}.edit-response-field input,.edit-response-field textarea,.edit-response-field select{border:thin solid #ddd;border-radius:.25em;padding:.5em;display:inline-block;height:auto;vertical-align:middle}.edit-response-field input:focus,.edit-response-field textarea:focus,.edit-response-field select:focus{outline:0}.edit-response-field select{font-size:14px;max-width:100%}input[readonly]{cursor:not-allowed;background-color:#eee}.fb-field-wrapper .subtemplate-wrapper{border:1px dashed transparent;margin-bottom:10px;padding:10px;position:relative}.fb-field-wrapper .subtemplate-wrapper .cover{position:absolute;top:0;left:0;height:100%;width:100%;z-index:2}.fb-field-wrapper .subtemplate-wrapper>label{display:block;border-bottom:thin solid #eee;padding-bottom:3px;margin-bottom:7px}.fb-field-wrapper .subtemplate-wrapper abbr{color:red}.fb-field-wrapper .input-line{clear:both;margin-bottom:10px}.fb-field-wrapper .input-line .above-line{margin-top:7px}.fb-field-wrapper .input-line>span{display:inline-block;vertical-align:top}.fb-field-wrapper .input-line>span input{width:100%}.fb-field-wrapper .input-line>span>label{display:block;font-size:13px;margin-left:3px}.fb-field-wrapper .help-block{display:block;font-size:12px;margin-top:5px}.fb-edit-field-wrapper{font-size:13px}.fb-edit-field-wrapper .fb-field-label{font-weight:400;background:#eee;padding:.75em;color:#666;font-size:1.25em}.fb-edit-field-wrapper .fb-field-label .type{margin-top:.5em;display:block;font-family:'Source Sans Pro',sans-serif;font-size:1em}.fb-edit-field-wrapper .fb-field-label .type:before{content:'Type: ';color:#999}.fb-edit-field-wrapper .fb-field-label .fa.fa-arrow-right{display:none}.fb-edit-field-wrapper .fb-edit-section-header{border-bottom:1px solid #ddd;margin-top:25px;margin-bottom:10px;padding-bottom:5px;clear:both;font-weight:700}.fb-edit-field-wrapper .js-add-option,.fb-edit-field-wrapper .js-remove-option{padding:3px 6px}.fb-edit-field-wrapper .fb-bottom-add{margin-top:8px}.fb-common-wrapper .fb-label-description{margin-bottom:10px}.fb-common-wrapper .fb-label-description input,.fb-common-wrapper .fb-label-description textarea{width:100%}.fb-common-wrapper .fb-label-description textarea{min-height:5em}.fb-conditional-question{float:right;font-size:.9em;max-width:50%;text-overflow:ellipsis;height:20px;white-space:nowrap;overflow:hidden}.fb-conditional-question-trigger>span{font-weight:700}.option-score-input{width:50px}.option-label-input{width:170px}.response-field-draggable-helper{border:1px dashed #ddd;background:#eee}.response-field-text input.rf-size-medium{width:300px}.response-field-text input.rf-size-large{width:100%}.response-field-textarea textarea.rf-size-small{width:200px;min-height:60px}.response-field-textarea textarea.rf-size-medium{width:400px;min-height:100px}.response-field-textarea textarea.rf-size-large{width:100%;min-height:200px}.response-field-address .street{width:400px}.response-field-address .city,.response-field-address .state,.response-field-address .zip,.response-field-address .country{width:198px}.response-field-date .month,.response-field-date .day,.response-field-date .year{width:50px}.response-field-time .input-group{width:145px}.response-field-checkbox .fb-option,.response-field-radio .fb-option{margin-bottom:5px;padding:3px 8px;display:inline-block}.editing .trigger-option,.fb-option.trigger-option{background-color:#5cb85c;border-radius:.25em;color:#fff}.fb-conditional-question .trigger-option{padding:1px 4px}.response-field-website input{width:200px}.response-field-signature .fb-signature{width:300px;height:150px}.response-field-signature .fb-signature-placeholder{color:#aaa}.response-field-approval .fb-approval-user{margin-bottom:20px}.response-field-approval .fb-signature{width:300px;height:150px}.response-field-approval .fb-signature-placeholder{color:#aaa}.response-field-grid .cover{display:none}.response-field-table{width:100%}.response-field-table .cover{display:none}.response-field-table .section-name{display:inline-block}.response-field-table .element-selector{margin:0 5px;float:right;position:absolute;right:5px;top:5px}.response-field-table tr{vertical-align:top}.response-field-table table{margin-bottom:30px}.response-field-table table td{padding:10px 10px 0}.response-field-table table td label{border:0!important}.response-field-table table .calculated{font-style:italic;color:#ccc}.response-field-table table select,.response-field-table table input[type=text],.response-field-table table textarea,.response-field-table table .fb-signature{width:100%}.fb-options-per-row-1:before{content:" ";display:table}.fb-options-per-row-1:after{content:" ";display:table;clear:both}.fb-options-per-row-1{clear:both}.fb-options-per-row-1 .fb-option-wrapper{width:100%}.fb-options-per-row-2:before{content:" ";display:table}.fb-options-per-row-2:after{content:" ";display:table;clear:both}.fb-options-per-row-2{clear:both}.fb-options-per-row-2 .fb-option-wrapper{width:50%}.fb-options-per-row-3:before{content:" ";display:table}.fb-options-per-row-3:after{content:" ";display:table;clear:both}.fb-options-per-row-3{clear:both}.fb-options-per-row-3 .fb-option-wrapper{width:33.333333333333336%}.fb-options-per-row-4:before{content:" ";display:table}.fb-options-per-row-4:after{content:" ";display:table;clear:both}.fb-options-per-row-4{clear:both}.fb-options-per-row-4 .fb-option-wrapper{width:25%}.fb-options-per-row-5:before{content:" ";display:table}.fb-options-per-row-5:after{content:" ";display:table;clear:both}.fb-options-per-row-5{clear:both}.fb-options-per-row-5 .fb-option-wrapper{width:20%}.fb-options-per-row-6:before{content:" ";display:table}.fb-options-per-row-6:after{content:" ";display:table;clear:both}.fb-options-per-row-6{clear:both}.fb-options-per-row-6 .fb-option-wrapper{width:16.666666666666668%}.fb-options-per-row-7:before{content:" ";display:table}.fb-options-per-row-7:after{content:" ";display:table;clear:both}.fb-options-per-row-7{clear:both}.fb-options-per-row-7 .fb-option-wrapper{width:14.285714285714286%}.fb-options-per-row-8:before{content:" ";display:table}.fb-options-per-row-8:after{content:" ";display:table;clear:both}.fb-options-per-row-8{clear:both}.fb-options-per-row-8 .fb-option-wrapper{width:12.5%}.fb-options-per-row-9:before{content:" ";display:table}.fb-options-per-row-9:after{content:" ";display:table;clear:both}.fb-options-per-row-9{clear:both}.fb-options-per-row-9 .fb-option-wrapper{width:11.11111111111111%}.fb-options-per-row-10:before{content:" ";display:table}.fb-options-per-row-10:after{content:" ";display:table;clear:both}.fb-options-per-row-10{clear:both}.fb-options-per-row-10 .fb-option-wrapper{width:10%}.fb-options-per-row-11:before{content:" ";display:table}.fb-options-per-row-11:after{content:" ";display:table;clear:both}.fb-options-per-row-11{clear:both}.fb-options-per-row-11 .fb-option-wrapper{width:9.090909090909092%}.fb-options-per-row-12:before{content:" ";display:table}.fb-options-per-row-12:after{content:" ";display:table;clear:both}.fb-options-per-row-12{clear:both}.fb-options-per-row-12 .fb-option-wrapper{width:8.333333333333334%}.fb-options-per-row-13:before{content:" ";display:table}.fb-options-per-row-13:after{content:" ";display:table;clear:both}.fb-options-per-row-13{clear:both}.fb-options-per-row-13 .fb-option-wrapper{width:7.6923076923076925%}.fb-options-per-row-14:before{content:" ";display:table}.fb-options-per-row-14:after{content:" ";display:table;clear:both}.fb-options-per-row-14{clear:both}.fb-options-per-row-14 .fb-option-wrapper{width:7.142857142857143%}.fb-options-per-row-15:before{content:" ";display:table}.fb-options-per-row-15:after{content:" ";display:table;clear:both}.fb-options-per-row-15{clear:both}.fb-options-per-row-15 .fb-option-wrapper{width:6.666666666666667%}.response-field-grid-table{border-collapse:collapse;border-spacing:0;margin-bottom:5px;table-layout:fixed;width:100%}.response-field-grid-table .response-field-grid-row{height:100px;vertical-align:top}.response-field-grid-table td{padding:10px 10px 0}.response-field-grid-table .element-selector{width:100%}.response-field-grid-table .element-selector .dropdown-toggle{width:100%}.response-field-grid-table .element-selector .dropdown-toggle span{font-size:2em}.response-field-grid-table .response-field-grid-cell{padding:10px 10px 0;border:1px dashed #ddd;background-color:rgba(255,255,255,.8)}.response-field-grid-table .response-field-grid-cell .cover{display:block}.response-field-grid-table .response-field-grid-cell .response-field-selector{margin:.5em}.response-field-grid-table .response-field-grid-cell .subtemplate-wrapper>label{display:none}.response-field-grid-table .response-field-grid-cell .help-block{display:none}.response-field-grid-table .response-field-grid-cell select,.response-field-grid-table .response-field-grid-cell input[type=text],.response-field-grid-table .response-field-grid-cell textarea,.response-field-grid-table .response-field-grid-cell .fb-signature{width:100%}.section-separator{border-top:1px solid #333}.fb-link-object-fields{padding:15px} \ No newline at end of file diff --git a/dist/formbuilder-min.js b/dist/formbuilder-min.js index cb44897a..93c7b5f8 100644 --- a/dist/formbuilder-min.js +++ b/dist/formbuilder-min.js @@ -1 +1,3 @@ -(function(){rivets.binders.input={publishes:!0,routine:rivets.binders.value.routine,bind:function(a){return a.addEventListener("input",this.publish)},unbind:function(a){return a.removeEventListener("input",this.publish)}},rivets.configure({prefix:"rv",adapter:{subscribe:function(a,b,c){return c.wrapped=function(a,b){return c(b)},a.on("change:"+b,c.wrapped)},unsubscribe:function(a,b,c){return a.off("change:"+b,c.wrapped)},read:function(a,b){return"cid"===b?a.cid:a.get(b)},publish:function(a,b,c){return a.cid?a.set(b,c):a[b]=c}}})}).call(this),function(){var a,b,c,d,e,f,g,h,i,j,k,l={}.hasOwnProperty,m=function(a,b){function c(){this.constructor=a}for(var d in b)l.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};e=function(a){function b(){return g=b.__super__.constructor.apply(this,arguments)}return m(b,a),b.prototype.sync=function(){},b.prototype.indexInDOM=function(){var a,b=this;return a=$(".fb-field-wrapper").filter(function(a,c){return $(c).data("cid")===b.cid}),$(".fb-field-wrapper").index(a)},b.prototype.is_input=function(){return null!=c.inputFields[this.get(c.options.mappings.FIELD_TYPE)]},b}(Backbone.DeepModel),d=function(a){function b(){return h=b.__super__.constructor.apply(this,arguments)}return m(b,a),b.prototype.initialize=function(){return this.on("add",this.copyCidToModel)},b.prototype.model=e,b.prototype.comparator=function(a){return a.indexInDOM()},b.prototype.copyCidToModel=function(a){return a.attributes.cid=a.cid},b}(Backbone.Collection),f=function(a){function b(){return i=b.__super__.constructor.apply(this,arguments)}return m(b,a),b.prototype.className="fb-field-wrapper",b.prototype.events={"click .subtemplate-wrapper":"focusEditView","click .js-duplicate":"duplicate","click .js-clear":"clear"},b.prototype.initialize=function(a){return this.parentView=a.parentView,this.listenTo(this.model,"change",this.render),this.listenTo(this.model,"destroy",this.remove)},b.prototype.render=function(){return this.$el.addClass("response-field-"+this.model.get(c.options.mappings.FIELD_TYPE)).data("cid",this.model.cid).html(c.templates["view/base"+(this.model.is_input()?"":"_non_input")]({rf:this.model})),this},b.prototype.focusEditView=function(){return this.parentView.createAndShowEditView(this.model)},b.prototype.clear=function(){return this.parentView.handleFormUpdate(),this.model.destroy()},b.prototype.duplicate=function(){var a;return a=_.clone(this.model.attributes),delete a.id,a.label+=" Copy",this.parentView.createField(a,{position:this.model.indexInDOM()+1})},b}(Backbone.View),b=function(a){function b(){return j=b.__super__.constructor.apply(this,arguments)}return m(b,a),b.prototype.className="edit-response-field",b.prototype.events={"click .js-add-option":"addOption","click .js-remove-option":"removeOption","click .js-default-updated":"defaultUpdated","input .option-label-input":"forceRender"},b.prototype.initialize=function(a){return this.parentView=a.parentView,this.listenTo(this.model,"destroy",this.remove)},b.prototype.render=function(){return this.$el.html(c.templates["edit/base"+(this.model.is_input()?"":"_non_input")]({rf:this.model})),rivets.bind(this.$el,{model:this.model}),this},b.prototype.remove=function(){return this.parentView.editView=void 0,this.parentView.$el.find('[data-target="#addField"]').click(),b.__super__.remove.apply(this,arguments)},b.prototype.addOption=function(a){var b,d,e,f;return b=$(a.currentTarget),d=this.$el.find(".option").index(b.closest(".option")),f=this.model.get(c.options.mappings.OPTIONS)||[],e={label:"",checked:!1},d>-1?f.splice(d+1,0,e):f.push(e),this.model.set(c.options.mappings.OPTIONS,f),this.model.trigger("change:"+c.options.mappings.OPTIONS),this.forceRender()},b.prototype.removeOption=function(a){var b,d,e;return b=$(a.currentTarget),d=this.$el.find(".js-remove-option").index(b),e=this.model.get(c.options.mappings.OPTIONS),e.splice(d,1),this.model.set(c.options.mappings.OPTIONS,e),this.model.trigger("change:"+c.options.mappings.OPTIONS),this.forceRender()},b.prototype.defaultUpdated=function(a){var b;return b=$(a.currentTarget),"checkboxes"!==this.model.get(c.options.mappings.FIELD_TYPE)&&this.$el.find(".js-default-updated").not(b).attr("checked",!1).trigger("change"),this.forceRender()},b.prototype.forceRender=function(){return this.model.trigger("change")},b}(Backbone.View),a=function(a){function e(){return k=e.__super__.constructor.apply(this,arguments)}return m(e,a),e.prototype.SUBVIEWS=[],e.prototype.events={"click .js-save-form":"saveForm","click .fb-tabs a":"showTab","click .fb-add-field-types a":"addField"},e.prototype.initialize=function(a){var b;return b=a.selector,this.formBuilder=a.formBuilder,this.bootstrapData=a.bootstrapData,null!=b&&this.setElement($(b)),this.collection=new d,this.collection.bind("add",this.addOne,this),this.collection.bind("reset",this.reset,this),this.collection.bind("change",this.handleFormUpdate,this),this.collection.bind("destroy add reset",this.hideShowNoResponseFields,this),this.collection.bind("destroy",this.ensureEditViewScrolled,this),this.render(),this.collection.reset(this.bootstrapData),this.initAutosave()},e.prototype.initAutosave=function(){var a=this;return this.formSaved=!0,this.saveFormButton=this.$el.find(".js-save-form"),this.saveFormButton.attr("disabled",!0).text(c.options.dict.ALL_CHANGES_SAVED),setInterval(function(){return a.saveForm.call(a)},5e3),$(window).bind("beforeunload",function(){return a.formSaved?void 0:c.options.dict.UNSAVED_CHANGES})},e.prototype.reset=function(){return this.$responseFields.html(""),this.addAll()},e.prototype.render=function(){var a,b,d,e;for(this.$el.html(c.templates.page()),this.$fbLeft=this.$el.find(".fb-left"),this.$responseFields=this.$el.find(".fb-response-fields"),this.bindWindowScrollEvent(),this.hideShowNoResponseFields(),e=this.SUBVIEWS,b=0,d=e.length;d>b;b++)a=e[b],new a({parentView:this}).render();return this},e.prototype.bindWindowScrollEvent=function(){var a=this;return $(window).on("scroll",function(){var b,c;if(a.$fbLeft.data("locked")!==!0)return c=Math.max(0,$(window).scrollTop()),b=a.$responseFields.height(),a.$fbLeft.css({"margin-top":Math.min(b,c)})})},e.prototype.showTab=function(a){var b,c,d;return b=$(a.currentTarget),d=b.data("target"),b.closest("li").addClass("active").siblings("li").removeClass("active"),$(d).addClass("active").siblings(".fb-tab-pane").removeClass("active"),"#editField"!==d&&this.unlockLeftWrapper(),"#editField"===d&&!this.editView&&(c=this.collection.models[0])?this.createAndShowEditView(c):void 0},e.prototype.addOne=function(a,b,c){var d,e;return e=new f({model:a,parentView:this}),null!=c.$replaceEl?c.$replaceEl.replaceWith(e.render().el):null==c.position||-1===c.position?this.$responseFields.append(e.render().el):0===c.position?this.$responseFields.prepend(e.render().el):(d=this.$responseFields.find(".fb-field-wrapper").eq(c.position))[0]?d.before(e.render().el):this.$responseFields.append(e.render().el)},e.prototype.setSortable=function(){var a=this;return this.$responseFields.hasClass("ui-sortable")&&this.$responseFields.sortable("destroy"),this.$responseFields.sortable({forcePlaceholderSize:!0,placeholder:"sortable-placeholder",stop:function(b,d){var e;return d.item.data("field-type")&&(e=a.collection.create(c.helpers.defaultFieldAttrs(d.item.data("field-type")),{$replaceEl:d.item}),a.createAndShowEditView(e)),a.handleFormUpdate(),!0},update:function(b,c){return c.item.data("field-type")?void 0:a.ensureEditViewScrolled()}}),this.setDraggable()},e.prototype.setDraggable=function(){var a,b=this;return a=this.$el.find("[data-field-type]"),a.draggable({connectToSortable:this.$responseFields,helper:function(){var a;return a=$("
"),a.css({width:b.$responseFields.width(),height:"80px"}),a}})},e.prototype.addAll=function(){return this.collection.each(this.addOne,this),this.setSortable()},e.prototype.hideShowNoResponseFields=function(){return this.$el.find(".fb-no-response-fields")[this.collection.length>0?"hide":"show"]()},e.prototype.addField=function(a){var b;return b=$(a.currentTarget).data("field-type"),this.createField(c.helpers.defaultFieldAttrs(b))},e.prototype.createField=function(a,b){var c;return c=this.collection.create(a,b),this.createAndShowEditView(c),this.handleFormUpdate()},e.prototype.createAndShowEditView=function(a){var c,d,e;if(d=this.$el.find(".fb-field-wrapper").filter(function(){return $(this).data("cid")===a.cid}),d.addClass("editing").siblings(".fb-field-wrapper").removeClass("editing"),this.editView){if(this.editView.model.cid===a.cid)return this.$el.find('.fb-tabs a[data-target="#editField"]').click(),this.scrollLeftWrapper(d,"undefined"!=typeof e&&null!==e&&e),void 0;e=this.$fbLeft.css("padding-top"),this.editView.remove()}return this.editView=new b({model:a,parentView:this}),c=this.editView.render().$el,this.$el.find(".fb-edit-field-wrapper").html(c),this.$el.find('.fb-tabs a[data-target="#editField"]').click(),this.scrollLeftWrapper(d),this},e.prototype.ensureEditViewScrolled=function(){return this.editView?this.scrollLeftWrapper($(".fb-field-wrapper.editing")):void 0},e.prototype.scrollLeftWrapper=function(a){var b=this;return this.unlockLeftWrapper(),a[0]?$.scrollWindowTo(a.offset().top-this.$responseFields.offset().top,200,function(){return b.lockLeftWrapper()}):void 0},e.prototype.lockLeftWrapper=function(){return this.$fbLeft.data("locked",!0)},e.prototype.unlockLeftWrapper=function(){return this.$fbLeft.data("locked",!1)},e.prototype.handleFormUpdate=function(){return this.updatingBatch?void 0:(this.formSaved=!1,this.saveFormButton.removeAttr("disabled").text(c.options.dict.SAVE_FORM))},e.prototype.saveForm=function(){var a;if(!this.formSaved)return this.formSaved=!0,this.saveFormButton.attr("disabled",!0).text(c.options.dict.ALL_CHANGES_SAVED),this.collection.sort(),a=JSON.stringify({fields:this.collection.toJSON()}),c.options.HTTP_ENDPOINT&&this.doAjaxSave(a),this.formBuilder.trigger("save",a)},e.prototype.doAjaxSave=function(a){var b=this;return $.ajax({url:c.options.HTTP_ENDPOINT,type:c.options.HTTP_METHOD,data:a,contentType:"application/json",success:function(a){var c,d,e,f;for(b.updatingBatch=!0,d=0,e=a.length;e>d;d++)c=a[d],null!=(f=b.collection.get(c.cid))&&f.set({id:c.id}),b.collection.trigger("sync");return b.updatingBatch=void 0}})},e}(Backbone.View),c=function(){function b(b){var c;null==b&&(b={}),_.extend(this,Backbone.Events),c=_.extend(b,{formBuilder:this}),this.mainView=new a(c)}return b.helpers={defaultFieldAttrs:function(a){var c,d;return c={label:"Untitled",field_type:a,required:!0,field_options:{}},("function"==typeof(d=b.fields[a]).defaultAttributes?d.defaultAttributes(c):void 0)||c},simple_format:function(a){return null!=a?a.replace(/\n/g,"
"):void 0}},b.options={BUTTON_CLASS:"fb-button",HTTP_ENDPOINT:"",HTTP_METHOD:"POST",mappings:{SIZE:"field_options.size",UNITS:"field_options.units",LABEL:"label",FIELD_TYPE:"field_type",REQUIRED:"required",ADMIN_ONLY:"admin_only",OPTIONS:"field_options.options",DESCRIPTION:"field_options.description",INCLUDE_OTHER:"field_options.include_other_option",INCLUDE_BLANK:"field_options.include_blank_option",INTEGER_ONLY:"field_options.integer_only",MIN:"field_options.min",MAX:"field_options.max",MINLENGTH:"field_options.minlength",MAXLENGTH:"field_options.maxlength",LENGTH_UNITS:"field_options.min_max_length_units"},dict:{ALL_CHANGES_SAVED:"All changes saved",SAVE_FORM:"Save form",UNSAVED_CHANGES:"You have unsaved changes. If you leave this page, you will lose those changes!"}},b.fields={},b.inputFields={},b.nonInputFields={},b.registerField=function(a,c){var d,e,f,g;for(g=["view","edit"],e=0,f=g.length;f>e;e++)d=g[e],c[d]=_.template(c[d]);return c.field_type=a,b.fields[a]=c,"non_input"===c.type?b.nonInputFields[a]=c:b.inputFields[a]=c},b}(),window.Formbuilder=c,"undefined"!=typeof module&&null!==module?module.exports=c:window.Formbuilder=c}.call(this),function(){Formbuilder.registerField("address",{order:50,view:"
\n \n \n \n \n
\n\n
\n \n \n \n \n\n \n \n \n \n
\n\n
\n \n \n \n \n\n \n \n \n \n
",edit:"",addButton:' Address'})}.call(this),function(){Formbuilder.registerField("checkboxes",{order:10,view:"<% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\n \n
\n<% } %>\n\n<% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n<% } %>",edit:"<%= Formbuilder.templates['edit/options']({ includeOther: true }) %>",addButton:' Checkboxes',defaultAttributes:function(a){return a.field_options.options=[{label:"",checked:!1},{label:"",checked:!1}],a}})}.call(this),function(){Formbuilder.registerField("date",{order:20,view:"
\n \n \n \n \n\n /\n\n \n \n \n \n\n /\n\n \n \n \n \n
",edit:"",addButton:' Date'})}.call(this),function(){Formbuilder.registerField("dropdown",{order:24,view:"",edit:"<%= Formbuilder.templates['edit/options']({ includeBlank: true }) %>",addButton:' Dropdown',defaultAttributes:function(a){return a.field_options.options=[{label:"",checked:!1},{label:"",checked:!1}],a.field_options.include_blank_option=!1,a}})}.call(this),function(){Formbuilder.registerField("email",{order:40,view:"",edit:"",addButton:' Email'})}.call(this),function(){Formbuilder.registerField("file",{order:55,view:"",edit:"",addButton:' File'})}.call(this),function(){Formbuilder.registerField("number",{order:30,view:"\n<% if (units = rf.get(Formbuilder.options.mappings.UNITS)) { %>\n <%= units %>\n<% } %>",edit:"<%= Formbuilder.templates['edit/min_max']() %>\n<%= Formbuilder.templates['edit/units']() %>\n<%= Formbuilder.templates['edit/integer_only']() %>",addButton:'123 Number'})}.call(this),function(){Formbuilder.registerField("paragraph",{order:5,view:"",edit:"<%= Formbuilder.templates['edit/size']() %>\n<%= Formbuilder.templates['edit/min_max_length']() %>",addButton:' Paragraph',defaultAttributes:function(a){return a.field_options.size="small",a}})}.call(this),function(){Formbuilder.registerField("price",{order:45,view:"
\n $\n \n \n \n \n .\n \n \n \n \n
",edit:"",addButton:' Price'})}.call(this),function(){Formbuilder.registerField("radio",{order:15,view:"<% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\n \n
\n<% } %>\n\n<% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n<% } %>",edit:"<%= Formbuilder.templates['edit/options']({ includeOther: true }) %>",addButton:' Multiple Choice',defaultAttributes:function(a){return a.field_options.options=[{label:"",checked:!1},{label:"",checked:!1}],a}})}.call(this),function(){Formbuilder.registerField("section_break",{order:0,type:"non_input",view:"\n

<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

",edit:"
Label
\n\n",addButton:" Section Break"})}.call(this),function(){Formbuilder.registerField("text",{order:0,view:"",edit:"<%= Formbuilder.templates['edit/size']() %>\n<%= Formbuilder.templates['edit/min_max_length']() %>",addButton:" Text",defaultAttributes:function(a){return a.field_options.size="small",a}})}.call(this),function(){Formbuilder.registerField("time",{order:25,view:"
\n \n \n \n \n\n :\n\n \n \n \n \n\n :\n\n \n \n \n \n\n \n \n \n
",edit:"",addButton:' Time'})}.call(this),function(){Formbuilder.registerField("website",{order:35,view:"",edit:"<%= Formbuilder.templates['edit/size']() %>",addButton:' Website'})}.call(this),this.Formbuilder=this.Formbuilder||{},this.Formbuilder.templates=this.Formbuilder.templates||{},this.Formbuilder.templates["edit/base"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+=(null==(__t=Formbuilder.templates["edit/base_header"]())?"":__t)+"\n"+(null==(__t=Formbuilder.templates["edit/common"]())?"":__t)+"\n"+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].edit({rf:rf}))?"":__t)+"\n";return __p},this.Formbuilder.templates["edit/base_header"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
\n \n \n \n
";return __p},this.Formbuilder.templates["edit/base_non_input"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+=(null==(__t=Formbuilder.templates["edit/base_header"]())?"":__t)+"\n"+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].edit({rf:rf}))?"":__t)+"\n";return __p},this.Formbuilder.templates["edit/checkboxes"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="\n";return __p},this.Formbuilder.templates["edit/common"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
Label
\n\n
\n
\n "+(null==(__t=Formbuilder.templates["edit/label_description"]())?"":__t)+"\n
\n
\n "+(null==(__t=Formbuilder.templates["edit/checkboxes"]())?"":__t)+"\n
\n
\n
\n";return __p},this.Formbuilder.templates["edit/integer_only"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
Integer only
\n\n";return __p},this.Formbuilder.templates["edit/label_description"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="\n";return __p},this.Formbuilder.templates["edit/min_max"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+='
Minimum / Maximum
\n\nAbove\n\n\n  \n\nBelow\n\n';return __p},this.Formbuilder.templates["edit/min_max_length"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+='
Length Limit
\n\nMin\n\n\n  \n\nMax\n\n\n  \n\n\n';return __p},this.Formbuilder.templates["edit/options"]=function(obj){obj||(obj={});{var __t,__p="";_.escape,Array.prototype.join}with(obj)__p+="
Options
\n\n","undefined"!=typeof includeBlank&&(__p+="\n \n"),__p+="\n\n
\n \n \n \n \n
\n\n',"undefined"!=typeof includeOther&&(__p+="\n \n'),__p+="\n\n
\n Add option\n
\n';return __p},this.Formbuilder.templates["edit/size"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
Size
\n\n';return __p},this.Formbuilder.templates["edit/units"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+='
Units
\n\n';return __p},this.Formbuilder.templates.page=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+=(null==(__t=Formbuilder.templates["partials/save_button"]())?"":__t)+"\n"+(null==(__t=Formbuilder.templates["partials/left_side"]())?"":__t)+"\n"+(null==(__t=Formbuilder.templates["partials/right_side"]())?"":__t)+"\n
";return __p},this.Formbuilder.templates["partials/add_field"]=function(obj){obj||(obj={});{var __t,__p="";_.escape,Array.prototype.join}with(obj)__p+="
\n
\n
\n ",_.each(_.sortBy(Formbuilder.inputFields,"order"),function(a){__p+='\n \n '+(null==(__t=a.addButton)?"":__t)+"\n \n "}),__p+="\n
\n\n
\n ",_.each(_.sortBy(Formbuilder.nonInputFields,"order"),function(a){__p+='\n \n '+(null==(__t=a.addButton)?"":__t)+"\n \n "}),__p+="\n
\n
\n
";return __p},this.Formbuilder.templates["partials/edit_field"]=function(obj){obj||(obj={});{var __p="";_.escape}with(obj)__p+="
\n
\n
\n";return __p},this.Formbuilder.templates["partials/left_side"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
\n \n\n
\n "+(null==(__t=Formbuilder.templates["partials/add_field"]())?"":__t)+"\n "+(null==(__t=Formbuilder.templates["partials/edit_field"]())?"":__t)+"\n
\n
";return __p},this.Formbuilder.templates["partials/right_side"]=function(obj){obj||(obj={});{var __p="";_.escape}with(obj)__p+="
\n
No response fields
\n
\n
\n";return __p},this.Formbuilder.templates["partials/save_button"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
\n \n
";return __p},this.Formbuilder.templates["view/base"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
\n
\n "+(null==(__t=Formbuilder.templates["view/label"]({rf:rf}))?"":__t)+"\n\n "+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].view({rf:rf}))?"":__t)+"\n\n "+(null==(__t=Formbuilder.templates["view/description"]({rf:rf}))?"":__t)+"\n "+(null==(__t=Formbuilder.templates["view/duplicate_remove"]({rf:rf}))?"":__t)+"\n
\n";return __p},this.Formbuilder.templates["view/base_non_input"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
\n
\n "+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].view({rf:rf}))?"":__t)+"\n "+(null==(__t=Formbuilder.templates["view/duplicate_remove"]({rf:rf}))?"":__t)+"\n
\n";return __p},this.Formbuilder.templates["view/description"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="\n "+(null==(__t=Formbuilder.helpers.simple_format(rf.get(Formbuilder.options.mappings.DESCRIPTION)))?"":__t)+"\n\n";return __p},this.Formbuilder.templates["view/duplicate_remove"]=function(obj){obj||(obj={});{var __t,__p="";_.escape}with(obj)__p+="
\n \n \n
';return __p},this.Formbuilder.templates["view/label"]=function(obj){obj||(obj={});{var __t,__p="";_.escape,Array.prototype.join}with(obj)__p+="\n";return __p}; \ No newline at end of file +(function(){rivets.binders.append={routine:function(a,b){return a.checked=void 0!==_.find(b,function(b){return String(b)===String(a.value)})},bind:function(a){var b=this;return this.callback=function(){var c,d;return c=_.clone(b.model.get(b.keypath))||[],_.contains(c,a.value)?(d=_.without(c,a.value),b.model.set(b.keypath,d)):(c.push(a.value),b.model.set(b.keypath,c))},$(a).on("change",this.callback)},unbind:function(a){return $(a).off("change",this.callback)}},rivets.formatters.length=function(a){return a?a.length:0},rivets.binders.input={publishes:!0,routine:rivets.binders.value.routine,bind:function(a){return $(a).bind("input.rivets",this.publish)},unbind:function(a){return $(a).unbind("input.rivets")}},rivets.configure({prefix:"rv",adapter:{subscribe:function(a,b,c){return c.wrapped=function(a,b){return c(b)},a.on("change:"+b,c.wrapped)},unsubscribe:function(a,b,c){return a.off("change:"+b,c.wrapped)},read:function(a,b){return"cid"===b?a.cid:a.get(b)},publish:function(a,b,c){return a.cid?a.set(b,c):a[b]=c}}})}).call(this),function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p={}.hasOwnProperty,q=function(a,b){function c(){this.constructor=a}for(var d in b)p.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},r=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};e=function(a){function b(){return i=b.__super__.constructor.apply(this,arguments)}var d;return q(b,a),d={},b.prototype.sync=function(){},b.prototype.indexInDOM=function(){return void 0===d[this.cid]&&$(".fb-field-wrapper").each(function(a,b){return d[$(b).data("cid")]=$(b),!0}),(d[this.cid]||{index:function(){return-1}}).index(".fb-field-wrapper")},b.prototype.is_input=function(){return null!=c.inputFields[this.get(c.options.mappings.TYPE)]},b.prototype.initialize=function(){return null==this.attributes.uuid&&(this.attributes.uuid=uuid.v4()),void 0===!this.attributes.parent_uuid&&(this.attributes.parent_uuid=null),this.attachMethods()},b.prototype.parentModel=function(){var a;return a=this.collection,a?this.collection.findWhereUuid(this.get("parent_uuid")):void 0},b.prototype.hasParent=function(){return void 0!==this.parentModel()},b.prototype.inTable=function(){var a;return a=this.parentModel(),a&&"table"===a.get("type")},b.prototype.inGrid=function(){var a;return a=this.parentModel(),a&&"grid"===a.get("type")},b.prototype.canBeConditionallyDisplayed=function(){return!this.inTable()&&!this.inGrid()&&c.conditionalFunctionality},b.prototype.canShowReferenceID=function(){return c.showReferenceIDFunctionality},b.prototype.conditionalParent=function(){var a;return a=this.get(c.options.mappings.CONDITIONAL_PARENT),a?this.collection.findWhereUuid(a):null},b.prototype.conditionalChildren=function(){var a;return a=this.attributes.uuid,this.collection.filter(function(b){return a===b.get(c.options.mappings.CONDITIONAL_PARENT)})},b.prototype.answers=function(){return this.get("answers")||[]},b.prototype.conditionalTriggerOptions=function(a){var b,d,e;return d=this.conditionalParent(),b=[],d&&("approval"===d.get("type")?b="Is Approved":(b=_.clone(d.answers()),b.unshift({uuid:"",label:"[No Selection]"}),a&&(e=this.get(c.options.mappings.CONDITIONAL_VALUES)||[],b=_.filter(b,function(a){var b;return b=a.uuid,r.call(e,b)>=0})))),b},b.prototype.isValid=function(){var a,b,d,e,f,g;return(b=this.canBeConditionallyDisplayed())?(f=this.attributes.options,a=f.conditional,a&&(d=a.parent,e=a.values,g=this.conditionalParent(),g&&"approval"===g.get("type")&&(this.get(c.options.mappings.CONDITIONAL_VALUES)||this.set(c.options.mappings.CONDITIONAL_VALUES,1),e=1)),d&&e&&0!==e.length||"undefined"==typeof e&&"undefined"==typeof d?!0:!1):!0},b.prototype.attachMethods=function(){return"function"==typeof this.attributes.initialize&&(this.attributes.initialize.call(this),delete this.attributes.initialize),"function"==typeof this.attributes.insertion&&(this.insertion=this.attributes.insertion,delete this.attributes.insertion),_.each(this.attributes,function(a,b){return"function"==typeof a&&void 0===this[b]?(this[b]=a,delete this.attributes[b]):void 0},this)},b}(Backbone.DeepModel),d=function(a){function b(){return j=b.__super__.constructor.apply(this,arguments)}return q(b,a),b.prototype.model=e,b.prototype.comparator=function(a){return a.indexInDOM()},b.prototype.add=function(a){var c;return c=a=b.__super__.add.call(this,a),_.isArray(a)||(c=[a]),_.each(c,function(a){return"function"==typeof a.insertion?a.insertion.call(a):void 0}),a},b.prototype.findWhereUuid=function(a){return this.findWhere({uuid:a})},b.prototype.findDataSourceFields=function(){return this.where({type:"datasource"})},b.prototype.findConditionalTriggers=function(a){var b;return b=this.filter(function(b){var c,d,e,f;return c="dropdown"===(f=b.get("type"))||"checkbox"===f||"radio"===f||"approval"===f,d=b!==a,e=!b.hasParent(),c&&d&&e})},b.prototype.clearConditionEle=function(a){return a.unset(c.options.mappings.CONDITIONAL)},b}(Backbone.Collection),h=function(a){function b(){return k=b.__super__.constructor.apply(this,arguments)}return q(b,a),b.insert=function(a,b,c,d,e){var f,g,h,i,j;return i=c.parentModel(),void 0===i||"grid"===i.get("type")||"table"===i.get("type")?(h=e.$appendEl||null,j=e.$replaceEl||null,f=a.$responseFields.find("a.dragdrop-placeholder"),null!=h?h.html(b.render().el):null!=j?j.replaceWith(b.render().el):f[0]?(f.after(b.render().el),f.remove()):null==e.position||-1===e.position?a.$responseFields.append(b.render().el):0===e.position?a.$responseFields.prepend(b.render().el):(g=a.$responseFields.find(".fb-field-wrapper").eq(e.position))[0]?g.before(b.render().el):a.$responseFields.append(b.render().el)):void 0},b.prototype.className="fb-field-wrapper",b.prototype.events={"click .subtemplate-wrapper":"focusEditView","click .js-duplicate":"duplicate","click .js-clear":"clear"},b.prototype.initialize=function(a){return this.parentView=a.parentView,this.listenTo(this.model,"change",this.render),this.listenTo(this.model,"destroy",this.remove)},b.prototype.render=function(){return this.$el.addClass("response-field-"+this.model.get(c.options.mappings.TYPE)).data("cid",this.model.cid).data("uuid",this.model.get("uuid")).html(c.templates["view/base"+(this.model.is_input()?"":"_non_input")]({rf:this.model})),this},b.prototype.focusEditView=function(){return this.parentView.createAndShowEditView(this.model)},b.prototype.clear=function(a){var b,d,e=this;switch(a.preventDefault(),a.stopPropagation(),_.each(this.model.conditionalChildren(),function(a){return a.unset(c.options.mappings.CONDITIONAL_PARENT),a.unset(c.options.mappings.CONDITIONAL_VALUES)}),b=function(){return e.parentView.handleFormUpdate(),e.model.destroy()},d=c.options.CLEAR_FIELD_CONFIRM,typeof d){case"string":if(confirm(d))return b();break;case"function":return d(b);default:return b()}},b.prototype.duplicate=function(a){var b,d,e;a.preventDefault(),a.stopPropagation(),d=c.helpers.clone(this.model.attributes),b=c.helpers.defaultFieldAttrs(d.type,{});for(e in d)b[e]=d[e];return delete b.id,delete b.cid,delete b.uuid,b.label+=" Copy",b.options.grid&&(b.options.grid.row=b.options.grid.row+1),this.parentView.createField(b,{position:this.model.indexInDOM()+1}),this.model.trigger("duplicate:viewfield")},b}(Backbone.View),g=function(a){function b(){return l=b.__super__.constructor.apply(this,arguments)}return q(b,a),b.prototype.className="fb-field-wrapper",b.prototype.initialize=function(a){return this.parentView=a.parentView,this.listenTo(this.model,"change",this.update),this.listenTo(this.model,"destroy",this.remove),_.each(this.model.get("options.elements"),function(a){var b;return b=this.model.collection.findWhereUuid(a.uuid),b?this.listenTo(b,"change",this.update):console.log(a.uuid)},this)},b.prototype.events={mouseenter:"showSelectors",mouseleave:"removeSelectors","click .drop-area li":"inlineAdd","click .subtemplate-wrapper":"focusEditView","click .response-field-table td.header":"focusSubelement","click .response-field-table td.element":"focusSubelement","click .js-clear":"clear","click .js-duplicate":"duplicate"},b.prototype.showSelectors=function(a){return this.$el.find(".drop-area").html(c.templates["view/element_selector"]())},b.prototype.removeSelectors=function(a){return this.$el.find(".drop-area").html("")},b.prototype.inlineAdd=function(a){var b,d,f;return a.preventDefault(),a.stopPropagation(),b=new e(c.helpers.defaultFieldAttrs($(a.currentTarget).data("type"))),b.set("parent_uuid",this.model.get("uuid")),b.set("options.in_sequence",!0),this.listenTo(b,"change",this.update),d=this.model.attributes.options.elements||[],f={uuid:b.get("uuid")},d.push(f),this.model.attributes.options.elements=d,this.parentView.collection.add(b),this.update(b)},b.prototype.update=function(a){return a?(this.render(),this.parentView.createAndShowEditView(a)):void 0},b.prototype.render=function(){return b.__super__.render.call(this),this.renderElements(),this},b.prototype.focusEditView=function(a){return $(a.target).parents(".dropdown-toggle").length||$(a.target).hasClass("dropdown-toggle")?void 0:this.parentView.createAndShowEditView(this.model)},b.prototype.focusSubelement=function(a){var b;return a.preventDefault(),a.stopPropagation(),b=$(a.currentTarget).data("uuid"),b?this.parentView.createAndShowEditView(this.parentView.modelByUuid(b)):void 0},b.prototype.renderElements=function(){return _.each(this.model.get("options.elements"),function(a){var b;return b=this.parentView.modelByUuid(a.uuid),this.$el.find(".header-"+a.uuid).html(c.templates["view/table_header"]({rf:b,element:a})).css("background-color",b.get(c.options.mappings.LABEL_BACKGROUND_COLOR)).data("cid",b.cid),this.$el.find(".element-"+a.uuid).html(c.templates["view/table_element"]({rf:b,element:a})).data("cid",b.cid),this.$el.find(".total-"+a.uuid).html(c.templates["view/table_total"]({rf:b,element:a})).data("cid",b.cid)},this)},b.prototype.clear=function(a){var b,c;return a.preventDefault(),a.stopPropagation(),c=$(a.currentTarget).parents(".element").data("uuid"),void 0===c?(b=_.each(this.model.get("options.elements"),function(a){return this.parentView.modelByUuid(a.uuid).destroy(),!0},this),this.model.destroy(),this.$el.remove()):(this.parentView.modelByUuid(c).destroy(),this.model.set("options.elements",_.filter(this.model.get("options.elements"),function(a){return a.uuid!==c})),this.render())},b.prototype.duplicate=function(){var a,b,d,f,g=this;return a=c.helpers.clone(this.model.attributes),delete a.id,delete a.cid,a.uuid=uuid.v4(),a.label+=" Copy",f=a.options.elements,a.options.elements=[],a=_.extend({},c.helpers.defaultFieldAttrs("table"),a),this.parentView.createField(a,{position:-1}),d=this.parentView.viewByUuid(a.uuid),b=this.parentView.modelByUuid(a.uuid),_.each(f,function(f){var h,i,j,k;return h=g.parentView.modelByUuid(f.uuid),i=c.helpers.clone(h),delete i.id,delete i.cid,f.uuid=i.uuid=uuid.v4(),i.parent_uuid=a.uuid,i=_.extend({},c.helpers.defaultFieldAttrs(i.type),i),j=new e(i),f.totalColumn&&(k=b.createTotalColumnModel(i.uuid),f.totalColumnUuid=k.get("uuid")),g.parentView.collection.add(j),void 0!==j.expression&&j.get("options.calculation_type")&&j.expression(),d.listenTo(j,"change",d.update),a.options.elements.push(f)}),d.render()},b.insert=function(a,b,c,d,e){var f;return f=a.viewByUuid(c.get("parent_uuid")),null!=f?!0:!1},b}(h),f=function(a){function b(){return m=b.__super__.constructor.apply(this,arguments)}return q(b,a),b.prototype.className="fb-field-wrapper",b.prototype.events={"click .response-field-grid-cell li":"inlineAdd","click .response-field-grid-cell .js-clear":"subelementClear","click .js-duplicate":"duplicate","click .js-clear":"clear","click .subtemplate-wrapper":"focusEditView"},b.prototype.initialize=function(a){return this.parentView=a.parentView,this.listenTo(this.model,"change",this.redraw),this.listenTo(this.model,"destroy",this.remove),this.parentView.collection.bind("add",this.addSubelement,this),this.parentView.collection.bind("destroy",this.removeSubelement,this),this.render},b.prototype.render=function(){return b.__super__.render.call(this),this.redraw(),this.renderChildren(),this},b.prototype.redraw=function(){var a;return a=this.$el.find(".response-field-grid-table").detach(),this.$el.addClass("response-field-"+this.model.get(c.options.mappings.TYPE)).data("cid",this.model.cid).data("uuid",this.model.get("uuid")).html(c.templates["view/base"+(this.model.is_input()?"":"_non_input")]({rf:this.model})),1===a.length&&this.$el.find(".response-field-grid-table").replaceWith(a),this.renderTable()},b.prototype.renderTable=function(){var a,b,d,e,f,g,h,i,j,k=this;return e=this.model.get("options.num_rows")||1,d=this.model.get("options.num_cols")||1,h=this.$el.find("table"),b=h.find("tr").length,a=h.find("tr:nth-child(1) td").length,f=$.makeArray(h.find("tr")),e>b&&(f=f.concat(function(){j=[];for(var a=i=f.length;e>=i?e>a:a>e;e>=i?a++:a--)j.push(a);return j}.apply(this))),f=_.map(f,function(a){var b,e,f;return _.isNumber(a)&&(a=$('').appendTo(h)),b=$.makeArray($(a).find("td")),b.length=e?d>a:a>d;d>=e?a++:a--)f.push(a);return f}.apply(this))),b=_.map(b,function(b){return _.isNumber(b)?b=$('').appendTo(a).html(c.templates["view/element_selector"]()):void 0}),a}),b>e&&(g=this.subelements(),_.each(g,function(a){var b;return b=k.parentView.gridAttr(a),b.row>e-1?a.destroy():void 0}),h.find("tr").slice(e-b).remove()),a>d?(g=this.subelements(),_.each(g,function(a){var b;return b=k.parentView.gridAttr(a),b.col>d-1?a.destroy():void 0}),h.find("tr").find("td:gt("+(d-1)+")").remove()):void 0},b.prototype.renderChildren=function(){var a,b=this;return a=this.model.get("children")||[],_.each(a,function(a){var c;return c=a.options.grid,b.createField(a,b.getSubelement(c.row,c.col))})},b.prototype.focusEditView=function(a){return 0===$(a.target).parents("table").length?this.parentView.createAndShowEditView(this.model):void 0},b.prototype.clear=function(a){var b,d,e=this;switch(a.preventDefault(),a.stopPropagation(),b=function(){var a;return e.parentView.handleFormUpdate(),a=e.subelements(),_.each(e.subelements(),function(a){return a.destroy(),!0}),e.model.destroy()},d=c.options.CLEAR_FIELD_CONFIRM,typeof d){case"string":if(confirm(d))return b();break;case"function":return d(b);default:return b()}},b.prototype.duplicate=function(){var a,b,d=this;return a=c.helpers.clone(this.model.attributes),delete a.id,delete a.cid,a.uuid=uuid.v4(),a.label+=" Copy",b=this.subelements(),delete a.children,this.parentView.createField(a,{position:-1}),a.children=_.map(b,function(b){var e;return e=c.helpers.clone(b.attributes),delete e.id,delete e.cid,delete e.uuid,e.parent_uuid=a.uuid,d.parentView.createField(e,{position:-1})})},b.prototype.addSubelement=function(a){var b,c;return this.belongsToMe(a)&&a.get("label").match(/Copy/)?(b=this.parentView.gridAttr(a),c=a.get("label").match(/(.+) Copy/),null!==c?a.attributes.label=c[1]+" "+(b.row+1):a.attributes.label="Row: "+(b.row+1)+", Col: "+(b.col+1)):void 0},b.prototype.removeSubelement=function(a){var b,d;return d=this.parentView.gridAttr(a),b=this.belongsToMe(a),b&&""===this.getSubelement(d.row,d.col).html()?this.getSubelement(d.row,d.col).html(c.templates["view/element_selector"]({rf:this.model})):void 0},b.prototype.subelements=function(){var a=this;return this.parentView.collection.filter(function(b){return a.belongsToMe(b)})},b.prototype.belongsToMe=function(a){return this.parentView.inGrid(a)&&a.get("parent_uuid")===this.model.get("uuid")},b.prototype.inlineAdd=function(a){var b,c;return a.preventDefault(),a.stopPropagation(),c=$(a.currentTarget).data("type"),b=$(a.currentTarget).parents(".response-field-grid-cell"),this.createField(c,b)},b.prototype.getSubelement=function(a,b){return a++,b++,this.$el.find("tr:nth-child("+a+") td:nth-child("+b+")")},b.prototype.createField=function(a,b){return _.isString(a)&&(a=c.helpers.defaultFieldAttrs(a)),a.options.disallow_duplication=!0,a.options.grid={col:b.prop("cellIndex"),row:b.parents("tr").prop("rowIndex")},a.parent_uuid=this.model.get("uuid"),this.parentView.createField(a,{$appendEl:b})},b.insert=function(a,b,c,d,e){var f,g,i;return e.$appendEl||(i=c.get("options.grid.row"),g=c.get("options.grid.col"),c.attributes.options.disallow_duplication=!0,f=a.wrapperByUuid(c.get("parent_uuid")),f=f.find("tr:nth-child("+(i+1)+") td:nth-child("+(g+1)+")"),1===f.length&&(e.$appendEl=f)),h.insert(a,b,c,d,e)},b}(Backbone.View),b=function(a){function b(){return n=b.__super__.constructor.apply(this,arguments)}return q(b,a),b.prototype.className="edit-response-field",b.prototype.events={"click .js-add-option":"addOption","click .js-remove-option":"removeOption","click .js-default-updated":"defaultUpdated","input .option-label-input":"forceRender"},b.prototype.initialize=function(a){var b=this;return this.parentView=a.parentView,this.listenTo(this.model,"destroy",this.remove),_.each(c.options.change,function(a,d){var e;return e="change:"+_.nested(c.options.mappings,d),b.listenTo(b.model,e,a)})},b.prototype.render=function(){return this.$el.html(c.templates["edit/base"+(this.model.is_input()?"":"_non_input")]({rf:this.model})),rivets.bind(this.$el,{model:this.model}),this},b.prototype.reset=function(){return this.stopListening(),this.parentView.editView=void 0,this.parentView.createAndShowEditView(this.model)},b.prototype.resetConditional=function(){return this.model.unset(c.options.mappings.CONDITIONAL_VALUES)},b.prototype.resetInlineImages=function(){return this.model.unset(c.options.mappings.INLINE_IMAGES_REQUIRED)},b.prototype.resetInlineActions=function(){return this.model.unset(c.options.mappings.INLINE_ACTIONS_REQUIRED)},b.prototype.deselectReadOnly=function(){return this.model.set(c.options.mappings.READ_ONLY,!1)},b.prototype.remove=function(){return this.parentView.editView=void 0,this.parentView.$el.find('[data-target="#addField"]').click(),this.stopListening(),b.__super__.remove.apply(this,arguments)},b.prototype.addOption=function(a){var b,d,e,f;return b=$(a.currentTarget),d=this.$el.find(".option").index(b.closest(".option")),f=this.model.get(c.options.mappings.OPTIONS)||[],e={uuid:uuid.v4(),label:"",checked:!1},d>-1?f.splice(d+1,0,e):f.push(e),this.model.set(c.options.mappings.OPTIONS,f),this.model.trigger("change:"+c.options.mappings.OPTIONS),this.forceRender()},b.prototype.removeOption=function(a){var b,d,e;return b=$(a.currentTarget),d=this.$el.find(".js-remove-option").index(b),e=this.model.get(c.options.mappings.OPTIONS),e.splice(d,1),this.model.set(c.options.mappings.OPTIONS,e),this.model.trigger("change:"+c.options.mappings.OPTIONS),this.forceRender()},b.prototype.defaultUpdated=function(a){var b;return b=$(a.currentTarget),"checkboxes"!==this.model.get(c.options.mappings.TYPE)&&this.$el.find(".js-default-updated").not(b).attr("checked",!1).trigger("change"),this.forceRender()},b.prototype.forceRender=function(){return this.model.trigger("change",this.model)},b}(Backbone.View),a=function(a){function e(){return o=e.__super__.constructor.apply(this,arguments)}return q(e,a),e.prototype.SUBVIEWS=[],e.prototype.saveFormButton=$(),e.prototype.events={"click .fb-tabs a":"showTab","click .fb-add-types a":"addField","mouseover .fb-add-types":"lockLeftWrapper","mouseout .fb-add-types":"unlockLeftWrapper"},e.prototype.initialize=function(a){var b;return b=a.selector,this.formBuilder=a.formBuilder,this.bootstrapData=a.bootstrapData,null!=b&&this.setElement($(b)),this.collection=new d,this.collection.bind("add",this.addOne,this),this.collection.bind("reset",this.reset,this),this.collection.bind("change",this.handleFormUpdate,this),this.collection.bind("destroy add reset",this.hideShowNoResponseFields,this),this.collection.bind("destroy",this.ensureEditViewScrolled,this),this.render(),this.collection.reset(this.bootstrapData),this.bindSaveEvent()},e.prototype.bindSaveEvent=function(){var a=this;return this.formSaved=!0,this.saveFormButton.attr("disabled",!0).text(c.options.dict.ALL_CHANGES_SAVED),c.options.AUTOSAVE&&setInterval(function(){return a.saveForm.call(a)},5e3),$(window).bind("beforeunload",function(){return a.formSaved?void 0:c.options.dict.UNSAVED_CHANGES})},e.prototype.reset=function(){return this.$responseFields.html(""),this.addAll()},e.prototype.render=function(){var a,b,d,e;for(this.$el.html(c.templates.page()),this.$fbLeft=this.$el.find(".fb-left"),this.$responseFields=this.$el.find(".fb-response-fields"),this.bindWindowScrollEvent(),this.hideShowNoResponseFields(),e=this.SUBVIEWS,b=0,d=e.length;d>b;b++)a=e[b],new a({parentView:this}).render();return this},e.prototype.bindWindowScrollEvent=function(){var a=this;return $(window).on("scroll",function(){var b,c;if(a.$fbLeft.data("locked")!==!0)return c=Math.max(0,$(window).scrollTop()-a.$el.offset().top),b=a.$responseFields.height(),a.$fbLeft.css({"margin-top":Math.min(b,c)})})},e.prototype.showTab=function(a){var b,c,d,e;return b=$(a.currentTarget),d=!0,e=b.data("target"),this.editView&&!this.editView.model.isValid()&&(d=!1),(d||!d&&"#editField"===e)&&(b.closest("li").addClass("active").siblings("li").removeClass("active"),$(e).addClass("active").siblings(".fb-tab-pane").removeClass("active")),"#editField"!==e&&this.unlockLeftWrapper(),"#editField"===e&&!this.editView&&(c=this.collection.models[0])?this.createAndShowEditView(c):void 0},e.prototype.createView=function(a){var b;return b="grid"===a.attributes.type?new f({model:a,parentView:this}):"table"===a.attributes.type?new g({model:a,parentView:this}):new h({model:a,parentView:this})},e.prototype.insert=function(a,b,c,d){var e,i,j,k;return e=!1,i=b.parentModel(),j=i?i.get("type"):void 0,k=j||b.get("type"),"grid"===k?e=f.insert(this,a,b,c,d):"table"===k&&(e=g.insert(this,a,b,c,d)),e||(e=h.insert(this,a,b,c,d)),e},e.prototype.addOne=function(a,b,c){var d;return d=this.createView(a),this.$responseFields.find("> .ui-draggable").remove(),a.get("model_only")!==!0&&this.insert(d,a,b,c),this.views[a.get("uuid")]=d},e.prototype.setSortable=function(){var a=this;return this.$responseFields.hasClass("ui-sortable")&&this.$responseFields.sortable("destroy"),this.$responseFields.sortable({forcePlaceholderSize:!0,placeholder:"sortable-placeholder",stop:function(b,d){var e;return d.item.data("type")&&(d.item.after(''),e=a.collection.create(c.helpers.defaultFieldAttrs(d.item.data("type")),{$replaceEl:d.item}),a.createAndShowEditView(e)),a.handleFormUpdate(),!0},update:function(b,c){return c.item.data("type")?void 0:a.ensureEditViewScrolled()}}),this.setDraggable()},e.prototype.setDraggable=function(){var a,b=this;return a=this.$el.find("[data-type]"),a.draggable({connectToSortable:this.$responseFields,helper:function(){var a;return a=$("
"),a.css({width:b.$responseFields.width(),height:"80px"}),a}})},e.prototype.addAll=function(){return this.collection.each(function(a,b,c){return this.addOne.call(this,a,b,{})},this),this.setSortable()},e.prototype.hideShowNoResponseFields=function(){return this.$el.find(".fb-no-response-fields")[this.collection.length>0?"hide":"show"]()},e.prototype.addField=function(a){var b;return b=$(a.currentTarget).data("type"),this.createField(c.helpers.defaultFieldAttrs(b,{}))},e.prototype.createField=function(a,b){var c;return c=this.collection.create(a,b),this.createAndShowEditView(c),this.handleFormUpdate()},e.prototype.createAndShowEditView=function(a){var d,e,f,g,h,i,j,k;if(f=this.$el.find(".fb-field-wrapper").filter(function(){return $(this).data("cid")===a.cid}),i=!0,this.editView){if(this.editView.model.cid===a.cid)return this.$el.find('.fb-tabs a[data-target="#editField"]').click(),void this.scrollLeftWrapper(f);i=this.editView.model.isValid(),i?this.editView.remove():$(".fb-edit-section-conditional-wrapper #warning-message").show()}return i&&($(".fb-field-wrapper").removeClass("parent"),$(".fb-option").removeClass("trigger-option"),$(".fb-field-wrapper").removeClass("editing"),f.addClass("editing")),j=a.conditionalParent(),j&&(k=a.get(c.options.mappings.CONDITIONAL_VALUES)||[],e=this.$el.find(".fb-field-wrapper").filter(function(){return $(this).data("cid")===j.cid}),e.addClass("parent"),e.find(".fb-option").filter(function(){var a,b;return a=$(this).data("uuid"),b=$(this).data("uuid"),r.call(k,b)>=0}).each(function(){return $(this).addClass("trigger-option")})),i&&(this.editView=new b({model:a,parentView:this}),d=this.editView.render().$el,h=this.$el.find(".fb-edit-field-wrapper"),h.html(d),this.inGrid(a)?h.addClass("fb-edit-field-grid"):h.removeClass("fb-edit-field-grid"),a.inTable()&&$(".spectrum-colorpicker",".fb-edit-field-wrapper").spectrum({allowEmpty:!0,preferredFormat:"hex",showPalette:!0,showPaletteOnly:!0,palette:["#000000","#424242","#636363","#9C9C94","#CEC6CE","#EFEFEF","#F7F7F7","#FFFFFF","#FF0000","#FF9C00","#FFFF00","#00FF00","#00FFFF","#0000FF","#9C00FF","#FF00FF","#F7C6CE","#FFE7CE","#FFEFC6","#D6EFD6","#CEDEE7","#CEE7F7","#D6D6E7","#E7D6DE","#E79C9C","#FFC69C","#FFE79C","#B5D6A5","#A5C6CE","#9CC6EF","#B5A5D6","#D6A5BD","#E76363","#F7AD6B","#FFD663","#94BD7B","#73A5AD","#6BADDE","#8C7BC6","#C67BA5","#CE0000","#E79439","#EFC631","#6BA54A","#4A7B8C","#3984C6","#634AA5","#A54A7B","#9C0000","#B56308","#BD9400","#397B21","#104A5A","#085294","#311873","#731842","#630000","#7B3900","#846300","#295218","#083139","#003163","#21104A","#4A1031"]}),this.$el.find('.fb-tabs a[data-target="#editField"]').click(),this.scrollLeftWrapper(f),g=c.helpers.defaultFieldAttrs(a.get("type")),void 0!==g.definition.onEdit&&g.definition.onEdit(a),this.$el.find("input, textarea, [contenteditable=true]").filter(":visible").first().focus()),this},e.prototype.inGrid=function(a){return this.hasParent(a)&&a.get("options.grid")},e.prototype.inTable=function(a){return this.hasParent(a)&&a.get("options.table")},e.prototype.hasParent=function(a){return a.get("parent_uuid")},e.prototype.modelByUuid=function(a){return this.collection.findWhere({uuid:a})},e.prototype.wrapperByUuid=function(a){return $(".fb-field-wrapper").filter(function(){return $(this).data("uuid")===a})},e.prototype.viewByUuid=function(a){return this.views[a]},e.prototype.views={},e.prototype.gridAttr=function(a){return this.inGrid(a)?a.get("options.grid"):null},e.prototype.ensureEditViewScrolled=function(){return this.editView?this.scrollLeftWrapper($(".fb-field-wrapper.editing")):void 0},e.prototype.scrollLeftWrapper=function(a){var b=this;return this.unlockLeftWrapper(),a[0]?$.scrollWindowTo(this.$el.offset().top+a.offset().top-this.$responseFields.offset().top,200,function(){return b.lockLeftWrapper()}):void 0},e.prototype.lockLeftWrapper=function(){return this.$fbLeft.data("locked",!0)},e.prototype.unlockLeftWrapper=function(){return this.$fbLeft.data("locked",!1)},e.prototype.handleFormUpdate=function(){return this.collection.sort(),this.updatingBatch?void 0:(this.formSaved=!1,this.saveFormButton.removeAttr("disabled").text(c.options.dict.SAVE_FORM))},e.prototype.getPayload=function(){return JSON.stringify({fields:this.collection.toJSON()})},e.prototype.saveForm=function(a){var b;if(!this.formSaved)return this.formSaved=!0,this.saveFormButton.attr("disabled",!0).text(c.options.dict.ALL_CHANGES_SAVED),this.collection.sort(),b=this.getPayload(),c.options.HTTP_ENDPOINT&&this.doAjaxSave(b),this.formBuilder.trigger("save",b)},e.prototype.doAjaxSave=function(a){var b=this;return $.ajax({url:c.options.HTTP_ENDPOINT,type:c.options.HTTP_METHOD,data:a,contentType:"application/json",success:function(a){var c,d,e,f;for(b.updatingBatch=!0,d=0,e=a.length;e>d;d++)c=a[d],null!=(f=b.collection.get(c.cid))&&f.set({id:c.id}),b.collection.trigger("sync");return b.updatingBatch=void 0}})},e}(Backbone.View),c=function(){function b(c){var d,e;null==c&&(c={}),_.extend(this,Backbone.Events),d=_.extend(c,{formBuilder:this}),this.attrs={},e=_(d.bootstrapData||[]).groupBy(function(a){return void 0===a.parent_uuid?0:1}).toArray().value(),e=_.reduce(e,function(a,b){return a.concat(b)}),d.bootstrapData=_.map(e,function(a){return _.extend({},b.helpers.defaultFieldAttrs(a.type),a)}),this.mainView=new a(d),this.mainView.collection,b.instances.push(this)}return b.attrs={},b.instances=[],b.attr=function(a,c){return void 0!==c&&(b.attrs[a]=c,_.each(this.instances,function(a){return a.mainView.reset()})),void 0!==b.attrs[a]?b.attrs[a]:void 0},b.conditionalFunctionality=!0,b.showReferenceIDFunctionality=!1,b.geolocationFunctionality=!0,b.linkAssetFunctionality=!1,b.linkAssetDisplayFields={},b.disableField=function(a){return this.fields[a].enabled=!1},b.helpers={defaultFieldAttrs:function(a){var c,d;return c={},c[b.options.mappings.LABEL]="Untitled",c[b.options.mappings.TYPE]=a,c[b.options.mappings.REQUIRED]=!1,c[b.options.mappings.INLINE_IMAGES_ENABLED]=!1,c[b.options.mappings.INLINE_IMAGES_REQUIRED]=!1,c[b.options.mappings.INLINE_ACTIONS_ENABLED]=!1,c[b.options.mappings.INLINE_ACTIONS_REQUIRED]=!1,c.definition=b.fields[a],c.options={},("function"==typeof(d=b.fields[a]).defaultAttributes?d.defaultAttributes(c,b):void 0)||c},simple_format:function(a){var b;return null!=(b=this.escape_html(a))?b.replace(/\n/g,"
"):void 0},clone:function(a){return JSON.parse(JSON.stringify(a))},escape_html:function(a){var b;return b={"&":"&","<":"<",">":">",'"':""","'":"'"},null!=a?a.replace(/[&<>"']/g,function(a){return b[a]}):void 0}},b.options={BUTTON_CLASS_SELECTOR:"fb-button btn btn-default",BUTTON_CLASS_ADD:"fb-button btn btn-xs btn-primary",BUTTON_CLASS_REMOVE:"fb-button btn btn-xs btn-danger",HTTP_ENDPOINT:"",HTTP_METHOD:"POST",AUTOSAVE:!1,CLEAR_FIELD_CONFIRM:!1,ENABLED_FIELDS:["text","checkbox","dropdown","textarea","radio","date","section","signature","info","grid","number","table","datasource","time","geolocation","approval"],INLINE_IMAGE_FIELDS:["text","info"],mappings:{SIZE:"options.size",UNITS:"options.units",LABEL:"label",NAME:"definition.name",TYPE:"type",REQUIRED:"required",ADMIN_ONLY:"admin_only",POPULATE_FROM:"options.populate_from",POPULATE_UUID:"options.populate_uuid",CONDITIONAL_PARENT:"options.conditional.parent",CONDITIONAL_VALUES:"options.conditional.values",CONDITIONAL:"options.conditional",OPTIONS:"answers",DESCRIPTION:"description",INCLUDE_OTHER:"options.include_other_option",INCLUDE_BLANK:"options.include_blank_option",INCLUDE_SCORING:"is_scored",INTEGER_ONLY:"options.integer_only",LABEL_COLOR:"options.label_color",LABEL_BACKGROUND_COLOR:"options.label_background_color",READ_ONLY:"options.read_only",COLUMN_WIDTH:"options.column_width",DEFAULT_TIME:"options.default_time",DEFAULT_DATE:"options.default_date",REFERENCE_ID:"reference_id",INLINE_IMAGES_ENABLED:"options.inline_images_enabled",INLINE_IMAGES_REQUIRED:"options.inline_images_required",INLINE_ACTIONS_ENABLED:"options.inline_actions_enabled",INLINE_ACTIONS_REQUIRED:"options.inline_actions_required",NUMERIC:{CALCULATION_TYPE:"options.calculation_type",CALCULATION_EXPRESSION:"options.calculation_expression",CALCULATION_DISPLAY:"options.calculation_display",TOTAL_SEQUENCE:"options.total_sequence"},GRID:{COLS:"options.cols",NUMCOLS:"options.num_cols",ROWS:"options.rows",NUMROWS:"options.num_rows",FULL_WIDTH:"options.full_width",FIRST_ROW_HEADINGS:"options.first_row_headings"},TABLE:{COLS:"options.cols",NUMCOLS:"options.num_cols",ROWS:"options.rows",INITIALROWS:"options.initial_rows",MAXROWS:"options.max_rows",FULL_WIDTH:"options.full_width",COLUMNTOTALS:"options.display_column_totals",ROWTOTALS:"options.display_row_totals"},DATA_SOURCE:{MULTIPLE:"options.multiple_selections",DATA_SOURCE:"options.data_source",VALUE_TEMPLATE:"options.value_template",REQUIRED_PROPERTIES:"options.required_properties",FILTER:"options.filter",FILTER_VALUES:"options.filter_values",IS_FILTERED:"options.is_filtered"},MIN:"options.min",MAX:"options.max",OPTIONS_PER_ROW:"options.options_per_row",MINLENGTH:"options.minlength",MAXLENGTH:"options.maxlength",LENGTH_UNITS:"options.min_max_length_units", +APPROVAL:{APPROVER_TYPE:"options.approver_type",APPROVER_ID:"options.approver_id"},DISALLOW_DUPLICATION:"options.disallow_duplication"},change:{REQUIRED:function(){return this.reset(),this.resetInlineImages(),this.resetInlineActions()},INLINE_IMAGES_ENABLED:function(){return this.reset(),this.resetInlineImages()},INLINE_IMAGES_REQUIRED:function(){return this.reset()},INLINE_ACTIONS_ENABLED:function(){return this.reset(),this.resetInlineActions()},INLINE_ACTIONS_REQUIRED:function(){return this.reset()},INCLUDE_SCORING:function(){return this.reset()},POPULATE_UUID:function(){return this.model.get(b.options.mappings.POPULATE_UUID)||this.deselectReadOnly(),this.reset()},CONDITIONAL_PARENT:function(){return this.reset(),this.resetConditional()},CONDITIONAL_VALUES:function(){return this.reset()},"DATA_SOURCE.DATA_SOURCE":function(){return this.reset()},"DATA_SOURCE.IS_FILTERED":function(){return this.reset()},"DATA_SOURCE.FILTER":function(){return this.reset()},"APPROVAL.APPROVER_TYPE":function(){return this.reset()}},dict:{ALL_CHANGES_SAVED:"All changes saved",SAVE_FORM:"Save form",UNSAVED_CHANGES:"You have unsaved changes. If you leave this page, you will lose those changes!"}},b.fields={},b.inputFields={},b.nonInputFields={},b.prototype.markSaved=function(){return this.mainView.formSaved=!0},b.prototype.isValid=function(){var a;return a=!0,this.mainView.editView&&!this.mainView.editView.model.isValid()&&(a=!1),a},b.prototype.getPayload=function(){return this.mainView.getPayload()},b.registerField=function(a,c){var d,e,f,g,h,i;for(d=!0,e=b.options.ENABLED_FIELDS,_.contains(e,a)||(d=!1),i=["view","edit"],g=0,h=i.length;h>g;g++)f=i[g],c[f]=d?_.template(c[f]):function(a){return""};return c.type=a,c.enabled=d,b.fields[a]=c,"non_input"===c.element_type?b.nonInputFields[a]=c:b.inputFields[a]=c},b}(),void 0===_.nested&&_.mixin({nested:function(a,b){return a&&b?a[b]||_.reduce(b.split("."),function(a,b){return a?a[b]:void 0},a):void 0}}),window.Formbuilder=c,window.FormbuilderModel=e,"undefined"!=typeof module&&null!==module?module.exports=c:window.Formbuilder=c}.call(this),function(){Formbuilder.registerField("address",{name:"Address",order:50,view:"
\n \n \n \n \n
\n\n
\n \n \n \n \n\n \n \n \n \n
\n\n
\n \n \n \n \n\n \n \n \n \n
",edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Address'})}.call(this),function(){Formbuilder.registerField("approval",{name:"Approval",order:75,view:'
\n \n
\n
\n
Sign Here
\n
\n
\n',edit:"<%= Formbuilder.templates['edit/approval_options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Approval',onEdit:function(a){return $(".fb-approval-user-select").select2()},defaultAttributes:function(a,b){return a.initialize=function(){return this.on("change",function(a){var b,c;return b=this.conditionalParent(),b&&"approval"===b.get("type")&&a.set(Formbuilder.options.mappings.CONDITIONAL_VALUES,1),1===parseInt(this.get(Formbuilder.options.mappings.APPROVAL.APPROVER_TYPE))?a.set(Formbuilder.options.mappings.APPROVAL.APPROVER_ID,void 0):(c=this.get("options.approver"),void 0!==c?a.set(Formbuilder.options.mappings.APPROVAL.APPROVER_ID,parseInt(c)):void 0)})},a.getApprovers=function(){return b.attr("approvers")},a.getSelectedUserName=function(a){return a?a.full_name+" ("+a.username+")":void 0},a.getSelectedUser=function(){var a,b,c;return c=this.options?options.approver_id:this.get(Formbuilder.options.mappings.APPROVAL.APPROVER_ID),a=this.getApprovers()||[],b=a.filter(function(a){return parseInt(a.id)===c}),this.getSelectedUserName(b[0])},a.showApprovers=function(){return 2===parseInt(this.get(Formbuilder.options.mappings.APPROVAL.APPROVER_TYPE))},a.options.approver_type=1,a}})}.call(this),function(){Formbuilder.registerField("checkbox",{name:"Checkboxes",order:10,view:"
\">\n <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\n \n
\n <% } %>\n\n <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n <% } %>\n
",edit:"<%= Formbuilder.templates['edit/options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/options_per_row']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Checkboxes',defaultAttributes:function(a){return a.answers=[{uuid:uuid.v4(),label:"",checked:!1,score:!1},{uuid:uuid.v4(),label:"",checked:!1,score:!1}],a.options.options_per_row=1,a}})}.call(this),function(){Formbuilder.registerField("datasource",{name:"List",order:70,view:"",edit:"<%= Formbuilder.templates['edit/data_source_options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Data Source',defaultAttributes:function(a,b){var c;return a.initialize=function(){return this.on("change",function(a){var b,c,d;return b=a.filters(),void 0!==_.nested(a,"changed.options.data_source")&&(c=_.keys(a.sourceProperties()),a.set("options.required_properties",c),d=_.first(c),a.set("options.value_template",d)),b?a.set("options.filter",_.first(_.keys(b))):void 0}),this.on("destroy",function(a){return this.collection.each(function(b){return b.get("options.populate_uuid")===a.get("uuid")?(b.set("options.populate_uuid",null),b.set("options.populate_from",null)):void 0})})},a.source=function(){var a,c;return a=this.options?this.options.data_source:this.get(Formbuilder.options.mappings.DATA_SOURCE.DATA_SOURCE),c=b.attr("sources"),_.nested(c,a)||{}},a.sourceProperties=function(){var a;return a=this.source(),_.nested(a,"properties")||[]},a.filters=function(){var a;return a=this.source(),_.nested(a,"filters")||null},a.currentFilter=function(){var a;return a=this.source(),_.nested(a,"filters."+this.get("options.filter"))||{}},a.filterValues=function(){return this.currentFilter().values||{}},a.sourceProperty=function(a){return this.sourceProperties()[a]||null},a.options.multiple_selections=!1,a.options.is_filtered=!1,c=b.attr("sources")||{},a.options.data_source=_.keys(c)[0],a.options.required_properties=_.keys(a.sourceProperties(a.options.data_source)),a.options.filter=null,a.options.filter_values=[],a.options.value_template=_.first(a.options.required_properties),a}})}.call(this),function(){Formbuilder.registerField("date",{name:"Date",order:20,view:'
\n \n
',edit:"<%= Formbuilder.templates['edit/date']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Date',defaultAttributes:function(a){return a.options.default_date=!1,a}})}.call(this),function(){Formbuilder.registerField("dropdown",{name:"Dropdown",order:24,view:"",edit:"<%= Formbuilder.templates['edit/scoring']() %>\n<%= Formbuilder.templates['edit/options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Dropdown',defaultAttributes:function(a){return a.answers=[{uuid:uuid.v4(),label:"",checked:!1,score:""},{uuid:uuid.v4(),label:"",checked:!1,score:""}],a.is_scored=!1,a.options.include_blank_option=!1,a}})}.call(this),function(){Formbuilder.registerField("email",{name:"Email",order:40,view:"",edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Email'})}.call(this),function(){Formbuilder.registerField("file",{name:"File",order:55,view:"",edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' File'})}.call(this),function(){Formbuilder.registerField("geolocation",{name:"Geolocation",order:60,view:"
\n \n
\n<%=rf.geolocationFunctionality%>",edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' GeoLocation'})}.call(this),function(){Formbuilder.registerField("grid",{name:"Layout Grid",order:99,element_type:"non_input",view:"\n\n
\n

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

",edit:'
Details
\n
\n
\n \n \n
\n \n \n
Number of Columns
\n \n
Number of Rows
\n \n
\n
',addButton:' Grid',hideAddButton:!0,defaultAttributes:function(a){return a.options.num_cols=1,a.options.num_rows=1,a.options.full_width=!1,a.options.first_row_headings=!1,a.children=[],a.childModels=function(){return this.collection.filter(function(a){return-1!==_.indexOf(this.get("options.elements"),a.get("uuid"))},this)},a}})}.call(this),function(){Formbuilder.registerField("info",{name:"Info",order:20,element_type:"non_input",view:"\n

<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

",edit:'
Details
\n
\n
\n \n
\n \n
\n<%= Formbuilder.templates[\'edit/inline_image_option\']({ rf: rf }) %>\n<%= Formbuilder.templates[\'edit/conditional_options\']({ rf: rf }) %>',addButton:' Info',onEdit:function(a){var b;return b=function(){return a.set(Formbuilder.options.mappings.DESCRIPTION,$(this).code()),a.trigger("change:"+Formbuilder.options.mappings.DESCRIPTION)},$(".fb-info-editor").summernote({onChange:function(){return b.call(this)},onKeyup:function(){return b.call(this)},disableDragAndDrop:!0,toolbar:[["style",["bold","italic","underline"]],["fontsize",["fontsize"]],["color",["color"]],["insert",["link"]],["table",["table"]],["misc",["codeview"]]]})}})}.call(this),function(){Formbuilder.registerField("number",{name:"Number",order:30,view:"\" <%- rf.get(Formbuilder.options.mappings.NUMERIC.CALCULATION_DISPLAY) ? 'readonly=\"readonly\"' : '' %> />\n<% if (units = rf.get(Formbuilder.options.mappings.UNITS)) { %>\n <%= units %>\n<% } %>",edit:"<%= Formbuilder.templates['edit/integer_only']({rf:rf}) %>\n<%= Formbuilder.templates['edit/total']({rf:rf}) %>\n<%= Formbuilder.templates['edit/min_max']({rf:rf}) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Number',defaultAttributes:function(a,b){return a.options.calculation_type="",a.options.calculation_expression="",a.options.calculation_display="",a.options.total_sequence=!1,a.insertion=function(){var a,b;return a=this.parentModel(),a&&"table"===a.get("type")?(b=a.totalColumn(this.get("uuid")),this.attributes.options.total_sequence=b):void 0},a.initialize=function(){return this.on("change",function(a){var b;return void 0!==_.nested(a,"changed.options.calculation_type")&&a.expression(),void 0!==_.nested(a,"changed.options.total_sequence")&&(b=_.nested(a,"changed.options.total_sequence"),this.parentModel().totalColumn(a.get("uuid"),b)),a})},a.numericSiblings=function(){var a;return a=this.parentModel(),a?_.filter(a.childModels(),function(a){return"number"===a.get("type")&&a.get("uuid")!==this.get("uuid")},this):[]},a.expression=function(){var a,b,c;return a=this.get("options.calculation_type"),""!==a?(c="SUM"===a?"+":"*",b=this.numericSiblings(),this.set("options.calculation_expression",_.map(b,function(a){return"uuid_"+a.get("uuid").replace(/-/g,"_")}).join(c)),this.set("options.calculation_display","= "+_.map(b,function(a){return a.get("label")}).join(c)),console.log(this.get("options.calculation_expression"))):(this.set("options.calculation_expression",""),this.set("options.calculation_display",""))},a.canTotalColumn=function(){var a;return a=this.parentModel(),a&&"table"===a.get("type")},a.canAcceptCalculatedTotal=function(){return this.numericSiblings().length>1},a}})}.call(this),function(){Formbuilder.registerField("price",{name:"Price",order:45,view:"
\n $\n \n \n \n \n .\n \n \n \n \n
",edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Price'})}.call(this),function(){Formbuilder.registerField("radio",{name:"Radio Button",order:15,view:"
\">\n <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\">\n \n
\n <% } %>\n\n <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n <% } %>\n
",edit:"<%= Formbuilder.templates['edit/scoring']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/options_per_row']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Radio Button',defaultAttributes:function(a){return a.answers=[{uuid:uuid.v4(),label:"",checked:!1,score:""},{uuid:uuid.v4(),label:"",checked:!1,score:""}],a.is_scored=!1,a.options.options_per_row=1,a}})}.call(this),function(){Formbuilder.registerField("section",{name:"Section",order:10,element_type:"non_input",view:"\n

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

",edit:'
Details
\n
\n
\n \n \n
\n
\n<%= Formbuilder.templates[\'edit/conditional_options\']({ rf: rf }) %>',addButton:' Section Break'})}.call(this),function(){Formbuilder.registerField("signature",{name:"Signature",order:65,view:'
\n
Sign Here
\n
\n
\n',edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Signature'})}.call(this),function(){Formbuilder.registerField("table",{name:"Table",order:0,element_type:"non_input",view:"\n<%= Formbuilder.templates[\"view/table_field\"]({rf: rf}) %>\n

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

",edit:"
Details
\n
\n
\n <%= Formbuilder.templates['edit/label_description']({rf: rf}) %>\n
\n
\n
\n",addButton:' Table',defaultAttributes:function(a){return a.options.full_width=!1,a.initialize=function(){var a;return a=this,_.each(this.childModels,function(b){return b.on("change",function(b){return void 0!==_.nested(b,"changed.options.column_width")&&a.columnWidth(b.get("uuid"),b.get("options.column_width")),b})})},a.childModels=function(){var a;return a=_.pluck(this.get("options.elements"),"uuid"),this.collection.filter(function(b){return-1!==_.indexOf(a,b.get("uuid"))},this)},a.elementOptions=function(a){return _.findWhere(this.get("options.elements"),{uuid:a})},a.createTotalColumnModel=function(a){var b;return b=new FormbuilderModel(Formbuilder.helpers.defaultFieldAttrs("number")),b.set("options.calculation_expression","sum(column_uuid_"+a.replace(/-/g,"_")+")"),b.set("model_only",!0),b.set("parent_uuid",a),this.collection.add(b),b},a.columnWidth=function(a,b){var c;return c=this.get("options.elements"),_.each(c,function(d,e){return d.uuid===a?c[e].columnWidth=b:void 0},this)},a.totalColumn=function(a,b){var c;return c=this.get("options.elements"),void 0!==b?(_.each(c,function(d,e){var f;return d.uuid===a?(void 0===d.totalColumnUuid&&(f=this.createTotalColumnModel(d.uuid),c[e].totalColumnUuid=f.get("uuid")),c[e].totalColumn=b):void 0},this),this.set("options.elements",c)):this.elementOptions(a)?this.elementOptions(a).totalColumn||!1:!1},a}})}.call(this),function(){Formbuilder.registerField("text",{name:"Text",order:0,view:"\n readonly=\"readonly\"\n <% } %>\n/>",edit:"<%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/populate_from']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Text',defaultAttributes:function(a){return a.options.size="small",a.options.read_only=!1,a}})}.call(this),function(){Formbuilder.registerField("textarea",{name:"Paragraph",order:5,view:"",edit:"<%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/populate_from']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Paragraph',defaultAttributes:function(a){return a.options.size="small",a.options.read_only=!1,a}})}.call(this),function(){Formbuilder.registerField("time",{name:"Time",order:25,view:'
\n
\n \n
\n
\n
',edit:"<%= Formbuilder.templates['edit/time']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Time',defaultAttributes:function(a){return a.options.default_time=!1,a}})}.call(this),function(){Formbuilder.registerField("website",{name:"Website",order:35,view:"",edit:"<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>",addButton:' Website'})}.call(this),this.Formbuilder=this.Formbuilder||{},this.Formbuilder.templates=this.Formbuilder.templates||{},this.Formbuilder.templates["edit/approval_options"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj){if(__p+='
Approver
\n
\n
\n \n
\n
\n \n
\n ",rf.showApprovers()){__p+='\n
\n \n
\n "}__p+="\n
\n\n"}return __p},this.Formbuilder.templates["edit/base"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+=(null==(__t=Formbuilder.templates["edit/base_header"]({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.templates["edit/common"]({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].edit({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.templates["edit/columnwidth"]({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.templates["edit/table_color"]({rf:rf}))?"":__t)+"\n";return __p},this.Formbuilder.templates["edit/base_header"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
\n \n \n \n
\n";return __p},this.Formbuilder.templates["edit/base_non_input"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+=(null==(__t=Formbuilder.templates["edit/base_header"]({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].edit({rf:rf}))?"":__t)+"\n";return __p},this.Formbuilder.templates["edit/checkboxes"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="\n";return __p},this.Formbuilder.templates["edit/columnwidth"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='';return __p},this.Formbuilder.templates["edit/common"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)rf.canShowReferenceID()&&(__p+="\n
\n
Reference ID
\n "+(null==(__t=Formbuilder.templates["edit/reference_id"]({rf:rf}))?"":__t)+"\n
\n"),__p+="\n
Details
\n\n
\n
\n "+(null==(__t=Formbuilder.templates["edit/label_description"]({rf:rf}))?"":__t)+"\n
\n
\n "+(null==(__t=Formbuilder.templates["edit/checkboxes"]())?"":__t)+"\n
\n
\n
";return __p},this.Formbuilder.templates["edit/conditional_options"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;Array.prototype.join;with(obj){if(rf.canBeConditionallyDisplayed()){__p+='\n
\n
Conditionally Display\n \n \n \n \n\n
\n ';var list=rf.collection.findConditionalTriggers(rf);if(list.length){__p+='\n \n ";var selectedList=rf.conditionalTriggerOptions();if(Array.isArray(selectedList)){0==selectedList.length&&rf.collection.clearConditionEle(rf);for(i in selectedList)__p+="\n \n "}else __p+="\n
\n \n
\n ";__p+="\n "}else __p+="\n No trigger elements\n ";__p+="\n "}__p+='\n \n
\n
\n'}return __p},this.Formbuilder.templates["edit/data_source_options"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;Array.prototype.join;with(obj){__p+="
Data Source
\n\n
Display
\n\n",rf.filters()){if(__p+="\n
Filter
\n \n ", +rf.get(Formbuilder.options.mappings.DATA_SOURCE.IS_FILTERED)){__p+='\n \n ";for(i in rf.filterValues())__p+="\n \n ";__p+="\n"}__p+="\n"}}return __p},this.Formbuilder.templates["edit/date"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='
\n \n
\n";return __p},this.Formbuilder.templates["edit/inline_action_option"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)rf.hasParent()||(__p+='\n
\n
Add action\n \n \n \n \n\n
\n \n ",rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED)&&(rf.get(Formbuilder.options.mappings.REQUIRED)||"info"===rf.get("type"))&&(__p+="\n \n "),__p+="\n\n
\n");return __p},this.Formbuilder.templates["edit/inline_image_option"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)rf.hasParent()||(__p+='\n
\n
Add photo\n \n \n \n \n\n
\n \n ",rf.get(Formbuilder.options.mappings.INLINE_IMAGES_ENABLED)&&(rf.get(Formbuilder.options.mappings.REQUIRED)||"info"===rf.get("type"))&&(__p+="\n \n "),__p+="\n\n
\n");return __p},this.Formbuilder.templates["edit/integer_only"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="\n";return __p},this.Formbuilder.templates["edit/label_description"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="\n";return __p},this.Formbuilder.templates["edit/min_max"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='
Minimum / Maximum
\n\nMin\n\n\n  \n\nMax\n\n';return __p},this.Formbuilder.templates["edit/min_max_length"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='
Length Limit
\n\nMin\n\n\n  \n\nMax\n\n\n  \n\n\n';return __p},this.Formbuilder.templates["edit/options"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)__p+="
Options
\n\n","undefined"!=typeof includeBlank&&(__p+="\n \n"),__p+="\n\n
\n\n \n ',rf.get(Formbuilder.options.mappings.INCLUDE_SCORING)&&(__p+='\n \n '),__p+='\n\n \n
\n\n',"undefined"!=typeof includeOther&&(__p+="\n \n'),__p+="\n\n
\n \n
\n';return __p},this.Formbuilder.templates["edit/options_per_row"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
Number of options per row
\n \n';return __p},this.Formbuilder.templates["edit/populate_from"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;Array.prototype.join;with(obj){var list=rf.collection.findDataSourceFields();if(list.length){__p+="\n
Populate From
\n \n \n ",rf.get(Formbuilder.options.mappings.POPULATE_UUID)&&(__p+='\n
\n \n
\n "),__p+="\n"}__p+="\n"}return __p},this.Formbuilder.templates["edit/reference_id"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='";return __p},this.Formbuilder.templates["edit/scoring"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='
\n \n
\n\n";return __p},this.Formbuilder.templates["edit/size"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
Size
\n\n';return __p},this.Formbuilder.templates["edit/table_color"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)rf.inTable()&&(__p+='\n
\n
Header Label Colour
\n
\n \n
\n
Header Background Colour
\n
\n \n
\n
\n");return __p},this.Formbuilder.templates["edit/table_layout"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
Layout
\n \n\n \n';return __p},this.Formbuilder.templates["edit/table_totals"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
Totals
\n \n";return __p},this.Formbuilder.templates["edit/time"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='
\n \n
\n";return __p},this.Formbuilder.templates["edit/total"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)rf.canTotalColumn()&&(__p+='\n\n"),__p+="\n",rf.canAcceptCalculatedTotal()&&(__p+="\n
Total
\n\n'),__p+="\n\n";return __p},this.Formbuilder.templates["edit/units"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+='
Units
\n\n';return __p},this.Formbuilder.templates.page=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+=(null==(__t=Formbuilder.templates["partials/left_side"]())?"":__t)+"\n"+(null==(__t=Formbuilder.templates["partials/right_side"]())?"":__t)+"\n
";return __p},this.Formbuilder.templates["partials/add_field"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)__p+="
\n
\n \n\n
\n ",_.chain(Formbuilder.nonInputFields).sortBy("order").filter(function(a){return a.enabled}).each(function(a){__p+='\n \n '+(null==(__t=a.addButton)?"":__t)+"\n \n "}),__p+="\n
\n
\n
";return __p},this.Formbuilder.templates["partials/edit_field"]=function(obj){obj||(obj={});var __p="";_.escape;with(obj)__p+="
\n
\n
\n";return __p},this.Formbuilder.templates["partials/left_side"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
\n \n\n
\n "+(null==(__t=Formbuilder.templates["partials/add_field"]())?"":__t)+"\n "+(null==(__t=Formbuilder.templates["partials/edit_field"]())?"":__t)+"\n
\n
";return __p},this.Formbuilder.templates["partials/right_side"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)__p+="
\n
No response fields
\n ",Formbuilder.linkAssetFunctionality&&(__p+="\n "+(null==(__t=Formbuilder.templates["view/link_object"]({object:Formbuilder.linkAssetDisplayFields}))?"":__t)+'\n
\n '),__p+="\n
\n
\n";return __p},this.Formbuilder.templates["view/afterelementlabel"]=function(obj){obj||(obj={});var __p="";_.escape,Array.prototype.join;with(obj)__p+="
\n ",rf.get(Formbuilder.options.mappings.INLINE_IMAGES_ENABLED)&&(__p+='\n \n Inline Photo\n ',rf.get(Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED)&&(__p+="\n *\n "),__p+="\n "),__p+="\n
\n";return __p},this.Formbuilder.templates["view/base"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)__p+="
\n
\n "+(null==(__t=Formbuilder.templates["view/conditional"]({rf:rf}))?"":__t)+"\n "+(null==(__t=Formbuilder.templates["view/label"]({rf:rf}))?"":__t)+"\n\n "+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf:rf}))?"":__t)+"\n\n "+(null==(__t=Formbuilder.templates["view/description"]({rf:rf}))?"":__t)+"\n \n ",__p+=rf.get(Formbuilder.options.mappings.DISALLOW_DUPLICATION)?"\n "+(null==(__t=Formbuilder.templates["view/remove"]({rf:rf}))?"":__t)+"\n ":"\n "+(null==(__t=Formbuilder.templates["view/duplicate_remove"]({rf:rf}))?"":__t)+"\n ",__p+="\n\n "+(null==(__t=Formbuilder.templates["view/afterelementlabel"]({rf:rf}))?"":__t)+"\n \n
\n";return __p},this.Formbuilder.templates["view/base_non_input"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)__p+="
\n
\n "+(null==(__t=Formbuilder.templates["view/conditional"]({rf:rf}))?"":__t)+"\n "+(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf:rf}))?"":__t)+"\n\n ",__p+=rf.get(Formbuilder.options.mappings.DISALLOW_DUPLICATION)?"\n "+(null==(__t=Formbuilder.templates["view/remove"]({rf:rf}))?"":__t)+"\n ":"\n "+(null==(__t=Formbuilder.templates["view/duplicate_remove"]({rf:rf}))?"":__t)+"\n ",__p+="\n\n "+(null==(__t=Formbuilder.templates["view/afterelementlabel"]({rf:rf}))?"":__t)+"\n
\n";return __p},this.Formbuilder.templates["view/conditional"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj){var parent=rf.conditionalParent();if(parent){if(__p+='\n
\n \n ',"approval"==parent.get("type"))__p+='\n \n display when '+(null==(__t=parent.get("label"))?"":__t)+'\n '+(null==(__t=rf.conditionalTriggerOptions(!0))?"":__t)+"\n \n ";else{var triggerValues=_.pluck(rf.conditionalTriggerOptions(!0),"label");__p+='\n \n display when '+(null==(__t=parent.get("label"))?"":__t)+' is\n '+(null==(__t=triggerValues.join('or'))?"":__t)+"\n \n "}__p+="\n
\n\n"}__p+="\n\n"}return __p},this.Formbuilder.templates["view/description"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj)__p+="\n ",__p+="info"==rf.get("type")?"\n "+(null==(__t=rf.get(Formbuilder.options.mappings.DESCRIPTION))?"":__t)+"\n ":"\n "+(null==(__t=Formbuilder.helpers.simple_format(rf.get(Formbuilder.options.mappings.DESCRIPTION)))?"":__t)+"\n ",__p+="\n";return __p},this.Formbuilder.templates["view/duplicate_remove"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
\n \n \n
';return __p},this.Formbuilder.templates["view/element_selector"]=function(obj){obj||(obj={});var __p="";_.escape;with(obj)__p+='
\n\n\n
\n';return __p},this.Formbuilder.templates["view/label"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;Array.prototype.join;with(obj)__p+='\n";return __p},this.Formbuilder.templates["view/link_object"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj){__p+='\n\n\n"}return __p},this.Formbuilder.templates["view/remove"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+="
\n \n
';return __p},this.Formbuilder.templates["view/table_element"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+=(null==(__t=Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.templates["view/remove"]({rf:rf}))?"":__t);return __p},this.Formbuilder.templates["view/table_field"]=function(obj){obj||(obj={});var __t,__p="";_.escape,Array.prototype.join;with(obj){__p+='\n'+(null==(__t=Formbuilder.templates["view/element_selector"]())?"":__t)+'\n\n\n\n \n \n ';for(i in rf.get("options.elements")||[])__p+='\n \n ';__p+="\n \n \n ";for(i in rf.get("options.elements")||[])__p+='\n \n ';__p+="\n \n \n \n \n ";for(i in rf.get("options.elements")||[])__p+='\n \n ';__p+="\n \n \n
"}return __p},this.Formbuilder.templates["view/table_header"]=function(obj){obj||(obj={});var __t,__p="";_.escape;with(obj)__p+=(null==(__t=Formbuilder.templates["view/label"]({rf:rf}))?"":__t)+"\n"+(null==(__t=Formbuilder.templates["view/description"]({rf:rf}))?"":__t);return __p},this.Formbuilder.templates["view/table_total"]=function(obj){obj||(obj={});var __p="";_.escape,Array.prototype.join;with(obj)rf.get("options.total_sequence")&&(__p+='\n(Column Total)\n');return __p}; \ No newline at end of file diff --git a/dist/formbuilder.css b/dist/formbuilder.css index 331fbb8e..589942ef 100644 --- a/dist/formbuilder.css +++ b/dist/formbuilder.css @@ -1,10 +1,27 @@ -.fb-button{display:inline-block;margin:0;padding:.563rem .844rem;border:0 none;background:#16a085;color:#fff;text-align:center;text-decoration:none;font-size:12px;line-height:1.5;cursor:pointer;border-radius:.125rem;border:thin solid #19b394;border-bottom:2px solid #16a085} -.fb-button[disabled]{background:#ddd !important;border:thin solid #ccc;color:#777 !important;text-shadow:none !important;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=65)";opacity:.65;cursor:default} +[class^="fb-icon-"]:before,[class*=" fb-icon-"]:before{font-family:"fontello";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em} +.fb-icon-date:before{content:'\f133'} +.fb-icon-radio:before{content:'\f192'} +.fb-icon-checkbox:before{content:'\e893'} +.fb-icon-data-source:before{content:'\f1c0'} +.fb-icon-dropdown:before{content:'\e854'} +.fb-icon-signature:before{content:'\e830'} +.fb-icon-info:before{content:'\f129'} +.fb-icon-table:before{content:'\f0ce'} +.fb-icon-textarea:before{content:'\f1dd'} +.fb-icon-section:before{content:'\f2d1'} +.fb-icon-text:before{content:'\e87d'} +.fb-icon-number:before{content:'\f162'} +.fb-icon-time:before{content:'\e84a'} +.fb-icon-conditional:before{content:'\E824'} +.fb-icon-geolocation:before{content:'\e839'} +.fb-icon-approval:before{content:'\f14b'} +.fb-icon-grid:before{content:'\e810'} +.fb-button{text-align:left} .fb-clear{clear:both} -.fb-main{max-width:1000px;margin:0 auto;padding:0 20px 0 0;position:relative;font-family:'Source Sans Pro','Open Sans',Tahoma} +.fb-main{padding:0 20px 0 0;position:relative} .fb-save-wrapper{position:absolute;right:20px;top:10px} .fb-left{float:left;width:320px;padding-top:30px} -.fb-right{padding-top:70px;margin-left:320px;border-left:1px solid #ddd;padding-left:20px;min-height:100%;overflow:hidden} +.fb-right{padding-top:70px;margin-left:320px;border-left:1px solid #ddd;padding-left:20px;padding-bottom:150px;min-height:100%;overflow:hidden} .fb-no-response-fields{color:#999} .fb-tabs{list-style:none;margin:0 0 20px 0;padding:0 0 0 20px;border-bottom:1px solid #ccc} .fb-tabs li{display:inline-block} @@ -12,26 +29,27 @@ .fb-tabs li.active a{border:1px solid #ccc;margin-bottom:-1px;border-bottom-color:#fff} .fb-tab-content .fb-tab-pane{padding:0 20px;display:none} .fb-tab-content .fb-tab-pane.active{display:block} -.fb-add-field-types .section{padding-bottom:5px;margin-bottom:20px} -.fb-add-field-types{font-size:0} -.fb-add-field-types a{font-size:13px;display:inline-block;width:48.5%;background-color:#1abc9c;margin-bottom:9px;box-sizing:border-box} -.fb-add-field-types a:nth-child(odd){margin-right:3%} -.fb-add-field-types a .symbol{opacity:.6;margin:0 .25em 0 -1em} +.fb-add-types .section{padding-bottom:5px;margin-bottom:20px} +.fb-add-types{font-size:0} +.fb-add-types a{font-size:13px;display:inline-block;width:48.5%;margin-bottom:9px;box-sizing:border-box} +.fb-add-types a:nth-child(odd){margin-right:3%} +.fb-add-types a .symbol{opacity:.6;margin:0 .25em 0 -1em} .fb-response-fields{padding-bottom:150px} .fb-response-fields a.sortable-placeholder{display:block;border:1px dashed #ddd;min-height:80px;height:80px;width:100%} .fb-field-wrapper{cursor:pointer;position:relative;margin-bottom:20px} .fb-field-wrapper input{border-radius:3px;border:thin solid #ddd} .fb-field-wrapper:hover .actions-wrapper,.fb-field-wrapper.editing .actions-wrapper{display:block} .fb-field-wrapper:hover .subtemplate-wrapper{border-color:#ddd;border-radius:3px} -.fb-field-wrapper.editing{background-color:#ecf0f1;border-radius:3px} +.fb-field-wrapper.editing{background-color:#ecf0f1;border-radius:3px;box-shadow:inset 0 0 7px 2px rgba(100,100,100,0.1);border:1px solid rgba(100,100,100,0.2)} +.fb-field-wrapper.parent{box-shadow:rgba(0,0,0,0.3) 1px 1px 10px} .fb-field-wrapper.editing .subtemplate-wrapper{border-color:#d9e1e3;border-style:solid;margin:0;border-radius:3px} .fb-field-wrapper .actions-wrapper{display:none;position:absolute;bottom:-7px;right:5px;z-index:3} .fb-field-wrapper .actions-wrapper a{display:inline-block;background-color:#ccc;padding:2px 8px} +.edit-response-field .options{background-color:#eee;max-height:600px;overflow-y:auto;padding:3px;border-radius:3px;border:thin solid #ddd} .edit-response-field input,.edit-response-field textarea,.edit-response-field select{border:thin solid #ddd;border-radius:.25em;padding:.5em;display:inline-block;height:auto;vertical-align:middle} -.edit-response-field input:focus,.edit-response-field textarea:focus,.edit-response-field select:focus{outline:none;border:thin solid #1abc9c} -.edit-response-field select{font-size:14px} -.fb-field-wrapper .actions-wrapper a.js-duplicate,.fb-edit-field-wrapper .js-add-option{background-color:#2ecc71;border:none} -.fb-field-wrapper .actions-wrapper a.js-clear,.fb-edit-field-wrapper .js-remove-option{background-color:#e74c3c;border:none} +.edit-response-field input:focus,.edit-response-field textarea:focus,.edit-response-field select:focus{outline:none} +.edit-response-field select{font-size:14px;max-width:100%} +input[readonly]{cursor:not-allowed;background-color:#eee} .fb-field-wrapper .subtemplate-wrapper{border:1px dashed transparent;margin-bottom:10px;padding:10px;position:relative} .fb-field-wrapper .subtemplate-wrapper .cover{position:absolute;top:0;left:0;height:100%;width:100%;z-index:2} .fb-field-wrapper .subtemplate-wrapper > label{display:block;border-bottom:thin solid #eee;padding-bottom:3px;margin-bottom:7px} @@ -44,8 +62,8 @@ .fb-field-wrapper .help-block{display:block;font-size:12px;margin-top:5px} .fb-edit-field-wrapper{font-size:13px} .fb-edit-field-wrapper .fb-field-label{font-weight:normal;background:#eee;padding:.75em;color:#666;font-size:1.25em} -.fb-edit-field-wrapper .fb-field-label .field-type{margin-top:.5em;display:block;font-family:'Source Sans Pro',sans-serif;font-size:1em} -.fb-edit-field-wrapper .fb-field-label .field-type:before{content:'Type: ';color:#999} +.fb-edit-field-wrapper .fb-field-label .type{margin-top:.5em;display:block;font-family:'Source Sans Pro',sans-serif;font-size:1em} +.fb-edit-field-wrapper .fb-field-label .type:before{content:'Type: ';color:#999} .fb-edit-field-wrapper .fb-field-label .fa.fa-arrow-right{display:none} .fb-edit-field-wrapper .fb-edit-section-header{border-bottom:1px solid #ddd;margin-top:25px;margin-bottom:10px;padding-bottom:5px;clear:both;font-weight:700} .fb-edit-field-wrapper .js-add-option,.fb-edit-field-wrapper .js-remove-option{padding:3px 6px} @@ -53,16 +71,111 @@ .fb-common-wrapper .fb-label-description{margin-bottom:10px} .fb-common-wrapper .fb-label-description input,.fb-common-wrapper .fb-label-description textarea{width:100%} .fb-common-wrapper .fb-label-description textarea{min-height:5em} +.fb-conditional-question{float:right;font-size:.9em;max-width:50%;text-overflow:ellipsis;height:20px;white-space:nowrap;overflow:hidden} +.fb-conditional-question-trigger > span{font-weight:bold} +.option-score-input{width:50px} +.option-label-input{width:170px} .response-field-draggable-helper{border:1px dashed #ddd;background:#eee} -.response-field-text input.rf-size-small{width:130px} .response-field-text input.rf-size-medium{width:300px} .response-field-text input.rf-size-large{width:100%} -.response-field-paragraph textarea.rf-size-small{width:200px;min-height:60px} -.response-field-paragraph textarea.rf-size-medium{width:400px;min-height:100px} -.response-field-paragraph textarea.rf-size-large{width:100%;min-height:200px} +.response-field-textarea textarea.rf-size-small{width:200px;min-height:60px} +.response-field-textarea textarea.rf-size-medium{width:400px;min-height:100px} +.response-field-textarea textarea.rf-size-large{width:100%;min-height:200px} .response-field-address .street{width:400px} .response-field-address .city,.response-field-address .state,.response-field-address .zip,.response-field-address .country{width:198px} .response-field-date .month,.response-field-date .day,.response-field-date .year{width:50px} -.response-field-time .hours,.response-field-time .minutes,.response-field-time .seconds{width:50px} -.response-field-checkboxes .fb-option,.response-field-radio .fb-option{margin-bottom:5px;display:inline-block} +.response-field-time .input-group{width:145px} +.response-field-checkbox .fb-option,.response-field-radio .fb-option{margin-bottom:5px;padding:3px 8px;display:inline-block} +.editing .trigger-option,.fb-option.trigger-option{background-color:#5cb85c;border-radius:.25em;color:#fff} +.fb-conditional-question .trigger-option{padding:1px 4px} .response-field-website input{width:200px} +.response-field-signature .fb-signature{width:300px;height:150px} +.response-field-signature .fb-signature-placeholder{color:#aaa} +.response-field-approval .fb-approval-user{margin-bottom:20px} +.response-field-approval .fb-signature{width:300px;height:150px} +.response-field-approval .fb-signature-placeholder{color:#aaa} +.response-field-grid .cover{display:none} +.response-field-table{width:100%} +.response-field-table .cover{display:none} +.response-field-table .section-name{display:inline-block} +.response-field-table .element-selector{margin:0 5px;float:right;position:absolute;right:5px;top:5px} +.response-field-table tr{vertical-align:top} +.response-field-table table{margin-bottom:30px} +.response-field-table table td{padding:10px 10px 0 10px} +.response-field-table table td label{border:none !important} +.response-field-table table .calculated{font-style:italic;color:#ccc} +.response-field-table table select,.response-field-table table input[type=text],.response-field-table table textarea,.response-field-table table .fb-signature{width:100%} +.fb-options-per-row-1:before{content:" ";display:table} +.fb-options-per-row-1:after{content:" ";display:table;clear:both} +.fb-options-per-row-1{clear:both} +.fb-options-per-row-1 .fb-option-wrapper{width:100%} +.fb-options-per-row-2:before{content:" ";display:table} +.fb-options-per-row-2:after{content:" ";display:table;clear:both} +.fb-options-per-row-2{clear:both} +.fb-options-per-row-2 .fb-option-wrapper{width:50%} +.fb-options-per-row-3:before{content:" ";display:table} +.fb-options-per-row-3:after{content:" ";display:table;clear:both} +.fb-options-per-row-3{clear:both} +.fb-options-per-row-3 .fb-option-wrapper{width:33.333333333333336%} +.fb-options-per-row-4:before{content:" ";display:table} +.fb-options-per-row-4:after{content:" ";display:table;clear:both} +.fb-options-per-row-4{clear:both} +.fb-options-per-row-4 .fb-option-wrapper{width:25%} +.fb-options-per-row-5:before{content:" ";display:table} +.fb-options-per-row-5:after{content:" ";display:table;clear:both} +.fb-options-per-row-5{clear:both} +.fb-options-per-row-5 .fb-option-wrapper{width:20%} +.fb-options-per-row-6:before{content:" ";display:table} +.fb-options-per-row-6:after{content:" ";display:table;clear:both} +.fb-options-per-row-6{clear:both} +.fb-options-per-row-6 .fb-option-wrapper{width:16.666666666666668%} +.fb-options-per-row-7:before{content:" ";display:table} +.fb-options-per-row-7:after{content:" ";display:table;clear:both} +.fb-options-per-row-7{clear:both} +.fb-options-per-row-7 .fb-option-wrapper{width:14.285714285714286%} +.fb-options-per-row-8:before{content:" ";display:table} +.fb-options-per-row-8:after{content:" ";display:table;clear:both} +.fb-options-per-row-8{clear:both} +.fb-options-per-row-8 .fb-option-wrapper{width:12.5%} +.fb-options-per-row-9:before{content:" ";display:table} +.fb-options-per-row-9:after{content:" ";display:table;clear:both} +.fb-options-per-row-9{clear:both} +.fb-options-per-row-9 .fb-option-wrapper{width:11.11111111111111%} +.fb-options-per-row-10:before{content:" ";display:table} +.fb-options-per-row-10:after{content:" ";display:table;clear:both} +.fb-options-per-row-10{clear:both} +.fb-options-per-row-10 .fb-option-wrapper{width:10%} +.fb-options-per-row-11:before{content:" ";display:table} +.fb-options-per-row-11:after{content:" ";display:table;clear:both} +.fb-options-per-row-11{clear:both} +.fb-options-per-row-11 .fb-option-wrapper{width:9.090909090909092%} +.fb-options-per-row-12:before{content:" ";display:table} +.fb-options-per-row-12:after{content:" ";display:table;clear:both} +.fb-options-per-row-12{clear:both} +.fb-options-per-row-12 .fb-option-wrapper{width:8.333333333333334%} +.fb-options-per-row-13:before{content:" ";display:table} +.fb-options-per-row-13:after{content:" ";display:table;clear:both} +.fb-options-per-row-13{clear:both} +.fb-options-per-row-13 .fb-option-wrapper{width:7.6923076923076925%} +.fb-options-per-row-14:before{content:" ";display:table} +.fb-options-per-row-14:after{content:" ";display:table;clear:both} +.fb-options-per-row-14{clear:both} +.fb-options-per-row-14 .fb-option-wrapper{width:7.142857142857143%} +.fb-options-per-row-15:before{content:" ";display:table} +.fb-options-per-row-15:after{content:" ";display:table;clear:both} +.fb-options-per-row-15{clear:both} +.fb-options-per-row-15 .fb-option-wrapper{width:6.666666666666667%} +.response-field-grid-table{border-collapse:collapse;border-spacing:0;margin-bottom:5px;table-layout:fixed;width:100%} +.response-field-grid-table .response-field-grid-row{height:100px;vertical-align:top} +.response-field-grid-table td{padding:10px 10px 0 10px} +.response-field-grid-table .element-selector{width:100%} +.response-field-grid-table .element-selector .dropdown-toggle{width:100%} +.response-field-grid-table .element-selector .dropdown-toggle span{font-size:2em} +.response-field-grid-table .response-field-grid-cell{padding:10px 10px 0 10px;border:1px dashed #ddd;background-color:rgba(255,255,255,0.8)} +.response-field-grid-table .response-field-grid-cell .cover{display:block} +.response-field-grid-table .response-field-grid-cell .response-field-selector{margin:.5em} +.response-field-grid-table .response-field-grid-cell .subtemplate-wrapper > label{display:none} +.response-field-grid-table .response-field-grid-cell .help-block{display:none} +.response-field-grid-table .response-field-grid-cell select,.response-field-grid-table .response-field-grid-cell input[type=text],.response-field-grid-table .response-field-grid-cell textarea,.response-field-grid-table .response-field-grid-cell .fb-signature{width:100%} +.section-separator{border-top:1px solid #333} +.fb-link-object-fields{padding:15px} diff --git a/dist/formbuilder.js b/dist/formbuilder.js index 47f8e09a..f8ed38c1 100644 --- a/dist/formbuilder.js +++ b/dist/formbuilder.js @@ -1,4 +1,38 @@ (function() { + rivets.binders.append = { + routine: function(el, value) { + return el.checked = _.find(value, function(item) { + return String(item) === String(el.value); + }) !== void 0; + }, + bind: function(el) { + var _this = this; + this.callback = function() { + var currentValue, newValue; + currentValue = _.clone(_this.model.get(_this.keypath)) || []; + if (_.contains(currentValue, el.value)) { + newValue = _.without(currentValue, el.value); + return _this.model.set(_this.keypath, newValue); + } else { + currentValue.push(el.value); + return _this.model.set(_this.keypath, currentValue); + } + }; + return $(el).on('change', this.callback); + }, + unbind: function(el) { + return $(el).off('change', this.callback); + } + }; + + rivets.formatters.length = function(value) { + if (value) { + return value.length; + } else { + return 0; + } + }; + rivets.binders.input = { publishes: true, routine: rivets.binders.value.routine, @@ -41,11 +75,14 @@ }).call(this); (function() { - var BuilderView, EditFieldView, Formbuilder, FormbuilderCollection, FormbuilderModel, ViewFieldView, _ref, _ref1, _ref2, _ref3, _ref4, + var BuilderView, EditFieldView, Formbuilder, FormbuilderCollection, FormbuilderModel, GridFieldView, TableFieldView, ViewFieldView, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; FormbuilderModel = (function(_super) { + var $wrappers; + __extends(FormbuilderModel, _super); function FormbuilderModel() { @@ -53,19 +90,187 @@ return _ref; } + $wrappers = {}; + FormbuilderModel.prototype.sync = function() {}; FormbuilderModel.prototype.indexInDOM = function() { - var $wrapper, - _this = this; - $wrapper = $(".fb-field-wrapper").filter((function(_, el) { - return $(el).data('cid') === _this.cid; - })); - return $(".fb-field-wrapper").index($wrapper); + if ($wrappers[this.cid] === void 0) { + $(".fb-field-wrapper").each((function(_, el) { + $wrappers[$(el).data('cid')] = $(el); + return true; + })); + } + return ($wrappers[this.cid] || { + index: function() { + return -1; + } + }).index(".fb-field-wrapper"); }; FormbuilderModel.prototype.is_input = function() { - return Formbuilder.inputFields[this.get(Formbuilder.options.mappings.FIELD_TYPE)] != null; + return Formbuilder.inputFields[this.get(Formbuilder.options.mappings.TYPE)] != null; + }; + + FormbuilderModel.prototype.initialize = function() { + if (this.attributes.uuid == null) { + this.attributes.uuid = uuid.v4(); + } + if (!this.attributes.parent_uuid === void 0) { + this.attributes.parent_uuid = null; + } + return this.attachMethods(); + }; + + FormbuilderModel.prototype.parentModel = function() { + var collention; + collention = this.collection; + if (collention) { + return this.collection.findWhereUuid(this.get('parent_uuid')); + } + }; + + FormbuilderModel.prototype.hasParent = function() { + return this.parentModel() !== void 0; + }; + + FormbuilderModel.prototype.inTable = function() { + var parent; + parent = this.parentModel(); + return parent && parent.get('type') === 'table'; + }; + + FormbuilderModel.prototype.inGrid = function() { + var parent; + parent = this.parentModel(); + return parent && parent.get('type') === 'grid'; + }; + + FormbuilderModel.prototype.canBeConditionallyDisplayed = function() { + return !this.inTable() && !this.inGrid() && Formbuilder.conditionalFunctionality; + }; + + FormbuilderModel.prototype.canShowReferenceID = function() { + return Formbuilder.showReferenceIDFunctionality; + }; + + FormbuilderModel.prototype.findConditionalAncestorUuids = function() { + var ancest, count, parent, parentUuid, size, temp, uuids; + parentUuid = this.get(Formbuilder.options.mappings.CONDITIONAL_PARENT); + size = this.collection.length; + count = 0; + uuids = []; + if (parentUuid) { + parent = this.collection.findWhereUuid(parentUuid); + uuids.push(parent.attributes.uuid); + if (parent.conditionalParent()) { + ancest = parent.conditionalParent(); + uuids.push(ancest.attributes.uuid); + temp = ancest; + while (temp) { + count++; + if (count === (size - 1)) { + return uuids; + } + ancest = temp; + uuids.push(temp.attributes.uuid); + temp = temp.conditionalParent(); + } + return uuids; + } + return uuids; + } + }; + + FormbuilderModel.prototype.conditionalParent = function() { + var parentUuid; + parentUuid = this.get(Formbuilder.options.mappings.CONDITIONAL_PARENT); + if (parentUuid) { + return this.collection.findWhereUuid(parentUuid); + } + return null; + }; + + FormbuilderModel.prototype.conditionalChildren = function() { + var uuid; + uuid = this.attributes.uuid; + return this.collection.filter(function(item) { + return uuid === item.get(Formbuilder.options.mappings.CONDITIONAL_PARENT); + }); + }; + + FormbuilderModel.prototype.answers = function() { + return this.get('answers') || []; + }; + + FormbuilderModel.prototype.conditionalTriggerOptions = function(selected) { + var options, parent, triggerValues; + parent = this.conditionalParent(); + options = []; + if (parent) { + if (parent.get('type') === 'approval') { + options = 'Is Approved'; + } else { + options = _.clone(parent.answers()); + options.unshift({ + 'uuid': '', + 'label': '[No Selection]' + }); + if (selected) { + triggerValues = this.get(Formbuilder.options.mappings.CONDITIONAL_VALUES) || []; + options = _.filter(options, function(trigger) { + var _ref1; + return _ref1 = trigger.uuid, __indexOf.call(triggerValues, _ref1) >= 0; + }); + } + } + } + return options; + }; + + FormbuilderModel.prototype.isValid = function() { + var conditional, conditional_ele, conditional_parent, conditional_values, flag, options, parent; + conditional_ele = this.canBeConditionallyDisplayed(); + if (!conditional_ele) { + return true; + } else { + options = this.attributes.options; + conditional = options.conditional; + if (conditional) { + conditional_parent = conditional.parent; + conditional_values = conditional.values; + parent = this.conditionalParent(); + if (parent && parent.get('type') === 'approval') { + if (!this.get(Formbuilder.options.mappings.CONDITIONAL_VALUES)) { + this.set(Formbuilder.options.mappings.CONDITIONAL_VALUES, 1); + } + conditional_values = 1; + } + } + } + flag = (_.isArray(conditional) && conditional.length === 0) || (conditional_parent === "" && typeof conditional_values === "undefined"); + if ((conditional_parent && (conditional_values && conditional_values.length !== 0)) || (typeof conditional_values === "undefined" && typeof conditional_parent === "undefined") || flag) { + return true; + } else { + return false; + } + }; + + FormbuilderModel.prototype.attachMethods = function() { + if (typeof this.attributes.initialize === 'function') { + this.attributes.initialize.call(this); + delete this.attributes['initialize']; + } + if (typeof this.attributes.insertion === 'function') { + this['insertion'] = this.attributes['insertion']; + delete this.attributes['insertion']; + } + return _.each(this.attributes, function(method, name) { + if (typeof method === 'function' && this[name] === void 0) { + this[name] = method; + return delete this.attributes[name]; + } + }, this); }; return FormbuilderModel; @@ -80,24 +285,79 @@ return _ref1; } - FormbuilderCollection.prototype.initialize = function() { - return this.on('add', this.copyCidToModel); - }; - FormbuilderCollection.prototype.model = FormbuilderModel; FormbuilderCollection.prototype.comparator = function(model) { return model.indexInDOM(); }; - FormbuilderCollection.prototype.copyCidToModel = function(model) { - return model.attributes.cid = model.cid; + FormbuilderCollection.prototype.add = function(model) { + var models; + models = model = FormbuilderCollection.__super__.add.call(this, model); + if (!_.isArray(model)) { + models = [model]; + } + _.each(models, function(model) { + if (typeof model.insertion === 'function') { + return model.insertion.call(model); + } + }); + return model; + }; + + FormbuilderCollection.prototype.findWhereUuid = function(uuid) { + return this.findWhere({ + 'uuid': uuid + }); + }; + + FormbuilderCollection.prototype.findDataSourceFields = function() { + return this.where({ + 'type': 'datasource' + }); + }; + + FormbuilderCollection.prototype.findConditionalTriggers = function(child) { + var items; + items = this.filter(function(model) { + var a, ancestorUuids, correctType, differentModel, flag, hasNoParent, parent, uuid, uuid_parent, _i, _len, _ref2; + correctType = (_ref2 = model.get('type')) === 'dropdown' || _ref2 === 'checkbox' || _ref2 === 'radio' || _ref2 === 'approval'; + differentModel = model !== child; + hasNoParent = !model.hasParent(); + flag = true; + uuid = child.attributes.uuid; + uuid_parent; + ancestorUuids; + parent = model.conditionalParent(); + if (parent) { + ancestorUuids = model.findConditionalAncestorUuids(); + uuid_parent = parent.attributes.uuid; + if (ancestorUuids && ancestorUuids.length > 0) { + for (_i = 0, _len = ancestorUuids.length; _i < _len; _i++) { + a = ancestorUuids[_i]; + if (a === uuid) { + flag = false; + break; + } + } + } + flag = (uuid !== uuid_parent) && flag; + } + return correctType && differentModel && hasNoParent && flag; + }); + return items; + }; + + FormbuilderCollection.prototype.clearConditionEle = function(conditionalChild) { + return conditionalChild.unset(Formbuilder.options.mappings.CONDITIONAL); }; return FormbuilderCollection; })(Backbone.Collection); + 'Individual elements'; + ViewFieldView = (function(_super) { __extends(ViewFieldView, _super); @@ -106,6 +366,32 @@ return _ref2; } + ViewFieldView.insert = function(builder, view, responseField, _, options) { + var $placeholder, $replacePosition, appendEl, parentModel, replaceEl; + parentModel = responseField.parentModel(); + if (parentModel === void 0 || parentModel.get('type') === 'grid' || parentModel.get('type') === 'table') { + appendEl = options.$appendEl || null; + replaceEl = options.$replaceEl || null; + $placeholder = builder.$responseFields.find("a.dragdrop-placeholder"); + if (appendEl != null) { + return appendEl.html(view.render().el); + } else if (replaceEl != null) { + return replaceEl.replaceWith(view.render().el); + } else if ($placeholder[0]) { + $placeholder.after(view.render().el); + return $placeholder.remove(); + } else if ((options.position == null) || options.position === -1) { + return builder.$responseFields.append(view.render().el); + } else if (options.position === 0) { + return builder.$responseFields.prepend(view.render().el); + } else if (($replacePosition = builder.$responseFields.find(".fb-field-wrapper").eq(options.position))[0]) { + return $replacePosition.before(view.render().el); + } else { + return builder.$responseFields.append(view.render().el); + } + } + }; + ViewFieldView.prototype.className = "fb-field-wrapper"; ViewFieldView.prototype.events = { @@ -121,7 +407,7 @@ }; ViewFieldView.prototype.render = function() { - this.$el.addClass('response-field-' + this.model.get(Formbuilder.options.mappings.FIELD_TYPE)).data('cid', this.model.cid).html(Formbuilder.templates["view/base" + (!this.model.is_input() ? '_non_input' : '')]({ + this.$el.addClass('response-field-' + this.model.get(Formbuilder.options.mappings.TYPE)).data('cid', this.model.cid).data('uuid', this.model.get('uuid')).html(Formbuilder.templates["view/base" + (!this.model.is_input() ? '_non_input' : '')]({ rf: this.model })); return this; @@ -136,6 +422,10 @@ _this = this; e.preventDefault(); e.stopPropagation(); + _.each(this.model.conditionalChildren(), function(conditionalChild) { + conditionalChild.unset(Formbuilder.options.mappings.CONDITIONAL_PARENT); + return conditionalChild.unset(Formbuilder.options.mappings.CONDITIONAL_VALUES); + }); cb = function() { _this.parentView.handleFormUpdate(); return _this.model.destroy(); @@ -154,26 +444,488 @@ } }; - ViewFieldView.prototype.duplicate = function() { - var attrs; - attrs = _.clone(this.model.attributes); + ViewFieldView.prototype.duplicate = function(e) { + var attrs, copyAttrs, key; + e.preventDefault(); + e.stopPropagation(); + copyAttrs = Formbuilder.helpers.clone(this.model.attributes); + attrs = Formbuilder.helpers.defaultFieldAttrs(copyAttrs.type, {}); + for (key in copyAttrs) { + attrs[key] = copyAttrs[key]; + } delete attrs['id']; + delete attrs['cid']; + delete attrs['uuid']; attrs['label'] += ' Copy'; - return this.parentView.createField(attrs, { + if (attrs.options.grid) { + attrs.options.grid.row = attrs.options.grid.row + 1; + } + this.parentView.createField(attrs, { position: this.model.indexInDOM() + 1 }); + return this.model.trigger("duplicate:viewfield"); }; return ViewFieldView; })(Backbone.View); + TableFieldView = (function(_super) { + __extends(TableFieldView, _super); + + function TableFieldView() { + _ref3 = TableFieldView.__super__.constructor.apply(this, arguments); + return _ref3; + } + + TableFieldView.prototype.className = "fb-field-wrapper"; + + TableFieldView.prototype.initialize = function(options) { + this.parentView = options.parentView; + this.listenTo(this.model, "change", this.update); + this.listenTo(this.model, "destroy", this.remove); + return _.each(this.model.get('options.elements'), function(element) { + var childModel; + childModel = this.model.collection.findWhereUuid(element.uuid); + if (childModel) { + return this.listenTo(childModel, "change", this.update); + } else { + return console.log(element.uuid); + } + }, this); + }; + + TableFieldView.prototype.events = { + 'mouseenter': 'showSelectors', + 'mouseleave': 'removeSelectors', + 'click .drop-area li': 'inlineAdd', + 'click .subtemplate-wrapper': 'focusEditView', + 'click .response-field-table td.header': 'focusSubelement', + 'click .response-field-table td.element': 'focusSubelement', + 'click .js-clear': 'clear', + 'click .js-duplicate': 'duplicate' + }; + + TableFieldView.prototype.showSelectors = function(e) { + return this.$el.find('.drop-area').html(Formbuilder.templates['view/element_selector']()); + }; + + TableFieldView.prototype.removeSelectors = function(e) { + return this.$el.find('.drop-area').html(''); + }; + + TableFieldView.prototype.inlineAdd = function(e) { + var childModel, elements, newElement; + e.preventDefault(); + e.stopPropagation(); + childModel = new FormbuilderModel(Formbuilder.helpers.defaultFieldAttrs($(e.currentTarget).data('type'))); + childModel.set('parent_uuid', this.model.get('uuid')); + childModel.set('options.in_sequence', true); + this.listenTo(childModel, "change", this.update); + elements = this.model.attributes.options.elements || []; + newElement = { + 'uuid': childModel.get('uuid') + }; + elements.push(newElement); + this.model.attributes.options.elements = elements; + this.parentView.collection.add(childModel); + return this.update(childModel); + }; + + TableFieldView.prototype.update = function(model) { + if (model) { + this.render(); + return this.parentView.createAndShowEditView(model); + } + }; + + TableFieldView.prototype.render = function() { + TableFieldView.__super__.render.call(this); + this.renderElements(); + return this; + }; + + TableFieldView.prototype.focusEditView = function(e) { + if (!$(e.target).parents('.dropdown-toggle').length && !$(e.target).hasClass('dropdown-toggle')) { + return this.parentView.createAndShowEditView(this.model); + } + }; + + TableFieldView.prototype.focusSubelement = function(e) { + var childUuid; + e.preventDefault(); + e.stopPropagation(); + childUuid = $(e.currentTarget).data('uuid'); + if (childUuid) { + return this.parentView.createAndShowEditView(this.parentView.modelByUuid(childUuid)); + } + }; + + TableFieldView.prototype.renderElements = function() { + return _.each(this.model.get('options.elements'), function(element) { + var model; + model = this.parentView.modelByUuid(element.uuid); + this.$el.find('.header-' + element.uuid).html(Formbuilder.templates["view/table_header"]({ + rf: model, + element: element + })).css('background-color', model.get(Formbuilder.options.mappings.LABEL_BACKGROUND_COLOR)).data('cid', model.cid); + this.$el.find('.element-' + element.uuid).html(Formbuilder.templates["view/table_element"]({ + rf: model, + element: element + })).data('cid', model.cid); + return this.$el.find('.total-' + element.uuid).html(Formbuilder.templates["view/table_total"]({ + rf: model, + element: element + })).data('cid', model.cid); + }, this); + }; + + TableFieldView.prototype.clear = function(e) { + var models, uuid; + e.preventDefault(); + e.stopPropagation(); + uuid = $(e.currentTarget).parents('.element').data('uuid'); + if (uuid === void 0) { + models = _.each(this.model.get('options.elements'), function(element) { + this.parentView.modelByUuid(element.uuid).destroy(); + return true; + }, this); + this.model.destroy(); + return this.$el.remove(); + } else { + this.parentView.modelByUuid(uuid).destroy(); + this.model.set('options.elements', _.filter(this.model.get('options.elements'), function(destroyedElement) { + return destroyedElement.uuid !== uuid; + })); + return this.render(); + } + }; + + TableFieldView.prototype.duplicate = function() { + var attrs, clonedTableModel, clonedView, elements, + _this = this; + attrs = Formbuilder.helpers.clone(this.model.attributes); + delete attrs['id']; + delete attrs['cid']; + attrs['uuid'] = uuid.v4(); + attrs['label'] += ' Copy'; + elements = attrs['options']['elements']; + attrs['options']['elements'] = []; + attrs = _.extend({}, Formbuilder.helpers.defaultFieldAttrs('table'), attrs); + this.parentView.createField(attrs, { + position: -1 + }); + clonedView = this.parentView.viewByUuid(attrs['uuid']); + clonedTableModel = this.parentView.modelByUuid(attrs['uuid']); + _.each(elements, function(child) { + var childModel, childattrs, clonedModel, totalColumnModel; + childModel = _this.parentView.modelByUuid(child.uuid); + childattrs = Formbuilder.helpers.clone(childModel); + delete childattrs['id']; + delete childattrs['cid']; + child.uuid = childattrs['uuid'] = uuid.v4(); + childattrs['parent_uuid'] = attrs['uuid']; + childattrs = _.extend({}, Formbuilder.helpers.defaultFieldAttrs(childattrs['type']), childattrs); + clonedModel = new FormbuilderModel(childattrs); + if (child.totalColumn) { + totalColumnModel = clonedTableModel.createTotalColumnModel(childattrs['uuid']); + child.totalColumnUuid = totalColumnModel.get('uuid'); + } + _this.parentView.collection.add(clonedModel); + if (clonedModel.expression !== void 0 && clonedModel.get('options.calculation_type')) { + clonedModel.expression(); + } + clonedView.listenTo(clonedModel, "change", clonedView.update); + return attrs['options']['elements'].push(child); + }); + return clonedView.render(); + }; + + TableFieldView.insert = function(builder, view, responseField, _, options) { + var instanceView; + instanceView = builder.viewByUuid(responseField.get('parent_uuid')); + if (instanceView != null) { + return true; + } else { + return false; + } + }; + + return TableFieldView; + + })(ViewFieldView); + + GridFieldView = (function(_super) { + __extends(GridFieldView, _super); + + function GridFieldView() { + _ref4 = GridFieldView.__super__.constructor.apply(this, arguments); + return _ref4; + } + + GridFieldView.prototype.className = "fb-field-wrapper"; + + GridFieldView.prototype.events = { + 'click .response-field-grid-cell li': 'inlineAdd', + 'click .response-field-grid-cell .js-clear': 'subelementClear', + 'click .js-duplicate': 'duplicate', + 'click .js-clear': 'clear', + 'click .subtemplate-wrapper': 'focusEditView' + }; + + GridFieldView.prototype.initialize = function(options) { + this.parentView = options.parentView; + this.listenTo(this.model, "change", this.redraw); + this.listenTo(this.model, "destroy", this.remove); + this.parentView.collection.bind('add', this.addSubelement, this); + this.parentView.collection.bind('destroy', this.removeSubelement, this); + return this.render; + }; + + GridFieldView.prototype.render = function() { + GridFieldView.__super__.render.call(this); + this.redraw(); + this.renderChildren(); + return this; + }; + + GridFieldView.prototype.redraw = function() { + var table; + table = this.$el.find('.response-field-grid-table').detach(); + this.$el.addClass('response-field-' + this.model.get(Formbuilder.options.mappings.TYPE)).data('cid', this.model.cid).data('uuid', this.model.get('uuid')).html(Formbuilder.templates["view/base" + (!this.model.is_input() ? '_non_input' : '')]({ + rf: this.model + })); + if (table.length === 1) { + this.$el.find('.response-field-grid-table').replaceWith(table); + } + return this.renderTable(); + }; + + GridFieldView.prototype.renderTable = function() { + var currentCols, currentRows, numCols, numRows, rows, subelements, table, _i, _ref5, _results, + _this = this; + numRows = this.model.get('options.num_rows') || 1; + numCols = this.model.get('options.num_cols') || 1; + table = this.$el.find('table'); + currentRows = table.find('tr').length; + currentCols = table.find("tr:nth-child(1) td").length; + rows = $.makeArray(table.find('tr')); + if (currentRows < numRows) { + rows = rows.concat((function() { + _results = []; + for (var _i = _ref5 = rows.length; _ref5 <= numRows ? _i < numRows : _i > numRows; _ref5 <= numRows ? _i++ : _i--){ _results.push(_i); } + return _results; + }).apply(this)); + } + rows = _.map(rows, function(row) { + var cols, _j, _ref6, _results1; + if (_.isNumber(row)) { + row = $('').appendTo(table); + } + cols = $.makeArray($(row).find('td')); + if (cols.length < numCols) { + cols = cols.concat((function() { + _results1 = []; + for (var _j = _ref6 = cols.length; _ref6 <= numCols ? _j < numCols : _j > numCols; _ref6 <= numCols ? _j++ : _j--){ _results1.push(_j); } + return _results1; + }).apply(this)); + } + cols = _.map(cols, function(col) { + if (_.isNumber(col)) { + return col = $('').appendTo(row).html(Formbuilder.templates["view/element_selector"]()); + } + }); + return row; + }); + if (currentRows > numRows) { + subelements = this.subelements(); + _.each(subelements, function(subelement) { + var grid; + grid = _this.parentView.gridAttr(subelement); + if (grid.row > (numRows - 1)) { + return subelement.destroy(); + } + }); + table.find('tr').slice(numRows - currentRows).remove(); + } + if (currentCols > numCols) { + subelements = this.subelements(); + _.each(subelements, function(subelement) { + var grid; + grid = _this.parentView.gridAttr(subelement); + if (grid.col > (numCols - 1)) { + return subelement.destroy(); + } + }); + return table.find('tr').find('td:gt(' + (numCols - 1) + ')').remove(); + } + }; + + GridFieldView.prototype.renderChildren = function() { + var children, + _this = this; + children = this.model.get('children') || []; + return _.each(children, function(child) { + var grid; + grid = child.options.grid; + return _this.createField(child, _this.getSubelement(grid.row, grid.col)); + }); + }; + + GridFieldView.prototype.focusEditView = function(e) { + if ($(e.target).parents('table').length === 0) { + return this.parentView.createAndShowEditView(this.model); + } + }; + + GridFieldView.prototype.clear = function(e) { + var cb, x, + _this = this; + e.preventDefault(); + e.stopPropagation(); + cb = function() { + var subelements; + _this.parentView.handleFormUpdate(); + subelements = _this.subelements(); + _.each(_this.subelements(), function(model) { + model.destroy(); + return true; + }); + return _this.model.destroy(); + }; + x = Formbuilder.options.CLEAR_FIELD_CONFIRM; + switch (typeof x) { + case 'string': + if (confirm(x)) { + return cb(); + } + break; + case 'function': + return x(cb); + default: + return cb(); + } + }; + + GridFieldView.prototype.duplicate = function() { + var attrs, children, + _this = this; + attrs = Formbuilder.helpers.clone(this.model.attributes); + delete attrs['id']; + delete attrs['cid']; + attrs['uuid'] = uuid.v4(); + attrs['label'] += ' Copy'; + children = this.subelements(); + delete attrs['children']; + this.parentView.createField(attrs, { + position: -1 + }); + return attrs['children'] = _.map(children, function(child) { + var childattrs; + childattrs = Formbuilder.helpers.clone(child.attributes); + delete childattrs['id']; + delete childattrs['cid']; + delete childattrs['uuid']; + childattrs['parent_uuid'] = attrs['uuid']; + childattrs; + return _this.parentView.createField(childattrs, { + position: -1 + }); + }); + }; + + GridFieldView.prototype.addSubelement = function(model) { + var grid, label; + if (this.belongsToMe(model) && model.get('label').match(/Copy/)) { + grid = this.parentView.gridAttr(model); + label = model.get('label').match(/(.+) Copy/); + if (label !== null) { + return model.attributes.label = label[1] + ' ' + (grid.row + 1); + } else { + return model.attributes.label = 'Row: ' + (grid.row + 1) + ', Col: ' + (grid.col + 1); + } + } + }; + + GridFieldView.prototype.removeSubelement = function(model) { + var belongsToMe, grid; + grid = this.parentView.gridAttr(model); + belongsToMe = this.belongsToMe(model); + if (belongsToMe && this.getSubelement(grid.row, grid.col).html() === '') { + return this.getSubelement(grid.row, grid.col).html(Formbuilder.templates["view/element_selector"]({ + rf: this.model + })); + } + }; + + GridFieldView.prototype.subelements = function() { + var _this = this; + return this.parentView.collection.filter(function(item) { + return _this.belongsToMe(item); + }); + }; + + GridFieldView.prototype.belongsToMe = function(model) { + return this.parentView.inGrid(model) && model.get('parent_uuid') === this.model.get('uuid'); + }; + + GridFieldView.prototype.inlineAdd = function(e) { + var target, type; + e.preventDefault(); + e.stopPropagation(); + type = $(e.currentTarget).data('type'); + target = $(e.currentTarget).parents('.response-field-grid-cell'); + return this.createField(type, target); + }; + + GridFieldView.prototype.getSubelement = function(row, col) { + row++; + col++; + return this.$el.find('tr:nth-child(' + row + ') td:nth-child(' + col + ')'); + }; + + GridFieldView.prototype.createField = function(attrs, target) { + if (_.isString(attrs)) { + attrs = Formbuilder.helpers.defaultFieldAttrs(attrs); + } + attrs.options.disallow_duplication = true; + attrs.options.grid = { + col: target.prop('cellIndex'), + row: target.parents('tr').prop('rowIndex') + }; + attrs.parent_uuid = this.model.get('uuid'); + return this.parentView.createField(attrs, { + $appendEl: target + }); + }; + + GridFieldView.insert = function(builder, view, responseField, _, options) { + var append, col, row; + if (!options.$appendEl) { + row = responseField.get('options.grid.row'); + col = responseField.get('options.grid.col'); + responseField.attributes.options.disallow_duplication = true; + append = builder.wrapperByUuid(responseField.get('parent_uuid')); + append = append.find('tr:nth-child(' + (row + 1) + ') td:nth-child(' + (col + 1) + ')'); + if (append.length === 1) { + options.$appendEl = append; + } + } + return ViewFieldView.insert(builder, view, responseField, _, options); + }; + + return GridFieldView; + + })(Backbone.View); + + '"Edit field" tab'; + EditFieldView = (function(_super) { __extends(EditFieldView, _super); function EditFieldView() { - _ref3 = EditFieldView.__super__.constructor.apply(this, arguments); - return _ref3; + _ref5 = EditFieldView.__super__.constructor.apply(this, arguments); + return _ref5; } EditFieldView.prototype.className = "edit-response-field"; @@ -186,8 +938,14 @@ }; EditFieldView.prototype.initialize = function(options) { + var _this = this; this.parentView = options.parentView; - return this.listenTo(this.model, "destroy", this.remove); + this.listenTo(this.model, "destroy", this.remove); + return _.each(Formbuilder.options.change, function(callback, key) { + var eventName; + eventName = 'change:' + _.nested(Formbuilder.options.mappings, key); + return _this.listenTo(_this.model, eventName, callback); + }); }; EditFieldView.prototype.render = function() { @@ -200,9 +958,32 @@ return this; }; + EditFieldView.prototype.reset = function() { + this.stopListening(); + this.parentView.editView = void 0; + return this.parentView.createAndShowEditView(this.model); + }; + + EditFieldView.prototype.resetConditional = function() { + return this.model.unset(Formbuilder.options.mappings.CONDITIONAL_VALUES); + }; + + EditFieldView.prototype.resetInlineImages = function() { + return this.model.unset(Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED); + }; + + EditFieldView.prototype.resetInlineActions = function() { + return this.model.unset(Formbuilder.options.mappings.INLINE_ACTIONS_REQUIRED); + }; + + EditFieldView.prototype.deselectReadOnly = function() { + return this.model.set(Formbuilder.options.mappings.READ_ONLY, false); + }; + EditFieldView.prototype.remove = function() { this.parentView.editView = void 0; this.parentView.$el.find("[data-target=\"#addField\"]").click(); + this.stopListening(); return EditFieldView.__super__.remove.apply(this, arguments); }; @@ -212,6 +993,7 @@ i = this.$el.find('.option').index($el.closest('.option')); options = this.model.get(Formbuilder.options.mappings.OPTIONS) || []; newOption = { + uuid: uuid.v4(), label: "", checked: false }; @@ -222,6 +1004,7 @@ } this.model.set(Formbuilder.options.mappings.OPTIONS, options); this.model.trigger("change:" + Formbuilder.options.mappings.OPTIONS); + this.$el.find('div.options').find('input.option-label-input').last().focus(); return this.forceRender(); }; @@ -239,36 +1022,39 @@ EditFieldView.prototype.defaultUpdated = function(e) { var $el; $el = $(e.currentTarget); - if (this.model.get(Formbuilder.options.mappings.FIELD_TYPE) !== 'checkboxes') { + if (this.model.get(Formbuilder.options.mappings.TYPE) !== 'checkboxes') { this.$el.find(".js-default-updated").not($el).attr('checked', false).trigger('change'); } return this.forceRender(); }; EditFieldView.prototype.forceRender = function() { - return this.model.trigger('change'); + return this.model.trigger('change', this.model); }; return EditFieldView; })(Backbone.View); + 'Main View for the editor'; + BuilderView = (function(_super) { __extends(BuilderView, _super); function BuilderView() { - _ref4 = BuilderView.__super__.constructor.apply(this, arguments); - return _ref4; + _ref6 = BuilderView.__super__.constructor.apply(this, arguments); + return _ref6; } BuilderView.prototype.SUBVIEWS = []; + BuilderView.prototype.saveFormButton = $(); + BuilderView.prototype.events = { - 'click .js-save-form': 'saveForm', 'click .fb-tabs a': 'showTab', - 'click .fb-add-field-types a': 'addField', - 'mouseover .fb-add-field-types': 'lockLeftWrapper', - 'mouseout .fb-add-field-types': 'unlockLeftWrapper' + 'click .fb-add-types a': 'addField', + 'mouseover .fb-add-types': 'lockLeftWrapper', + 'mouseout .fb-add-types': 'unlockLeftWrapper' }; BuilderView.prototype.initialize = function(options) { @@ -291,13 +1077,7 @@ BuilderView.prototype.bindSaveEvent = function() { var _this = this; this.formSaved = true; - this.saveFormButton = this.$el.find(".js-save-form"); this.saveFormButton.attr('disabled', true).text(Formbuilder.options.dict.ALL_CHANGES_SAVED); - if (!!Formbuilder.options.AUTOSAVE) { - setInterval(function() { - return _this.saveForm.call(_this); - }, 5000); - } return $(window).bind('beforeunload', function() { if (_this.formSaved) { return void 0; @@ -313,15 +1093,15 @@ }; BuilderView.prototype.render = function() { - var subview, _i, _len, _ref5; + var subview, _i, _len, _ref7; this.$el.html(Formbuilder.templates['page']()); this.$fbLeft = this.$el.find('.fb-left'); this.$responseFields = this.$el.find('.fb-response-fields'); this.bindWindowScrollEvent(); this.hideShowNoResponseFields(); - _ref5 = this.SUBVIEWS; - for (_i = 0, _len = _ref5.length; _i < _len; _i++) { - subview = _ref5[_i]; + _ref7 = this.SUBVIEWS; + for (_i = 0, _len = _ref7.length; _i < _len; _i++) { + subview = _ref7[_i]; new subview({ parentView: this }).render(); @@ -345,11 +1125,17 @@ }; BuilderView.prototype.showTab = function(e) { - var $el, first_model, target; + var $el, first_model, go, target; $el = $(e.currentTarget); + go = true; target = $el.data('target'); - $el.closest('li').addClass('active').siblings('li').removeClass('active'); - $(target).addClass('active').siblings('.fb-tab-pane').removeClass('active'); + if (this.editView && !this.editView.model.isValid()) { + go = false; + } + if (go || (!go && target === '#editField')) { + $el.closest('li').addClass('active').siblings('li').removeClass('active'); + $(target).addClass('active').siblings('.fb-tab-pane').removeClass('active'); + } if (target !== '#editField') { this.unlockLeftWrapper(); } @@ -358,23 +1144,52 @@ } }; - BuilderView.prototype.addOne = function(responseField, _, options) { - var $replacePosition, view; - view = new ViewFieldView({ - model: responseField, - parentView: this - }); - if (options.$replaceEl != null) { - return options.$replaceEl.replaceWith(view.render().el); - } else if ((options.position == null) || options.position === -1) { - return this.$responseFields.append(view.render().el); - } else if (options.position === 0) { - return this.$responseFields.prepend(view.render().el); - } else if (($replacePosition = this.$responseFields.find(".fb-field-wrapper").eq(options.position))[0]) { - return $replacePosition.before(view.render().el); + BuilderView.prototype.createView = function(responseField) { + var view; + if (responseField.attributes.type === 'grid') { + view = new GridFieldView({ + model: responseField, + parentView: this + }); + } else if (responseField.attributes.type === 'table') { + view = new TableFieldView({ + model: responseField, + parentView: this + }); } else { - return this.$responseFields.append(view.render().el); + view = new ViewFieldView({ + model: responseField, + parentView: this + }); + } + return view; + }; + + BuilderView.prototype.insert = function(view, responseField, _, options) { + var inserted, parentModel, parentType, type; + inserted = false; + parentModel = responseField.parentModel(); + parentType = parentModel ? parentModel.get('type') : void 0; + type = parentType || responseField.get('type'); + if (type === 'grid') { + inserted = GridFieldView.insert(this, view, responseField, _, options); + } else if (type === 'table') { + inserted = TableFieldView.insert(this, view, responseField, _, options); + } + if (!inserted) { + inserted = ViewFieldView.insert(this, view, responseField, _, options); } + return inserted; + }; + + BuilderView.prototype.addOne = function(responseField, _, options) { + var view; + view = this.createView(responseField); + this.$responseFields.find('> .ui-draggable').remove(); + if (responseField.get('model_only') !== true) { + this.insert(view, responseField, _, options); + } + return this.views[responseField.get('uuid')] = view; }; BuilderView.prototype.setSortable = function() { @@ -387,8 +1202,9 @@ placeholder: 'sortable-placeholder', stop: function(e, ui) { var rf; - if (ui.item.data('field-type')) { - rf = _this.collection.create(Formbuilder.helpers.defaultFieldAttrs(ui.item.data('field-type')), { + if (ui.item.data('type')) { + ui.item.after(''); + rf = _this.collection.create(Formbuilder.helpers.defaultFieldAttrs(ui.item.data('type')), { $replaceEl: ui.item }); _this.createAndShowEditView(rf); @@ -397,7 +1213,7 @@ return true; }, update: function(e, ui) { - if (!ui.item.data('field-type')) { + if (!ui.item.data('type')) { return _this.ensureEditViewScrolled(); } } @@ -408,7 +1224,7 @@ BuilderView.prototype.setDraggable = function() { var $addFieldButtons, _this = this; - $addFieldButtons = this.$el.find("[data-field-type]"); + $addFieldButtons = this.$el.find("[data-type]"); return $addFieldButtons.draggable({ connectToSortable: this.$responseFields, helper: function() { @@ -424,7 +1240,9 @@ }; BuilderView.prototype.addAll = function() { - this.collection.each(this.addOne, this); + this.collection.each(function(item, _, collection) { + return this.addOne.call(this, item, _, {}); + }, this); return this.setSortable(); }; @@ -433,9 +1251,9 @@ }; BuilderView.prototype.addField = function(e) { - var field_type; - field_type = $(e.currentTarget).data('field-type'); - return this.createField(Formbuilder.helpers.defaultFieldAttrs(field_type)); + var type; + type = $(e.currentTarget).data('type'); + return this.createField(Formbuilder.helpers.defaultFieldAttrs(type, {})); }; BuilderView.prototype.createField = function(attrs, options) { @@ -446,30 +1264,116 @@ }; BuilderView.prototype.createAndShowEditView = function(model) { - var $newEditEl, $responseFieldEl; + var $newEditEl, $parentWrapper, $responseFieldEl, attrs, editModeButton, fieldWrapper, go, parent, selectedTriggers; $responseFieldEl = this.$el.find(".fb-field-wrapper").filter(function() { return $(this).data('cid') === model.cid; }); - $responseFieldEl.addClass('editing').siblings('.fb-field-wrapper').removeClass('editing'); + go = true; if (this.editView) { if (this.editView.model.cid === model.cid) { - this.$el.find(".fb-tabs a[data-target=\"#editField\"]").click(); - this.scrollLeftWrapper($responseFieldEl); return; } - this.editView.remove(); + go = this.editView.model.isValid(); + if (!go) { + $('.fb-edit-section-conditional-wrapper #warning-message').show(); + } else { + this.editView.remove(); + } + } + if (go) { + $('.fb-field-wrapper').removeClass('parent'); + $('.fb-option').removeClass('trigger-option'); + $('.fb-field-wrapper').removeClass('editing'); + $responseFieldEl.addClass('editing'); + } + parent = model.conditionalParent(); + if (parent) { + selectedTriggers = model.get(Formbuilder.options.mappings.CONDITIONAL_VALUES) || []; + $parentWrapper = this.$el.find(".fb-field-wrapper").filter(function() { + return $(this).data('cid') === parent.cid; + }); + $parentWrapper.addClass('parent'); + $parentWrapper.find('.fb-option').filter(function() { + var uuid, _ref7; + uuid = $(this).data('uuid'); + return _ref7 = $(this).data('uuid'), __indexOf.call(selectedTriggers, _ref7) >= 0; + }).each(function() { + return $(this).addClass('trigger-option'); + }); + } + if (go) { + this.editView = new EditFieldView({ + model: model, + parentView: this + }); + $newEditEl = this.editView.render().$el; + fieldWrapper = this.$el.find(".fb-edit-field-wrapper"); + fieldWrapper.html($newEditEl); + if (this.inGrid(model)) { + fieldWrapper.addClass('fb-edit-field-grid'); + } else { + fieldWrapper.removeClass('fb-edit-field-grid'); + } + if (model.inTable()) { + $('.spectrum-colorpicker', ".fb-edit-field-wrapper").spectrum({ + allowEmpty: true, + preferredFormat: 'hex', + showPalette: true, + showPaletteOnly: true, + palette: ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF', '#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF', '#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE', '#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD', '#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5', '#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B', '#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842', '#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031'] + }); + } + editModeButton = this.$el.find(".fb-tabs a[data-target=\"#editField\"]"); + if (!editModeButton.parent().hasClass('active')) { + editModeButton.click(); + } + this.scrollLeftWrapper($responseFieldEl); + attrs = Formbuilder.helpers.defaultFieldAttrs(model.get('type')); + if (attrs.definition.onEdit !== void 0) { + attrs.definition.onEdit(model); + } + this.$el.find("input, textarea, [contenteditable=true]").filter(':visible').first().focus(); } - this.editView = new EditFieldView({ - model: model, - parentView: this - }); - $newEditEl = this.editView.render().$el; - this.$el.find(".fb-edit-field-wrapper").html($newEditEl); - this.$el.find(".fb-tabs a[data-target=\"#editField\"]").click(); - this.scrollLeftWrapper($responseFieldEl); return this; }; + BuilderView.prototype.inGrid = function(model) { + return this.hasParent(model) && model.get('options.grid'); + }; + + BuilderView.prototype.inTable = function(model) { + return this.hasParent(model) && model.get('options.table'); + }; + + BuilderView.prototype.hasParent = function(model) { + return model.get('parent_uuid'); + }; + + BuilderView.prototype.modelByUuid = function(uuid) { + return this.collection.findWhere({ + 'uuid': uuid + }); + }; + + BuilderView.prototype.wrapperByUuid = function(uuid) { + return $('.fb-field-wrapper').filter(function() { + return $(this).data('uuid') === uuid; + }); + }; + + BuilderView.prototype.viewByUuid = function(uuid) { + return this.views[uuid]; + }; + + BuilderView.prototype.views = {}; + + BuilderView.prototype.gridAttr = function(model) { + if (this.inGrid(model)) { + return model.get('options.grid'); + } + return null; + }; + BuilderView.prototype.ensureEditViewScrolled = function() { if (!this.editView) { return; @@ -497,6 +1401,7 @@ }; BuilderView.prototype.handleFormUpdate = function() { + this.collection.sort(); if (this.updatingBatch) { return; } @@ -504,6 +1409,12 @@ return this.saveFormButton.removeAttr('disabled').text(Formbuilder.options.dict.SAVE_FORM); }; + BuilderView.prototype.getPayload = function() { + return JSON.stringify({ + fields: this.collection.toJSON() + }); + }; + BuilderView.prototype.saveForm = function(e) { var payload; if (this.formSaved) { @@ -512,9 +1423,7 @@ this.formSaved = true; this.saveFormButton.attr('disabled', true).text(Formbuilder.options.dict.ALL_CHANGES_SAVED); this.collection.sort(); - payload = JSON.stringify({ - fields: this.collection.toJSON() - }); + payload = this.getPayload(); if (Formbuilder.options.HTTP_ENDPOINT) { this.doAjaxSave(payload); } @@ -529,12 +1438,12 @@ data: payload, contentType: "application/json", success: function(data) { - var datum, _i, _len, _ref5; + var datum, _i, _len, _ref7; _this.updatingBatch = true; for (_i = 0, _len = data.length; _i < _len; _i++) { datum = data[_i]; - if ((_ref5 = _this.collection.get(datum.cid)) != null) { - _ref5.set({ + if ((_ref7 = _this.collection.get(datum.cid)) != null) { + _ref7.set({ id: datum.id }); } @@ -545,49 +1454,212 @@ }); }; - return BuilderView; + return BuilderView; + + })(Backbone.View); + + Formbuilder = (function() { + Formbuilder.attrs = {}; + + Formbuilder.instances = []; + + Formbuilder.attr = function(name, value) { + if (value !== void 0) { + Formbuilder.attrs[name] = value; + _.each(this.instances, function(instance) { + return instance.mainView.reset(); + }); + } + if (Formbuilder.attrs[name] !== void 0) { + return Formbuilder.attrs[name]; + } else { + return void 0; + } + }; + + Formbuilder.conditionalFunctionality = true; - })(Backbone.View); + Formbuilder.showReferenceIDFunctionality = false; + + Formbuilder.geolocationFunctionality = true; + + Formbuilder.linkAssetFunctionality = false; + + Formbuilder.linkAssetDisplayFields = {}; + + Formbuilder.disableField = function(field) { + return this.fields[field].enabled = false; + }; - Formbuilder = (function() { Formbuilder.helpers = { - defaultFieldAttrs: function(field_type) { + defaultFieldAttrs: function(type) { var attrs, _base; attrs = {}; attrs[Formbuilder.options.mappings.LABEL] = 'Untitled'; - attrs[Formbuilder.options.mappings.FIELD_TYPE] = field_type; - attrs[Formbuilder.options.mappings.REQUIRED] = true; - attrs['field_options'] = {}; - return (typeof (_base = Formbuilder.fields[field_type]).defaultAttributes === "function" ? _base.defaultAttributes(attrs) : void 0) || attrs; + attrs[Formbuilder.options.mappings.TYPE] = type; + attrs[Formbuilder.options.mappings.REQUIRED] = false; + attrs[Formbuilder.options.mappings.INLINE_IMAGES_ENABLED] = false; + attrs[Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED] = false; + attrs[Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED] = false; + attrs[Formbuilder.options.mappings.INLINE_ACTIONS_REQUIRED] = false; + attrs['definition'] = Formbuilder.fields[type]; + attrs['options'] = {}; + return (typeof (_base = Formbuilder.fields[type]).defaultAttributes === "function" ? _base.defaultAttributes(attrs, Formbuilder) : void 0) || attrs; }, simple_format: function(x) { - return x != null ? x.replace(/\n/g, '
') : void 0; + var _ref7; + return (_ref7 = this.escape_html(x)) != null ? _ref7.replace(/\n/g, '
') : void 0; + }, + clone: function(obj) { + return JSON.parse(JSON.stringify(obj)); + }, + escape_html: function(text) { + var map; + map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + return text != null ? text.replace(/[&<>"']/g, function(m) { + return map[m]; + }) : void 0; } }; Formbuilder.options = { - BUTTON_CLASS: 'fb-button', + BUTTON_CLASS_SELECTOR: 'fb-button btn btn-default', + BUTTON_CLASS_ADD: 'fb-button btn btn-xs btn-primary', + BUTTON_CLASS_REMOVE: 'fb-button btn btn-xs btn-danger', HTTP_ENDPOINT: '', HTTP_METHOD: 'POST', - AUTOSAVE: true, CLEAR_FIELD_CONFIRM: false, + ENABLED_FIELDS: ['text', 'checkbox', 'dropdown', 'textarea', 'radio', 'date', 'section', 'signature', 'info', 'grid', 'number', 'table', 'datasource', 'time', 'geolocation', 'approval'], + INLINE_IMAGE_FIELDS: ['text', 'info'], mappings: { - SIZE: 'field_options.size', - UNITS: 'field_options.units', + SIZE: 'options.size', + UNITS: 'options.units', LABEL: 'label', - FIELD_TYPE: 'field_type', + NAME: 'definition.name', + TYPE: 'type', REQUIRED: 'required', ADMIN_ONLY: 'admin_only', - OPTIONS: 'field_options.options', - DESCRIPTION: 'field_options.description', - INCLUDE_OTHER: 'field_options.include_other_option', - INCLUDE_BLANK: 'field_options.include_blank_option', - INTEGER_ONLY: 'field_options.integer_only', - MIN: 'field_options.min', - MAX: 'field_options.max', - MINLENGTH: 'field_options.minlength', - MAXLENGTH: 'field_options.maxlength', - LENGTH_UNITS: 'field_options.min_max_length_units' + POPULATE_FROM: 'options.populate_from', + POPULATE_UUID: 'options.populate_uuid', + CONDITIONAL_PARENT: 'options.conditional.parent', + CONDITIONAL_VALUES: 'options.conditional.values', + CONDITIONAL: 'options.conditional', + OPTIONS: 'answers', + DESCRIPTION: 'description', + INCLUDE_OTHER: 'options.include_other_option', + INCLUDE_BLANK: 'options.include_blank_option', + INCLUDE_SCORING: 'is_scored', + INTEGER_ONLY: 'options.integer_only', + LABEL_COLOR: 'options.label_color', + LABEL_BACKGROUND_COLOR: 'options.label_background_color', + READ_ONLY: 'options.read_only', + COLUMN_WIDTH: 'options.column_width', + DEFAULT_TIME: 'options.default_time', + DEFAULT_DATE: 'options.default_date', + REFERENCE_ID: 'reference_id', + INLINE_IMAGES_ENABLED: 'options.inline_images_enabled', + INLINE_IMAGES_REQUIRED: 'options.inline_images_required', + INLINE_ACTIONS_ENABLED: 'options.inline_actions_enabled', + INLINE_ACTIONS_REQUIRED: 'options.inline_actions_required', + NUMERIC: { + CALCULATION_TYPE: 'options.calculation_type', + CALCULATION_EXPRESSION: 'options.calculation_expression', + CALCULATION_DISPLAY: 'options.calculation_display', + TOTAL_SEQUENCE: 'options.total_sequence' + }, + GRID: { + COLS: 'options.cols', + NUMCOLS: 'options.num_cols', + ROWS: 'options.rows', + NUMROWS: 'options.num_rows', + FULL_WIDTH: 'options.full_width', + FIRST_ROW_HEADINGS: 'options.first_row_headings' + }, + TABLE: { + COLS: 'options.cols', + NUMCOLS: 'options.num_cols', + ROWS: 'options.rows', + INITIALROWS: 'options.initial_rows', + MAXROWS: 'options.max_rows', + FULL_WIDTH: 'options.full_width', + COLUMNTOTALS: 'options.display_column_totals', + ROWTOTALS: 'options.display_row_totals' + }, + DATA_SOURCE: { + MULTIPLE: 'options.multiple_selections', + DATA_SOURCE: 'options.data_source', + VALUE_TEMPLATE: 'options.value_template', + REQUIRED_PROPERTIES: 'options.required_properties', + FILTER: 'options.filter', + FILTER_VALUES: 'options.filter_values', + IS_FILTERED: 'options.is_filtered' + }, + MIN: 'options.min', + MAX: 'options.max', + OPTIONS_PER_ROW: 'options.options_per_row', + MINLENGTH: 'options.minlength', + MAXLENGTH: 'options.maxlength', + LENGTH_UNITS: 'options.min_max_length_units', + APPROVAL: { + APPROVER_TYPE: 'options.approver_type', + APPROVER_ID: 'options.approver_id' + }, + DISALLOW_DUPLICATION: 'options.disallow_duplication' + }, + change: { + REQUIRED: function() { + this.reset(); + this.resetInlineImages(); + return this.resetInlineActions(); + }, + INLINE_IMAGES_ENABLED: function() { + this.reset(); + return this.resetInlineImages(); + }, + INLINE_IMAGES_REQUIRED: function() { + return this.reset(); + }, + INLINE_ACTIONS_ENABLED: function() { + this.reset(); + return this.resetInlineActions(); + }, + INLINE_ACTIONS_REQUIRED: function() { + return this.reset(); + }, + INCLUDE_SCORING: function() { + return this.reset(); + }, + POPULATE_UUID: function() { + if (!this.model.get(Formbuilder.options.mappings.POPULATE_UUID)) { + this.deselectReadOnly(); + } + return this.reset(); + }, + CONDITIONAL_PARENT: function() { + this.reset(); + return this.resetConditional(); + }, + CONDITIONAL_VALUES: function() { + return this.reset(); + }, + 'DATA_SOURCE.DATA_SOURCE': function() { + return this.reset(); + }, + 'DATA_SOURCE.IS_FILTERED': function() { + return this.reset(); + }, + 'DATA_SOURCE.FILTER': function() { + return this.reset(); + }, + 'APPROVAL.APPROVER_TYPE': function() { + return this.reset(); + } }, dict: { ALL_CHANGES_SAVED: 'All changes saved', @@ -602,16 +1674,41 @@ Formbuilder.nonInputFields = {}; + Formbuilder.prototype.markSaved = function() { + return this.mainView.formSaved = true; + }; + + Formbuilder.prototype.isValid = function() { + var go; + go = true; + if (this.mainView.editView && !this.mainView.editView.model.isValid()) { + go = false; + } + return go; + }; + + Formbuilder.prototype.getPayload = function() { + return this.mainView.getPayload(); + }; + Formbuilder.registerField = function(name, opts) { - var x, _i, _len, _ref5; - _ref5 = ['view', 'edit']; - for (_i = 0, _len = _ref5.length; _i < _len; _i++) { - x = _ref5[_i]; - opts[x] = _.template(opts[x]); + var enabled, fields, x, _i, _len, _ref7; + enabled = true; + fields = Formbuilder.options.ENABLED_FIELDS; + if (!_.contains(fields, name)) { + enabled = false; } - opts.field_type = name; + _ref7 = ['view', 'edit']; + for (_i = 0, _len = _ref7.length; _i < _len; _i++) { + x = _ref7[_i]; + opts[x] = enabled ? _.template(opts[x]) : function(x) { + return ''; + }; + } + opts.type = name; + opts.enabled = enabled; Formbuilder.fields[name] = opts; - if (opts.type === 'non_input') { + if (opts.element_type === 'non_input') { return Formbuilder.nonInputFields[name] = opts; } else { return Formbuilder.inputFields[name] = opts; @@ -619,7 +1716,7 @@ }; function Formbuilder(opts) { - var args; + var args, partionedData; if (opts == null) { opts = {}; } @@ -627,15 +1724,51 @@ args = _.extend(opts, { formBuilder: this }); + this.attrs = {}; + partionedData = _(args.bootstrapData || []).groupBy(function(i) { + if (i.parent_uuid === void 0) { + return 0; + } else { + return 1; + } + }).toArray().value(); + partionedData = _.reduce(partionedData, function(a, i) { + return a.concat(i); + }); + args.bootstrapData = _.map(partionedData, function(i) { + return _.extend({}, Formbuilder.helpers.defaultFieldAttrs(i.type), i); + }); this.mainView = new BuilderView(args); + this.mainView.collection; + Formbuilder.instances.push(this); } return Formbuilder; })(); + if (_.nested === void 0) { + _.mixin({ + 'nested': function(obj, key) { + if (obj && key) { + return obj[key] || _.reduce(key.split('.'), function(obj, key) { + if (obj) { + return obj[key]; + } else { + return void 0; + } + }, obj); + } else { + return void 0; + } + } + }); + } + window.Formbuilder = Formbuilder; + window.FormbuilderModel = FormbuilderModel; + if (typeof module !== "undefined" && module !== null) { module.exports = Formbuilder; } else { @@ -646,30 +1779,169 @@ (function() { Formbuilder.registerField('address', { + name: 'Address', order: 50, view: "
\n \n \n \n \n
\n\n
\n \n \n \n \n\n \n \n \n \n
\n\n
\n \n \n \n \n\n \n \n \n \n
", - edit: "", - addButton: " Address" + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Address" + }); + +}).call(this); + +(function() { + Formbuilder.registerField('approval', { + name: 'Approval', + order: 75, + view: "
\n \n
\n
\n
Sign Here
\n
\n
\n", + edit: "<%= Formbuilder.templates['edit/approval_options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Approval", + onEdit: function(model) { + return $('.fb-approval-user-select').select2(); + }, + defaultAttributes: function(attrs, formbuilder) { + attrs.initialize = function() { + return this.on("change", function(model) { + var parent, selectUser; + parent = this.conditionalParent(); + if (parent && parent.get('type') === 'approval') { + model.set(Formbuilder.options.mappings.CONDITIONAL_VALUES, 1); + } + if (parseInt(this.get(Formbuilder.options.mappings.APPROVAL.APPROVER_TYPE)) === 1) { + return model.set(Formbuilder.options.mappings.APPROVAL.APPROVER_ID, void 0); + } else { + selectUser = this.get('options.approver'); + if (selectUser !== void 0) { + return model.set(Formbuilder.options.mappings.APPROVAL.APPROVER_ID, parseInt(selectUser)); + } + } + }); + }; + attrs.getApprovers = function() { + return formbuilder.attr('approvers'); + }; + attrs.getSelectedUserName = function(selectUser) { + if (selectUser) { + return selectUser.full_name + ' (' + selectUser.username + ')'; + } + }; + attrs.getSelectedUser = function() { + var approvers, user, user_id; + if (this.options) { + user_id = options.approver_id; + } else { + user_id = this.get(Formbuilder.options.mappings.APPROVAL.APPROVER_ID); + } + approvers = this.getApprovers() || []; + user = approvers.filter(function(item) { + return parseInt(item.id) === user_id; + }); + return this.getSelectedUserName(user[0]); + }; + attrs.showApprovers = function() { + return parseInt(this.get(Formbuilder.options.mappings.APPROVAL.APPROVER_TYPE)) === 2; + }; + attrs.options.approver_type = 1; + return attrs; + } }); }).call(this); (function() { - Formbuilder.registerField('checkboxes', { + Formbuilder.registerField('checkbox', { + name: 'Checkboxes', order: 10, - view: "<% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\n \n
\n<% } %>\n\n<% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n<% } %>", - edit: "<%= Formbuilder.templates['edit/options']({ includeOther: true }) %>", - addButton: " Checkboxes", + view: "
\">\n <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\n \n
\n <% } %>\n\n <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n <% } %>\n
", + edit: "<%= Formbuilder.templates['edit/options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/options_per_row']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Checkboxes", defaultAttributes: function(attrs) { - attrs.field_options.options = [ + attrs.answers = [ { + uuid: uuid.v4(), label: "", - checked: false + checked: false, + score: false }, { + uuid: uuid.v4(), label: "", - checked: false + checked: false, + score: false } ]; + attrs.options.options_per_row = 1; + return attrs; + } + }); + +}).call(this); + +(function() { + Formbuilder.registerField('datasource', { + name: 'List', + order: 70, + view: "", + edit: "<%= Formbuilder.templates['edit/data_source_options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Data Source", + defaultAttributes: function(attrs, formbuilder) { + var datasources; + attrs.initialize = function() { + this.on("change", function(model) { + var filters, sourceProperties, valueTemplate; + filters = model.filters(); + if (_.nested(model, 'changed.options.data_source') !== void 0) { + sourceProperties = _.keys(model.sourceProperties()); + model.set('options.required_properties', sourceProperties); + valueTemplate = _.first(sourceProperties); + model.set('options.value_template', valueTemplate); + } + if (filters) { + return model.set('options.filter', _.first(_.keys(filters))); + } + }); + return this.on("destroy", function(model) { + return this.collection.each(function(collectionModel) { + if (collectionModel.get('options.populate_uuid') === model.get('uuid')) { + collectionModel.set('options.populate_uuid', null); + return collectionModel.set('options.populate_from', null); + } + }); + }); + }; + attrs.source = function() { + var source, sources; + source = this.options ? this.options.data_source : this.get(Formbuilder.options.mappings.DATA_SOURCE.DATA_SOURCE); + sources = formbuilder.attr('sources'); + return _.nested(sources, source) || {}; + }; + attrs.sourceProperties = function() { + var source; + source = this.source(); + return _.nested(source, 'properties') || []; + }; + attrs.filters = function() { + var source; + source = this.source(); + return _.nested(source, 'filters') || null; + }; + attrs.currentFilter = function() { + var source; + source = this.source(); + return _.nested(source, 'filters.' + this.get('options.filter')) || {}; + }; + attrs.filterValues = function() { + return this.currentFilter().values || {}; + }; + attrs.sourceProperty = function(property) { + return this.sourceProperties()[property] || null; + }; + attrs.options.multiple_selections = false; + attrs.options.is_filtered = false; + datasources = formbuilder.attr('sources') || {}; + attrs.options.data_source = _.keys(datasources)[0]; + attrs.options.required_properties = _.keys(attrs.sourceProperties(attrs.options.data_source)); + attrs.options.filter = null; + attrs.options.filter_values = []; + attrs.options.value_template = _.first(attrs.options.required_properties); return attrs; } }); @@ -678,31 +1950,42 @@ (function() { Formbuilder.registerField('date', { + name: 'Date', order: 20, - view: "
\n \n \n \n \n\n /\n\n \n \n \n \n\n /\n\n \n \n \n \n
", - edit: "", - addButton: " Date" + view: "
\n \n
", + edit: "<%= Formbuilder.templates['edit/date']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Date", + defaultAttributes: function(attrs) { + attrs.options.default_date = false; + return attrs; + } }); }).call(this); (function() { Formbuilder.registerField('dropdown', { + name: 'Dropdown', order: 24, - view: "", - edit: "<%= Formbuilder.templates['edit/options']({ includeBlank: true }) %>", - addButton: " Dropdown", + view: "", + edit: "<%= Formbuilder.templates['edit/scoring']() %>\n<%= Formbuilder.templates['edit/options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Dropdown", defaultAttributes: function(attrs) { - attrs.field_options.options = [ + attrs.answers = [ { + uuid: uuid.v4(), label: "", - checked: false + checked: false, + score: "" }, { + uuid: uuid.v4(), label: "", - checked: false + checked: false, + score: "" } ]; - attrs.field_options.include_blank_option = false; + attrs.is_scored = false; + attrs.options.include_blank_option = false; return attrs; } }); @@ -711,42 +1994,192 @@ (function() { Formbuilder.registerField('email', { + name: 'Email', order: 40, - view: "", - edit: "", - addButton: " Email" + view: "", + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Email" }); }).call(this); (function() { Formbuilder.registerField('file', { + name: 'File', order: 55, - view: "", - edit: "", - addButton: " File" + view: "", + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " File" }); }).call(this); (function() { - Formbuilder.registerField('number', { - order: 30, - view: "\n<% if (units = rf.get(Formbuilder.options.mappings.UNITS)) { %>\n <%= units %>\n<% } %>", - edit: "<%= Formbuilder.templates['edit/min_max']() %>\n<%= Formbuilder.templates['edit/units']() %>\n<%= Formbuilder.templates['edit/integer_only']() %>", - addButton: "123 Number" + Formbuilder.registerField('geolocation', { + name: 'Geolocation', + order: 60, + view: "
\n \n
\n<%=rf.geolocationFunctionality%>", + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " GeoLocation" }); }).call(this); (function() { - Formbuilder.registerField('paragraph', { - order: 5, - view: "", - edit: "<%= Formbuilder.templates['edit/size']() %>\n<%= Formbuilder.templates['edit/min_max_length']() %>", - addButton: " Paragraph", + Formbuilder.registerField('grid', { + /* + This element type is undergoing a gradual culling, by way of not allowing most users to add Grid elements into their Form Templates. + Some more annoying clients will refuse this, so regrettably on the integral site we will support a feature for those few that will re-show the add button. + */ + + name: 'Layout Grid', + order: 99, + element_type: 'non_input', + view: "\n\n
\n

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

", + edit: "
Details
\n
\n
\n \">\n \n
\n \n \n
Number of Columns
\n \n
Number of Rows
\n \n
\n", + addButton: " Grid", + hideAddButton: true, defaultAttributes: function(attrs) { - attrs.field_options.size = 'small'; + attrs.options.num_cols = 1; + attrs.options.num_rows = 1; + attrs.options.full_width = false; + attrs.options.first_row_headings = false; + attrs.children = []; + attrs.childModels = function() { + return this.collection.filter(function(model) { + return _.indexOf(this.get('options.elements'), model.get('uuid')) !== -1; + }, this); + }; + return attrs; + } + }); + +}).call(this); + +(function() { + Formbuilder.registerField('info', { + name: 'Info', + order: 20, + element_type: 'non_input', + view: "\n

<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

", + edit: "
Details
\n
\n
\n \">\n
\n \n
\n<%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Info", + onEdit: function(model) { + var defaultProtocol, update; + defaultProtocol = 'http://'; + update = function() { + model.set(Formbuilder.options.mappings.DESCRIPTION, $(this).summernote('code')); + return model.trigger('change:' + Formbuilder.options.mappings.DESCRIPTION); + }; + return $('.fb-info-editor').summernote({ + callbacks: { + onChange: function() { + return update.call(this); + }, + onKeyup: function() { + return update.call(this); + }, + onInit: function() { + var insertLinkBtn, newTabBtn, noteLinkUrl, protocalBtn; + insertLinkBtn = document.querySelector('input.note-link-btn'); + noteLinkUrl = document.querySelector('.note-link-url'); + protocalBtn = document.querySelector('div.sn-checkbox-use-protocol > label > input'); + newTabBtn = document.querySelector('div.sn-checkbox-open-in-new-window > label > input'); + noteLinkUrl.addEventListener('keydown', function() { + protocalBtn.checked = true; + return newTabBtn.checked = true; + }); + return insertLinkBtn.addEventListener('click', function() { + var url; + newTabBtn.checked = true; + url = noteLinkUrl.value; + if (url.substring(0, 8) !== 'https://' && url.substring(0, 7) !== 'http://') { + return noteLinkUrl.value = defaultProtocol + url; + } + }); + } + }, + disableDragAndDrop: true, + linkTargetBlank: true, + useProtocol: true, + defaultProtocol: defaultProtocol, + toolbar: [['style', ['bold', 'italic', 'underline']], ['fontsize', ['fontsize']], ['color', ['color']], ['insert', ['link']], ['table', ['table']], ['misc', ['codeview']]] + }); + } + }); + +}).call(this); + +(function() { + Formbuilder.registerField('number', { + name: 'Number', + order: 30, + view: "\" <%- rf.get(Formbuilder.options.mappings.NUMERIC.CALCULATION_DISPLAY) ? 'readonly=\"readonly\"' : '' %> />\n<% if (units = rf.get(Formbuilder.options.mappings.UNITS)) { %>\n <%= units %>\n<% } %>", + edit: "<%= Formbuilder.templates['edit/integer_only']({rf:rf}) %>\n<%= Formbuilder.templates['edit/total']({rf:rf}) %>\n<%= Formbuilder.templates['edit/min_max']({rf:rf}) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Number", + defaultAttributes: function(attrs, formbuilder) { + attrs.options.calculation_type = ''; + attrs.options.calculation_expression = ''; + attrs.options.calculation_display = ''; + attrs.options.total_sequence = false; + attrs.insertion = function() { + var parentModel, totalColumn; + parentModel = this.parentModel(); + if (parentModel && parentModel.get('type') === 'table') { + totalColumn = parentModel.totalColumn(this.get('uuid')); + return this.attributes.options.total_sequence = totalColumn; + } + }; + attrs.initialize = function() { + return this.on("change", function(model) { + var totalSequence; + if (_.nested(model, 'changed.options.calculation_type') !== void 0) { + model.expression(); + } + if (_.nested(model, 'changed.options.total_sequence') !== void 0) { + totalSequence = _.nested(model, 'changed.options.total_sequence'); + this.parentModel().totalColumn(model.get('uuid'), totalSequence); + } + return model; + }); + }; + attrs.numericSiblings = function() { + var parentModel; + parentModel = this.parentModel(); + if (parentModel) { + return _.filter(parentModel.childModels(), function(i) { + return i.get('type') === 'number' && i.get('uuid') !== this.get('uuid'); + }, this); + } else { + return []; + } + }; + attrs.expression = function() { + var calculation_type, numericSiblings, operator; + calculation_type = this.get('options.calculation_type'); + if (calculation_type !== '') { + operator = calculation_type === 'SUM' ? '+' : '*'; + numericSiblings = this.numericSiblings(); + this.set('options.calculation_expression', _.map(numericSiblings, function(model) { + return 'uuid_' + model.get('uuid').replace(/-/g, '_'); + }).join(operator)); + this.set('options.calculation_display', '= ' + _.map(numericSiblings, function(model) { + return model.get('label'); + }).join(operator)); + return console.log(this.get('options.calculation_expression')); + } else { + this.set('options.calculation_expression', ''); + return this.set('options.calculation_display', ''); + } + }; + attrs.canTotalColumn = function() { + var parent; + parent = this.parentModel(); + return parent && parent.get('type') === 'table'; + }; + attrs.canAcceptCalculatedTotal = function() { + return this.numericSiblings().length > 1; + }; return attrs; } }); @@ -755,30 +2188,38 @@ (function() { Formbuilder.registerField('price', { + name: 'Price', order: 45, view: "
\n $\n \n \n \n \n .\n \n \n \n \n
", - edit: "", - addButton: " Price" + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Price" }); }).call(this); (function() { Formbuilder.registerField('radio', { + name: 'Radio Button', order: 15, - view: "<% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\n \n
\n<% } %>\n\n<% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n<% } %>", - edit: "<%= Formbuilder.templates['edit/options']({ includeOther: true }) %>", - addButton: " Multiple Choice", + view: "
\">\n <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %>\n
\">\n \n
\n <% } %>\n\n <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %>\n
\n \n\n \n
\n <% } %>\n
", + edit: "<%= Formbuilder.templates['edit/scoring']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/options']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/options_per_row']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Radio Button", defaultAttributes: function(attrs) { - attrs.field_options.options = [ + attrs.answers = [ { + uuid: uuid.v4(), label: "", - checked: false + checked: false, + score: "" }, { + uuid: uuid.v4(), label: "", - checked: false + checked: false, + score: "" } ]; + attrs.is_scored = false; + attrs.options.options_per_row = 1; return attrs; } }); @@ -786,24 +2227,135 @@ }).call(this); (function() { - Formbuilder.registerField('section_break', { + Formbuilder.registerField('section', { + name: 'Section', + order: 10, + element_type: 'non_input', + view: "\n

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

", + edit: "
Details
\n
\n
\n \">\n \n
\n
\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Section Break" + }); + +}).call(this); + +(function() { + Formbuilder.registerField('signature', { + name: 'Signature', + order: 65, + view: "
\n
Sign Here
\n
\n
\n", + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Signature" + }); + +}).call(this); + +(function() { + Formbuilder.registerField('table', { + name: 'Table', order: 0, - type: 'non_input', - view: "\n

<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

", - edit: "
Label
\n\n", - addButton: " Section Break" + element_type: 'non_input', + view: "\n<%= Formbuilder.templates[\"view/table_field\"]({rf: rf}) %>\n

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

", + edit: "
Details
\n
\n
\n <%= Formbuilder.templates['edit/label_description']({rf: rf}) %>\n
\n
\n
\n", + addButton: " Table", + defaultAttributes: function(attrs) { + attrs.options.full_width = false; + attrs.initialize = function() { + var parent; + parent = this; + return _.each(this.childModels, function(childModel) { + return childModel.on("change", function(model) { + if (_.nested(model, 'changed.options.column_width') !== void 0) { + parent.columnWidth(model.get('uuid'), model.get('options.column_width')); + } + return model; + }); + }); + }; + attrs.childModels = function() { + var elementsUuids; + elementsUuids = _.pluck(this.get('options.elements'), 'uuid'); + return this.collection.filter(function(model) { + return _.indexOf(elementsUuids, model.get('uuid')) !== -1; + }, this); + }; + attrs.elementOptions = function(elementUuid) { + return _.findWhere(this.get('options.elements'), { + uuid: elementUuid + }); + }; + attrs.createTotalColumnModel = function(parentUuid) { + var totalColumnModel; + totalColumnModel = new FormbuilderModel(Formbuilder.helpers.defaultFieldAttrs('number')); + totalColumnModel.set('options.calculation_expression', 'sum(column_uuid_' + parentUuid.replace(/-/g, '_') + ')'); + totalColumnModel.set('model_only', true); + totalColumnModel.set('parent_uuid', parentUuid); + this.collection.add(totalColumnModel); + return totalColumnModel; + }; + attrs.columnWidth = function(elementUuid, width) { + var elements; + elements = this.get('options.elements'); + return _.each(elements, function(element, index) { + if (element.uuid === elementUuid) { + return elements[index].columnWidth = width; + } + }, this); + }; + attrs.totalColumn = function(elementUuid, value) { + var elements; + elements = this.get('options.elements'); + if (value !== void 0) { + _.each(elements, function(element, index) { + var totalColumnModel; + if (element.uuid === elementUuid) { + if (element.totalColumnUuid === void 0) { + totalColumnModel = this.createTotalColumnModel(element.uuid); + elements[index].totalColumnUuid = totalColumnModel.get('uuid'); + } + return elements[index].totalColumn = value; + } + }, this); + return this.set('options.elements', elements); + } else { + if (this.elementOptions(elementUuid)) { + return this.elementOptions(elementUuid).totalColumn || false; + } else { + return false; + } + } + }; + return attrs; + } }); }).call(this); (function() { Formbuilder.registerField('text', { + name: 'Text', order: 0, - view: "", - edit: "<%= Formbuilder.templates['edit/size']() %>\n<%= Formbuilder.templates['edit/min_max_length']() %>", - addButton: " Text", + view: "\n readonly=\"readonly\"\n <% } %>\n/>", + edit: "<%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/populate_from']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Text", + defaultAttributes: function(attrs) { + attrs.options.size = 'small'; + attrs.options.read_only = false; + return attrs; + } + }); + +}).call(this); + +(function() { + Formbuilder.registerField('textarea', { + name: 'Paragraph', + order: 5, + view: "", + edit: "<%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/populate_from']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Paragraph", defaultAttributes: function(attrs) { - attrs.field_options.size = 'small'; + attrs.options.size = 'small'; + attrs.options.read_only = false; return attrs; } }); @@ -812,20 +2364,26 @@ (function() { Formbuilder.registerField('time', { + name: 'Time', order: 25, - view: "
\n \n \n \n \n\n :\n\n \n \n \n \n\n :\n\n \n \n \n \n\n \n \n \n
", - edit: "", - addButton: " Time" + view: "
\n
\n \n
\n
\n
", + edit: "<%= Formbuilder.templates['edit/time']({ rf: rf }) %>\n<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Time", + defaultAttributes: function(attrs) { + attrs.options.default_time = false; + return attrs; + } }); }).call(this); (function() { Formbuilder.registerField('website', { + name: 'Website', order: 35, view: "", - edit: "", - addButton: " Website" + edit: "<%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %>", + addButton: " Website" }); }).call(this); @@ -833,73 +2391,307 @@ this["Formbuilder"] = this["Formbuilder"] || {}; this["Formbuilder"]["templates"] = this["Formbuilder"]["templates"] || {}; -this["Formbuilder"]["templates"]["edit/base"] = function(obj) { +this["Formbuilder"]["templates"]["edit/approval_options"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } +with (obj) { +__p += '
Approver
\n
\n
\n \n
\n
\n \n
\n '; + if (rf.showApprovers()) { ; +__p += '\n
\n \n
\n '; + } ; +__p += '\n
\n\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/base"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += +((__t = ( Formbuilder.templates['edit/base_header']({rf: rf}) )) == null ? '' : __t) + +'\n' + +((__t = ( Formbuilder.templates['edit/common']({rf: rf}) )) == null ? '' : __t) + +'\n' + +((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].edit({rf: rf}) )) == null ? '' : __t) + +'\n' + +((__t = ( Formbuilder.templates['edit/columnwidth']({rf: rf}) )) == null ? '' : __t) + +'\n' + +((__t = ( Formbuilder.templates['edit/table_color']({rf: rf}) )) == null ? '' : __t) + +'\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/base_header"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
\n \n \n \n
\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/base_non_input"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += +((__t = ( Formbuilder.templates['edit/base_header']({rf: rf}) )) == null ? '' : __t) + +'\n' + +((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].edit({rf: rf}) )) == null ? '' : __t) + +'\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/checkboxes"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/columnwidth"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += ''; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/common"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } +with (obj) { + + if (rf.canShowReferenceID()) { ; +__p += '\n
\n
Reference ID
\n ' + +((__t = ( Formbuilder.templates['edit/reference_id']({rf: rf}) )) == null ? '' : __t) + +'\n
\n'; + } ; +__p += '\n
Details
\n\n
\n
\n ' + +((__t = ( Formbuilder.templates['edit/label_description']({rf: rf}) )) == null ? '' : __t) + +'\n
\n
\n ' + +((__t = ( Formbuilder.templates['edit/checkboxes']() )) == null ? '' : __t) + +'\n
\n
\n
'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/conditional_options"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += -((__t = ( Formbuilder.templates['edit/base_header']() )) == null ? '' : __t) + -'\n' + -((__t = ( Formbuilder.templates['edit/common']() )) == null ? '' : __t) + -'\n' + -((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].edit({rf: rf}) )) == null ? '' : __t) + -'\n'; + + if (rf.canBeConditionallyDisplayed()) { ; +__p += '\n
\n
Conditionally Display\n \n \n \n \n\n
\n '; + + var list = rf.collection.findConditionalTriggers(rf); + if (list.length) { ; +__p += '\n \n '; + + var selectedList = rf.conditionalTriggerOptions(); + if (!Array.isArray(selectedList)) { ; +__p += '\n
\n \n
\n '; + } else { + if (selectedList.length == 0) + rf.collection.clearConditionEle(rf); + for (i in selectedList) { ; +__p += '\n \n '; + } + } + ; +__p += '\n '; + } else { ; +__p += '\n No trigger elements\n '; + } ; +__p += '\n '; + } ; +__p += '\n \n
\n\n'; } return __p }; -this["Formbuilder"]["templates"]["edit/base_header"] = function(obj) { +this["Formbuilder"]["templates"]["edit/data_source_options"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '
\n \n \n \n
'; +__p += '
Data Source
\n\n
Display
\n\n'; + if (rf.filters()) { ; +__p += '\n
Filter
\n \n '; + if (rf.get(Formbuilder.options.mappings.DATA_SOURCE.IS_FILTERED)) { ; +__p += '\n \n '; + + for (i in rf.filterValues()) { ; +__p += '\n \n '; + } ; +__p += '\n'; + } ; +__p += '\n'; + } ; + } return __p }; -this["Formbuilder"]["templates"]["edit/base_non_input"] = function(obj) { +this["Formbuilder"]["templates"]["edit/date"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { -__p += -((__t = ( Formbuilder.templates['edit/base_header']() )) == null ? '' : __t) + -'\n' + -((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].edit({rf: rf}) )) == null ? '' : __t) + -'\n'; +__p += '
\n \n
\n'; } return __p }; -this["Formbuilder"]["templates"]["edit/checkboxes"] = function(obj) { +this["Formbuilder"]["templates"]["edit/inline_action_option"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '\n'; + + if (!rf.hasParent()) { ; +__p += '\n
\n
Add action\n \n \n \n \n\n
\n \n '; + if (rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED) && (rf.get(Formbuilder.options.mappings.REQUIRED) || rf.get('type') === "info") ) { ; +__p += '\n \n '; + } ; +__p += '\n\n
\n'; + } ; + } return __p }; -this["Formbuilder"]["templates"]["edit/common"] = function(obj) { +this["Formbuilder"]["templates"]["edit/inline_image_option"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '
Label
\n\n
\n
\n ' + -((__t = ( Formbuilder.templates['edit/label_description']() )) == null ? '' : __t) + -'\n
\n
\n ' + -((__t = ( Formbuilder.templates['edit/checkboxes']() )) == null ? '' : __t) + -'\n
\n
\n
\n'; + + if (!rf.hasParent()) { ; +__p += '\n
\n
Add photo\n \n \n \n \n\n
\n \n '; + if (rf.get(Formbuilder.options.mappings.INLINE_IMAGES_ENABLED) && (rf.get(Formbuilder.options.mappings.REQUIRED) || rf.get('type') === "info") ) { ; +__p += '\n \n '; + } ; +__p += '\n\n
\n'; + } ; + } return __p @@ -909,9 +2701,9 @@ this["Formbuilder"]["templates"]["edit/integer_only"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { -__p += '
Integer only
\n\n'; +'\' />\n Whole numbers only?\n\n'; } return __p @@ -921,9 +2713,9 @@ this["Formbuilder"]["templates"]["edit/label_description"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { -__p += '\n'; @@ -935,9 +2727,9 @@ this["Formbuilder"]["templates"]["edit/min_max"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { -__p += '
Minimum / Maximum
\n\nAbove\n\n\n  \n\nBelow\n\n\n  \n\nMax\n\n'; @@ -949,11 +2741,11 @@ this["Formbuilder"]["templates"]["edit/min_max_length"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { -__p += '
Length Limit
\n\nMin\n\n\n  \n\nMax\n\n\n  \n\nMax\n\n\n  \n\n\n \n \n\n'; @@ -968,25 +2760,113 @@ function print() { __p += __j.call(arguments, '') } with (obj) { __p += '
Options
\n\n'; if (typeof includeBlank !== 'undefined'){ ; -__p += '\n \n'; } ; -__p += '\n\n
\n \n \n \n \n
\n\n'; +'\'>\n \n \n '; + if (rf.get(Formbuilder.options.mappings.INCLUDE_SCORING)) { ; +__p += '\n \n '; + } ; +__p += '\n\n \n \n\n\n\n'; if (typeof includeOther !== 'undefined'){ ; -__p += '\n \n'; } ; -__p += '\n\n
\n Add option\n
\n'; +__p += '\n\n
\n \n
\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/options_per_row"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
Number of options per row
\n \n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/populate_from"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } +with (obj) { + + var list = rf.collection.findDataSourceFields(); +if (list.length) { ; +__p += '\n
Populate From
\n \n \n '; + if (rf.get(Formbuilder.options.mappings.POPULATE_UUID)) { ; +__p += '\n
\n \n
\n '; + } ; +__p += '\n'; + } ; +__p += '\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/reference_id"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += ''; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/scoring"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
\n \n
\n\n'; } return __p @@ -1004,6 +2884,86 @@ __p += '
Size
\n\n \n
Header Background Colour
\n
\n \n
\n\n'; + } ; + + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/table_layout"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
Layout
\n \n\n \n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/table_totals"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
Totals
\n \n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/time"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
\n \n
\n'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["edit/total"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } +with (obj) { + + if (rf.canTotalColumn()) { ; +__p += '\n\n'; + } ; +__p += '\n'; + if (rf.canAcceptCalculatedTotal()) { ; +__p += '\n
Total
\n\n'; + } ; +__p += '\n\n'; + +} +return __p +}; + this["Formbuilder"]["templates"]["edit/units"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; @@ -1021,8 +2981,6 @@ obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { __p += -((__t = ( Formbuilder.templates['partials/save_button']() )) == null ? '' : __t) + -'\n' + ((__t = ( Formbuilder.templates['partials/left_side']() )) == null ? '' : __t) + '\n' + ((__t = ( Formbuilder.templates['partials/right_side']() )) == null ? '' : __t) + @@ -1037,23 +2995,37 @@ obj || (obj = {}); var __t, __p = '', __e = _.escape, __j = Array.prototype.join; function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '
\n
\n
\n '; - _.each(_.sortBy(Formbuilder.inputFields, 'order'), function(f){ ; -__p += '\n \n ' + +__p += '
\n
\n \n\n
\n '; - _.each(_.sortBy(Formbuilder.nonInputFields, 'order'), function(f){ ; -__p += '\n \n ' + + _.chain(Formbuilder.nonInputFields) + .sortBy('order') + .filter(function(f){ return f.enabled; }) + .each(function(f){ ; +__p += '\n \n ' + ((__t = ( f.addButton )) == null ? '' : __t) + '\n \n '; }); ; @@ -1089,21 +3061,43 @@ return __p this["Formbuilder"]["templates"]["partials/right_side"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '
\n
No response fields
\n
\n
\n'; +__p += '
\n
No response fields
\n '; + if (Formbuilder.linkAssetFunctionality) { ; +__p += '\n ' + +((__t = ( Formbuilder.templates['view/link_object']({object: Formbuilder.linkAssetDisplayFields}) )) == null ? '' : __t) + +'\n
\n '; + } ; +__p += '\n
\n
\n'; } return __p }; -this["Formbuilder"]["templates"]["partials/save_button"] = function(obj) { +this["Formbuilder"]["templates"]["view/afterelementlabel"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '
\n \n
'; +__p += '
\n '; + if (rf.get(Formbuilder.options.mappings.INLINE_IMAGES_ENABLED)) { ; +__p += '\n
\n \n Inline Photo\n '; + if (rf.get(Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED)) { ; +__p += '\n *\n '; + } ; +__p += '\n
\n '; + } ; +__p += '\n\n '; + if (rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED)) { ; +__p += '\n
\n \n Inline Action\n '; + if (rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_REQUIRED)) { ; +__p += '\n *\n '; + } ; +__p += '\n
\n '; + } ; +__p += '\n
\n'; } return __p @@ -1111,17 +3105,30 @@ return __p this["Formbuilder"]["templates"]["view/base"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { __p += '
\n
\n ' + +((__t = ( Formbuilder.templates['view/conditional']({rf: rf}) )) == null ? '' : __t) + +'\n ' + ((__t = ( Formbuilder.templates['view/label']({rf: rf}) )) == null ? '' : __t) + '\n\n ' + -((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].view({rf: rf}) )) == null ? '' : __t) + +((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf: rf}) )) == null ? '' : __t) + '\n\n ' + ((__t = ( Formbuilder.templates['view/description']({rf: rf}) )) == null ? '' : __t) + -'\n ' + +'\n \n '; + if (rf.get(Formbuilder.options.mappings.DISALLOW_DUPLICATION)) { ; +__p += '\n ' + +((__t = ( Formbuilder.templates['view/remove']({rf: rf}) )) == null ? '' : __t) + +'\n '; + } else { ; +__p += '\n ' + ((__t = ( Formbuilder.templates['view/duplicate_remove']({rf: rf}) )) == null ? '' : __t) + -'\n
\n'; +'\n '; + } ; +__p += '\n\n ' + +((__t = ( Formbuilder.templates['view/afterelementlabel']({rf: rf}) )) == null ? '' : __t) + +'\n \n
\n'; } return __p @@ -1129,25 +3136,83 @@ return __p this["Formbuilder"]["templates"]["view/base_non_input"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { __p += '
\n
\n ' + -((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].view({rf: rf}) )) == null ? '' : __t) + +((__t = ( Formbuilder.templates['view/conditional']({rf: rf}) )) == null ? '' : __t) + '\n ' + +((__t = ( Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf: rf}) )) == null ? '' : __t) + +'\n\n '; + if (rf.get(Formbuilder.options.mappings.DISALLOW_DUPLICATION)) { ; +__p += '\n ' + +((__t = ( Formbuilder.templates['view/remove']({rf: rf}) )) == null ? '' : __t) + +'\n '; + } else { ; +__p += '\n ' + ((__t = ( Formbuilder.templates['view/duplicate_remove']({rf: rf}) )) == null ? '' : __t) + +'\n '; + } ; +__p += '\n\n ' + +((__t = ( Formbuilder.templates['view/afterelementlabel']({rf: rf}) )) == null ? '' : __t) + '\n
\n'; } return __p }; +this["Formbuilder"]["templates"]["view/conditional"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } +with (obj) { + + +var parent = rf.conditionalParent(); +if(parent) { +; +__p += '\n
\n \n '; + + if(parent.get('type') == 'approval') { ; +__p += '\n \n display when ' + +((__t = ( parent.get('label') )) == null ? '' : __t) + +'\n ' + +((__t = ( rf.conditionalTriggerOptions(true) )) == null ? '' : __t) + +'\n \n '; + } else { + var triggerValues = _.pluck(rf.conditionalTriggerOptions(true), 'label'); + ; +__p += '\n \n display when ' + +((__t = ( parent.get('label') )) == null ? '' : __t) + +' is\n ' + +((__t = ( triggerValues.join('or') )) == null ? '' : __t) + +'\n \n '; + } + ; +__p += '\n
\n\n'; + } ; +__p += '\n\n'; + +} +return __p +}; + this["Formbuilder"]["templates"]["view/description"] = function(obj) { obj || (obj = {}); -var __t, __p = '', __e = _.escape; +var __t, __p = '', __e = _.escape, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '\n ' + +__p += '\n '; + if (rf.get("type") == "info") { ; +__p += '\n ' + +((__t = ( rf.get(Formbuilder.options.mappings.DESCRIPTION) )) == null ? '' : __t) + +'\n '; + } else { ; +__p += '\n ' + ((__t = ( Formbuilder.helpers.simple_format(rf.get(Formbuilder.options.mappings.DESCRIPTION)) )) == null ? '' : __t) + -'\n\n'; +'\n '; + } ; +__p += '\n'; } return __p @@ -1157,11 +3222,21 @@ this["Formbuilder"]["templates"]["view/duplicate_remove"] = function(obj) { obj || (obj = {}); var __t, __p = '', __e = _.escape; with (obj) { -__p += '
\n \n \n
'; +__p += '
\n \n \n
'; + +} +return __p +}; + +this["Formbuilder"]["templates"]["view/element_selector"] = function(obj) { +obj || (obj = {}); +var __t, __p = '', __e = _.escape; +with (obj) { +__p += '
\n\n\n
\n'; } return __p @@ -1172,7 +3247,9 @@ obj || (obj = {}); var __t, __p = '', __e = _.escape, __j = Array.prototype.join; function print() { __p += __j.call(arguments, '') } with (obj) { -__p += '
""" - edit: "" + edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ addButton: """ - Address + Address """ diff --git a/src/scripts/fields/approval.coffee b/src/scripts/fields/approval.coffee new file mode 100644 index 00000000..fcb85898 --- /dev/null +++ b/src/scripts/fields/approval.coffee @@ -0,0 +1,77 @@ +Formbuilder.registerField 'approval', + + name: 'Approval' + + order: 75 + + view: """ +
+ +
+
+
Sign Here
+
+
+ + """ + + edit: """ + <%= Formbuilder.templates['edit/approval_options']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Approval + """ + + onEdit: (model) -> + $('.fb-approval-user-select').select2() + + defaultAttributes: (attrs, formbuilder) -> + attrs.initialize = () -> + @on "change", (model) -> + parent = @conditionalParent() + if parent && parent.get('type') == 'approval' + model.set(Formbuilder.options.mappings.CONDITIONAL_VALUES, 1) + + if parseInt(@get(Formbuilder.options.mappings.APPROVAL.APPROVER_TYPE)) == 1 + model.set(Formbuilder.options.mappings.APPROVAL.APPROVER_ID, undefined) + else + selectUser = @get('options.approver') + if (selectUser) != undefined + model.set(Formbuilder.options.mappings.APPROVAL.APPROVER_ID, parseInt(selectUser)) + + attrs.getApprovers = () -> + formbuilder.attr('approvers') + + attrs.getSelectedUserName = (selectUser) -> + if selectUser + selectUser.full_name + ' (' + selectUser.username + ')' + + attrs.getSelectedUser = () -> + if @options + user_id = options.approver_id + else + user_id = @get(Formbuilder.options.mappings.APPROVAL.APPROVER_ID) + + approvers = @getApprovers() || [] + user = approvers.filter (item) -> parseInt(item.id) == user_id + + @getSelectedUserName(user[0]) + + attrs.showApprovers = () -> + (parseInt(@get(Formbuilder.options.mappings.APPROVAL.APPROVER_TYPE)) == 2) + + attrs.options.approver_type = 1 + attrs + + + diff --git a/src/scripts/fields/checkbox.coffee b/src/scripts/fields/checkbox.coffee new file mode 100644 index 00000000..26e024fe --- /dev/null +++ b/src/scripts/fields/checkbox.coffee @@ -0,0 +1,55 @@ +Formbuilder.registerField 'checkbox', + name: 'Checkboxes' + + order: 10 + + view: """ +
+ <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %> +
+ +
+ <% } %> + + <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %> +
+ + + +
+ <% } %> +
+ """ + + edit: """ + <%= Formbuilder.templates['edit/options']({ rf: rf }) %> + <%= Formbuilder.templates['edit/options_per_row']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Checkboxes + """ + + defaultAttributes: (attrs) -> + attrs.answers = [ + uuid: uuid.v4() + label: "", + checked: false, + score: false + , + uuid: uuid.v4() + label: "", + checked: false, + score: false + ] + + attrs.options.options_per_row = 1 + + attrs diff --git a/src/scripts/fields/checkboxes.coffee b/src/scripts/fields/checkboxes.coffee deleted file mode 100644 index 89368a71..00000000 --- a/src/scripts/fields/checkboxes.coffee +++ /dev/null @@ -1,44 +0,0 @@ -Formbuilder.registerField 'checkboxes', - - order: 10 - - view: """ - <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %> -
- -
- <% } %> - - <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %> -
- - - -
- <% } %> - """ - - edit: """ - <%= Formbuilder.templates['edit/options']({ includeOther: true }) %> - """ - - addButton: """ - Checkboxes - """ - - defaultAttributes: (attrs) -> - attrs.field_options.options = [ - label: "", - checked: false - , - label: "", - checked: false - ] - - attrs \ No newline at end of file diff --git a/src/scripts/fields/datasource.coffee b/src/scripts/fields/datasource.coffee new file mode 100644 index 00000000..8cf81e9a --- /dev/null +++ b/src/scripts/fields/datasource.coffee @@ -0,0 +1,80 @@ +Formbuilder.registerField 'datasource', + + name: 'List' + + order: 70 + + view: """ + + """ + + edit: """ + <%= Formbuilder.templates['edit/data_source_options']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Data Source + """ + + defaultAttributes: (attrs, formbuilder) -> + attrs.initialize = () -> + + @on "change", (model) -> + filters = model.filters() + if _.nested(model, 'changed.options.data_source') != undefined + sourceProperties = _.keys(model.sourceProperties()) + model.set('options.required_properties', sourceProperties) + valueTemplate = _.first(sourceProperties) + model.set('options.value_template', valueTemplate) + if filters + model.set('options.filter', _.first(_.keys(filters))) + + + @on "destroy", (model) -> + @collection.each (collectionModel) -> + if collectionModel.get('options.populate_uuid') is model.get('uuid') + collectionModel.set('options.populate_uuid', null) + collectionModel.set('options.populate_from', null) + + + + attrs.source = () -> + source = if @options then @options.data_source else @get(Formbuilder.options.mappings.DATA_SOURCE.DATA_SOURCE) + sources = formbuilder.attr('sources') + _.nested(sources, source) || {} + + attrs.sourceProperties = () -> + source = @source() + _.nested(source, 'properties') || [] + + attrs.filters = () -> + source = @source() + _.nested(source, 'filters') || null + + attrs.currentFilter = () -> + source = @source() + _.nested(source, 'filters.' + @get('options.filter')) || {} + + attrs.filterValues = () -> + @currentFilter().values || {} + + + + attrs.sourceProperty = (property) -> + @sourceProperties()[property] || null + + attrs.options.multiple_selections = false + attrs.options.is_filtered = false + datasources = formbuilder.attr('sources') || {} + attrs.options.data_source = _.keys(datasources)[0]; + attrs.options.required_properties = _.keys(attrs.sourceProperties(attrs.options.data_source)) + attrs.options.filter = null + attrs.options.filter_values = [] + attrs.options.value_template = _.first(attrs.options.required_properties) + attrs diff --git a/src/scripts/fields/date.coffee b/src/scripts/fields/date.coffee index b54114ce..d9013f2b 100644 --- a/src/scripts/fields/date.coffee +++ b/src/scripts/fields/date.coffee @@ -1,32 +1,23 @@ Formbuilder.registerField 'date', + name: 'Date' + order: 20 view: """
- - - - - - / - - - - - - - / - - - - - +
""" - edit: "" + edit: """ + <%= Formbuilder.templates['edit/date']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ addButton: """ - Date + Date """ + defaultAttributes: (attrs) -> + attrs.options.default_date = false + attrs diff --git a/src/scripts/fields/dropdown.coffee b/src/scripts/fields/dropdown.coffee index 2061cbc2..9aa5705e 100644 --- a/src/scripts/fields/dropdown.coffee +++ b/src/scripts/fields/dropdown.coffee @@ -1,4 +1,5 @@ Formbuilder.registerField 'dropdown', + name: 'Dropdown' order: 24 @@ -9,30 +10,37 @@ Formbuilder.registerField 'dropdown', <% } %> <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %> - <% } %> """ edit: """ - <%= Formbuilder.templates['edit/options']({ includeBlank: true }) %> + <%= Formbuilder.templates['edit/scoring']() %> + <%= Formbuilder.templates['edit/options']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> """ addButton: """ - Dropdown + Dropdown """ defaultAttributes: (attrs) -> - attrs.field_options.options = [ + attrs.answers = [ + uuid: uuid.v4() label: "", - checked: false + checked: false, + score: "" , + uuid: uuid.v4() label: "", - checked: false + checked: false, + score: "" ] - attrs.field_options.include_blank_option = false + attrs.is_scored = false + attrs.options.include_blank_option = false - attrs \ No newline at end of file + attrs diff --git a/src/scripts/fields/email.coffee b/src/scripts/fields/email.coffee index 103b4590..45f10f40 100644 --- a/src/scripts/fields/email.coffee +++ b/src/scripts/fields/email.coffee @@ -1,13 +1,17 @@ Formbuilder.registerField 'email', + name: 'Email' + order: 40 view: """ - + """ - edit: "" + edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ addButton: """ - Email + Email """ diff --git a/src/scripts/fields/file.coffee b/src/scripts/fields/file.coffee index 8b5cd48a..1f149c6b 100644 --- a/src/scripts/fields/file.coffee +++ b/src/scripts/fields/file.coffee @@ -1,13 +1,17 @@ Formbuilder.registerField 'file', + name: 'File' + order: 55 view: """ - + """ - edit: "" + edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ addButton: """ - File + File """ diff --git a/src/scripts/fields/geoLocation.coffee b/src/scripts/fields/geoLocation.coffee new file mode 100644 index 00000000..f8cf4f7c --- /dev/null +++ b/src/scripts/fields/geoLocation.coffee @@ -0,0 +1,21 @@ +Formbuilder.registerField 'geolocation', + + name: 'Geolocation' + + order: 60 + + view: """ +
+ +
+ <%=rf.geolocationFunctionality%> + """ + + edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + GeoLocation + """ + diff --git a/src/scripts/fields/grid.coffee b/src/scripts/fields/grid.coffee new file mode 100644 index 00000000..4cb78910 --- /dev/null +++ b/src/scripts/fields/grid.coffee @@ -0,0 +1,92 @@ +Formbuilder.registerField 'grid', + ### + This element type is undergoing a gradual culling, by way of not allowing most users to add Grid elements into their Form Templates. + Some more annoying clients will refuse this, so regrettably on the integral site we will support a feature for those few that will re-show the add button. + ### + name: 'Layout Grid' + + # Should appear last to prevent empty spaces, as it will be hidden on most client sites + order: 99 + + element_type: 'non_input' + + view: """ + + +
+

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

+ """ + + edit: """ +
Details
+
+
+ + +
+ + +
Number of Columns
+ +
Number of Rows
+ +
+
+ """ + + addButton: """ + Grid + """ + + # Will hide the button for the reasons mentioned at the top of the file. + hideAddButton: true + + defaultAttributes: (attrs) -> + # @todo + attrs.options.num_cols = 1 + attrs.options.num_rows = 1 + attrs.options.full_width = false + attrs.options.first_row_headings = false + attrs.children = [] + attrs.childModels = () -> + @collection.filter (model) -> + _.indexOf(@get('options.elements'), model.get('uuid')) != -1 + , @ + attrs \ No newline at end of file diff --git a/src/scripts/fields/info.coffee b/src/scripts/fields/info.coffee new file mode 100644 index 00000000..ce5887d6 --- /dev/null +++ b/src/scripts/fields/info.coffee @@ -0,0 +1,75 @@ +Formbuilder.registerField 'info', + + name: 'Info' + + order: 20 + + element_type: 'non_input' + + view: """ + +

<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

+ """ + + # Info uses CK editor so we directly output HTML here + + edit: """ +
Details
+
+
+ +
+ +
+ <%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %> + <%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Info + """ + + onEdit: (model) -> + defaultProtocol = 'http://' + update = -> + model.set(Formbuilder.options.mappings.DESCRIPTION, $(@).summernote('code')) + model.trigger('change:' + Formbuilder.options.mappings.DESCRIPTION) + $('.fb-info-editor').summernote( + callbacks: { + onChange: -> update.call(@) + onKeyup: -> update.call(@) + onInit: -> + # Bit of a hack here, the plugin currently only enforces the http protocol on a create - not on an update. + insertLinkBtn = document.querySelector('input.note-link-btn') + noteLinkUrl = document.querySelector('.note-link-url') + protocalBtn = document.querySelector('div.sn-checkbox-use-protocol > label > input') + newTabBtn = document.querySelector('div.sn-checkbox-open-in-new-window > label > input') + noteLinkUrl.addEventListener('keydown', -> #account for keyboard shortcuts + #protocalBtn.setAttribute('checked', true) + protocalBtn.checked = true; + #newTabBtn.setAttribute('checked', true) + newTabBtn.checked = true; + ) + insertLinkBtn.addEventListener('click', -> + newTabBtn.checked = true; + #protocalBtn.setAttribute('checked', true); + url = noteLinkUrl.value + if (url.substring(0, 8) != 'https://' && url.substring(0, 7) != 'http://') + noteLinkUrl.value = defaultProtocol + url + ) + } + disableDragAndDrop: true + linkTargetBlank: true + useProtocol: true + defaultProtocol: defaultProtocol + toolbar: [ + ['style', ['bold', 'italic', 'underline']], + ['fontsize', ['fontsize']], + ['color', ['color']], + ['insert', ['link']], + ['table', ['table']], + ['misc', ['codeview']] + ] + ) diff --git a/src/scripts/fields/number.coffee b/src/scripts/fields/number.coffee index 3ad18788..987b2572 100644 --- a/src/scripts/fields/number.coffee +++ b/src/scripts/fields/number.coffee @@ -1,20 +1,73 @@ Formbuilder.registerField 'number', + name: 'Number' + order: 30 view: """ - + /> <% if (units = rf.get(Formbuilder.options.mappings.UNITS)) { %> <%= units %> <% } %> """ edit: """ - <%= Formbuilder.templates['edit/min_max']() %> - <%= Formbuilder.templates['edit/units']() %> - <%= Formbuilder.templates['edit/integer_only']() %> + <%= Formbuilder.templates['edit/integer_only']({rf:rf}) %> + <%= Formbuilder.templates['edit/total']({rf:rf}) %> + <%= Formbuilder.templates['edit/min_max']({rf:rf}) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> """ - addButton: """ - 123 Number + Number """ + + defaultAttributes: (attrs, formbuilder) -> + attrs.options.calculation_type = '' + attrs.options.calculation_expression = '' + attrs.options.calculation_display = '' + attrs.options.total_sequence = false + + attrs.insertion = () -> + parentModel = @parentModel() + if parentModel and parentModel.get('type') == 'table' + totalColumn = parentModel.totalColumn @get('uuid') + @attributes.options.total_sequence = totalColumn + + attrs.initialize = () -> + + @on "change", (model) -> + if _.nested(model, 'changed.options.calculation_type') != undefined + model.expression() + + if _.nested(model, 'changed.options.total_sequence') != undefined + totalSequence = _.nested model, 'changed.options.total_sequence' + @parentModel().totalColumn model.get('uuid'), totalSequence + model + + attrs.numericSiblings = () -> + parentModel = @parentModel() + if (parentModel) + _.filter parentModel.childModels(), (i) -> + i.get('type') is 'number' and i.get('uuid') != @get('uuid') + , @ + else + [] + + attrs.expression = () -> + calculation_type = @get('options.calculation_type') + if calculation_type != '' + operator = if calculation_type is 'SUM' then '+' else '*' + numericSiblings = @numericSiblings() + #Prefix with uuid_ and underscore '-' to prevent illegal identifiers + @set('options.calculation_expression', _.map(numericSiblings, (model) -> 'uuid_' + model.get('uuid').replace(/-/g, '_')).join(operator)) + @set('options.calculation_display', '= ' + _.map(numericSiblings, (model) -> model.get('label')).join(operator)) + console.log(@get('options.calculation_expression')) + else + @set('options.calculation_expression', '') + @set('options.calculation_display', '') + attrs.canTotalColumn = () -> + parent = @parentModel() + parent and parent.get('type') is 'table' + attrs.canAcceptCalculatedTotal = () -> + @numericSiblings().length > 1 + attrs diff --git a/src/scripts/fields/paragraph.coffee b/src/scripts/fields/paragraph.coffee deleted file mode 100644 index b1e506c5..00000000 --- a/src/scripts/fields/paragraph.coffee +++ /dev/null @@ -1,20 +0,0 @@ -Formbuilder.registerField 'paragraph', - - order: 5 - - view: """ - - """ - - edit: """ - <%= Formbuilder.templates['edit/size']() %> - <%= Formbuilder.templates['edit/min_max_length']() %> - """ - - addButton: """ - Paragraph - """ - - defaultAttributes: (attrs) -> - attrs.field_options.size = 'small' - attrs diff --git a/src/scripts/fields/price.coffee b/src/scripts/fields/price.coffee index 62252255..811acbd6 100644 --- a/src/scripts/fields/price.coffee +++ b/src/scripts/fields/price.coffee @@ -1,5 +1,7 @@ Formbuilder.registerField 'price', + name: 'Price' + order: 45 view: """ @@ -17,8 +19,10 @@ Formbuilder.registerField 'price',
""" - edit: "" + edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ addButton: """ - Price + Price """ diff --git a/src/scripts/fields/radio.coffee b/src/scripts/fields/radio.coffee index 14dbfaf0..5bda820f 100644 --- a/src/scripts/fields/radio.coffee +++ b/src/scripts/fields/radio.coffee @@ -1,45 +1,60 @@ Formbuilder.registerField 'radio', + name: 'Radio Button' + order: 15 view: """ - <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %> -
- -
- <% } %> - - <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %> -
- - - -
- <% } %> +
+ <% for (i in (rf.get(Formbuilder.options.mappings.OPTIONS) || [])) { %> +
+ +
+ <% } %> + + <% if (rf.get(Formbuilder.options.mappings.INCLUDE_OTHER)) { %> +
+ + + +
+ <% } %> +
""" edit: """ - <%= Formbuilder.templates['edit/options']({ includeOther: true }) %> + <%= Formbuilder.templates['edit/scoring']({ rf: rf }) %> + <%= Formbuilder.templates['edit/options']({ rf: rf }) %> + <%= Formbuilder.templates['edit/options_per_row']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> """ + addButton: """ - Multiple Choice + Radio Button """ defaultAttributes: (attrs) -> # @todo - attrs.field_options.options = [ + attrs.answers = [ + uuid: uuid.v4() label: "", - checked: false + checked: false, + score: "" , + uuid: uuid.v4() label: "", - checked: false + checked: false, + score: "" ] - attrs \ No newline at end of file + attrs.is_scored = false + attrs.options.options_per_row = 1 + + attrs diff --git a/src/scripts/fields/section.coffee b/src/scripts/fields/section.coffee new file mode 100644 index 00000000..73fc68f8 --- /dev/null +++ b/src/scripts/fields/section.coffee @@ -0,0 +1,28 @@ +Formbuilder.registerField 'section', + + name: 'Section' + + order: 10 + + element_type: 'non_input' + + view: """ + +

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

+ """ + + edit: """ +
Details
+
+
+ + +
+
+ <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Section Break + """ diff --git a/src/scripts/fields/section_break.coffee b/src/scripts/fields/section_break.coffee deleted file mode 100644 index 5e06ccb1..00000000 --- a/src/scripts/fields/section_break.coffee +++ /dev/null @@ -1,21 +0,0 @@ -Formbuilder.registerField 'section_break', - - order: 0 - - type: 'non_input' - - view: """ - -

<%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

- """ - - edit: """ -
Label
- - - """ - - addButton: """ - Section Break - """ diff --git a/src/scripts/fields/signature.coffee b/src/scripts/fields/signature.coffee new file mode 100644 index 00000000..1b3d0f8e --- /dev/null +++ b/src/scripts/fields/signature.coffee @@ -0,0 +1,21 @@ +Formbuilder.registerField 'signature', + + name: 'Signature' + + order: 65 + + view: """ +
+
Sign Here
+
+
+ + """ + + edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Signature + """ diff --git a/src/scripts/fields/table.coffee b/src/scripts/fields/table.coffee new file mode 100644 index 00000000..4bda1146 --- /dev/null +++ b/src/scripts/fields/table.coffee @@ -0,0 +1,87 @@ +Formbuilder.registerField 'table', + + name: 'Table' + + order: 0 + + element_type: 'non_input' + + view: """ + + <%= Formbuilder.templates["view/table_field"]({rf: rf}) %> +

<%- rf.get(Formbuilder.options.mappings.DESCRIPTION) %>

+ """ + + edit: """ +
Details
+
+
+ <%= Formbuilder.templates['edit/label_description']({rf: rf}) %> +
+
+
+ + """ + + addButton: """ + Table + """ + + defaultAttributes: (attrs) -> + attrs.options.full_width = false + attrs.initialize = () -> + parent = @ + _.each @childModels, (childModel) -> + childModel.on "change", (model) -> + if _.nested(model, 'changed.options.column_width') != undefined + parent.columnWidth(model.get('uuid'), model.get('options.column_width')) + model + + + attrs.childModels = () -> + elementsUuids = _.pluck @get('options.elements'), 'uuid' + @collection.filter (model) -> + _.indexOf(elementsUuids, model.get('uuid')) != -1 + , @ + + attrs.elementOptions = (elementUuid) -> + _.findWhere @get('options.elements'), {uuid:elementUuid} + + + attrs.createTotalColumnModel = (parentUuid) -> + totalColumnModel = new FormbuilderModel(Formbuilder.helpers.defaultFieldAttrs('number')) + totalColumnModel.set('options.calculation_expression', 'sum(column_uuid_' + parentUuid.replace(/-/g, '_') + ')') + totalColumnModel.set('model_only', true) + totalColumnModel.set('parent_uuid', parentUuid) + @collection.add totalColumnModel + totalColumnModel + + attrs.columnWidth = (elementUuid, width) -> + elements = @get('options.elements') + _.each elements, (element, index) -> + if element.uuid is elementUuid + elements[index].columnWidth = width + ,@ + + attrs.totalColumn = (elementUuid, value) -> + elements = @get('options.elements') + if value != undefined + _.each elements, (element, index) -> + if element.uuid is elementUuid + if element.totalColumnUuid is undefined + totalColumnModel = @createTotalColumnModel(element.uuid) + elements[index].totalColumnUuid = totalColumnModel.get('uuid') + elements[index].totalColumn = value + , @ + + @set 'options.elements', elements + else + if @elementOptions(elementUuid) + @elementOptions(elementUuid).totalColumn || false + else + false + + + attrs diff --git a/src/scripts/fields/text.coffee b/src/scripts/fields/text.coffee index 8147569f..acab3bf6 100644 --- a/src/scripts/fields/text.coffee +++ b/src/scripts/fields/text.coffee @@ -1,20 +1,29 @@ Formbuilder.registerField 'text', + name: 'Text' + order: 0 view: """ - + + readonly="readonly" + <% } %> + /> """ edit: """ - <%= Formbuilder.templates['edit/size']() %> - <%= Formbuilder.templates['edit/min_max_length']() %> + <%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %> + <%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %> + <%= Formbuilder.templates['edit/populate_from']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> """ addButton: """ - Text + Text """ defaultAttributes: (attrs) -> - attrs.field_options.size = 'small' + attrs.options.size = 'small' + attrs.options.read_only = false attrs diff --git a/src/scripts/fields/textarea.coffee b/src/scripts/fields/textarea.coffee new file mode 100644 index 00000000..6ae12fce --- /dev/null +++ b/src/scripts/fields/textarea.coffee @@ -0,0 +1,29 @@ +Formbuilder.registerField 'textarea', + + name: 'Paragraph' + + order: 5 + + view: """ + + """ + + edit: """ + <%= Formbuilder.templates['edit/inline_image_option']({ rf: rf }) %> + <%= Formbuilder.templates['edit/inline_action_option']({ rf: rf }) %> + <%= Formbuilder.templates['edit/populate_from']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ + + addButton: """ + Paragraph + """ + + defaultAttributes: (attrs) -> + attrs.options.size = 'small' + attrs.options.read_only = false + attrs diff --git a/src/scripts/fields/time.coffee b/src/scripts/fields/time.coffee index c8e14cce..2e08d628 100644 --- a/src/scripts/fields/time.coffee +++ b/src/scripts/fields/time.coffee @@ -1,39 +1,27 @@ Formbuilder.registerField 'time', + name: 'Time' + order: 25 view: """ -
- - - - - - : - - - - - - - : - - - - - - - - - +
+
+ +
+
""" - edit: "" + edit: """ + <%= Formbuilder.templates['edit/time']({ rf: rf }) %> + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> + """ addButton: """ - Time + Time """ + + defaultAttributes: (attrs) -> + attrs.options.default_time = false + attrs diff --git a/src/scripts/fields/website.coffee b/src/scripts/fields/website.coffee index f50224e4..05a54337 100644 --- a/src/scripts/fields/website.coffee +++ b/src/scripts/fields/website.coffee @@ -1,5 +1,7 @@ Formbuilder.registerField 'website', + name: 'Website' + order: 35 view: """ @@ -7,8 +9,9 @@ Formbuilder.registerField 'website', """ edit: """ + <%= Formbuilder.templates['edit/conditional_options']({ rf: rf }) %> """ addButton: """ - Website + Website """ diff --git a/src/scripts/main.coffee b/src/scripts/main.coffee index 54aeb6b9..917b4e15 100644 --- a/src/scripts/main.coffee +++ b/src/scripts/main.coffee @@ -1,26 +1,212 @@ class FormbuilderModel extends Backbone.DeepModel + $wrappers = {}; sync: -> # noop + indexInDOM: -> - $wrapper = $(".fb-field-wrapper").filter ( (_, el) => $(el).data('cid') == @cid ) - $(".fb-field-wrapper").index $wrapper +# https://stackoverflow.com/questions/4806286/difference-between-void-0-and-undefined TLDR: void 0 and undefined evaluate to the same thing + if $wrappers[this.cid] == undefined + $(".fb-field-wrapper").each ((_, el) -> + $wrappers[$(el).data('cid')] = $(el) + return true; + ) + ($wrappers[this.cid] || {index: -> (-1)}).index(".fb-field-wrapper"); + is_input: -> - Formbuilder.inputFields[@get(Formbuilder.options.mappings.FIELD_TYPE)]? + Formbuilder.inputFields[@get(Formbuilder.options.mappings.TYPE)]? + initialize: -> + if not @attributes.uuid? + @attributes.uuid = uuid.v4() + if not @attributes.parent_uuid is undefined + @attributes.parent_uuid = null + @attachMethods() + parentModel: () -> + collention = @collection + if collention + @collection.findWhereUuid(@get('parent_uuid')) + hasParent: () -> @parentModel() != undefined + inTable: () -> + parent = @parentModel() + parent and parent.get('type') is 'table' + inGrid: () -> + parent = @parentModel() + parent and parent.get('type') is 'grid' + canBeConditionallyDisplayed: () -> !@inTable() and !@inGrid() and Formbuilder.conditionalFunctionality + canShowReferenceID: () -> Formbuilder.showReferenceIDFunctionality + + findConditionalAncestorUuids: () -> + parentUuid = @get(Formbuilder.options.mappings.CONDITIONAL_PARENT) + size = this.collection.length; + count = 0; + uuids = []; + if parentUuid + parent = this.collection.findWhereUuid(parentUuid); + uuids.push(parent.attributes.uuid); + if parent.conditionalParent() + ancest = parent.conditionalParent(); + uuids.push(ancest.attributes.uuid); + temp = ancest; + while temp + count++; + if count == (size - 1) + return uuids; + ancest = temp; + uuids.push(temp.attributes.uuid); + temp = temp.conditionalParent(); + return uuids; + return uuids; + + + conditionalParent: () -> + parentUuid = @get(Formbuilder.options.mappings.CONDITIONAL_PARENT) + if parentUuid + return @collection.findWhereUuid(parentUuid) + null + + conditionalChildren: () -> + uuid = @attributes.uuid + @collection.filter (item) -> uuid is item.get(Formbuilder.options.mappings.CONDITIONAL_PARENT) + + answers: () -> @get('answers') || [] + + conditionalTriggerOptions: (selected) -> + parent = @conditionalParent() + options = [] + if parent + if parent.get('type') == 'approval' + options = 'Is Approved' + else + options = _.clone(parent.answers()) + options.unshift({'uuid': '', 'label': '[No Selection]'}) + if selected + triggerValues = @get(Formbuilder.options.mappings.CONDITIONAL_VALUES) || [] + options = _.filter options, (trigger) -> trigger.uuid in triggerValues + options + + isValid: ()-> + conditional_ele = @canBeConditionallyDisplayed() + if !conditional_ele + return true + else + options = @attributes.options + conditional = options.conditional + if conditional + conditional_parent = conditional.parent + conditional_values = conditional.values + parent = @conditionalParent(); + + if parent && parent.get('type') == 'approval' + if !@get(Formbuilder.options.mappings.CONDITIONAL_VALUES) + @set(Formbuilder.options.mappings.CONDITIONAL_VALUES, 1) + conditional_values = 1 + + flag = (_.isArray(conditional) && conditional.length == 0) || (conditional_parent == "" && typeof conditional_values is "undefined"); + if ((conditional_parent && (conditional_values && conditional_values.length != 0)) || (typeof conditional_values is "undefined" && typeof conditional_parent is "undefined") || flag) + return true + else + return false + attachMethods: ()-> + if typeof @attributes.initialize is 'function' + @attributes.initialize.call(@) + delete @attributes['initialize'] -class FormbuilderCollection extends Backbone.Collection - initialize: -> - @on 'add', @copyCidToModel + #Shift function from attributes to model + if typeof @attributes.insertion is 'function' + @['insertion'] = @attributes['insertion'] + delete @attributes['insertion'] - model: FormbuilderModel - comparator: (model) -> - model.indexInDOM() + _.each(@attributes, (method, name)-> + if typeof method is 'function' and @[name] is undefined + @[name] = method + delete @attributes[name] - copyCidToModel: (model) -> - model.attributes.cid = model.cid + , @) +class FormbuilderCollection extends Backbone.Collection + model: FormbuilderModel + comparator: (model) -> + model.indexInDOM() + add: (model) -> + models = model = super(model) + + if not _.isArray(model) + models = [model] + + _.each models, (model) -> + if typeof model.insertion is 'function' + model.insertion.call(model) + model + + findWhereUuid: (uuid) -> @findWhere({'uuid': uuid}) + findDataSourceFields: () -> @where({'type': 'datasource'}) + findConditionalTriggers: (child) -> + items = @filter (model) -> + correctType = model.get('type') in ['dropdown', 'checkbox', 'radio', 'approval'] + differentModel = model != child + hasNoParent = !model.hasParent() + flag = true + uuid = child.attributes.uuid + uuid_parent + ancestorUuids + parent = model.conditionalParent() + if parent + ancestorUuids = model.findConditionalAncestorUuids() + uuid_parent = parent.attributes.uuid + if ancestorUuids and ancestorUuids.length > 0 + for a in ancestorUuids + if a == uuid + flag = false; + break; + flag = (uuid != uuid_parent) && flag + correctType and differentModel and hasNoParent and flag + items + clearConditionEle: (conditionalChild)-> + conditionalChild.unset(Formbuilder.options.mappings.CONDITIONAL) + +''' +Individual elements +''' class ViewFieldView extends Backbone.View + @insert: (builder, view, responseField, _, options) -> + parentModel = responseField.parentModel() + if parentModel is undefined or parentModel.get('type') is 'grid' or parentModel.get('type') is 'table' + appendEl = options.$appendEl || null + replaceEl = options.$replaceEl || null + $placeholder = builder.$responseFields.find("a.dragdrop-placeholder") + ##### + # Calculates where to place this new field. + # + # Are we replacing a temporarily drag placeholder? + + if appendEl? + appendEl.html(view.render().el) + + else if replaceEl? + replaceEl.replaceWith(view.render().el) + +# If a dragdrop placeholder been left for us to insert after? (workaround because backbone kills the replaceEl before this point) + else if ($placeholder[0]) + $placeholder.after(view.render().el) + $placeholder.remove() + +# Are we adding to the bottom? + else if !options.position? || options.position == -1 + builder.$responseFields.append view.render().el + +# Are we adding to the top? + else if options.position == 0 + builder.$responseFields.prepend view.render().el + +# Are we adding below an existing field? + else if ($replacePosition = builder.$responseFields.find(".fb-field-wrapper").eq(options.position))[0] + $replacePosition.before view.render().el + +# Catch-all: add to bottom + else + builder.$responseFields.append view.render().el + className: "fb-field-wrapper" events: @@ -34,10 +220,10 @@ class ViewFieldView extends Backbone.View @listenTo @model, "destroy", @remove render: -> - @$el.addClass('response-field-' + @model.get(Formbuilder.options.mappings.FIELD_TYPE)) - .data('cid', @model.cid) - .html(Formbuilder.templates["view/base#{if !@model.is_input() then '_non_input' else ''}"]({rf: @model})) - + @$el.addClass('response-field-' + @model.get(Formbuilder.options.mappings.TYPE)) + .data('cid', @model.cid) + .data('uuid', @model.get('uuid')) + .html(Formbuilder.templates["view/base#{if !@model.is_input() then '_non_input' else ''}"]({rf: @model})) return @ focusEditView: -> @@ -47,6 +233,11 @@ class ViewFieldView extends Backbone.View e.preventDefault() e.stopPropagation() + _.each @model.conditionalChildren(), (conditionalChild) -> + conditionalChild.unset(Formbuilder.options.mappings.CONDITIONAL_PARENT) + conditionalChild.unset(Formbuilder.options.mappings.CONDITIONAL_VALUES) + + cb = => @parentView.handleFormUpdate() @model.destroy() @@ -61,13 +252,352 @@ class ViewFieldView extends Backbone.View else cb() + duplicate: (e) -> + e.preventDefault(); + e.stopPropagation(); + copyAttrs = Formbuilder.helpers.clone(@model.attributes); + attrs = Formbuilder.helpers.defaultFieldAttrs(copyAttrs.type, {}) + + for key of copyAttrs + attrs[key] = copyAttrs[key] + + delete attrs['id'] + delete attrs['cid'] + delete attrs['uuid'] + attrs['label'] += ' Copy' + if attrs.options.grid + attrs.options.grid.row = attrs.options.grid.row + 1 + @parentView.createField attrs, {position: @model.indexInDOM() + 1} + @model.trigger "duplicate:viewfield" + + +class TableFieldView extends ViewFieldView + className: "fb-field-wrapper" + initialize: (options) -> + @parentView = options.parentView + @listenTo @model, "change", @update + @listenTo @model, "destroy", @remove + _.each @model.get('options.elements'), (element) -> + childModel = @model.collection.findWhereUuid(element.uuid) + if childModel + @listenTo childModel, "change", @update + else + console.log(element.uuid) + , @ + events: + 'mouseenter': 'showSelectors', + 'mouseleave': 'removeSelectors' + 'click .drop-area li': 'inlineAdd' + 'click .subtemplate-wrapper': 'focusEditView' + 'click .response-field-table td.header': 'focusSubelement' + 'click .response-field-table td.element': 'focusSubelement' + 'click .js-clear': 'clear' + 'click .js-duplicate': 'duplicate' + + showSelectors: (e) -> + @$el.find('.drop-area').html(Formbuilder.templates['view/element_selector']()) + + removeSelectors: (e) -> + @$el.find('.drop-area').html('') + + inlineAdd: (e) -> + e.preventDefault() + e.stopPropagation() + childModel = new FormbuilderModel(Formbuilder.helpers.defaultFieldAttrs($(e.currentTarget).data('type'))) + childModel.set('parent_uuid', @model.get('uuid')) + childModel.set('options.in_sequence', true) + @listenTo childModel, "change", @update + elements = @model.attributes.options.elements || [] + newElement = { + 'uuid': childModel.get('uuid') + } + elements.push(newElement) + @model.attributes.options.elements = elements + @parentView.collection.add childModel + @update(childModel) + + update: (model) -> + if model + @render() + @parentView.createAndShowEditView(model) + + render: () -> + super() + @renderElements() + @ + + focusEditView: (e) -> + if (!$(e.target).parents('.dropdown-toggle').length && !$(e.target).hasClass('dropdown-toggle')) + @parentView.createAndShowEditView(@model) + + focusSubelement: (e) -> + e.preventDefault(); + e.stopPropagation(); + childUuid = $(e.currentTarget).data('uuid') + if childUuid + @parentView.createAndShowEditView(@parentView.modelByUuid(childUuid)) +# else +# @parentView.createAndShowEditView(@model) + + renderElements: () -> + _.each @model.get('options.elements'), (element) -> + model = @parentView.modelByUuid(element.uuid) + @$el.find('.header-' + element.uuid).html(Formbuilder.templates["view/table_header"]({ + rf: model, + element: element + })).css('background-color', model.get(Formbuilder.options.mappings.LABEL_BACKGROUND_COLOR)).data('cid', model.cid) + @$el.find('.element-' + element.uuid).html(Formbuilder.templates["view/table_element"]({ + rf: model, + element: element + })).data('cid', model.cid) + @$el.find('.total-' + element.uuid).html(Formbuilder.templates["view/table_total"]({ + rf: model, + element: element + })).data('cid', model.cid) + , @ + + + clear: (e) -> + e.preventDefault() + e.stopPropagation() + + uuid = $(e.currentTarget).parents('.element').data('uuid') + + if uuid is undefined + models = _.each @model.get('options.elements'), (element) -> + @parentView.modelByUuid(element.uuid).destroy() + true + , @ + @model.destroy() + @$el.remove() + else + @parentView.modelByUuid(uuid).destroy() + @model.set('options.elements', _.filter @model.get('options.elements'), (destroyedElement) -> destroyedElement.uuid != uuid) + @render() + duplicate: -> - attrs = _.clone(@model.attributes) + attrs = Formbuilder.helpers.clone(@model.attributes); delete attrs['id'] + delete attrs['cid'] + attrs['uuid'] = uuid.v4(); attrs['label'] += ' Copy' - @parentView.createField attrs, { position: @model.indexInDOM() + 1 } + elements = attrs['options']['elements'] + attrs['options']['elements'] = [] + attrs = _.extend({}, Formbuilder.helpers.defaultFieldAttrs('table'), attrs) + @parentView.createField attrs, {position: -1} + clonedView = @parentView.viewByUuid(attrs['uuid']) + clonedTableModel = @parentView.modelByUuid(attrs['uuid']) + _.each elements, (child) => + childModel = @parentView.modelByUuid(child.uuid) + childattrs = Formbuilder.helpers.clone(childModel); + delete childattrs['id'] + delete childattrs['cid'] + child.uuid = childattrs['uuid'] = uuid.v4() + childattrs['parent_uuid'] = attrs['uuid'] + childattrs = _.extend({}, Formbuilder.helpers.defaultFieldAttrs(childattrs['type']), childattrs) + clonedModel = new FormbuilderModel(childattrs) + + + if child.totalColumn + totalColumnModel = clonedTableModel.createTotalColumnModel(childattrs['uuid']) + child.totalColumnUuid = totalColumnModel.get('uuid') + @parentView.collection.add(clonedModel) + if clonedModel.expression != undefined and clonedModel.get('options.calculation_type') + clonedModel.expression() + clonedView.listenTo clonedModel, "change", clonedView.update + attrs['options']['elements'].push(child) + clonedView.render() + + @insert: (builder, view, responseField, _, options) -> + instanceView = builder.viewByUuid(responseField.get('parent_uuid')) + if instanceView? + true + else + false +class GridFieldView extends Backbone.View + className: "fb-field-wrapper" + events: + 'click .response-field-grid-cell li': 'inlineAdd' + 'click .response-field-grid-cell .js-clear': 'subelementClear' + 'click .js-duplicate': 'duplicate' + 'click .js-clear': 'clear' + 'click .subtemplate-wrapper': 'focusEditView' + + initialize: (options) -> + {@parentView} = options + @listenTo @model, "change", @redraw + @listenTo @model, "destroy", @remove + #bind models on subelement add instead of like this + @parentView.collection.bind 'add', @addSubelement, @ + @parentView.collection.bind 'destroy', @removeSubelement, @ + @render + + render: -> + super() + @redraw() + @renderChildren() + return @ + +#boo + redraw: -> + table = @$el.find('.response-field-grid-table').detach() + @$el.addClass('response-field-' + @model.get(Formbuilder.options.mappings.TYPE)) + .data('cid', @model.cid) + .data('uuid', @model.get('uuid')) + .html(Formbuilder.templates["view/base#{if !@model.is_input() then '_non_input' else ''}"]({rf: @model})) + if table.length == 1 + @$el.find('.response-field-grid-table').replaceWith(table); + @renderTable() + +# make less gross + renderTable: -> + numRows = @model.get('options.num_rows') || 1 + numCols = @model.get('options.num_cols') || 1 + table = @$el.find 'table' + currentRows = table.find('tr').length + currentCols = table.find("tr:nth-child(1) td").length + rows = $.makeArray table.find('tr') + if currentRows < numRows + rows = rows.concat [rows.length...numRows] + rows = _.map rows, (row) => + if _.isNumber row + row = $('').appendTo(table) + + cols = $.makeArray $(row).find('td') + if cols.length < numCols + cols = cols.concat [cols.length...numCols] + cols = _.map cols, (col) -> + if _.isNumber col + col = $('').appendTo(row).html(Formbuilder.templates["view/element_selector"]()) + row + + if currentRows > numRows + subelements = @subelements() + _.each subelements, (subelement) => + grid = @parentView.gridAttr(subelement) + if grid.row > (numRows - 1) then subelement.destroy() + table.find('tr').slice(numRows - currentRows).remove() + + if currentCols > numCols + subelements = @subelements() + _.each subelements, (subelement) => + grid = @parentView.gridAttr(subelement) + if grid.col > (numCols - 1) then subelement.destroy() + table.find('tr').find('td:gt(' + (numCols - 1) + ')').remove() + + renderChildren: -> + children = @model.get('children') || []; + _.each children, (child) => + grid = child.options.grid + @createField child, @getSubelement(grid.row, grid.col) + + + focusEditView: (e) -> + if $(e.target).parents('table').length == 0 then @parentView.createAndShowEditView(@model) + + clear: (e) -> + e.preventDefault() + e.stopPropagation() + + cb = => + @parentView.handleFormUpdate() + subelements = @subelements() + _.each @subelements(), (model) -> + model.destroy() + true + @model.destroy() + + x = Formbuilder.options.CLEAR_FIELD_CONFIRM + + switch typeof x + when 'string' + if confirm(x) then cb() + when 'function' + x(cb) + else + cb() + + duplicate: -> + attrs = Formbuilder.helpers.clone(@model.attributes); + delete attrs['id'] + delete attrs['cid'] + attrs['uuid'] = uuid.v4(); + attrs['label'] += ' Copy' + children = @subelements() + delete attrs['children'] + @parentView.createField attrs, {position: -1} + + attrs['children'] = _.map children, (child) => + childattrs = Formbuilder.helpers.clone(child.attributes); + delete childattrs['id'] + delete childattrs['cid'] + delete childattrs['uuid'] + childattrs['parent_uuid'] = attrs['uuid'] + childattrs + @parentView.createField childattrs, {position: -1} + + + + addSubelement: (model) -> + if @belongsToMe(model) and model.get('label').match(/Copy/) + grid = @parentView.gridAttr(model) + label = model.get('label').match(/(.+) Copy/) + if label != null + model.attributes.label = label[1] + ' ' + (grid.row + 1) + else + model.attributes.label = 'Row: ' + (grid.row + 1) + ', Col: ' + (grid.col + 1) + + removeSubelement: (model) -> + grid = @parentView.gridAttr(model) + belongsToMe = @belongsToMe(model) + if belongsToMe && @getSubelement(grid.row, grid.col).html() == '' + @getSubelement(grid.row, grid.col).html(Formbuilder.templates["view/element_selector"]({rf: @model})) + + subelements: -> + @parentView.collection.filter (item) => + return @belongsToMe(item) + + belongsToMe: (model) -> + @parentView.inGrid(model) && model.get('parent_uuid') == @model.get('uuid') + + inlineAdd: (e) -> + e.preventDefault() + e.stopPropagation() + type = $(e.currentTarget).data('type') + target = $(e.currentTarget).parents('.response-field-grid-cell') + @createField(type, target) + + getSubelement: (row, col) -> + row++ + col++ + @$el.find('tr:nth-child(' + row + ') td:nth-child(' + col + ')'); + + createField: (attrs, target) -> + if _.isString(attrs) + attrs = Formbuilder.helpers.defaultFieldAttrs(attrs) + attrs.options.disallow_duplication = true + attrs.options.grid = + col: target.prop('cellIndex') + row: target.parents('tr').prop('rowIndex') + attrs.parent_uuid = @model.get('uuid') + @parentView.createField attrs, {$appendEl: target} + + @insert: (builder, view, responseField, _, options) -> + if not options.$appendEl + row = responseField.get('options.grid.row') + col = responseField.get('options.grid.col') + responseField.attributes.options.disallow_duplication = true #this disables duplication for both parent and children + append = builder.wrapperByUuid(responseField.get('parent_uuid')) + append = append.find('tr:nth-child(' + (row + 1) + ') td:nth-child(' + (col + 1) + ')') + if append.length == 1 + options.$appendEl = append + ViewFieldView.insert(builder, view, responseField, _, options) + +''' +"Edit field" tab +''' class EditFieldView extends Backbone.View className: "edit-response-field" @@ -77,26 +607,52 @@ class EditFieldView extends Backbone.View 'click .js-default-updated': 'defaultUpdated' 'input .option-label-input': 'forceRender' + + initialize: (options) -> {@parentView} = options @listenTo @model, "destroy", @remove + _.each Formbuilder.options.change, (callback, key) => + eventName = 'change:' + _.nested(Formbuilder.options.mappings, key) + @listenTo @model, eventName, callback + + render: -> @$el.html(Formbuilder.templates["edit/base#{if !@model.is_input() then '_non_input' else ''}"]({rf: @model})) - rivets.bind @$el, { model: @model } + rivets.bind @$el, {model: @model} return @ + + reset: -> + @stopListening() + @parentView.editView = undefined + @parentView.createAndShowEditView(@model) + + resetConditional: -> + @model.unset(Formbuilder.options.mappings.CONDITIONAL_VALUES) + + resetInlineImages: -> + @model.unset(Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED) + + resetInlineActions: -> + @model.unset(Formbuilder.options.mappings.INLINE_ACTIONS_REQUIRED) + + deselectReadOnly: -> + @model.set(Formbuilder.options.mappings.READ_ONLY, false) + remove: -> @parentView.editView = undefined @parentView.$el.find("[data-target=\"#addField\"]").click() + @stopListening() super - # @todo this should really be on the model, not the view +# @todo this should really be on the model, not the view addOption: (e) -> $el = $(e.currentTarget) i = @$el.find('.option').index($el.closest('.option')) options = @model.get(Formbuilder.options.mappings.OPTIONS) || [] - newOption = {label: "", checked: false} + newOption = {uuid: uuid.v4(), label: "", checked: false} if i > -1 options.splice(i + 1, 0, newOption) @@ -105,6 +661,7 @@ class EditFieldView extends Backbone.View @model.set Formbuilder.options.mappings.OPTIONS, options @model.trigger "change:#{Formbuilder.options.mappings.OPTIONS}" + @.$el.find('div.options').find('input.option-label-input').last().focus(); @forceRender() removeOption: (e) -> @@ -119,24 +676,29 @@ class EditFieldView extends Backbone.View defaultUpdated: (e) -> $el = $(e.currentTarget) - unless @model.get(Formbuilder.options.mappings.FIELD_TYPE) == 'checkboxes' # checkboxes can have multiple options selected + unless @model.get(Formbuilder.options.mappings.TYPE) == 'checkboxes' # checkboxes can have multiple options selected @$el.find(".js-default-updated").not($el).attr('checked', false).trigger('change') @forceRender() forceRender: -> - @model.trigger('change') + @model.trigger 'change', @model +''' +Main View for the editor +''' class BuilderView extends Backbone.View SUBVIEWS: [] + + saveFormButton: $() + events: - 'click .js-save-form': 'saveForm' 'click .fb-tabs a': 'showTab' - 'click .fb-add-field-types a': 'addField' - 'mouseover .fb-add-field-types': 'lockLeftWrapper' - 'mouseout .fb-add-field-types': 'unlockLeftWrapper' + 'click .fb-add-types a': 'addField' + 'mouseover .fb-add-types': 'lockLeftWrapper' + 'mouseout .fb-add-types': 'unlockLeftWrapper' initialize: (options) -> {selector, @formBuilder, @bootstrapData} = options @@ -153,19 +715,15 @@ class BuilderView extends Backbone.View @collection.bind 'destroy add reset', @hideShowNoResponseFields, @ @collection.bind 'destroy', @ensureEditViewScrolled, @ + @render() @collection.reset(@bootstrapData) @bindSaveEvent() bindSaveEvent: -> @formSaved = true - @saveFormButton = @$el.find(".js-save-form") @saveFormButton.attr('disabled', true).text(Formbuilder.options.dict.ALL_CHANGES_SAVED) - unless !Formbuilder.options.AUTOSAVE - setInterval => - @saveForm.call(@) - , 5000 $(window).bind 'beforeunload', => if @formSaved then undefined else Formbuilder.options.dict.UNSAVED_CHANGES @@ -200,42 +758,56 @@ class BuilderView extends Backbone.View showTab: (e) -> $el = $(e.currentTarget) + go = true target = $el.data('target') - $el.closest('li').addClass('active').siblings('li').removeClass('active') - $(target).addClass('active').siblings('.fb-tab-pane').removeClass('active') + + if (this.editView && !this.editView.model.isValid()) + go = false; + + if (go || (!go && target == '#editField')) + $el.closest('li').addClass('active').siblings('li').removeClass('active') + $(target).addClass('active').siblings('.fb-tab-pane').removeClass('active') @unlockLeftWrapper() unless target == '#editField' if target == '#editField' && !@editView && (first_model = @collection.models[0]) @createAndShowEditView(first_model) - addOne: (responseField, _, options) -> - view = new ViewFieldView - model: responseField - parentView: @ - - ##### - # Calculates where to place this new field. - # - # Are we replacing a temporarily drag placeholder? - if options.$replaceEl? - options.$replaceEl.replaceWith(view.render().el) - - # Are we adding to the bottom? - else if !options.position? || options.position == -1 - @$responseFields.append view.render().el - - # Are we adding to the top? - else if options.position == 0 - @$responseFields.prepend view.render().el - - # Are we adding below an existing field? - else if ($replacePosition = @$responseFields.find(".fb-field-wrapper").eq(options.position))[0] - $replacePosition.before view.render().el - - # Catch-all: add to bottom + createView: (responseField) -> + if responseField.attributes.type == 'grid' + view = new GridFieldView + model: responseField + parentView: @ + else if responseField.attributes.type == 'table' + view = new TableFieldView + model: responseField + parentView: @ else - @$responseFields.append view.render().el + view = new ViewFieldView + model: responseField + parentView: @ + view + + insert: (view, responseField, _, options) -> + inserted = false + parentModel = responseField.parentModel() + parentType = if parentModel then parentModel.get('type') else undefined + type = parentType || responseField.get('type') + if type == 'grid' + inserted = GridFieldView.insert(@, view, responseField, _, options) + else if type == 'table' + inserted = TableFieldView.insert(@, view, responseField, _, options) + + if not inserted + inserted = ViewFieldView.insert(@, view, responseField, _, options) + inserted + + addOne: (responseField, _, options) -> + view = @createView responseField + @$responseFields.find('> .ui-draggable').remove(); + if responseField.get('model_only') != true + @insert(view, responseField, _, options) + @views[responseField.get('uuid')] = view setSortable: -> @$responseFields.sortable('destroy') if @$responseFields.hasClass('ui-sortable') @@ -243,20 +815,21 @@ class BuilderView extends Backbone.View forcePlaceholderSize: true placeholder: 'sortable-placeholder' stop: (e, ui) => - if ui.item.data('field-type') - rf = @collection.create Formbuilder.helpers.defaultFieldAttrs(ui.item.data('field-type')), {$replaceEl: ui.item} + if ui.item.data('type') + ui.item.after '' #backbone kills the original placeholder before element is placed so leave something to target + rf = @collection.create Formbuilder.helpers.defaultFieldAttrs(ui.item.data('type')), {$replaceEl: ui.item} @createAndShowEditView(rf) @handleFormUpdate() return true update: (e, ui) => - # ensureEditViewScrolled, unless we're updating from the draggable - @ensureEditViewScrolled() unless ui.item.data('field-type') +# ensureEditViewScrolled, unless we're updating from the draggable + @ensureEditViewScrolled() unless ui.item.data('type') @setDraggable() setDraggable: -> - $addFieldButtons = @$el.find("[data-field-type]") + $addFieldButtons = @$el.find("[data-type]") $addFieldButtons.draggable connectToSortable: @$responseFields @@ -269,15 +842,18 @@ class BuilderView extends Backbone.View $helper addAll: -> - @collection.each @addOne, @ + @collection.each (item, _, collection) -> + @addOne.call(@, item, _, {}) + , @ @setSortable() hideShowNoResponseFields: -> @$el.find(".fb-no-response-fields")[if @collection.length > 0 then 'hide' else 'show']() addField: (e) -> - field_type = $(e.currentTarget).data('field-type') - @createField Formbuilder.helpers.defaultFieldAttrs(field_type) + type = $(e.currentTarget).data('type') + + @createField Formbuilder.helpers.defaultFieldAttrs(type, {}) createField: (attrs, options) -> rf = @collection.create attrs, options @@ -285,26 +861,87 @@ class BuilderView extends Backbone.View @handleFormUpdate() createAndShowEditView: (model) -> - $responseFieldEl = @$el.find(".fb-field-wrapper").filter( -> $(@).data('cid') == model.cid ) - $responseFieldEl.addClass('editing').siblings('.fb-field-wrapper').removeClass('editing') - + $responseFieldEl = @$el.find(".fb-field-wrapper").filter(-> $(@).data('cid') == model.cid) + go = true if @editView if @editView.model.cid is model.cid - @$el.find(".fb-tabs a[data-target=\"#editField\"]").click() - @scrollLeftWrapper($responseFieldEl) return - @editView.remove() + go = @editView.model.isValid() + if (!go) + $('.fb-edit-section-conditional-wrapper #warning-message').show(); + else + @editView.remove() + if go + $('.fb-field-wrapper').removeClass('parent') + $('.fb-option').removeClass('trigger-option') + $('.fb-field-wrapper').removeClass('editing') + $responseFieldEl.addClass('editing') + + parent = model.conditionalParent() + if parent + selectedTriggers = model.get(Formbuilder.options.mappings.CONDITIONAL_VALUES) || [] + $parentWrapper = @$el.find(".fb-field-wrapper").filter(-> $(@).data('cid') == parent.cid) + $parentWrapper.addClass('parent') + $parentWrapper.find('.fb-option') + .filter(-> uuid = $(@).data('uuid'); $(@).data('uuid') in selectedTriggers) + .each(-> $(@).addClass('trigger-option')) + + if go + @editView = new EditFieldView + model: model + parentView: @ + + $newEditEl = @editView.render().$el + fieldWrapper = @$el.find(".fb-edit-field-wrapper") + fieldWrapper.html $newEditEl + if @inGrid(model) then fieldWrapper.addClass('fb-edit-field-grid') else fieldWrapper.removeClass('fb-edit-field-grid') + if model.inTable() then $('.spectrum-colorpicker', ".fb-edit-field-wrapper").spectrum({ + allowEmpty: true, + preferredFormat: 'hex', + showPalette: true, + showPaletteOnly: true, + palette: [ + '#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF', + '#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF', + '#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE', + '#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD', + '#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5', + '#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B', + '#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842', + '#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031'] + }) + + editModeButton = @$el.find(".fb-tabs a[data-target=\"#editField\"]") + if !editModeButton.parent().hasClass('active') + editModeButton.click() #only select edit mode when necessary, as it causes unwanted page jumps for many children types + + @scrollLeftWrapper($responseFieldEl) + attrs = Formbuilder.helpers.defaultFieldAttrs(model.get('type')) + if attrs.definition.onEdit != undefined + attrs.definition.onEdit model + @$el.find("input, textarea, [contenteditable=true]").filter(':visible').first().focus() + return @ + - @editView = new EditFieldView - model: model - parentView: @ + inGrid: (model) -> @hasParent(model) and model.get('options.grid') - $newEditEl = @editView.render().$el - @$el.find(".fb-edit-field-wrapper").html $newEditEl - @$el.find(".fb-tabs a[data-target=\"#editField\"]").click() - @scrollLeftWrapper($responseFieldEl) - return @ + inTable: (model) -> @hasParent(model) and model.get('options.table') + + hasParent: (model) -> model.get('parent_uuid') + + modelByUuid: (uuid) -> @collection.findWhere {'uuid': uuid} + + wrapperByUuid: (uuid) -> $('.fb-field-wrapper').filter () -> $(@).data('uuid') is uuid + + viewByUuid: (uuid) -> @views[uuid] + + views: {} + + gridAttr: (model) -> + if @inGrid(model) + return model.get('options.grid') + null ensureEditViewScrolled: -> return unless @editView @@ -323,16 +960,20 @@ class BuilderView extends Backbone.View @$fbLeft.data('locked', false) handleFormUpdate: -> + @collection.sort() return if @updatingBatch @formSaved = false @saveFormButton.removeAttr('disabled').text(Formbuilder.options.dict.SAVE_FORM) + getPayload: -> + return JSON.stringify fields: @collection.toJSON() + saveForm: (e) -> return if @formSaved @formSaved = true @saveFormButton.attr('disabled', true).text(Formbuilder.options.dict.ALL_CHANGES_SAVED) @collection.sort() - payload = JSON.stringify fields: @collection.toJSON() + payload = @getPayload() if Formbuilder.options.HTTP_ENDPOINT then @doAjaxSave(payload) @formBuilder.trigger 'save', payload @@ -347,7 +988,7 @@ class BuilderView extends Backbone.View @updatingBatch = true for datum in data - # set the IDs of new response fields, returned from the server +# set the IDs of new response fields, returned from the server @collection.get(datum.cid)?.set({id: datum.id}) @collection.trigger 'sync' @@ -355,42 +996,169 @@ class BuilderView extends Backbone.View class Formbuilder + @attrs: {} + @instances: [] + @attr: (name, value) -> + if value != undefined + Formbuilder.attrs[name] = value + _.each @instances, (instance) -> + instance.mainView.reset() + if Formbuilder.attrs[name] != undefined then Formbuilder.attrs[name] else undefined + + @conditionalFunctionality = true; + @showReferenceIDFunctionality = false; + @geolocationFunctionality = true; + @linkAssetFunctionality = false; + @linkAssetDisplayFields = {}; + @disableField: (field) -> @fields[field].enabled = false; + + @helpers: - defaultFieldAttrs: (field_type) -> + defaultFieldAttrs: (type) -> attrs = {} attrs[Formbuilder.options.mappings.LABEL] = 'Untitled' - attrs[Formbuilder.options.mappings.FIELD_TYPE] = field_type - attrs[Formbuilder.options.mappings.REQUIRED] = true - attrs['field_options'] = {} - Formbuilder.fields[field_type].defaultAttributes?(attrs) || attrs + attrs[Formbuilder.options.mappings.TYPE] = type + attrs[Formbuilder.options.mappings.REQUIRED] = false + attrs[Formbuilder.options.mappings.INLINE_IMAGES_ENABLED] = false + attrs[Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED] = false + attrs[Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED] = false + attrs[Formbuilder.options.mappings.INLINE_ACTIONS_REQUIRED] = false + attrs['definition'] = Formbuilder.fields[type] + attrs['options'] = {} + Formbuilder.fields[type].defaultAttributes?(attrs, Formbuilder) || attrs simple_format: (x) -> - x?.replace(/\n/g, '
') + @escape_html(x)?.replace(/\n/g, '
') + clone: (obj) -> + JSON.parse(JSON.stringify(obj)) + + escape_html: (text) -> + map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + } + text?.replace(/[&<>"']/g, (m) -> return map[m]) + @options: - BUTTON_CLASS: 'fb-button' + BUTTON_CLASS_SELECTOR: 'fb-button btn btn-default' + BUTTON_CLASS_ADD: 'fb-button btn btn-xs btn-primary' + BUTTON_CLASS_REMOVE: 'fb-button btn btn-xs btn-danger' HTTP_ENDPOINT: '' HTTP_METHOD: 'POST' - AUTOSAVE: true CLEAR_FIELD_CONFIRM: false - + ENABLED_FIELDS: ['text', 'checkbox', 'dropdown', 'textarea', 'radio', 'date', 'section', 'signature', 'info', + 'grid', 'number', 'table', 'datasource', 'time', 'geolocation', 'approval'] + INLINE_IMAGE_FIELDS: [ + 'text', 'info' + ] mappings: - SIZE: 'field_options.size' - UNITS: 'field_options.units' + SIZE: 'options.size' + UNITS: 'options.units' LABEL: 'label' - FIELD_TYPE: 'field_type' + NAME: 'definition.name' + TYPE: 'type' REQUIRED: 'required' ADMIN_ONLY: 'admin_only' - OPTIONS: 'field_options.options' - DESCRIPTION: 'field_options.description' - INCLUDE_OTHER: 'field_options.include_other_option' - INCLUDE_BLANK: 'field_options.include_blank_option' - INTEGER_ONLY: 'field_options.integer_only' - MIN: 'field_options.min' - MAX: 'field_options.max' - MINLENGTH: 'field_options.minlength' - MAXLENGTH: 'field_options.maxlength' - LENGTH_UNITS: 'field_options.min_max_length_units' + POPULATE_FROM: 'options.populate_from' + POPULATE_UUID: 'options.populate_uuid' + CONDITIONAL_PARENT: 'options.conditional.parent' + CONDITIONAL_VALUES: 'options.conditional.values' + CONDITIONAL: 'options.conditional' + OPTIONS: 'answers' + DESCRIPTION: 'description' + INCLUDE_OTHER: 'options.include_other_option' + INCLUDE_BLANK: 'options.include_blank_option' + INCLUDE_SCORING: 'is_scored' + INTEGER_ONLY: 'options.integer_only' + LABEL_COLOR: 'options.label_color' + LABEL_BACKGROUND_COLOR: 'options.label_background_color' + READ_ONLY: 'options.read_only' + COLUMN_WIDTH: 'options.column_width' + DEFAULT_TIME: 'options.default_time' + DEFAULT_DATE: 'options.default_date' + REFERENCE_ID: 'reference_id' + INLINE_IMAGES_ENABLED: 'options.inline_images_enabled' + INLINE_IMAGES_REQUIRED: 'options.inline_images_required' + INLINE_ACTIONS_ENABLED: 'options.inline_actions_enabled' + INLINE_ACTIONS_REQUIRED: 'options.inline_actions_required' + NUMERIC: + CALCULATION_TYPE: 'options.calculation_type' + CALCULATION_EXPRESSION: 'options.calculation_expression' + CALCULATION_DISPLAY: 'options.calculation_display' + TOTAL_SEQUENCE: 'options.total_sequence' + GRID: + COLS: 'options.cols', + NUMCOLS: 'options.num_cols', + ROWS: 'options.rows', + NUMROWS: 'options.num_rows', + FULL_WIDTH: 'options.full_width', + FIRST_ROW_HEADINGS: 'options.first_row_headings' + TABLE: + COLS: 'options.cols', + NUMCOLS: 'options.num_cols', + ROWS: 'options.rows', + INITIALROWS: 'options.initial_rows', + MAXROWS: 'options.max_rows', + FULL_WIDTH: 'options.full_width' + COLUMNTOTALS: 'options.display_column_totals' + ROWTOTALS: 'options.display_row_totals' + DATA_SOURCE: + MULTIPLE: 'options.multiple_selections' + DATA_SOURCE: 'options.data_source' + VALUE_TEMPLATE: 'options.value_template' + REQUIRED_PROPERTIES: 'options.required_properties' + FILTER: 'options.filter' + FILTER_VALUES: 'options.filter_values' + IS_FILTERED: 'options.is_filtered' + MIN: 'options.min' + MAX: 'options.max' + OPTIONS_PER_ROW: 'options.options_per_row' + MINLENGTH: 'options.minlength' + MAXLENGTH: 'options.maxlength' + LENGTH_UNITS: 'options.min_max_length_units' + APPROVAL: + APPROVER_TYPE: 'options.approver_type' + APPROVER_ID: 'options.approver_id' + DISALLOW_DUPLICATION: 'options.disallow_duplication' + + change: + REQUIRED: -> + @reset() + @resetInlineImages() + @resetInlineActions() + INLINE_IMAGES_ENABLED: -> + @reset() + @resetInlineImages() + INLINE_IMAGES_REQUIRED: -> + @reset() + INLINE_ACTIONS_ENABLED: -> + @reset() + @resetInlineActions() + INLINE_ACTIONS_REQUIRED: -> + @reset() + INCLUDE_SCORING: -> + @reset() + POPULATE_UUID: -> + if !@.model.get(Formbuilder.options.mappings.POPULATE_UUID) + @deselectReadOnly() + @reset() + CONDITIONAL_PARENT: -> + @reset() + @resetConditional() + CONDITIONAL_VALUES: -> + @reset() + 'DATA_SOURCE.DATA_SOURCE': -> + @reset() + 'DATA_SOURCE.IS_FILTERED': -> + @reset() + 'DATA_SOURCE.FILTER': -> + @reset() + 'APPROVAL.APPROVER_TYPE': -> + @reset() dict: ALL_CHANGES_SAVED: 'All changes saved' @@ -401,25 +1169,71 @@ class Formbuilder @inputFields: {} @nonInputFields: {} + markSaved: -> + @mainView.formSaved = true + + isValid: -> + go = true; + if ((this.mainView.editView) && !this.mainView.editView.model.isValid()) + go = false; + return go + + getPayload: -> + return @mainView.getPayload() + + @registerField: (name, opts) -> + enabled = true + + fields = Formbuilder.options.ENABLED_FIELDS + unless _.contains(fields, name) + enabled = false for x in ['view', 'edit'] - opts[x] = _.template(opts[x]) + opts[x] = if enabled then _.template(opts[x]) else (x) -> '' - opts.field_type = name + opts.type = name + opts.enabled = enabled Formbuilder.fields[name] = opts - if opts.type == 'non_input' + if opts.element_type == 'non_input' Formbuilder.nonInputFields[name] = opts else Formbuilder.inputFields[name] = opts - constructor: (opts={}) -> + constructor: (opts = {}) -> _.extend @, Backbone.Events args = _.extend opts, {formBuilder: @} + @attrs = {} + #Move child elements to end of collection to ensure parent are created first + partionedData = _(args.bootstrapData || []) + .groupBy((i) -> if i.parent_uuid is undefined then 0 else 1) + .toArray() + .value() + partionedData = _.reduce(partionedData, (a, i) -> a.concat(i)) + args.bootstrapData = _.map(partionedData, (i) -> _.extend({}, Formbuilder.helpers.defaultFieldAttrs(i.type), i)) + + @mainView = new BuilderView args + @mainView.collection + Formbuilder.instances.push(@) + +#nested mixin +if _.nested is undefined + _.mixin { + 'nested': (obj, key) -> + if obj and key + obj[key] || _.reduce key.split('.'), (obj, key) -> + if obj then obj[key] else undefined; + , obj + else + undefined + } + window.Formbuilder = Formbuilder +window.FormbuilderModel = FormbuilderModel + if module? module.exports = Formbuilder diff --git a/src/scripts/rivets-config.coffee b/src/scripts/rivets-config.coffee index 6f958fc7..4b4cf658 100644 --- a/src/scripts/rivets-config.coffee +++ b/src/scripts/rivets-config.coffee @@ -1,3 +1,25 @@ +rivets.binders.append = + routine: (el, value) -> + el.checked = _.find(value, (item) -> String(item) == String(el.value)) != undefined + bind: (el) -> + + @callback = () => + currentValue = _.clone(@model.get(@keypath)) || [] + if _.contains(currentValue, el.value) + newValue = _.without(currentValue, el.value) + @model.set(@keypath, newValue) + else + currentValue.push(el.value) + @model.set(@keypath, currentValue) + $(el).on('change', @callback) + unbind: (el) -> + $(el).off('change', @callback) + + +rivets.formatters.length = (value) -> + if value then value.length else 0 + + rivets.binders.input = publishes: true routine: rivets.binders.value.routine @@ -24,4 +46,4 @@ rivets.configure if obj.cid obj.set(keypath, value); else - obj[keypath] = value \ No newline at end of file + obj[keypath] = value diff --git a/src/styles/formbuilder.styl b/src/styles/formbuilder.styl index 62925dba..8d2ac266 100644 --- a/src/styles/formbuilder.styl +++ b/src/styles/formbuilder.styl @@ -1,49 +1,134 @@ -$prim-color = #1abc9c -$sec-color = #16a085 - -$affirmitive-color = #2ecc71 -$negative-color = #e74c3c - $editing-bg = #ecf0f1 $editing-border = darken($editing-bg, 7%) -.fb-button { +[class^="fb-icon-"]:before, [class*=" fb-icon-"]:before { + font-family: "fontello"; + font-style: normal; + font-weight: normal; + speak: none; + display: inline-block; - margin: 0; - padding: .563rem .844rem; - border: 0 none; - background: #16a085; - color: #fff; + text-decoration: inherit; + width: 1em; + margin-right: .2em; text-align: center; - text-decoration: none; - font-size: 12px; - line-height: 1.5; - cursor: pointer; - border-radius: .125rem; - border: thin solid darken($prim-color, 5%); - border-bottom: 2px solid $sec-color; + /* opacity: .8; */ + + /* For safety - reset parent styles, that can break glyph codes*/ + font-variant: normal; + text-transform: none; + + /* fix buttons height, for twitter bootstrap */ + line-height: 1em; + + /* Animation center compensation - margins should be symmetric */ + /* remove if not needed */ + margin-left: .2em; + + /* you can be more comfortable with increased icons size */ + /* font-size: 120%; */ + + /* Uncomment for 3D effect */ + /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ +} + + +.fb-icon-date:before { + content: '\f133'; +} + +/* '' */ +.fb-icon-radio:before { + content: '\f192'; +} + +/* '' */ +.fb-icon-checkbox:before { + content: '\e893'; +} + +/* '' */ +.fb-icon-data-source:before { + content: '\f1c0'; +} + +/* '' */ +.fb-icon-dropdown:before { + content: '\e854'; +} + +/* '' */ +.fb-icon-signature:before { + content: '\e830'; +} + +/* '' */ +.fb-icon-info:before { + content: '\f129'; +} + +/* '' */ +.fb-icon-table:before { + content: '\f0ce'; +} + +/* '' */ +.fb-icon-textarea:before { + content: '\f1dd'; +} + +/* '' */ +.fb-icon-section:before { + content: '\f2d1'; +} + +/* '' */ +.fb-icon-text:before { + content: '\e87d'; +} + +/* '' */ +.fb-icon-number:before { + content: '\f162'; } -.fb-button[disabled] { - background: #ddd !important; - border: thin solid #ccc; - color: #777 !important; - text-shadow: none !important; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=65)"; - opacity: .65; - cursor: default; +/* '' */ +.fb-icon-time:before { + content: '\e84a'; } +/* '' */ +.fb-icon-conditional:before { + content: '\E824'; +} + +/* '' */ +.fb-icon-geolocation:before { + content: '\e839'; +} + +/* '' */ +.fb-icon-approval:before { + content: '\f14b'; +} + +/* '' */ +.fb-icon-grid:before { + content: '\e810' +} + +.fb-button { + text-align: left; +} + + .fb-clear { clear: both; } .fb-main { - max-width: 1000px; - margin: 0 auto; padding: 0 20px 0 0; position: relative; - font-family: 'Source Sans Pro', 'Open Sans', Tahoma; } .fb-save-wrapper { @@ -63,6 +148,7 @@ $editing-border = darken($editing-bg, 7%) margin-left: 320px; border-left: 1px solid #ddd; padding-left: 20px; + padding-bottom: 150px; min-height: 100%; overflow: hidden; } @@ -92,6 +178,7 @@ $editing-border = darken($editing-bg, 7%) border-right: 1px solid transparent; } + .fb-tabs li.active a { border: 1px solid #ccc; margin-bottom: -1px; @@ -107,21 +194,20 @@ $editing-border = darken($editing-bg, 7%) display: block; } -.fb-add-field-types .section { +.fb-add-types .section { padding-bottom: 5px; margin-bottom: 20px; } -.fb-add-field-types { +.fb-add-types { font-size: 0; /* Inline block fix */ } -.fb-add-field-types a { +.fb-add-types a { font-size: 13px; display: inline-block; width: 48.5%; - background-color: $prim-color; margin-bottom: 9px; box-sizing: border-box; @@ -161,7 +247,7 @@ $editing-border = darken($editing-bg, 7%) } } -.fb-field-wrapper:hover .actions-wrapper,.fb-field-wrapper.editing .actions-wrapper { +.fb-field-wrapper:hover .actions-wrapper, .fb-field-wrapper.editing .actions-wrapper { display: block; } @@ -175,8 +261,15 @@ $editing-border = darken($editing-bg, 7%) .fb-field-wrapper.editing { background-color: $editing-bg; border-radius: 3px; + box-shadow: inset 0 0 7px 2px rgba(100, 100, 100, 0.1); + border: 1px solid rgba(100, 100, 100, 0.2); } +.fb-field-wrapper.parent { + box-shadow: rgba(0, 0, 0, 0.3) 1px 1px 10px; +} + + .fb-field-wrapper.editing .subtemplate-wrapper { border-color: $editing-border; border-style: solid; @@ -198,6 +291,15 @@ $editing-border = darken($editing-bg, 7%) padding: 2px 8px; } +.edit-response-field .options { + background-color: #eeeeee; + max-height: 600px; + overflow-y: auto; + padding: 3px; + border-radius: 3px; + border: thin solid #ddd; +} + .edit-response-field { input, textarea, select { border: thin solid #ddd; @@ -209,25 +311,20 @@ $editing-border = darken($editing-bg, 7%) &:focus { outline: none; - border: thin solid $prim-color; } } + select { font-size: 14px; + max-width: 100%; } } -.fb-field-wrapper .actions-wrapper a.js-duplicate, -.fb-edit-field-wrapper .js-add-option { - background-color: $affirmitive-color; - border: none; +input[readonly] { + cursor: not-allowed; + background-color: #eeeeee; } -.fb-field-wrapper .actions-wrapper a.js-clear, -.fb-edit-field-wrapper .js-remove-option { - background-color: $negative-color; - border: none; -} .fb-field-wrapper .subtemplate-wrapper { border: 1px dashed transparent; @@ -297,11 +394,12 @@ $editing-border = darken($editing-bg, 7%) color: #666; font-size: 1.25em; - .field-type { + .type { margin-top: .5em; display: block; font-family: 'Source Sans Pro', sans-serif; font-size: 1em; + &:before { content: 'Type: '; color: #999; @@ -322,7 +420,7 @@ $editing-border = darken($editing-bg, 7%) font-weight: 700; } -.fb-edit-field-wrapper .js-add-option,.fb-edit-field-wrapper .js-remove-option { +.fb-edit-field-wrapper .js-add-option, .fb-edit-field-wrapper .js-remove-option { padding: 3px 6px; } @@ -334,7 +432,7 @@ $editing-border = darken($editing-bg, 7%) margin-bottom: 10px; } -.fb-common-wrapper .fb-label-description input,.fb-common-wrapper .fb-label-description textarea { +.fb-common-wrapper .fb-label-description input, .fb-common-wrapper .fb-label-description textarea { width: 100%; } @@ -342,13 +440,34 @@ $editing-border = darken($editing-bg, 7%) min-height: 5em; } +.fb-conditional-question { + float: right; + font-size: .9em; + max-width: 50%; + text-overflow: ellipsis; + height: 20px; + white-space: nowrap; + overflow: hidden; +} + +.fb-conditional-question-trigger > span { + font-weight: bold; +} + +.option-score-input { + width: 50px; +} + +.option-label-input { + width: 170px; +} + .response-field-draggable-helper { border: 1px dashed #ddd; background: #eee; } .response-field-text input.rf-size-small { - width: 130px; } .response-field-text input.rf-size-medium { @@ -359,17 +478,17 @@ $editing-border = darken($editing-bg, 7%) width: 100%; } -.response-field-paragraph textarea.rf-size-small { +.response-field-textarea textarea.rf-size-small { width: 200px; min-height: 60px; } -.response-field-paragraph textarea.rf-size-medium { +.response-field-textarea textarea.rf-size-medium { width: 400px; min-height: 100px; } -.response-field-paragraph textarea.rf-size-large { +.response-field-textarea textarea.rf-size-large { width: 100%; min-height: 200px; } @@ -378,23 +497,190 @@ $editing-border = darken($editing-bg, 7%) width: 400px; } -.response-field-address .city,.response-field-address .state,.response-field-address .zip,.response-field-address .country { +.response-field-address .city, .response-field-address .state, .response-field-address .zip, .response-field-address .country { width: 198px; } -.response-field-date .month,.response-field-date .day,.response-field-date .year { +.response-field-date .month, .response-field-date .day, .response-field-date .year { width: 50px; } -.response-field-time .hours,.response-field-time .minutes,.response-field-time .seconds { - width: 50px; +.response-field-time .input-group { + width: 145px; } -.response-field-checkboxes .fb-option,.response-field-radio .fb-option { +.response-field-checkbox .fb-option, .response-field-radio .fb-option { margin-bottom: 5px; + padding: 3px 8px; display: inline-block; } +.fb-option { + +} + +.editing .trigger-option, .fb-option.trigger-option { + background-color: #5cb85c; + border-radius: 0.25em; + color: white; +} + +.fb-conditional-question .trigger-option { + padding: 1px 4px; +} + .response-field-website input { width: 200px; -} \ No newline at end of file +} + +.response-field-signature .fb-signature { + width: 300px; + height: 150px; +} + +.response-field-signature .fb-signature-placeholder { + color: #AAA; +} +.response-field-approval .fb-approval-user { + margin-bottom 20px +} +.response-field-approval .fb-signature { + width: 300px; + height: 150px; +} + +.response-field-approval .fb-signature-placeholder { + color: #AAA; +} + + +.response-field-grid { + .cover { + display: none; + } +} + +.response-field-table { + width: 100% + + .cover { + display: none; + } + + .section-name { + display: inline-block; + } + + .element-selector { + margin: 0 5px; + float: right; + position: absolute; + right: 5px; + top: 5px; + } + + tr { + vertical-align: top; + } + + + table { + margin-bottom: 30px; + + td { + padding: 10px 10px 0 10px + + label { + border: none !important; + } + } + + .calculated { + font-style: italic; + color: #ccc; + } + + select, input[type=text], textarea, .fb-signature { + width: 100%; + } + } +} + +for row in (1..15) + .fb-options-per-row-{row}:before + content " " + display table + .fb-options-per-row-{row}:after + content " " + display table + clear both + .fb-options-per-row-{row} + clear both + + .fb-option-wrapper + width (100% / row) + + +.response-field-grid-table { + border-collapse: collapse; + border-spacing: 0; + margin-bottom: 5px; + table-layout: fixed; + width: 100%; + + .response-field-grid-row { + height: 100px; + vertical-align: top; + } + + td { + padding: 10px 10px 0 10px; + } + + .element-selector { + width: 100%; + + .dropdown-toggle { + width: 100%; + + span { + font-size: 2em; + } + } + } + + .response-field-grid-cell { + padding: 10px 10px 0 10px; + border: 1px dashed #ddd + background-color: rgba(255, 255, 255, 0.8); + + .cover { + display: block; + } + + .response-field-selector { + margin: 0.5em; + } + + .subtemplate-wrapper > label { + display: none; + } + + .help-block { + display: none; + } + + select, input[type=text], textarea, .fb-signature { + width: 100%; + } + } +} + + +.section-separator { + border-top: 1px solid #333; +} + +.fb-link-object-fields { + padding: 15px; +} diff --git a/src/templates/edit/approval_options.html b/src/templates/edit/approval_options.html new file mode 100644 index 00000000..be918ed1 --- /dev/null +++ b/src/templates/edit/approval_options.html @@ -0,0 +1,31 @@ +
Approver
+
+
+ +
+
+ +
+ <% if (rf.showApprovers()) { %> +
+ +
+ <% } %> +
+ diff --git a/src/templates/edit/base.html b/src/templates/edit/base.html index 7c7256c2..a7cc352f 100644 --- a/src/templates/edit/base.html +++ b/src/templates/edit/base.html @@ -1,3 +1,5 @@ -<%= Formbuilder.templates['edit/base_header']() %> -<%= Formbuilder.templates['edit/common']() %> -<%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].edit({rf: rf}) %> +<%= Formbuilder.templates['edit/base_header']({rf: rf}) %> +<%= Formbuilder.templates['edit/common']({rf: rf}) %> +<%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].edit({rf: rf}) %> +<%= Formbuilder.templates['edit/columnwidth']({rf: rf}) %> +<%= Formbuilder.templates['edit/table_color']({rf: rf}) %> diff --git a/src/templates/edit/base_header.html b/src/templates/edit/base_header.html index a56d59ee..57145033 100644 --- a/src/templates/edit/base_header.html +++ b/src/templates/edit/base_header.html @@ -1,5 +1,5 @@
- + -
\ No newline at end of file +
diff --git a/src/templates/edit/base_non_input.html b/src/templates/edit/base_non_input.html index d2c01e5a..871004a4 100644 --- a/src/templates/edit/base_non_input.html +++ b/src/templates/edit/base_non_input.html @@ -1,2 +1,2 @@ -<%= Formbuilder.templates['edit/base_header']() %> -<%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].edit({rf: rf}) %> +<%= Formbuilder.templates['edit/base_header']({rf: rf}) %> +<%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].edit({rf: rf}) %> diff --git a/src/templates/edit/checkboxes.html b/src/templates/edit/checkboxes.html index 61fd4f93..63a3f166 100644 --- a/src/templates/edit/checkboxes.html +++ b/src/templates/edit/checkboxes.html @@ -1,8 +1,4 @@ -
\ No newline at end of file diff --git a/src/templates/edit/conditional_options.html b/src/templates/edit/conditional_options.html new file mode 100644 index 00000000..ea92714d --- /dev/null +++ b/src/templates/edit/conditional_options.html @@ -0,0 +1,52 @@ +<% if (rf.canBeConditionallyDisplayed()) { %> +
+
Conditionally Display + + + + + +
+ <% + var list = rf.collection.findConditionalTriggers(rf); + if (list.length) { %> + + <% + var selectedList = rf.conditionalTriggerOptions(); + if (!Array.isArray(selectedList)) { %> +
+ +
+ <% } else { + if (selectedList.length == 0) + rf.collection.clearConditionEle(rf); + for (i in selectedList) { %> + + <% } + } + %> + <% } else { %> + No trigger elements + <% } %> + <% } %> + +
+
diff --git a/src/templates/edit/data_source_options.html b/src/templates/edit/data_source_options.html new file mode 100644 index 00000000..f51d65a0 --- /dev/null +++ b/src/templates/edit/data_source_options.html @@ -0,0 +1,41 @@ +
Data Source
+ +
Display
+ +<% if (rf.filters()) { %> +
Filter
+ + <% if (rf.get(Formbuilder.options.mappings.DATA_SOURCE.IS_FILTERED)) { %> + + <% + for (i in rf.filterValues()) { %> + + <% } %> +<% } %> +<% } %> \ No newline at end of file diff --git a/src/templates/edit/date.html b/src/templates/edit/date.html new file mode 100644 index 00000000..be342f98 --- /dev/null +++ b/src/templates/edit/date.html @@ -0,0 +1,6 @@ +
+ +
diff --git a/src/templates/edit/inline_action_option.html b/src/templates/edit/inline_action_option.html new file mode 100644 index 00000000..0ce6e307 --- /dev/null +++ b/src/templates/edit/inline_action_option.html @@ -0,0 +1,22 @@ +<% if (!rf.hasParent()) { %> +
+
Add action + + + + + +
+ + <% if (rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED) && (rf.get(Formbuilder.options.mappings.REQUIRED) || rf.get('type') === "info") ) { %> + + <% } %> + +
+<% } %> \ No newline at end of file diff --git a/src/templates/edit/inline_image_option.html b/src/templates/edit/inline_image_option.html new file mode 100644 index 00000000..a9bb2d3e --- /dev/null +++ b/src/templates/edit/inline_image_option.html @@ -0,0 +1,22 @@ +<% if (!rf.hasParent()) { %> +
+
Add photo + + + + + +
+ + <% if (rf.get(Formbuilder.options.mappings.INLINE_IMAGES_ENABLED) && (rf.get(Formbuilder.options.mappings.REQUIRED) || rf.get('type') === "info") ) { %> + + <% } %> + +
+<% } %> \ No newline at end of file diff --git a/src/templates/edit/integer_only.html b/src/templates/edit/integer_only.html index 7b13b268..80afac52 100644 --- a/src/templates/edit/integer_only.html +++ b/src/templates/edit/integer_only.html @@ -1,5 +1,4 @@ -
Integer only
-
- - - - +
+
+ + + <% if (rf.get(Formbuilder.options.mappings.INCLUDE_SCORING)) { %> + + <% } %> + + +
+
<% if (typeof includeOther !== 'undefined'){ %> -
\ No newline at end of file diff --git a/src/templates/edit/populate_from.html b/src/templates/edit/populate_from.html new file mode 100644 index 00000000..593d0ba6 --- /dev/null +++ b/src/templates/edit/populate_from.html @@ -0,0 +1,36 @@ +<% var list = rf.collection.findDataSourceFields(); +if (list.length) { %> +
Populate From
+ + + <% if (rf.get(Formbuilder.options.mappings.POPULATE_UUID)) { %> +
+ +
+ <% } %> +<% } %> diff --git a/src/templates/edit/reference_id.html b/src/templates/edit/reference_id.html new file mode 100644 index 00000000..55081297 --- /dev/null +++ b/src/templates/edit/reference_id.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/templates/edit/scoring.html b/src/templates/edit/scoring.html new file mode 100644 index 00000000..94adfaca --- /dev/null +++ b/src/templates/edit/scoring.html @@ -0,0 +1,7 @@ +
+ +
+ diff --git a/src/templates/edit/table_color.html b/src/templates/edit/table_color.html new file mode 100644 index 00000000..0332e215 --- /dev/null +++ b/src/templates/edit/table_color.html @@ -0,0 +1,14 @@ +<% if (rf.inTable()) { %> +
+
Header Label Colour
+
+ +
+
Header Background Colour
+
+ +
+
+<% } %> \ No newline at end of file diff --git a/src/templates/edit/table_layout.html b/src/templates/edit/table_layout.html new file mode 100644 index 00000000..f4349aa5 --- /dev/null +++ b/src/templates/edit/table_layout.html @@ -0,0 +1,22 @@ +
Layout
+ + + + \ No newline at end of file diff --git a/src/templates/edit/table_totals.html b/src/templates/edit/table_totals.html new file mode 100644 index 00000000..5a9001d7 --- /dev/null +++ b/src/templates/edit/table_totals.html @@ -0,0 +1,6 @@ +
Totals
+ + \ No newline at end of file diff --git a/src/templates/edit/time.html b/src/templates/edit/time.html new file mode 100644 index 00000000..c4855773 --- /dev/null +++ b/src/templates/edit/time.html @@ -0,0 +1,6 @@ +
+ +
diff --git a/src/templates/edit/total.html b/src/templates/edit/total.html new file mode 100644 index 00000000..8a9325c7 --- /dev/null +++ b/src/templates/edit/total.html @@ -0,0 +1,18 @@ +<% if (rf.canTotalColumn()) { %> + +<% } %> +<% if (rf.canAcceptCalculatedTotal()) { %> +
Total
+ +<% } %> + diff --git a/src/templates/page.html b/src/templates/page.html index 6ef928b2..b187080a 100644 --- a/src/templates/page.html +++ b/src/templates/page.html @@ -1,4 +1,3 @@ -<%= Formbuilder.templates['partials/save_button']() %> <%= Formbuilder.templates['partials/left_side']() %> <%= Formbuilder.templates['partials/right_side']() %>
\ No newline at end of file diff --git a/src/templates/partials/add_field.html b/src/templates/partials/add_field.html index 4ec2c9c8..a7c7dd10 100644 --- a/src/templates/partials/add_field.html +++ b/src/templates/partials/add_field.html @@ -1,16 +1,26 @@
-
+
- <% _.each(_.sortBy(Formbuilder.nonInputFields, 'order'), function(f){ %> - + <% _.chain(Formbuilder.nonInputFields) + .sortBy('order') + .filter(function(f){ return f.enabled; }) + .each(function(f){ %> + <%= f.addButton %> <% }); %> diff --git a/src/templates/partials/right_side.html b/src/templates/partials/right_side.html index 7164c13c..d1d550b4 100644 --- a/src/templates/partials/right_side.html +++ b/src/templates/partials/right_side.html @@ -1,4 +1,8 @@ -
-
No response fields
-
+
+
No response fields
+ <% if (Formbuilder.linkAssetFunctionality) { %> + <%= Formbuilder.templates['view/link_object']({object: Formbuilder.linkAssetDisplayFields}) %> +
+ <% } %> +
diff --git a/src/templates/partials/save_button.html b/src/templates/partials/save_button.html deleted file mode 100644 index 7d799e82..00000000 --- a/src/templates/partials/save_button.html +++ /dev/null @@ -1,3 +0,0 @@ -
- -
\ No newline at end of file diff --git a/src/templates/view/afterelementlabel.html b/src/templates/view/afterelementlabel.html new file mode 100644 index 00000000..14afee0e --- /dev/null +++ b/src/templates/view/afterelementlabel.html @@ -0,0 +1,21 @@ +
+ <% if (rf.get(Formbuilder.options.mappings.INLINE_IMAGES_ENABLED)) { %> +
+ + Inline Photo + <% if (rf.get(Formbuilder.options.mappings.INLINE_IMAGES_REQUIRED)) { %> + * + <% } %> +
+ <% } %> + + <% if (rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_ENABLED)) { %> +
+ + Inline Action + <% if (rf.get(Formbuilder.options.mappings.INLINE_ACTIONS_REQUIRED)) { %> + * + <% } %> +
+ <% } %> +
diff --git a/src/templates/view/base.html b/src/templates/view/base.html index 46e7e629..08b122ae 100644 --- a/src/templates/view/base.html +++ b/src/templates/view/base.html @@ -1,9 +1,18 @@
+ <%= Formbuilder.templates['view/conditional']({rf: rf}) %> <%= Formbuilder.templates['view/label']({rf: rf}) %> - <%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].view({rf: rf}) %> + <%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf: rf}) %> <%= Formbuilder.templates['view/description']({rf: rf}) %> - <%= Formbuilder.templates['view/duplicate_remove']({rf: rf}) %> + + <% if (rf.get(Formbuilder.options.mappings.DISALLOW_DUPLICATION)) { %> + <%= Formbuilder.templates['view/remove']({rf: rf}) %> + <% } else { %> + <%= Formbuilder.templates['view/duplicate_remove']({rf: rf}) %> + <% } %> + + <%= Formbuilder.templates['view/afterelementlabel']({rf: rf}) %> +
diff --git a/src/templates/view/base_non_input.html b/src/templates/view/base_non_input.html index a3cffdca..bf30bc13 100644 --- a/src/templates/view/base_non_input.html +++ b/src/templates/view/base_non_input.html @@ -1,5 +1,13 @@
- <%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.FIELD_TYPE)].view({rf: rf}) %> - <%= Formbuilder.templates['view/duplicate_remove']({rf: rf}) %> + <%= Formbuilder.templates['view/conditional']({rf: rf}) %> + <%= Formbuilder.fields[rf.get(Formbuilder.options.mappings.TYPE)].view({rf: rf}) %> + + <% if (rf.get(Formbuilder.options.mappings.DISALLOW_DUPLICATION)) { %> + <%= Formbuilder.templates['view/remove']({rf: rf}) %> + <% } else { %> + <%= Formbuilder.templates['view/duplicate_remove']({rf: rf}) %> + <% } %> + + <%= Formbuilder.templates['view/afterelementlabel']({rf: rf}) %>
diff --git a/src/templates/view/conditional.html b/src/templates/view/conditional.html new file mode 100644 index 00000000..43f317ec --- /dev/null +++ b/src/templates/view/conditional.html @@ -0,0 +1,25 @@ +<% +var parent = rf.conditionalParent(); +if(parent) { +%> +
+ + <% + if(parent.get('type') == 'approval') { %> + + display when <%= parent.get('label') %> + <%= rf.conditionalTriggerOptions(true) %> + + <% } else { + var triggerValues = _.pluck(rf.conditionalTriggerOptions(true), 'label'); + %> + + display when <%= parent.get('label') %> is + <%= triggerValues.join('or') %> + + <% } + %> +
+ +<% } %> + diff --git a/src/templates/view/description.html b/src/templates/view/description.html index c3f5a789..a9e4b959 100644 --- a/src/templates/view/description.html +++ b/src/templates/view/description.html @@ -1,3 +1,7 @@ - <%= Formbuilder.helpers.simple_format(rf.get(Formbuilder.options.mappings.DESCRIPTION)) %> - + <% if (rf.get("type") == "info") { %> + <%= rf.get(Formbuilder.options.mappings.DESCRIPTION) %> + <% } else { %> + <%= Formbuilder.helpers.simple_format(rf.get(Formbuilder.options.mappings.DESCRIPTION)) %> + <% } %> + \ No newline at end of file diff --git a/src/templates/view/duplicate_remove.html b/src/templates/view/duplicate_remove.html index b1e6816f..64e99351 100644 --- a/src/templates/view/duplicate_remove.html +++ b/src/templates/view/duplicate_remove.html @@ -1,4 +1,4 @@
- - + +
\ No newline at end of file diff --git a/src/templates/view/element_selector.html b/src/templates/view/element_selector.html new file mode 100644 index 00000000..e99fc1ae --- /dev/null +++ b/src/templates/view/element_selector.html @@ -0,0 +1,21 @@ +
+ + +
diff --git a/src/templates/view/label.html b/src/templates/view/label.html index 8e7fc9c0..6076d35c 100644 --- a/src/templates/view/label.html +++ b/src/templates/view/label.html @@ -1,5 +1,5 @@