├── .bowerrc ├── publish.js ├── .gitignore ├── views ├── submit-form.client.view.html └── directiveViews │ ├── field │ ├── hidden.html │ ├── password.html │ ├── natural.html │ ├── statement.html │ ├── rating.html │ ├── date.html │ ├── dropdown.html │ ├── radio.html │ ├── file.html │ ├── textarea.html │ ├── legal.html │ ├── yes_no.html │ └── textfield.html │ └── form │ └── submit-form.client.view.html ├── services ├── current-form.client.service.js ├── auth.client.service.js ├── forms.client.service.js ├── time-counter.client.service.js └── form-fields.client.service.js ├── index.js ├── controllers └── submit-form.client.controller.js ├── directives ├── on-finish-render.client.directive.js ├── field-icon.client.directive.js ├── render-form.client.directive.js ├── on-enter-key.client.directive.js ├── field.client.directive.js └── submit-form.client.directive.js ├── LICENSE ├── config ├── i18n │ ├── german.js │ ├── italian.js │ ├── french.js │ ├── spanish.js │ └── english.js └── forms.client.config.js ├── gruntfile.js ├── bower.json ├── demo ├── index.html ├── dist │ └── form.css └── app.js ├── package.json ├── dist ├── form.css └── template.js ├── README.md └── css └── form.css /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "demo/lib", 3 | "analytics": false 4 | } 5 | -------------------------------------------------------------------------------- /publish.js: -------------------------------------------------------------------------------- 1 | require('./dist/bundle.js'); 2 | module.exports = 'angular-tellform'; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | demo/lib 2 | node_modules 3 | demo/node_modules 4 | demo/modules 5 | demo/bundle.js 6 | .idea/ 7 | -------------------------------------------------------------------------------- /views/submit-form.client.view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | -------------------------------------------------------------------------------- /views/directiveViews/field/hidden.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /services/current-form.client.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //Forms service used for communicating with the forms REST endpoints 4 | angular.module('angular-tellform').service('CurrentForm', 5 | function(){ 6 | 7 | //Private variables 8 | var _form = {}; 9 | 10 | //Public Methods 11 | this.getForm = function() { 12 | return _form; 13 | }; 14 | this.setForm = function(form) { 15 | _form = form; 16 | }; 17 | } 18 | ); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform', [ 4 | 'ui.utils', 5 | 'duScroll', 6 | 'ui.select', 7 | 'cgBusy', 8 | 'ngSanitize', 9 | 'vButton', 10 | 'ngResource', 11 | 'ui.router', 12 | 'ui.bootstrap', 13 | 'pascalprecht.translate', 14 | 'angular-input-stars', 15 | 'angular-tellform.templates' 16 | ]).constant('version', require('./package.json').version); 17 | 18 | //FIXME: App breaks when I remove this line and put modules in above statement 19 | //angular.module('angular-tellform', ['ngResource', 'angular-tellform.templates']); 20 | 21 | require('./dist/form.js'); 22 | 23 | -------------------------------------------------------------------------------- /services/auth.client.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').factory('Auth', function() { 4 | var service = { 5 | _currentUser: null, 6 | get currentUser(){ 7 | return this._currentUser; 8 | }, 9 | ensureHasCurrentUser: function() { 10 | return null; 11 | }, 12 | isAuthenticated: function() { 13 | return false; 14 | }, 15 | getUserState: function() { 16 | return ''; 17 | }, 18 | login: function() { 19 | }, 20 | logout: function() { 21 | } 22 | }; 23 | return service; 24 | }); 25 | -------------------------------------------------------------------------------- /views/directiveViews/field/password.html: -------------------------------------------------------------------------------- 1 |
2 |

{{field.title}} *(required)

3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /services/forms.client.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //Forms service used for communicating with the forms REST endpoints 4 | angular.module('angular-tellform').factory('Forms', ['$resource', 'FORM_URL', 5 | function($resource, FORM_URL) { 6 | return $resource(FORM_URL, { 7 | formId: '@_id' 8 | }, { 9 | 'query' : { 10 | method: 'GET', 11 | isArray: true 12 | }, 13 | 'get' : { 14 | method: 'GET', 15 | transformResponse: function(data, header) { 16 | var form = angular.fromJson(data); 17 | 18 | form.visible_form_fields = _.filter(form.form_fields, function(field){ 19 | return (field.deletePreserved === false); 20 | }); 21 | return form; 22 | } 23 | }, 24 | 'update': { 25 | method: 'PUT' 26 | }, 27 | 'save': { 28 | method: 'POST' 29 | } 30 | }); 31 | } 32 | ]); -------------------------------------------------------------------------------- /controllers/submit-form.client.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // SubmitForm controller 4 | angular.module('angular-tellform').controller('SubmitFormController', [ 5 | '$scope', '$rootScope', '$state', '$translate', 'myForm', 'Auth', 6 | function($scope, $rootScope, $state, $translate, myForm, Auth) { 7 | $scope.authentication = Auth; 8 | $scope.myform = myForm; 9 | 10 | $translate.use(myForm.language); 11 | 12 | if(!$scope.myform.isLive){ 13 | // Show navbar if form is not public AND user IS loggedin 14 | if($scope.authentication.isAuthenticated()){ 15 | $scope.hideNav = $rootScope.hideNav = false; 16 | } 17 | // Redirect if form is not public user IS NOT loggedin 18 | else { 19 | $scope.hideNav = $rootScope.hideNav = true; 20 | $state.go('access_denied'); 21 | } 22 | }else{ 23 | $scope.hideNav = $rootScope.hideNav = true; 24 | } 25 | } 26 | ]); 27 | -------------------------------------------------------------------------------- /views/directiveViews/field/natural.html: -------------------------------------------------------------------------------- 1 |
2 |

{{field.title}} *(required)

3 |
4 | 11 |
12 |
13 |
14 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /services/time-counter.client.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').service('TimeCounter', [ 4 | function(){ 5 | var _startTime, _endTime = null, that=this; 6 | 7 | this.timeSpent = 0; 8 | 9 | this.restartClock = function(){ 10 | _startTime = Date.now(); 11 | _endTime = null; 12 | // console.log('Clock Started'); 13 | }; 14 | 15 | this.getTimeElapsed = function(){ 16 | if(_startTime) { 17 | return Math.abs(Date.now().valueOf() - _startTime.valueOf()) / 1000; 18 | } 19 | }; 20 | 21 | this.stopClock = function(){ 22 | if(_startTime && _endTime === null){ 23 | _endTime = Date.now(); 24 | this.timeSpent = Math.abs(_endTime.valueOf() - _startTime.valueOf())/1000; 25 | this._startTime = this._endTime = null; 26 | 27 | return this.timeSpent; 28 | }else{ 29 | return new Error('Clock has not been started'); 30 | } 31 | }; 32 | 33 | this.clockStarted = function(){ 34 | return !!this._startTime; 35 | }; 36 | 37 | } 38 | ]); -------------------------------------------------------------------------------- /directives/on-finish-render.client.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').directive('onFinishRender', function ($rootScope, $timeout) { 4 | return { 5 | restrict: 'A', 6 | link: function (scope, element, attrs) { 7 | 8 | //Don't do anything if we don't have a ng-repeat on the current element 9 | if(!element.attr('ng-repeat') && !element.attr('data-ng-repeat')){ 10 | return; 11 | } 12 | 13 | var broadcastMessage = attrs.onFinishRender || 'ngRepeat'; 14 | 15 | if(scope.$first && !scope.$last) { 16 | scope.$evalAsync(function () { 17 | $rootScope.$broadcast(broadcastMessage+' Started'); 18 | }); 19 | }else if(scope.$last) { 20 | scope.$evalAsync(function () { 21 | // console.log(broadcastMessage+'Finished'); 22 | $rootScope.$broadcast(broadcastMessage+' Finished'); 23 | }); 24 | } 25 | } 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /directives/field-icon.client.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').directive('fieldIconDirective', function() { 4 | return { 5 | template: '', 6 | restrict: 'E', 7 | scope: { 8 | typeName: '@' 9 | }, 10 | controller: function($scope){ 11 | var iconTypeMap = { 12 | 'textfield': 'fa fa-pencil-square-o', 13 | 'dropdown': 'fa fa-th-list', 14 | 'date': 'fa fa-calendar', 15 | 'checkbox': 'fa fa-check-square-o', 16 | 'radio': 'fa fa-dot-circle-o', 17 | 'email': 'fa fa-envelope-o', 18 | 'textarea': 'fa fa-pencil-square', 19 | 'legal': 'fa fa-legal', 20 | 'file': 'fa fa-cloud-upload', 21 | 'rating': 'fa fa-star-half-o', 22 | 'link': 'fa fa-link', 23 | 'scale': 'fa fa-sliders', 24 | 'stripe': 'fa fa-credit-card', 25 | 'statement': 'fa fa-quote-left', 26 | 'yes_no': 'fa fa-toggle-on', 27 | 'number': 'fa fa-slack' 28 | }; 29 | $scope.typeIcon = iconTypeMap[$scope.typeName]; 30 | } 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /views/directiveViews/field/statement.html: -------------------------------------------------------------------------------- 1 |
5 |
6 |
7 |

{{field.title}}

8 |

9 | {{field.description}} 10 |

11 |
12 |
13 |

{{field.description}}

14 |
15 |
16 | 22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 tellform 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/i18n/german.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').config(['$translateProvider', function ($translateProvider) { 4 | 5 | $translateProvider.translations('german', { 6 | FORM_SUCCESS: 'Ihre Angaben wurden gespeichert.', 7 | REVIEW: 'Unvollständig', 8 | BACK_TO_FORM: 'Zurück zum Formular', 9 | EDIT_FORM: 'Bearbeiten Sie diese TellForm', 10 | CREATE_FORM: 'Erstellen Sie eine TellForm', 11 | ADVANCEMENT: '{{done}} von {{total}} beantwortet', 12 | CONTINUE_FORM: 'Zum Formular', 13 | REQUIRED: 'verpflichtend', 14 | COMPLETING_NEEDED: 'Es fehlen/fehtl noch {{answers_not_completed}} Antwort(en)', 15 | OPTIONAL: 'fakultativ', 16 | ERROR_EMAIL_INVALID: 'Bitte gültige Mailadresse eingeben', 17 | ERROR_NOT_A_NUMBER: 'Bitte nur Zahlen eingeben', 18 | ERROR_URL_INVALID: 'Bitte eine gültige URL eingeben', 19 | OK: 'Okay', 20 | ENTER: 'Eingabetaste drücken', 21 | YES: 'Ja', 22 | NO: 'Nein', 23 | NEWLINE: 'Für eine neue Zeile SHIFT+ENTER drücken', 24 | CONTINUE: 'Weiter', 25 | LEGAL_ACCEPT: 'Ich akzeptiere', 26 | LEGAL_NO_ACCEPT: 'Ich akzeptiere nicht', 27 | DELETE: 'Entfernen', 28 | CANCEL: 'Canceln', 29 | SUBMIT: 'Speichern', 30 | UPLOAD_FILE: 'Datei versenden', 31 | Y: 'J', 32 | N: 'N' 33 | }); 34 | 35 | }]); 36 | -------------------------------------------------------------------------------- /config/i18n/italian.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').config(['$translateProvider', function ($translateProvider) { 4 | 5 | $translateProvider.translations('italian', { 6 | FORM_SUCCESS: 'Il formulario è stato inviato con successo!', 7 | REVIEW: 'Incompleto', 8 | BACK_TO_FORM: 'Ritorna al formulario', 9 | EDIT_FORM: 'Modifica questo Tellform', 10 | CREATE_FORM: 'Creare un TellForm', 11 | ADVANCEMENT: '{{done}} su {{total}} completate', 12 | CONTINUE_FORM: 'Vai al formulario', 13 | REQUIRED: 'obbligatorio', 14 | COMPLETING_NEEDED: '{{answers_not_completed}} risposta/e deve/ono essere completata/e', 15 | OPTIONAL: 'opzionale', 16 | ERROR_EMAIL_INVALID: 'Si prega di inserire un indirizzo email valido', 17 | ERROR_NOT_A_NUMBER: 'Si prega di inserire solo numeri', 18 | ERROR_URL_INVALID: 'Grazie per inserire un URL valido', 19 | OK: 'OK', 20 | ENTER: 'premere INVIO', 21 | YES: 'Sì', 22 | NO: 'No', 23 | NEWLINE: 'premere SHIFT+INVIO per creare una nuova linea', 24 | CONTINUE: 'Continua', 25 | LEGAL_ACCEPT: 'Accetto', 26 | LEGAL_NO_ACCEPT: 'Non accetto', 27 | DELETE: 'Cancella', 28 | CANCEL: 'Reset', 29 | SUBMIT: 'Registra', 30 | UPLOAD_FILE: 'Invia un file', 31 | Y: 'S', 32 | N: 'N' 33 | }); 34 | 35 | }]); 36 | -------------------------------------------------------------------------------- /config/i18n/french.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').config(['$translateProvider', function ($translateProvider) { 4 | 5 | $translateProvider.translations('french', { 6 | FORM_SUCCESS: 'Votre formulaire a été enregistré!', 7 | REVIEW: 'Incomplet', 8 | BACK_TO_FORM: 'Retourner au formulaire', 9 | EDIT_FORM: 'Éditer le Tellform', 10 | CREATE_FORM: 'Créer un TellForm', 11 | ADVANCEMENT: '{{done}} complétés sur {{total}}', 12 | CONTINUE_FORM: 'Aller au formulaire', 13 | REQUIRED: 'obligatoire', 14 | COMPLETING_NEEDED: '{{answers_not_completed}} réponse(s) doive(nt) être complétée(s)', 15 | OPTIONAL: 'facultatif', 16 | ERROR_EMAIL_INVALID: 'Merci de rentrer une adresse mail valide', 17 | ERROR_NOT_A_NUMBER: 'Merce de ne rentrer que des nombres', 18 | ERROR_URL_INVALID: 'Merci de rentrer une url valide', 19 | OK: 'OK', 20 | ENTER: 'presser ENTRÉE', 21 | YES: 'Oui', 22 | NO: 'Non', 23 | NEWLINE: 'presser SHIFT+ENTER pour créer une nouvelle ligne', 24 | CONTINUE: 'Continuer', 25 | LEGAL_ACCEPT: 'J’accepte', 26 | LEGAL_NO_ACCEPT: 'Je n’accepte pas', 27 | DELETE: 'Supprimer', 28 | CANCEL: 'Réinitialiser', 29 | SUBMIT: 'Enregistrer', 30 | UPLOAD_FILE: 'Envoyer un fichier', 31 | Y: 'O', 32 | N: 'N' 33 | }); 34 | 35 | }]); 36 | -------------------------------------------------------------------------------- /config/i18n/spanish.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').config(['$translateProvider', function ($translateProvider) { 4 | 5 | $translateProvider.translations('spanish', { 6 | FORM_SUCCESS: '¡El formulario ha sido enviado con éxito!', 7 | REVIEW: 'Revisar', 8 | BACK_TO_FORM: 'Regresar al formulario', 9 | EDIT_FORM: 'Crear un TellForm', 10 | CREATE_FORM: 'Editar este TellForm', 11 | ADVANCEMENT: '{{done}} de {{total}} contestadas', 12 | CONTINUE_FORM: 'Continuar al formulario', 13 | REQUIRED: 'Información requerida', 14 | COMPLETING_NEEDED: '{{answers_not_completed}} respuesta(s) necesita(n) ser completada(s)', 15 | OPTIONAL: 'Opcional', 16 | ERROR_EMAIL_INVALID: 'Favor de proporcionar un correo electrónico válido', 17 | ERROR_NOT_A_NUMBER: 'Por favor, introduzca sólo números válidos', 18 | ERROR_URL_INVALID: 'Favor de proporcionar un url válido', 19 | OK: 'OK', 20 | ENTER: 'pulse INTRO', 21 | YES: 'Si', 22 | NO: 'No', 23 | NEWLINE: 'presione SHIFT+INTRO para crear una nueva línea', 24 | CONTINUE: 'Continuar', 25 | LEGAL_ACCEPT: 'Acepto', 26 | LEGAL_NO_ACCEPT: 'No acepto', 27 | DELETE: 'Eliminar', 28 | CANCEL: 'Cancelar', 29 | SUBMIT: 'Registrar', 30 | UPLOAD_FILE: 'Cargar el archivo', 31 | Y: 'S', 32 | N: 'N' 33 | }); 34 | 35 | }]); 36 | -------------------------------------------------------------------------------- /config/i18n/english.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').config(['$translateProvider', function ($translateProvider) { 4 | 5 | $translateProvider.translations('english', { 6 | FORM_SUCCESS: 'Form entry successfully submitted!', 7 | REVIEW: 'Review', 8 | BACK_TO_FORM: 'Go back to Form', 9 | EDIT_FORM: 'Edit this TellForm', 10 | CREATE_FORM: 'Create this TellForm', 11 | ADVANCEMENT: '{{done}} out of {{total}} answered', 12 | CONTINUE_FORM: 'Continue to Form', 13 | REQUIRED: 'required', 14 | COMPLETING_NEEDED: '{{answers_not_completed}} answer(s) need completing', 15 | OPTIONAL: 'optional', 16 | ERROR_EMAIL_INVALID: 'Please enter a valid email address', 17 | ERROR_NOT_A_NUMBER: 'Please enter valid numbers only', 18 | ERROR_URL_INVALID: 'Please a valid url', 19 | OK: 'OK', 20 | ENTER: 'press ENTER', 21 | YES: 'Yes', 22 | NO: 'No', 23 | NEWLINE: 'press SHIFT+ENTER to create a newline', 24 | CONTINUE: 'Continue', 25 | LEGAL_ACCEPT: 'I accept', 26 | LEGAL_NO_ACCEPT: 'I don’t accept', 27 | DELETE: 'Delete', 28 | CANCEL: 'Cancel', 29 | SUBMIT: 'Submit', 30 | UPLOAD_FILE: 'Upload your File' 31 | }); 32 | 33 | $translateProvider.preferredLanguage('english') 34 | .fallbackLanguage('english') 35 | .useSanitizeValueStrategy('escape'); 36 | 37 | }]); 38 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | require('jit-grunt')(grunt); 5 | 6 | // Project Configuration 7 | grunt.initConfig({ 8 | ngAnnotate: { 9 | production: { 10 | files: { 11 | 'dist/form.js': [ 12 | 'config/**/*.js', 'controllers/**/*.js', 13 | 'directives/**/*.js', 'services/**/*.js', 14 | 'dist/template.js' 15 | ] 16 | } 17 | } 18 | }, 19 | html2js: { 20 | options: { 21 | base: '', 22 | module: 'angular-tellform.templates', 23 | singleModule: true, 24 | rename: function (moduleName) { 25 | return 'modules/forms/base/' + moduleName; 26 | } 27 | }, 28 | form: { 29 | src: ['views/**/*.html'], 30 | dest: 'dist/template.js' 31 | } 32 | }, 33 | cssmin: { 34 | combine: { 35 | files: { 36 | 'dist/form.css': 'css/**/*.css' 37 | } 38 | } 39 | }, 40 | browserify: { 41 | dist: { 42 | files: { 43 | 'dist/bundle.js': ['index.js', 'dist/template.js'] 44 | } 45 | } 46 | } 47 | }); 48 | 49 | // Making grunt default to force in order not to break the project. 50 | grunt.option('force', true); 51 | 52 | // Default task(s). 53 | grunt.registerTask('default', ['html2js:form', 'ngAnnotate', 'cssmin', 'browserify:dist']); 54 | }; 55 | -------------------------------------------------------------------------------- /views/directiveViews/field/rating.html: -------------------------------------------------------------------------------- 1 |
3 |
4 |

5 | 6 | {{index+1}} 7 | 8 | 9 | {{field.title}} 10 | {{ 'OPTIONAL' | translate }} 11 |

12 |

13 | {{field.description}} 14 |

15 |
16 |
17 | 18 | 32 | 33 |
34 |
35 | -------------------------------------------------------------------------------- /views/directiveViews/field/date.html: -------------------------------------------------------------------------------- 1 |
3 |
4 |

5 | 6 | {{index+1}} 7 | 8 | 9 | {{field.title}} 10 | {{ 'OPTIONAL' | translate }} 11 |

12 |

13 | {{field.description}} 14 |

15 |
16 |
17 |
18 | 31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /directives/render-form.client.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').directive('angularTellform', 4 | ['$rootScope', '$state', 'Auth', function ($rootScope, $state, Auth) { 5 | return { 6 | templateUrl: 'modules/forms/base/views/submit-form.client.view.html', 7 | restrict: 'E', 8 | scope: { 9 | myform:'=' 10 | }, 11 | controller: function($document, $window, $scope){ 12 | console.log('angular-tellform directive'); 13 | $scope.authentication = Auth; 14 | $scope.myform.visible_form_fields = _.filter($scope.myform.form_fields, function(field){ 15 | return (field.deletePreserved === false); 16 | }); 17 | 18 | if(!$scope.myform.isLive){ 19 | // Show navbar if form is not public AND user IS loggedin 20 | if($scope.authentication.isAuthenticated()){ 21 | $scope.hideNav = $rootScope.hideNav = false; 22 | } 23 | // Redirect if form is not public user IS NOT loggedin 24 | else { 25 | $scope.hideNav = $rootScope.hideNav = true; 26 | $state.go('access_denied'); 27 | } 28 | }else{ 29 | $scope.hideNav = $rootScope.hideNav = true; 30 | } 31 | 32 | } 33 | }; 34 | }]); 35 | -------------------------------------------------------------------------------- /services/form-fields.client.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //TODO: DAVID: URGENT: Make this a $resource that fetches valid field types from server 4 | angular.module('angular-tellform').service('FormFields', function() { 5 | this.types = [ 6 | { 7 | name : 'textfield', 8 | value : 'Short Text' 9 | }, 10 | { 11 | name : 'email', 12 | value : 'Email' 13 | }, 14 | { 15 | name : 'radio', 16 | value : 'Multiple Choice' 17 | }, 18 | { 19 | name : 'dropdown', 20 | value : 'Dropdown' 21 | }, 22 | { 23 | name : 'date', 24 | value : 'Date' 25 | }, 26 | { 27 | name : 'textarea', 28 | value : 'Paragraph Text' 29 | }, 30 | { 31 | name : 'yes_no', 32 | value : 'Yes/No' 33 | }, 34 | { 35 | name : 'legal', 36 | value : 'Legal' 37 | }, 38 | // { 39 | // name : 'sig', 40 | // value : 'Signature' 41 | // }, 42 | // { 43 | // name : 'file', 44 | // value : 'File Upload' 45 | // }, 46 | { 47 | name : 'rating', 48 | value : 'Rating' 49 | }, 50 | { 51 | name : 'link', 52 | value : 'Link' 53 | }, 54 | { 55 | name : 'number', 56 | value : 'Numbers' 57 | }, 58 | // { 59 | // name : 'scale', 60 | // value : 'Opinion Scale' 61 | // }, 62 | // { 63 | // name : 'stripe', 64 | // value : 'Payment' 65 | // }, 66 | { 67 | name : 'statement', 68 | value : 'Statement' 69 | } 70 | ]; 71 | }); -------------------------------------------------------------------------------- /views/directiveViews/field/dropdown.html: -------------------------------------------------------------------------------- 1 | 36 |
37 | -------------------------------------------------------------------------------- /views/directiveViews/field/radio.html: -------------------------------------------------------------------------------- 1 |
5 |
6 |

7 | 8 | {{index+1}} 9 | 10 | 11 | {{field.title}} 12 | {{ 'OPTIONAL' | translate }} 13 |

14 |

15 | {{field.description}} 16 |

17 |
18 |
19 | 20 |
21 | 38 |
39 |
40 |
41 |
42 | -------------------------------------------------------------------------------- /config/forms.client.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Configuring the Forms drop-down menus 4 | angular.module('angular-tellform') 5 | .filter('formValidity', function(){ 6 | return function(formObj){ 7 | if(formObj && formObj.form_fields && formObj.visible_form_fields){ 8 | 9 | //get keys 10 | var formKeys = Object.keys(formObj); 11 | 12 | //we only care about things that don't start with $ 13 | var fieldKeys = formKeys.filter(function(key){ 14 | return key[0] !== '$'; 15 | }); 16 | 17 | var fields = formObj.form_fields; 18 | 19 | var valid_count = fields.filter(function(field){ 20 | if(typeof field === 'object' && field.fieldType !== 'statement' && field.fieldType !== 'rating'){ 21 | return !!(field.fieldValue); 22 | } 23 | 24 | }).length; 25 | return valid_count - (formObj.form_fields.length - formObj.visible_form_fields.length); 26 | } 27 | return 0; 28 | }; 29 | }).factory('$state', [function() { 30 | return { 31 | go: function() {} 32 | }; 33 | }]).constant('FORM_URL', '/form/:formId') 34 | .value('supportedFields', [ 35 | 'textfield', 36 | 'textarea', 37 | 'date', 38 | 'dropdown', 39 | 'hidden', 40 | 'password', 41 | 'radio', 42 | 'legal', 43 | 'statement', 44 | 'rating', 45 | 'yes_no', 46 | 'number', 47 | 'natural' 48 | ]).value('SendVisitorData', { 49 | send: function(){} 50 | }).factory('Auth', [ 51 | function() { 52 | var service = { 53 | _currentUser: null, 54 | get currentUser(){ 55 | return this._currentUser; 56 | }, 57 | ensureHasCurrentUser: function() { 58 | return null; 59 | }, 60 | isAuthenticated: function() { 61 | return false; 62 | }, 63 | getUserState: function() { 64 | return ''; 65 | }, 66 | login: function() { 67 | }, 68 | logout: function() { 69 | } 70 | }; 71 | return service; 72 | } 73 | ]); 74 | -------------------------------------------------------------------------------- /views/directiveViews/field/file.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

5 | 6 | {{index+1}} 7 | 8 | 9 | {{field.title}} 10 | {{ 'OPTIONAL' | translate }} 11 |

12 |
13 |
14 |
15 |
16 | 17 |
18 | {{field.file.originalname}} 19 |
20 |
21 |
22 | 27 | 28 | 32 | 33 |
34 | 35 | {{ UPLOAD_FILE | translate }} 36 |
37 |
38 |
39 |
40 |
41 | -------------------------------------------------------------------------------- /views/directiveViews/field/textarea.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | {{index+1}} 6 | 7 | 8 | {{field.title}} 9 | {{ 'OPTIONAL' | translate }} 10 |

11 | {{ 'NEWLINE' | translate }} 12 |

13 | {{field.description}} 14 |

15 |
16 |
17 | Press SHIFT+ENTER to add a newline 18 | 30 |
31 |
32 | 33 |
34 | 49 |
50 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-tellform", 3 | "description": "Frontend UI for Tellform", 4 | "version": "1.0.0", 5 | "main": [ 6 | "dist/bundle.js", 7 | "dist/form.css" 8 | ], 9 | "authors": [ 10 | "David Baldwynn (http://baldwynn.me)", 11 | "Samuel Laulhau (https://lalop.co)" 12 | ], 13 | "license": "MIT", 14 | "keywords": [ 15 | "forms", 16 | "tellform", 17 | "formui", 18 | "ui" 19 | ], 20 | "moduleType": [ 21 | "amd", 22 | "globals" 23 | ], 24 | "homepage": "https://github.com/tellform/angular-tellform", 25 | "ignore": [ 26 | ".*", 27 | "node_modules", 28 | "bower_components", 29 | "demo", 30 | "test" 31 | ], 32 | "dependencies": { 33 | "angular-bootstrap": "^1.3.3", 34 | "angular-busy": "^4.1.3", 35 | "angular-animate": "^1.5.6", 36 | "angular-input-stars": "*", 37 | "angular-resource": "^1.5.6", 38 | "angular-sanitize": "^1.5.6", 39 | "angular-scroll": "^1.0.0", 40 | "angular-strap": "^2.3.9", 41 | "angular-ui-date": "^1.0.1", 42 | "angular-ui-event": "*", 43 | "angular-ui-indeterminate": "*", 44 | "angular-ui-mask": "*", 45 | "angular-ui-scroll": "*", 46 | "angular-ui-scrollpoint": "*", 47 | "angular-ui-select": "^0.18.0", 48 | "angular-ui-utils": "~3.0.0", 49 | "angular": "^1.5.6", 50 | "bootstrap": "~3", 51 | "components-font-awesome": "~4.6.1", 52 | "font-awesome": "^4.6.3", 53 | "file-saver.js": "~1.20150507.2", 54 | "jquery": "~3.0.0", 55 | "lodash": ">=1.3.0", 56 | "ng-file-upload": "^12.0.4", 57 | "restangular": "~1.5.2", 58 | "v-button": "^1.1.1", 59 | "ui-select": "angular-ui-select#^0.16.1", 60 | "angular-ui-router": "^0.3.1", 61 | "angular-translate": "^2.11.0", 62 | "js-yaml": "^3.6.1" 63 | }, 64 | "resolutions": { 65 | "angular-animate": "^1.5.6", 66 | "jquery": "~2", 67 | "font-awesome": "^4.6.3", 68 | "angular": "^1.5.6" 69 | }, 70 | "private": false 71 | } 72 | -------------------------------------------------------------------------------- /directives/on-enter-key.client.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //TODO: DAVID: Need to refactor this 4 | angular.module('angular-tellform').directive('onEnterKey', ['$rootScope', function($rootScope){ 5 | return { 6 | restrict: 'A', 7 | link: function($scope, $element, $attrs) { 8 | $element.bind('keydown keypress', function(event) { 9 | 10 | var keyCode = event.which || event.keyCode; 11 | 12 | var onEnterKeyDisabled = false; 13 | if($attrs.onEnterKeyDisabled !== null) onEnterKeyDisabled = $attrs.onEnterKeyDisabled; 14 | 15 | if(keyCode === 13 && !event.shiftKey && !onEnterKeyDisabled) { 16 | event.preventDefault(); 17 | $rootScope.$apply(function() { 18 | $rootScope.$eval($attrs.onEnterKey); 19 | }); 20 | } 21 | }); 22 | } 23 | }; 24 | }]).directive('onTabKey', ['$rootScope', function($rootScope){ 25 | return { 26 | restrict: 'A', 27 | link: function($scope, $element, $attrs) { 28 | $element.bind('keydown keypress', function(event) { 29 | 30 | var keyCode = event.which || event.keyCode; 31 | 32 | if(keyCode === 9 && !event.shiftKey) { 33 | 34 | event.preventDefault(); 35 | $rootScope.$apply(function() { 36 | $rootScope.$eval($attrs.onTabKey); 37 | }); 38 | } 39 | }); 40 | } 41 | }; 42 | }]).directive('onEnterOrTabKey', ['$rootScope', function($rootScope){ 43 | return { 44 | restrict: 'A', 45 | link: function($scope, $element, $attrs) { 46 | $element.bind('keydown keypress', function(event) { 47 | 48 | var keyCode = event.which || event.keyCode; 49 | 50 | if((keyCode === 13 || keyCode === 9) && !event.shiftKey) { 51 | event.preventDefault(); 52 | $rootScope.$apply(function() { 53 | $rootScope.$eval($attrs.onEnterOrTabKey); 54 | }); 55 | } 56 | }); 57 | } 58 | }; 59 | }]).directive('onTabAndShiftKey', ['$rootScope', function($rootScope){ 60 | return { 61 | restrict: 'A', 62 | link: function($scope, $element, $attrs) { 63 | $element.bind('keydown keypress', function(event) { 64 | 65 | var keyCode = event.which || event.keyCode; 66 | 67 | if(keyCode === 9 && event.shiftKey) { 68 | event.preventDefault(); 69 | $rootScope.$apply(function() { 70 | $rootScope.$eval($attrs.onTabAndShiftKey); 71 | }); 72 | } 73 | }); 74 | } 75 | }; 76 | }]); 77 | -------------------------------------------------------------------------------- /views/directiveViews/field/legal.html: -------------------------------------------------------------------------------- 1 | 54 |
55 | -------------------------------------------------------------------------------- /views/directiveViews/field/yes_no.html: -------------------------------------------------------------------------------- 1 |
5 |
6 |

7 | 8 | {{index+1}} 9 | 10 | 11 | {{field.title}} 12 | 13 | {{ 'OPTIONAL' | translate }} 14 | 15 |

16 |

17 | {{field.description}} 18 |

19 |
20 | 21 |
22 |
23 | 40 |
41 | 42 |
43 | 60 |
61 |
62 |
63 |
64 | -------------------------------------------------------------------------------- /views/directiveViews/field/textfield.html: -------------------------------------------------------------------------------- 1 |
3 |
4 |

5 | 6 | {{index+1}} 7 | 8 | 9 | 10 | {{field.title}} 11 | 12 | 13 | ({{ 'OPTIONAL' | translate }}) 14 | 15 |

16 | 17 |

18 | {{field.description}} 19 |

20 |
21 |
22 | 38 |
39 |
40 | 47 |
48 |
49 |
50 | 65 |
66 | -------------------------------------------------------------------------------- /directives/field.client.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // coffeescript's for in loop 4 | var __indexOf = [].indexOf || function(item) { 5 | for (var i = 0, l = this.length; i < l; i++) { 6 | if (i in this && this[i] === item) return i; 7 | } 8 | return -1; 9 | }; 10 | 11 | angular.module('angular-tellform').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields', 12 | function($http, $compile, $rootScope, $templateCache, supportedFields) { 13 | 14 | var getTemplateUrl = function(fieldType) { 15 | var type = fieldType; 16 | 17 | var templateUrl = 'modules/forms/base/views/directiveViews/field/'; 18 | 19 | if (__indexOf.call(supportedFields, type) >= 0) { 20 | templateUrl = templateUrl+type+'.html'; 21 | } 22 | return $templateCache.get(templateUrl); 23 | }; 24 | 25 | return { 26 | template: '
{{field.title}}
', 27 | restrict: 'E', 28 | scope: { 29 | field: '=', 30 | required: '&', 31 | design: '=', 32 | index: '=' 33 | }, 34 | link: function(scope, element) { 35 | 36 | $rootScope.chooseDefaultOption = scope.chooseDefaultOption = function(type) { 37 | if(type === 'yes_no'){ 38 | scope.field.fieldValue = 'true'; 39 | }else if(type === 'rating'){ 40 | scope.field.fieldValue = 0; 41 | }else if(scope.field.fieldType === 'radio'){ 42 | console.log(scope.field); 43 | scope.field.fieldValue = scope.field.fieldOptions[0].option_value; 44 | console.log(scope.field.fieldValue); 45 | }else if(type === 'legal'){ 46 | scope.field.fieldValue = 'true'; 47 | $rootScope.nextField(); 48 | } 49 | }; 50 | 51 | scope.setActiveField = $rootScope.setActiveField; 52 | 53 | //Set format only if field is a date 54 | if(scope.field.fieldType === 'date'){ 55 | scope.dateOptions = { 56 | changeYear: true, 57 | changeMonth: true, 58 | altFormat: 'mm/dd/yyyy', 59 | yearRange: '1900:-0', 60 | defaultDate: 0 61 | }; 62 | } 63 | 64 | var fieldType = scope.field.fieldType; 65 | 66 | if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){ 67 | switch(scope.field.fieldType){ 68 | case 'textfield': 69 | scope.field.input_type = 'text'; 70 | break; 71 | case 'email': 72 | scope.field.input_type = 'email'; 73 | scope.field.placeholder = 'joesmith@example.com'; 74 | break; 75 | case 'number': 76 | scope.field.input_type = 'text'; 77 | scope.field.validateRegex = /^-?\d+$/; 78 | break; 79 | default: 80 | scope.field.input_type = 'url'; 81 | scope.field.placeholder = 'http://example.com'; 82 | break; 83 | } 84 | fieldType = 'textfield'; 85 | } 86 | var template = getTemplateUrl(fieldType); 87 | element.html(template); 88 | $compile(element.contents())(scope); 89 | } 90 | }; 91 | }]); 92 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | angular-tellform Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
81 | 82 |
83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-tellform", 3 | "description": "Frontend UI for Tellform", 4 | "version": "1.0.2", 5 | "homepage": "https://github.com/tellform/angular-tellform", 6 | "authors": [ 7 | "David Baldwynn (http://baldwynn.me)", 8 | "Samuel Laulhau (https://samuellaulhau.fr)" 9 | ], 10 | "license": "MIT", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/tellform/angular-tellform.git" 14 | }, 15 | "main": "publish.js", 16 | "engines": { 17 | "node": "~5.0.0", 18 | "npm": "~2.11.2" 19 | }, 20 | "keywords": [ 21 | "tellform", 22 | "forms", 23 | "formly", 24 | "angularjs", 25 | "angular forms", 26 | "typeform" 27 | ], 28 | "scripts": {}, 29 | "dependencies": { 30 | "angular": "^1.5.7", 31 | "angular-animate": "^1.5.7", 32 | "angular-bootstrap": "^0.12.2", 33 | "angular-busy": "^4.1.3", 34 | "angular-input-stars": "^1.5.5", 35 | "angular-resource": "^1.5.7", 36 | "angular-sanitize": "^1.5.7", 37 | "angular-scroll": "^1.0.0", 38 | "angular-strap": "^2.3.9", 39 | "angular-translate": "^2.11.0", 40 | "angular-ui-date": "^1.1.1", 41 | "angular-ui-router": "^0.3.1", 42 | "angular-ui-utils": "^0.1.1", 43 | "jquery": "^2.2.3", 44 | "jquery-ui": "^1.10.5", 45 | "lodash": "~4.11.1", 46 | "ng-file-upload": "^10.0.4", 47 | "ui-select": "~0.16.1", 48 | "v-button": "git+https://git@github.com/whitef0x0/v-button.git" 49 | }, 50 | "devDependencies": { 51 | "grunt-browserify": "^5.0.0", 52 | "http-server": "^0.9.0", 53 | "grunt-cli": "~0.1.13", 54 | "grunt-contrib-cssmin": "~0.14.0", 55 | "grunt-contrib-uglify": "~0.11.0", 56 | "grunt-html2js": "~0.3.5", 57 | "grunt-ng-annotate": "~1.0.1", 58 | "jit-grunt": "^0.10.0" 59 | }, 60 | "browser": { 61 | "jquery": "./node_modules/jquery/dist/jquery.js", 62 | "jquery-ui-sortable": "./node_modules/jquery-ui/jquery-ui.js", 63 | "angular": "./node_modules/angular/angular.js", 64 | "ng-file-upload": "./node_modules/ng-file-upload/dist/ng-file-upload-all.js", 65 | "angular-animate": "./node_modules/angular-animate/angular-animate.min.js", 66 | "angular-bootstrap": "./node_modules/angular-bootstrap/ui-bootstrap.min.js", 67 | "angular-busy": "./node_modules/angular-busy/dist/angular-busy.min.js", 68 | "angular-input-stars": "./node_modules/angular-input-stars/angular-input-stars.js", 69 | "angular-resource": "./node_modules/angular-resource/angular-resource.min.js", 70 | "angular-sanitize": "./node_modules/angular-sanitize/angular-sanitize.min.js", 71 | "angular-scroll": "./node_modules/angular-scroll/angular-scroll.min.js", 72 | "angular-strap": "./node_modules/angular-strap/dist/angular-strap.min.js", 73 | "angular-ui-date": "./node_modules/angular-ui-date/src/date.js", 74 | "angular-ui-router": "./node_modules/angular-ui-router/release/angular-ui-router.min.js", 75 | "angular-ui-utils": "./node_modules/angular-ui-utils/publish.js" 76 | }, 77 | "browserify-shim": { 78 | "jquery": { 79 | "exports": "jQuery" 80 | }, 81 | "jquery-ui": { 82 | "depends": "jquery", 83 | "exports": null 84 | }, 85 | "angular": { 86 | "exports": "angular", 87 | "depends": "jQuery" 88 | }, 89 | "ng-file-upload": { 90 | "exports": "angular.module('ngFileUpload').name" 91 | }, 92 | "angular-animate": { 93 | "exports": "angular.module('ngAnimate').name" 94 | }, 95 | "angular-bootstrap": { 96 | "exports": "angular.module('ui.bootstrap').name" 97 | }, 98 | "angular-busy": { 99 | "exports": "angular.module('cgBusy').name" 100 | }, 101 | "angular-input-stars": { 102 | "exports": "angular.module('angular-input-stars').name" 103 | }, 104 | "angular-resource": { 105 | "exports": "angular.module('ngResource').name" 106 | }, 107 | "angular-sanitize": { 108 | "exports": "angular.module('ngSanitize').name" 109 | }, 110 | "angular-scroll": { 111 | "exports": "angular.module('duScroll').name" 112 | }, 113 | "angular-strap": { 114 | "exports": "angular.module('mgcrea.ngStrap').name" 115 | }, 116 | "angular-ui-date": { 117 | "depends": [ 118 | "angular", 119 | "jquery-ui" 120 | ], 121 | "exports": "null" 122 | }, 123 | "angular-ui-router": { 124 | "depends": [ 125 | "angular" 126 | ], 127 | "exports": null 128 | } 129 | }, 130 | "browserify": { 131 | "transform": [ 132 | "browserify-shim" 133 | ] 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /views/directiveViews/form/submit-form.client.view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 42 | 43 | 44 |
46 |
47 |
50 | 51 |
57 | 58 | 59 | 60 |
61 | 62 | 63 |
64 |
65 | 66 | 67 |
71 | 72 |
75 | {{ 'COMPLETING_NEEDED' | translate:translateAdvancementData }} 76 |
77 | 78 | 90 | 91 | 99 | 100 | 105 |
106 | 107 | 147 |
148 | 149 | 150 | 166 | -------------------------------------------------------------------------------- /demo/dist/form.css: -------------------------------------------------------------------------------- 1 | .container.admin-form,section.content>section>section.container{margin-top:70px}.admin-form .panel-heading a:hover,.current-fields .tool-panel>.panel-default .panel-heading a:hover{text-decoration:none}.panel-default.startPage{border-style:dashed;border-color:#a9a9a9;border-width:3px}.busy-updating-wrapper{text-align:center;font-size:20px;position:fixed;bottom:0;right:55px;z-index:1}.busy-submitting-wrapper{position:fixed;top:50%;left:0;right:0;bottom:0}.form-item,.letter,div.form-fields{position:relative}.dropzone h4.panel-title{height:17px;overflow:hidden}.public-form input,.public-form textarea{background-color:rgba(0,0,0,0);border:2px dashed #ddd!important}.public-form input:focus,.public-form textarea:focus{border:2px dashed #ddd!important;outline:0}.public-form input.no-border,.public-form textarea.no-border{border:none!important}section.content p.breakwords{word-break:break-all}.btn{border:1px solid #c6c6c6}.btn[type=submit]{font-size:1.5em;padding:.35em 1.2em}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;font-size:18px;font-weight:400}.input-block{display:block;width:100%}.modal-footer input[type=text]{min-height:34px;padding:7px 8px;font-size:13px;color:#333;vertical-align:middle;background-color:#fff;background-repeat:no-repeat;background-position:right 8px center;border:1px solid #ccc;border-radius:3px;box-shadow:inset 0 1px 2px rgba(0,0,0,.075)}.modal-footer input[type=text]:focus{outline:0}.modal-body>.modal-body-alert{color:#796620;background-color:#f8eec7;border-color:#f2e09a;margin:-16px -15px 15px;padding:10px 15px;border-style:solid;border-width:1px 0}div.form-fields{padding-top:35vh}.letter{display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;width:16px;padding:0;height:17px;font-size:12px;line-height:19px;border:1px solid #000;border:1px solid rgba(0,0,0,.2);margin-right:7px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;text-align:center;font-weight:700}div.form-submitted>.field.row{padding-bottom:2%;margin-top:35vh}div.form-submitted>.field.row>div{font-size:1.7em}form .accordion-edit{width:inherit}.ui-datepicker.ui-widget{z-index:99!important}form .row.field{padding:1em 0 0;width:inherit}form .row.field>.field-title{margin-top:.5em;font-size:1.2em;padding-bottom:1.8em;width:inherit}form .row.field>.field-input{font-size:1.4em;color:#777}form.submission-form .row.field.statement>.field-title{font-size:1.7em}form.submission-form .row.field.statement>.field-input{font-size:1em;color:#ddd}form.submission-form .select.radio>.field-input input,form.submission-form .select>.field-input input{width:20%}form.submission-form .field.row.radio .btn.activeBtn{background-color:#000!important;background-color:rgba(0,0,0,.7)!important;color:#fff}form.submission-form .field.row.radio .btn{margin-right:1.2em}form.submission-form .select>.field-input .btn{text-align:left;margin-bottom:.7em}form.submission-form .select>.field-input .btn>span{font-size:1.1em}form .field-input>textarea{padding:.45em .9em;width:100%;line-height:160%}form .field-input>input.hasDatepicker{padding:.45em .9em;width:50%;line-height:160%}form .field-input>input.text-field-input{padding:.45em .9em;width:100%;line-height:160%}form .required-error{color:#ddd;font-size:.8em}form .row.field.dropdown>.field-input input{height:34px;border-width:0 0 2px;border-radius:5px}form .row.field.dropdown>.field-input input:focus{border:none}form .row.field.dropdown>.field-input .ui-select-match{border:0 solid grey;border-width:0 0 2px;border-radius:5px}form .dropdown>.field-input .ui-select-choices-row-inner{border-radius:3px;margin:5px;padding:10px;background-color:rgba(0,0,0,.05)}form .dropdown>.field-input .ui-select-choices-row-inner.active,form .dropdown>.field-input .ui-select-choices-row-inner.active:focus{background-color:rgba(0,0,0,.1)}.config-form{max-width:100%}.config-form>.row{padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}div.config-form .row.field{padding-top:1.5em}div.config-form>.row>.container:nth-of-type(odd){border-right:1px #ddd solid}div.config-form.design>.row>.container:nth-of-type(odd){border-right:none}div.config-form .row>.field-input{padding-left:.1em}div.config-form .row>.field-input label{padding-left:1.3em;display:block}.admin-form>.page-header{padding-bottom:0;margin-bottom:40px}.admin-form>.page-header h1{margin-bottom:0;margin-top:0}.admin-form>.page-header>.col-xs-3{padding-top:1.4em}.admin-form .form-controls .row{padding:5px}.admin-form .page-header{border:none}.admin-form .tab-content{padding-top:3em}.admin-form .panel-heading{background-color:#f1f1f1}.admin-form .panel-heading:hover{background-color:#fff;cursor:pointer}.current-fields .panel-body .row.description textarea,.current-fields .panel-body .row.question input[type=text]{width:100%}.current-fields .panel-body .row.options input[type=text]{width:80%}.current-fields .tool-panel>.panel-default:hover{border-color:#9d9d9d;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading{background-color:#fff;color:#9d9d9d!important}.current-fields .tool-panel>.panel-default .panel-heading:hover{background-color:#eee;color:#000!important;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading a{color:inherit}.submissions-table .table-outer.row{margin:1.5em 0 2em!important}.submissions-table .table-outer .col-xs-12{padding-left:0!important;border:1px solid #ddd;overflow-x:scroll;border-radius:3px}.submissions-table .table>thead>tr>th{min-width:8em}.submissions-table .table>tbody>tr.selected{background-color:#efefef}.admin-form .add-field{background-color:#ddd;padding:0 2%;border-radius:3px}.admin-form .add-field .col-xs-6{padding:.25em .4em}.admin-form .add-field .col-xs-6 .panel-heading{border-width:1px;border-style:solid;border-color:#bbb;border-radius:4px}.admin-form .oscar-field-select{margin:10px 0}.view-form-btn.span{padding-right:.6em}.status-light.status-light-off{color:#BE0000}.status-light.status-light-on{color:#3C0}section.public-form{padding:0 10%}section.public-form .form-submitted{height:100vh}section.public-form .btn{border:1px solid}.form-item{text-align:center;border-bottom:6px inset #ccc;background-color:#eee;width:180px;height:215px;margin-bottom:45px}.form-item.create-new input[type=text]{width:inherit;color:#000;border:none}.form-item.create-new{background-color:#838383;color:#fff}.form-item.create-new.new-form{background-color:#ff8383;z-index:11}.form-item.create-new.new-form:hover{background-color:#ff6464}.form-item.new-form input[type=text]{margin-top:.2em;width:inherit;color:#000;border:none;padding:.3em .6em}.form-item.new-form .custom-select{margin-top:.2em}.form-item.new-form .custom-select select{background-color:#fff}.form-item.new-form .details-row{margin-top:1em}.form-item.new-form .details-row.submit{margin-top:1.7em}.form-item.new-form .details-row.submit .btn{font-size:.95em}.form-item.new-form .title-row{margin-top:1em;top:0}.overlay{position:fixed;top:0;left:0;height:100%;width:100%;background-color:#000;background-color:rgba(0,0,0,.5);z-index:10}.overlay.submitform{background-color:#fff;background-color:rgba(256,256,256,.8)}.activeField,.activeField input{background-color:transparent}.field-directive{z-index:9;padding:10% 10% 10% 0;border:25px solid transparent;position:relative}.activeField{z-index:11;position:relative}.activeField.field-directive{display:inline-block;border-radius:7px;width:100%;border:25px solid transparent}.form-item.create-new:hover,.form-item:hover{border-bottom:8px inset #ccc;background-color:#d9d9d9}.form-item.create-new:hover{background-color:#515151}.form-item>.row.footer{position:absolute;bottom:0;left:30%}.form-item .title-row{position:relative;top:15px;padding-top:3em;padding-bottom:3.65em}.form-item .title-row h4{font-size:1.3em}.form-item.create-new .title-row{padding:0}.form-item.create-new .title-row h4{font-size:7em}.form-item .details-row{margin-top:3.2em}.form-item .details-row small{font-size:.6em}.form-item.create-new .details-row small{font-size:.95em} -------------------------------------------------------------------------------- /dist/form.css: -------------------------------------------------------------------------------- 1 | .container.admin-form,section.content>section>section.container{margin-top:70px}.admin-form .panel-heading a:hover,.current-fields .tool-panel>.panel-default .panel-heading a:hover{text-decoration:none}.panel-default.startPage{border-style:dashed;border-color:#a9a9a9;border-width:3px}.busy-updating-wrapper{text-align:center;font-size:20px;position:fixed;bottom:0;right:55px;z-index:1}.busy-submitting-wrapper{position:fixed;top:50%;left:0;right:0;bottom:0}.dropzone h4.panel-title{height:17px;overflow:hidden}.public-form input,.public-form textarea{background-color:#000;border:2px dashed #ddd!important}.public-form input:focus,.public-form textarea:focus{border:2px dashed #ddd!important;outline:0}.public-form input.ng-valid,.public-form textarea.ng-valid{border-color:#20FF20!important;border-style:solid!important;border-width:3px!important}.public-form input.ng-invalid.ng-dirty,.public-form textarea.ng-invalid.ng-dirty{border-color:#FA787E!important;border-style:solid!important;border-width:3px!important}section.content p.breakwords{word-break:break-all}.btn{border:1px solid #c6c6c6}.btn[type=submit]{font-size:1.5em;padding:.35em 1.2em}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;font-size:18px;font-weight:400}.input-block{display:block;width:100%}.modal-footer input[type=text]{min-height:34px;padding:7px 8px;font-size:13px;color:#333;vertical-align:middle;background-color:#fff;background-repeat:no-repeat;background-position:right 8px center;border:1px solid #ccc;border-radius:3px;box-shadow:inset 0 1px 2px rgba(0,0,0,.075)}.modal-footer input[type=text]:focus{outline:0}.modal-body>.modal-body-alert{color:#796620;background-color:#f8eec7;border-color:#f2e09a;margin:-16px -15px 15px;padding:10px 15px;border-style:solid;border-width:1px 0}div.form-fields{position:relative;padding-top:35vh}.letter{position:relative;display:-moz-inline-stack;display:inline-block;vertical-align:top;zoom:1;width:16px;padding:0;height:17px;font-size:12px;line-height:19px;border:1px solid #000;border:1px solid rgba(0,0,0,.2);margin-right:7px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;text-align:center;font-weight:700}div.form-submitted>.field.row{padding-bottom:2%;margin-top:35vh}div.form-submitted>.field.row>div{font-size:1.7em}form .accordion-edit{width:inherit}.ui-datepicker.ui-widget{z-index:99!important}form .row.field .field-number{margin-right:.5em}form .row.field{padding:1em 0 0;width:inherit}form .row.field>.field-title{margin-top:.5em;font-size:1.2em;padding-bottom:1.8em;width:inherit}form .row.field>.field-input{font-size:1.4em;color:#777}form.submission-form .row.field.statement>.field-title{font-size:1.7em}form.submission-form .row.field.statement>.field-input{font-size:1em;color:#ddd}form.submission-form .select.radio>.field-input input,form.submission-form .select>.field-input input{width:20%}form.submission-form .field.row.radio .btn.activeBtn{background-color:#000!important;background-color:rgba(0,0,0,.7)!important;color:#fff}form.submission-form .field.row.radio .btn{margin-right:1.2em}form.submission-form .select>.field-input .btn{text-align:left;margin-bottom:.7em}form.submission-form .select>.field-input .btn>span{font-size:1.1em}form .field-input>textarea{padding:.45em .9em;width:100%;line-height:160%}form .field-input>input.hasDatepicker{padding:.45em .9em;width:50%;line-height:160%}form .field-input>input.text-field-input{padding:.45em .9em;width:100%;line-height:160%}form .required-error{color:#ddd;font-size:.8em}form .row.field.dropdown>.field-input input{height:34px;border-width:0 0 2px;border-radius:5px}form .row.field.dropdown>.field-input input:focus{border:none}form .dropdown>.field-input .ui-select-choices-row-inner{border-radius:3px;margin:5px;padding:10px;background-color:#000;background-color:rgba(0,0,0,.05)}form .dropdown>.field-input .ui-select-choices-row-inner.active,form .dropdown>.field-input .ui-select-choices-row-inner.active:focus{background-color:#000;background-color:rgba(0,0,0,.1)}.config-form{max-width:100%}.config-form>.row{padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}div.config-form .row.field{padding-top:1.5em}div.config-form>.row>.container:nth-of-type(odd){border-right:1px #ddd solid}div.config-form.design>.row>.container:nth-of-type(odd){border-right:none}div.config-form .row>.field-input{padding-left:.1em}div.config-form .row>.field-input label{padding-left:1.3em;display:block}.admin-form>.page-header{padding-bottom:0;margin-bottom:40px}.admin-form>.page-header h1{margin-bottom:0;margin-top:0}.admin-form>.page-header>.col-xs-3{padding-top:1.4em}.admin-form .form-controls .row{padding:5px}.admin-form .page-header{border:none}.admin-form .tab-content{padding-top:3em}.admin-form .panel-heading{background-color:#f1f1f1;position:relative!important}.admin-form .panel-heading:hover{background-color:#fff;cursor:pointer}.current-fields .panel-body .row.description textarea,.current-fields .panel-body .row.question input[type=text]{width:100%}.current-fields .panel-body .row.options input[type=text]{width:80%}.ui-select-choices.ui-select-dropdown{top:2.5em!important}.ui-select-toggle{box-shadow:none!important;border:none!important}.current-fields .tool-panel>.panel-default:hover{border-color:#9d9d9d;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading{background-color:#fff;color:#9d9d9d!important}.current-fields .tool-panel>.panel-default .panel-heading:hover{background-color:#eee;color:#000!important;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading a{color:inherit}.submissions-table .table-outer.row{margin:1.5em 0 2em!important}.submissions-table .table-outer .col-xs-12{padding-left:0!important;border:1px solid #ddd;overflow-x:scroll;border-radius:3px}.submissions-table .table>thead>tr>th{min-width:8em}.submissions-table .table>tbody>tr.selected{background-color:#efefef}.admin-form .add-field{background-color:#ddd;padding:0 2%;border-radius:3px}.admin-form .add-field .col-xs-6{padding:.25em .4em}.admin-form .add-field .col-xs-6 .panel-heading{border-width:1px;border-style:solid;border-color:#bbb;border-radius:4px}.admin-form .oscar-field-select{margin:10px 0}.view-form-btn.span{padding-right:.6em}.status-light.status-light-off{color:#BE0000}.status-light.status-light-on{color:#3C0}section.public-form{padding:0 10%}section.public-form .form-submitted{height:100vh}section.public-form .btn{border:1px solid}.form-item{text-align:center;border-bottom:6px inset #ccc;background-color:#eee;width:180px;position:relative;height:215px;margin-bottom:45px}.form-item.create-new input[type=text]{width:inherit;color:#000;border:none}.form-item.create-new{background-color:#838383;color:#fff}.form-item.create-new.new-form{background-color:#ff8383;z-index:11}.form-item.create-new.new-form:hover{background-color:#ff6464}.form-item.new-form input[type=text]{margin-top:.2em;width:inherit;color:#000;border:none;padding:.3em .6em}.form-item.new-form .custom-select{margin-top:.2em}.form-item.new-form .custom-select select{background-color:#fff}.form-item.new-form .details-row{margin-top:1em}.form-item.new-form .details-row.submit{margin-top:1.7em}.form-item.new-form .details-row.submit .btn{font-size:.95em}.form-item.new-form .title-row{margin-top:1em;top:0}.overlay{position:fixed;top:0;left:0;height:100%;width:100%;background-color:#000;background-color:rgba(0,0,0,.5);z-index:10}.overlay.submitform{background-color:#fff;background-color:rgba(256,256,256,.8)}.activeField,.activeField input{background-color:transparent}.field-directive{z-index:9;padding:10% 10% 10% 0;border:25px solid transparent;position:relative}.activeField{z-index:11;position:relative}.activeField.field-directive{display:inline-block;border-radius:7px;width:100%;border:25px solid transparent}.form-item.create-new:hover,.form-item:hover{border-bottom:8px inset #ccc;background-color:#d9d9d9}.form-item.create-new:hover{background-color:#515151}.form-item>.row.footer{position:absolute;bottom:0;left:30%}.form-item .title-row{position:relative;top:15px;padding-top:3em;padding-bottom:3.65em}.form-item .title-row h4{font-size:1.3em}.form-item.create-new .title-row{padding:0}.form-item.create-new .title-row h4{font-size:7em}.form-item .details-row{margin-top:3.2em}.form-item .details-row small{font-size:.6em}.form-item.create-new .details-row small{font-size:.95em} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Tellform 2 | 3 | This module gives you the standalone front-end of tellform. It handles form rendering and form ui. For you to use this module you must have an API endpoint, such as [FormKeep](https://formkeep.com) or [Formlets](https://formlets.org). 4 | 5 | ``` 6 |
7 | 8 |
9 | ``` 10 | 11 | ## Installation 12 | 13 | via bower 14 | 15 | ```bower install angular-tellform``` 16 | 17 | via npm 18 | 19 | ```npm install angular-tellform``` 20 | 21 | ## Quick Example 22 | 23 | This serves as a quick guide to setting up and using angular-tellform in a small angular project. If you are looking for API documentation, please refer to the next section instead. 24 | 25 | ### Step 1. Add as a dependency 26 | First add *angular-tellform* as a dependency to your angular module/app. 27 | 28 | _app.js_ 29 | ``` 30 | 'use strict'; 31 | 32 | angular.module('myModule', ['angular-tellform']); 33 | ``` 34 | 35 | ### Step 2. Set the form data 36 | Set $scope.form in your controller to the JSON object of your form. 37 | 38 | *app.js* 39 | ``` 40 | ... 41 | 42 | angular.module('myModule').controller('MyFormCtrl', function MyFormCtrl($scope) { 43 | 44 | $scope.form = { 45 | "title": "Job Application Example", 46 | "design": { 47 | "colors": { 48 | "buttonTextColor": "#5C780A", 49 | "buttonColor": "#C5F044", 50 | "answerColor": "#333", 51 | "questionColor": "#6D8524", 52 | "backgroundColor": "#E4F8A8" 53 | } 54 | }, 55 | "hideFooter": false, 56 | "startPage": { 57 | "buttons": [], 58 | "introButtonText": "Apply Now", 59 | "introTitle": "We're looking for a great Growth Hacker", 60 | "showStart": true 61 | }, 62 | "form_fields": [{ 63 | "lastModified": "2016-04-22T23:02:46.017Z", 64 | "title": "How would you rate your experience and knowledge of running split tests?", 65 | "fieldType": "rating", 66 | "fieldValue": 1, 67 | "_id": "571940102aa1f3ff5e205b5d", 68 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 69 | "deletePreserved": false, 70 | "disabled": false, 71 | "required": true, 72 | "ratingOptions": { 73 | "shape": "thumbs-up", 74 | "steps": 5 75 | }, 76 | "description": "" 77 | }, { 78 | "lastModified": "2016-04-22T23:02:46.017Z", 79 | "title": "And how would you rate your creativity and ability to find innovative solutions?", 80 | "fieldType": "rating", 81 | "fieldValue": 1, 82 | "_id": "571940222aa1f3ff5e205b5e", 83 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 84 | "deletePreserved": false, 85 | "disabled": false, 86 | "required": true, 87 | "ratingOptions": { 88 | "shape": "thumbs-up", 89 | "steps": 5 90 | }, 91 | "description": "" 92 | }], 93 | "language": "english" 94 | }; 95 | 96 | $scope.endPoint="https://myurl.com/endpoint"; 97 | 98 | }); 99 | ``` 100 | 101 | ### Step 3. Modifying the view 102 | Then add the angular-tellform directive to your controller's html view 103 | 104 | *view.html* 105 | ``` 106 | ... 107 | 108 |
109 | 110 |
111 | 112 | ... 113 | ``` 114 | 115 | After this you will have a form displayed inside your **section** element. Since the directive is bounded to $scope.form, if you want to update the form all you need to do is change $scope.form to a new value. 116 | 117 | ## Form JSON Spec 118 | 119 | A typical JSON object for form data will look like this: 120 | ``` 121 | { 122 | "title": "Job Application Example", 123 | "design": { 124 | "colors": { 125 | "buttonTextColor": "#5C780A", 126 | "buttonColor": "#C5F044", 127 | "answerColor": "#333", 128 | "questionColor": "#6D8524", 129 | "backgroundColor": "#E4F8A8" 130 | } 131 | }, 132 | "hideFooter": false, 133 | "startPage": { 134 | "buttons": [], 135 | "introButtonText": "Apply Now", 136 | "introTitle": "We're looking for a great Growth Hacker", 137 | "showStart": true 138 | }, 139 | "form_fields": [{ 140 | "lastModified": "2016-04-22T23:02:46.017Z", 141 | "title": "How would you rate your experience and knowledge of running split tests?", 142 | "fieldType": "rating", 143 | "fieldValue": 1, 144 | "_id": "571940102aa1f3ff5e205b5d", 145 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 146 | "deletePreserved": false, 147 | "disabled": false, 148 | "required": true, 149 | "ratingOptions": { 150 | "shape": "thumbs-up", 151 | "steps": 5 152 | }, 153 | "description": "" 154 | }, { 155 | "lastModified": "2016-04-22T23:02:46.017Z", 156 | "title": "And how would you rate your creativity and ability to find innovative solutions?", 157 | "fieldType": "rating", 158 | "fieldValue": 1, 159 | "_id": "571940222aa1f3ff5e205b5e", 160 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 161 | "deletePreserved": false, 162 | "disabled": false, 163 | "required": true, 164 | "ratingOptions": { 165 | "shape": "thumbs-up", 166 | "steps": 5 167 | }, 168 | "description": "" 169 | }], 170 | "language": "english" 171 | ``` 172 | 173 | ### title 174 | 175 | **Required** 176 | 177 | Type: `String` 178 | 179 | The title of the form 180 | 181 | * Must be unique. 182 | * Consecutive dashes or dots not allowed. 183 | 184 | 185 | ### design 186 | 187 | **Required** 188 | 189 | Type: `Object` 190 | 191 | The object containing the CSS styles and colors for the form 192 | 193 | #### design.colors.buttonTextColor 194 | 195 | **Required** 196 | 197 | Type: `String` 198 | 199 | The hex color of the button text 200 | 201 | #### design.colors.buttonColor 202 | 203 | **Required** 204 | 205 | Type: `String` 206 | 207 | The hex color of the button background 208 | 209 | #### colors.answerColor 210 | 211 | **Required** 212 | 213 | Type: `String` 214 | 215 | The hex color of the answer (input field) text. 216 | 217 | #### design.colors.questionColor 218 | 219 | **Required** 220 | 221 | Type: `String` 222 | 223 | The hex color of the question text. 224 | 225 | #### design.colors.backgroundColor 226 | 227 | **Required** 228 | 229 | Type: `String` 230 | 231 | The hex color of the form background. 232 | 233 | ### hideFooter 234 | *Recommended* 235 | 236 | Type: `Boolean` 237 | 238 | If it is true, form footer will be hidden and vice-versa if it is false 239 | 240 | ### startPage 241 | **Required** 242 | 243 | Type: `Object` 244 | 245 | Stores form's startPage data 246 | 247 | ``` 248 | "startPage": { 249 | "buttons": [], //Array of Buttons 250 | "introButtonText": "Apply Now", //Continue button text 251 | "introTitle": "We're looking for a great Growth Hacker", //Intro title 252 | "showStart": true //Hides Start Page if false 253 | } 254 | ``` 255 | 256 | ### form_fields 257 | 258 | **Required** 259 | 260 | Type: `Array` of `Object` 261 | 262 | The array of form fields that your form will display. 263 | 264 | ### language 265 | 266 | *Reccomended* 267 | 268 | Type: `String` 269 | 270 | Specifies the language that your form will be rendered in 271 | 272 | * Must be either `english`, `spanish`, `french`, `german` or `italian` 273 | * Defaults to `english` if specified 274 | 275 | ## Development 276 | 277 | First clone the repository and run `bower install`. 278 | 279 | When you want to test your code, run 280 | ``` 281 | grunt 282 | bower install 283 | ``` 284 | and then open the demo/index.html file for an example form. 285 | 286 | ## Contributing 287 | 288 | When submitting a PR, please make sure to delete your /dist directory. 289 | 290 | ## License 291 | 292 | Uses MIT License. See LICENSE.md for full license terms. 293 | -------------------------------------------------------------------------------- /directives/submit-form.client.directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angular-tellform').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'Auth', 'SendVisitorData', 4 | function ($http, TimeCounter, $filter, $rootScope, Auth, SendVisitorData) { 5 | return { 6 | templateUrl: 'modules/forms/base/views/directiveViews/form/submit-form.client.view.html', 7 | restrict: 'E', 8 | scope: { 9 | myform:'=', 10 | formEndPoint: '=' 11 | }, 12 | controller: function($document, $window, $scope){ 13 | $scope.authentication = $rootScope.authentication; 14 | $scope.noscroll = false; 15 | $scope.forms = {}; 16 | 17 | var form_fields_count = $scope.myform.visible_form_fields.filter(function(field){ 18 | if(field.fieldType === 'statement' || field.fieldType === 'rating'){ 19 | return false; 20 | } 21 | return true; 22 | }).length; 23 | 24 | var nb_valid = $filter('formValidity')($scope.myform); 25 | $scope.translateAdvancementData = { 26 | done: nb_valid, 27 | total: form_fields_count, 28 | answers_not_completed: form_fields_count - nb_valid 29 | }; 30 | 31 | $scope.reloadForm = function(){ 32 | //Reset Form 33 | $scope.myform.submitted = false; 34 | $scope.myform.form_fields = _.chain($scope.myform.visible_form_fields).map(function(field){ 35 | field.fieldValue = ''; 36 | return field; 37 | }).value(); 38 | 39 | $scope.loading = false; 40 | $scope.error = ''; 41 | 42 | $scope.selected = { 43 | _id: '', 44 | index: 0 45 | }; 46 | $scope.setActiveField($scope.myform.visible_form_fields[0]._id, 0, false); 47 | 48 | //console.log($scope.selected); 49 | //Reset Timer 50 | TimeCounter.restartClock(); 51 | }; 52 | 53 | //Fire event when window is scrolled 54 | $window.onscroll = function(){ 55 | $scope.scrollPos = document.body.scrollTop || document.documentElement.scrollTop || 0; 56 | var elemBox = document.getElementsByClassName('activeField')[0].getBoundingClientRect(); 57 | $scope.fieldTop = elemBox.top; 58 | $scope.fieldBottom = elemBox.bottom; 59 | 60 | //console.log($scope.forms.myForm); 61 | var field_id; 62 | var field_index; 63 | 64 | if(!$scope.noscroll){ 65 | //Focus on submit button 66 | if( $scope.selected.index === $scope.myform.visible_form_fields.length-1 && $scope.fieldBottom < 200){ 67 | field_index = $scope.selected.index+1; 68 | field_id = 'submit_field'; 69 | $scope.setActiveField(field_id, field_index, false); 70 | } 71 | //Focus on field above submit button 72 | else if($scope.selected.index === $scope.myform.visible_form_fields.length){ 73 | if($scope.fieldTop > 200){ 74 | field_index = $scope.selected.index-1; 75 | field_id = $scope.myform.visible_form_fields[field_index]._id; 76 | $scope.setActiveField(field_id, field_index, false); 77 | } 78 | }else if( $scope.fieldBottom < 0){ 79 | field_index = $scope.selected.index+1; 80 | field_id = $scope.myform.visible_form_fields[field_index]._id; 81 | $scope.setActiveField(field_id, field_index, false); 82 | }else if ( $scope.selected.index !== 0 && $scope.fieldTop > 0) { 83 | field_index = $scope.selected.index-1; 84 | field_id = $scope.myform.visible_form_fields[field_index]._id; 85 | $scope.setActiveField(field_id, field_index, false); 86 | } 87 | //console.log('$scope.selected.index: '+$scope.selected.index); 88 | //console.log('scroll pos: '+$scope.scrollPos+' fieldTop: '+$scope.fieldTop+' fieldBottom: '+$scope.fieldBottom); 89 | $scope.$apply(); 90 | } 91 | }; 92 | 93 | /* 94 | ** Field Controls 95 | */ 96 | var getActiveField = function(){ 97 | if($scope.selected === null){ 98 | console.error('current active field is null'); 99 | throw new Error('current active field is null'); 100 | } 101 | 102 | if($scope.selected._id === 'submit_field') { 103 | return $scope.myform.form_fields.length - 1; 104 | } else { 105 | return $scope.selected.index; 106 | } 107 | }; 108 | 109 | $scope.setActiveField = $rootScope.setActiveField = function(field_id, field_index, animateScroll) { 110 | if($scope.selected === null || $scope.selected._id === field_id){ 111 | //console.log('not scrolling'); 112 | //console.log($scope.selected); 113 | return; 114 | } 115 | //console.log('field_id: '+field_id); 116 | //console.log('field_index: '+field_index); 117 | //console.log($scope.selected); 118 | 119 | $scope.selected._id = field_id; 120 | $scope.selected.index = field_index; 121 | 122 | var nb_valid = $filter('formValidity')($scope.myform); 123 | $scope.translateAdvancementData = { 124 | done: nb_valid, 125 | total: form_fields_count, 126 | answers_not_completed: form_fields_count - nb_valid 127 | }; 128 | 129 | if(animateScroll){ 130 | $scope.noscroll=true; 131 | setTimeout(function() { 132 | $document.scrollToElement(angular.element('.activeField'), -10, 200).then(function() { 133 | $scope.noscroll = false; 134 | setTimeout(function() { 135 | if (document.querySelectorAll('.activeField .focusOn').length) { 136 | //Handle default case 137 | document.querySelectorAll('.activeField .focusOn')[0].focus(); 138 | } else if(document.querySelectorAll('.activeField input').length) { 139 | //Handle case for rating input 140 | document.querySelectorAll('.activeField input')[0].focus(); 141 | } else { 142 | //Handle case for dropdown input 143 | document.querySelectorAll('.activeField .selectize-input')[0].focus(); 144 | } 145 | }); 146 | }); 147 | }); 148 | }else { 149 | setTimeout(function() { 150 | if (document.querySelectorAll('.activeField .focusOn')[0]) { 151 | //FIXME: DAVID: Figure out how to set focus without scroll movement in HTML Dom 152 | document.querySelectorAll('.activeField .focusOn')[0].focus(); 153 | } else { 154 | document.querySelectorAll('.activeField input')[0].focus(); 155 | } 156 | }); 157 | } 158 | 159 | SendVisitorData.send($scope.myform, getActiveField(), TimeCounter.getTimeElapsed()); 160 | }; 161 | 162 | $rootScope.nextField = $scope.nextField = function(){ 163 | //console.log('nextfield'); 164 | //console.log($scope.selected.index); 165 | //console.log($scope.myform.visible_form_fields.length-1); 166 | var selected_index, selected_id; 167 | if($scope.selected.index < $scope.myform.visible_form_fields.length-1){ 168 | selected_index = $scope.selected.index+1; 169 | selected_id = $scope.myform.visible_form_fields[selected_index]._id; 170 | $rootScope.setActiveField(selected_id, selected_index, true); 171 | } else if($scope.selected.index === $scope.myform.visible_form_fields.length-1) { 172 | //console.log('Second last element'); 173 | selected_index = $scope.selected.index+1; 174 | selected_id = 'submit_field'; 175 | $rootScope.setActiveField(selected_id, selected_index, true); 176 | } 177 | }; 178 | 179 | $rootScope.prevField = $scope.prevField = function(){ 180 | if($scope.selected.index > 0){ 181 | var selected_index = $scope.selected.index - 1; 182 | var selected_id = $scope.myform.visible_form_fields[selected_index]._id; 183 | $scope.setActiveField(selected_id, selected_index, true); 184 | } 185 | }; 186 | 187 | /* 188 | ** Form Display Functions 189 | */ 190 | $scope.exitStartPage = function(){ 191 | $scope.myform.startPage.showStart = false; 192 | if($scope.myform.visible_form_fields.length > 0){ 193 | $scope.selected._id = $scope.myform.visible_form_fields[0]._id; 194 | } 195 | }; 196 | 197 | $rootScope.goToInvalid = $scope.goToInvalid = function() { 198 | document.querySelectorAll('.ng-invalid.focusOn')[0].focus(); 199 | }; 200 | 201 | $rootScope.submitForm = $scope.submitForm = function() { 202 | 203 | var _timeElapsed = TimeCounter.stopClock(); 204 | $scope.loading = true; 205 | 206 | var form = _.cloneDeep($scope.myform); 207 | 208 | form.timeElapsed = _timeElapsed; 209 | 210 | form.percentageComplete = $filter('formValidity')($scope.myform) / $scope.myform.visible_form_fields.length * 100; 211 | delete form.visible_form_fields; 212 | 213 | for(var i=0; i < $scope.myform.form_fields.length; i++){ 214 | if($scope.myform.form_fields[i].fieldType === 'dropdown' && !$scope.myform.form_fields[i].deletePreserved){ 215 | $scope.myform.form_fields[i].fieldValue = $scope.myform.form_fields[i].fieldValue.option_value; 216 | } 217 | } 218 | 219 | setTimeout(function () { 220 | $scope.submitPromise = $http.post($scope.formEndPoint, form) 221 | .success(function (data, status, headers) { 222 | console.log($scope.myform.form_fields[0]); 223 | $scope.myform.submitted = true; 224 | $scope.loading = false; 225 | SendVisitorData.send($scope.myform, getActiveField(), _timeElapsed); 226 | }) 227 | .error(function (error) { 228 | $scope.loading = false; 229 | console.error(error); 230 | $scope.error = error.message; 231 | }); 232 | }, 500); 233 | }; 234 | 235 | //Reload our form 236 | $scope.reloadForm(); 237 | } 238 | }; 239 | } 240 | ]); 241 | -------------------------------------------------------------------------------- /css/form.css: -------------------------------------------------------------------------------- 1 | .panel-default.startPage { 2 | border-style: dashed; 3 | border-color: #a9a9a9; 4 | border-width:3px; 5 | } 6 | 7 | .busy-updating-wrapper { 8 | text-align: center; 9 | font-size: 20px; 10 | position: fixed; 11 | bottom: 0; 12 | right: 55px; 13 | z-index: 1; 14 | } 15 | 16 | .busy-submitting-wrapper { 17 | position: fixed; 18 | top: 50%; 19 | left: 0; 20 | right: 0; 21 | bottom: 0; 22 | } 23 | 24 | .dropzone h4.panel-title { 25 | height: 17px; 26 | overflow: hidden; 27 | } 28 | 29 | .container.admin-form { 30 | margin-top: 70px; 31 | } 32 | 33 | .public-form input, .public-form textarea { 34 | background-color: rgba(0,0,0,0); 35 | background-color: #000000; 36 | border: 2px dashed #ddd!important; 37 | } 38 | 39 | .public-form input:focus, .public-form textarea:focus { 40 | border: 2px dashed #ddd!important; 41 | outline: none; 42 | } 43 | 44 | /*.public-form input.no-border.ng-invalid, .public-form textarea.no-border { 45 | border-color: none; 46 | }*/ 47 | .public-form input.ng-valid, .public-form textarea.ng-valid { 48 | border-color: #20FF20!important; 49 | border-style: solid!important; 50 | border-width: 3px!important; 51 | } 52 | 53 | .public-form input.ng-invalid.ng-dirty, .public-form textarea.ng-invalid.ng-dirty { 54 | border-color: #FA787E!important; 55 | border-style: solid!important; 56 | border-width: 3px!important; 57 | } 58 | 59 | section.content p.breakwords { 60 | word-break: break-all; 61 | } 62 | 63 | .btn { 64 | border: 1px solid #c6c6c6; 65 | } 66 | 67 | .btn[type='submit'] { 68 | font-size: 1.5em; 69 | padding: 0.35em 1.2em 0.35em 1.2em; 70 | } 71 | 72 | section.content > section > section.container { 73 | margin-top: 70px; 74 | } 75 | 76 | /* 77 | ** Modal CSS Styles 78 | */ 79 | .modal-header { 80 | padding: 15px; 81 | border-bottom: 1px solid #e5e5e5; 82 | font-size: 18px; 83 | font-weight: normal; 84 | } 85 | .input-block { 86 | display: block; 87 | width: 100%; 88 | } 89 | .modal-footer input[type='text'] { 90 | min-height: 34px; 91 | padding: 7px 8px; 92 | font-size: 13px; 93 | color: #333; 94 | vertical-align: middle; 95 | background-color: #fff; 96 | background-repeat: no-repeat; 97 | background-position: right 8px center; 98 | border: 1px solid #ccc; 99 | border-radius: 3px; 100 | box-shadow: inset 0 1px 2px rgba(0,0,0,0.075); 101 | } 102 | .modal-footer input[type='text']:focus { 103 | outline: 0; 104 | } 105 | .modal-body > .modal-body-alert { 106 | color: #796620; 107 | background-color: #f8eec7; 108 | border-color: #f2e09a; 109 | margin: -16px -15px 15px; 110 | padding: 10px 15px; 111 | border-style: solid; 112 | border-width: 1px 0; 113 | } 114 | 115 | div.form-fields { 116 | position: relative; 117 | padding-top: 35vh; 118 | } 119 | .letter { 120 | position: relative; 121 | display: -moz-inline-stack; 122 | display: inline-block; 123 | vertical-align: top; 124 | zoom: 1; 125 | width: 16px; 126 | padding: 0; 127 | height: 17px; 128 | font-size: 12px; 129 | line-height: 19px; 130 | border: 1px solid #000; 131 | border: 1px solid rgba(0,0,0,.2); 132 | margin-right: 7px; 133 | -webkit-border-radius: 3px; 134 | -moz-border-radius: 3px; 135 | border-radius: 3px; 136 | text-align: center; 137 | font-weight: 700; 138 | } 139 | 140 | div.form-submitted > .field.row { 141 | padding-bottom: 2%; 142 | margin-top: 35vh; 143 | } 144 | div.form-submitted > .field.row > div { 145 | font-size: 1.7em; 146 | } 147 | 148 | /* Styles for accordion */ 149 | form .accordion-edit { 150 | width: inherit; 151 | } 152 | 153 | /*Styles for ui-datepicker*/ 154 | .ui-datepicker.ui-widget { 155 | z-index: 99!important; 156 | } 157 | 158 | form .row.field .field-number { 159 | margin-right: 0.5em; 160 | } 161 | 162 | /* Styles for form submission view (/forms/:formID) */ 163 | form .row.field { 164 | padding: 1em 0 0 0; 165 | width: inherit; 166 | } 167 | form .row.field > .field-title { 168 | margin-top:0.5em; 169 | font-size:1.2em; 170 | padding-bottom: 1.8em; 171 | width: inherit; 172 | } 173 | form .row.field > .field-input { 174 | font-size: 1.4em; 175 | color: #777; 176 | } 177 | form.submission-form .row.field.statement > .field-title { 178 | font-size:1.7em; 179 | } 180 | form.submission-form .row.field.statement > .field-input { 181 | font-size:1em; 182 | color:#ddd; 183 | } 184 | 185 | form.submission-form .select.radio > .field-input input, form.submission-form .select > .field-input input { 186 | width:20%; 187 | } 188 | 189 | form.submission-form .field.row.radio .btn.activeBtn { 190 | background-color: rgb(0,0,0)!important; 191 | background-color: rgba(0,0,0,0.7)!important; 192 | color: white; 193 | } 194 | form.submission-form .field.row.radio .btn { 195 | margin-right:1.2em; 196 | } 197 | 198 | form.submission-form .select > .field-input .btn { 199 | text-align: left; 200 | margin-bottom:0.7em; 201 | } 202 | form.submission-form .select > .field-input .btn > span { 203 | font-size: 1.10em; 204 | } 205 | 206 | /*form.submission-form .field-input > input:focus { 207 | font-size:1em; 208 | }*/ 209 | 210 | form .field-input > textarea{ 211 | padding: 0.45em 0.9em; 212 | width: 100%; 213 | line-height: 160%; 214 | } 215 | 216 | form .field-input > input.hasDatepicker{ 217 | padding: 0.45em 0.9em; 218 | width: 50%; 219 | line-height: 160%; 220 | } 221 | form .field-input > input.text-field-input{ 222 | padding: 0.45em 0.9em; 223 | width: 100%; 224 | line-height: 160%; 225 | } 226 | form .required-error{ 227 | color: #ddd; 228 | font-size:0.8em; 229 | } 230 | 231 | form .row.field.dropdown > .field-input input { 232 | height: 34px; 233 | border-width: 0 0 2px 0; 234 | border-radius: 5px; 235 | } 236 | 237 | form .row.field.dropdown > .field-input input:focus { 238 | border: none; 239 | } 240 | 241 | form .dropdown > .field-input .ui-select-choices-row-inner { 242 | border-radius: 3px; 243 | margin: 5px; 244 | padding: 10px; 245 | background-color: #000000; 246 | background-color: rgba(0,0,0,0.05); 247 | } 248 | 249 | form .dropdown > .field-input .ui-select-choices-row-inner.active, form .dropdown > .field-input .ui-select-choices-row-inner.active:focus { 250 | background-color: #000000; 251 | background-color: rgba(0,0,0,0.1); 252 | } 253 | .config-form { 254 | max-width: 100%; 255 | } 256 | 257 | .config-form > .row { 258 | padding: 19px; 259 | margin-bottom: 20px; 260 | background-color: #f5f5f5; 261 | border: 1px solid #e3e3e3; 262 | border-radius: 4px; 263 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); 264 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); 265 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); 266 | } 267 | 268 | div.config-form .row.field { 269 | padding-top:1.5em; 270 | } 271 | 272 | div.config-form > .row > .container:nth-of-type(odd){ 273 | border-right: 1px #ddd solid; 274 | } 275 | div.config-form.design > .row > .container:nth-of-type(odd){ 276 | border-right: none; 277 | } 278 | 279 | div.config-form .row > .field-input { 280 | padding-left:0.1em; 281 | } 282 | div.config-form .row > .field-input label { 283 | padding-left:1.3em; 284 | display: block; 285 | } 286 | 287 | 288 | /* Styles for form admin view (/forms/:formID/admin) */ 289 | .admin-form > .page-header { 290 | padding-bottom: 0; 291 | margin-bottom: 40px; 292 | } 293 | .admin-form > .page-header h1 { 294 | margin-bottom: 0; 295 | margin-top: 0; 296 | } 297 | .admin-form > .page-header > .col-xs-3 { 298 | padding-top: 1.4em; 299 | } 300 | .admin-form .form-controls .row { 301 | padding: 5px; 302 | } 303 | .admin-form .page-header { 304 | border: none; 305 | } 306 | 307 | /*Styles for admin view tabs */ 308 | .admin-form .tab-content { 309 | padding-top: 3em; 310 | } 311 | 312 | .admin-form .panel-heading { 313 | background-color: #f1f1f1; 314 | position: relative!important; 315 | } 316 | .admin-form .panel-heading:hover { 317 | background-color: #fff; 318 | cursor: pointer; 319 | } 320 | .admin-form .panel-heading a:hover { 321 | text-decoration: none; 322 | } 323 | 324 | .current-fields .panel-body .row.question input[type='text'], .current-fields .panel-body .row.description textarea{ 325 | width: 100%; 326 | } 327 | .current-fields .panel-body .row.options input[type='text'] { 328 | width: 80%; 329 | } 330 | 331 | /*Override Select2 UI*/ 332 | .ui-select-choices.ui-select-dropdown { 333 | top:2.5em!important; 334 | } 335 | .ui-select-toggle { 336 | box-shadow:none!important; 337 | border:none!important; 338 | } 339 | 340 | .current-fields .tool-panel > .panel-default:hover { 341 | border-color: #9d9d9d; 342 | cursor: pointer; 343 | } 344 | 345 | .current-fields .tool-panel > .panel-default .panel-heading { 346 | background-color: #fff; 347 | color: #9d9d9d!important; 348 | } 349 | .current-fields .tool-panel > .panel-default .panel-heading:hover { 350 | background-color: #eee; 351 | color: #000!important; 352 | cursor: pointer; 353 | } 354 | .current-fields .tool-panel > .panel-default .panel-heading a { 355 | color: inherit; 356 | } 357 | .current-fields .tool-panel > .panel-default .panel-heading a:hover{ 358 | text-decoration: none; 359 | } 360 | 361 | /*Styles for submission table*/ 362 | .submissions-table .table-outer.row { 363 | margin: 1.5em 0 2em 0!important; 364 | } 365 | .submissions-table .table-outer .col-xs-12 { 366 | padding-left: 0!important; 367 | border:1px solid #ddd; 368 | overflow-x: scroll; 369 | border-radius:3px; 370 | } 371 | .submissions-table .table > thead > tr > th { 372 | min-width:8em; 373 | } 374 | .submissions-table .table > tbody > tr.selected { 375 | background-color:#efefef; 376 | } 377 | 378 | 379 | /*Styles for add fields tab*/ 380 | .admin-form .add-field { 381 | background-color: #ddd; 382 | padding: 0 2% 0 2%; 383 | border-radius: 3px; 384 | } 385 | .admin-form .add-field .col-xs-6 { 386 | padding: 0.25em 0.4em; 387 | } 388 | .admin-form .add-field .col-xs-6 .panel-heading { 389 | border-width: 1px; 390 | border-style: solid; 391 | border-color: #bbb; 392 | border-radius: 4px; 393 | } 394 | 395 | .admin-form .oscar-field-select { 396 | margin: 10px 0 10px; 397 | } 398 | 399 | .view-form-btn.span { 400 | padding-right:0.6em; 401 | } 402 | .status-light.status-light-off { 403 | color: #BE0000; 404 | } 405 | .status-light.status-light-on { 406 | color: #33CC00; 407 | } 408 | 409 | /* Styles for form list view (/forms) */ 410 | section.public-form { 411 | padding: 0 10% 0 10%; 412 | } 413 | section.public-form .form-submitted { 414 | height: 100vh; 415 | } 416 | 417 | section.public-form .btn { 418 | border: 1px solid; 419 | } 420 | 421 | .form-item { 422 | text-align: center; 423 | border-bottom: 6px inset #ccc; 424 | background-color: #eee; 425 | width: 180px; 426 | /*width:100%;*/ 427 | position: relative; 428 | height: 215px; 429 | /*padding-bottom: 25%;*/ 430 | margin-bottom: 45px; 431 | } 432 | .form-item.create-new input[type='text']{ 433 | width: inherit; 434 | color:black; 435 | border:none; 436 | } 437 | 438 | .form-item.create-new { 439 | background-color: rgb(131,131,131); 440 | color: white; 441 | } 442 | 443 | /*CREATE-NEW FORM MODAL*/ 444 | .form-item.create-new.new-form { 445 | background-color: rgb(300,131,131); 446 | z-index: 11; 447 | } 448 | .form-item.create-new.new-form:hover { 449 | background-color: rgb(300,100,100); 450 | } 451 | .form-item.new-form input[type='text'] { 452 | margin-top:0.2em; 453 | width: inherit; 454 | color:black; 455 | border:none; 456 | padding: 0.3em 0.6em 0.3em 0.6em; 457 | } 458 | .form-item.new-form .custom-select { 459 | margin-top: 0.2em 460 | } 461 | .form-item.new-form .custom-select select { 462 | background-color: white; 463 | } 464 | 465 | 466 | .form-item.new-form .details-row { 467 | margin-top: 1em; 468 | } 469 | .form-item.new-form .details-row.submit { 470 | margin-top: 1.7em; 471 | } 472 | .form-item.new-form .details-row.submit .btn { 473 | font-size: 0.95em; 474 | } 475 | 476 | .form-item.new-form .title-row { 477 | margin-top: 1em; 478 | top:0; 479 | } 480 | 481 | /*Modal overlay (for lightbox effect)*/ 482 | .overlay { 483 | position: fixed; 484 | top: 0; 485 | left: 0; 486 | height: 100%; 487 | width: 100%; 488 | background-color: rgb(0,0,0); 489 | background-color: rgba(0,0,0,0.5); 490 | z-index: 10; 491 | } 492 | .overlay.submitform { 493 | background-color: rgb(256,256,256); 494 | background-color: rgba(256,256,256,0.8); 495 | } 496 | .field-directive { 497 | z-index: 9; 498 | padding: 10% 10% 10% 0; 499 | border: 25px transparent solid; 500 | position: relative; 501 | } 502 | .activeField { 503 | z-index: 11; 504 | position: relative; 505 | background-color: transparent; 506 | } 507 | .activeField.field-directive { 508 | display: inline-block; 509 | border-radius: 7px; 510 | width: 100%; 511 | border: 25px transparent solid; 512 | } 513 | .activeField input { 514 | background-color: transparent; 515 | } 516 | 517 | .form-item:hover, .form-item.create-new:hover { 518 | border-bottom: 8px inset #ccc; 519 | background-color: #d9d9d9; 520 | } 521 | 522 | .form-item.create-new:hover { 523 | background-color: rgb(81,81,81); 524 | } 525 | 526 | .form-item > .row.footer { 527 | position: absolute; 528 | bottom: 0; 529 | left: 30%; 530 | } 531 | 532 | .form-item .title-row{ 533 | position: relative; 534 | top: 15px; 535 | padding-top:3em; 536 | padding-bottom:3.65em; 537 | } 538 | .form-item .title-row h4 { 539 | font-size: 1.3em; 540 | } 541 | 542 | .form-item.create-new .title-row{ 543 | padding: 0; 544 | } 545 | .form-item.create-new .title-row h4 { 546 | font-size: 7em; 547 | } 548 | 549 | .form-item .details-row{ 550 | margin-top: 3.2em; 551 | } 552 | .form-item .details-row small { 553 | font-size: 0.6em; 554 | } 555 | .form-item.create-new .details-row small { 556 | font-size: 0.95em; 557 | } 558 | -------------------------------------------------------------------------------- /demo/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('myModule', ['angular-tellform']); 4 | angular.module('myModule').controller('MyFormCtrl', function MyFormCtrl($scope) { 5 | 6 | $scope.myform = { 7 | "title": "Job Application Example", 8 | "_id": "57193ffa2aa1f3ff5e205b5c", 9 | "design": { 10 | "colors": { 11 | "buttonTextColor": "#5C780A", 12 | "buttonColor": "#C5F044", 13 | "answerColor": "#333", 14 | "questionColor": "#6D8524", 15 | "backgroundColor": "#E4F8A8" 16 | } 17 | }, 18 | "hideFooter": false, 19 | "startPage": { 20 | "buttons": [], 21 | "introButtonText": "Apply Now", 22 | "introTitle": "We're looking for a great Growth Hacker", 23 | "showStart": true 24 | }, 25 | "form_fields": [{ 26 | "lastModified": "2016-04-22T23:02:46.017Z", 27 | "title": "How would you rate your experience and knowledge of running split tests?", 28 | "fieldType": "rating", 29 | "fieldValue": 1, 30 | "_id": "571940102aa1f3ff5e205b5d", 31 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 32 | "deletePreserved": false, 33 | "disabled": false, 34 | "required": true, 35 | "ratingOptions": { 36 | "shape": "thumbs-up", 37 | "steps": 5 38 | }, 39 | "description": "" 40 | }, { 41 | "lastModified": "2016-04-22T23:02:46.017Z", 42 | "title": "And how would you rate your creativity and ability to find innovative solutions?", 43 | "fieldType": "rating", 44 | "fieldValue": 1, 45 | "_id": "571940222aa1f3ff5e205b5e", 46 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 47 | "deletePreserved": false, 48 | "disabled": false, 49 | "required": true, 50 | "ratingOptions": { 51 | "shape": "thumbs-up", 52 | "steps": 5 53 | }, 54 | "description": "" 55 | }, { 56 | "_id": "57193ffa2aa1f3ff5e205b5c", 57 | "fieldValue": "no", 58 | "fieldType": "textfield", 59 | "title": "Can we get the link to your LinkedIn profile?", 60 | "lastModified": "2016-04-22T19:48:42.690Z", 61 | "created": "2016-04-21T21:02:50.583Z", 62 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 63 | "deletePreserved": true, 64 | "disabled": false, 65 | "required": false, 66 | "fieldOptions": [], 67 | "description": "" 68 | }, { 69 | "_id": "57193ffa2aa1f3ff5e205b5c", 70 | "fieldValue": "no", 71 | "fieldType": "textfield", 72 | "title": "Can we get the link to your LinkedIn profile?", 73 | "lastModified": "2016-04-22T19:48:42.690Z", 74 | "created": "2016-04-21T21:02:50.583Z", 75 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 76 | "deletePreserved": true, 77 | "disabled": false, 78 | "required": false, 79 | "fieldOptions": [], 80 | "description": "" 81 | }, { 82 | "_id": "57193ffa2aa1f3ff5e205b5c", 83 | "fieldValue": "no", 84 | "fieldType": "textfield", 85 | "title": "Can we get the link to your LinkedIn profile?", 86 | "lastModified": "2016-04-22T19:48:42.690Z", 87 | "created": "2016-04-21T21:02:50.583Z", 88 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 89 | "deletePreserved": true, 90 | "disabled": false, 91 | "required": false, 92 | "fieldOptions": [], 93 | "description": "" 94 | }, { 95 | "_id": "57193ffa2aa1f3ff5e205b5c", 96 | "fieldValue": "no", 97 | "fieldType": "textfield", 98 | "title": "Can we get the link to your LinkedIn profile?", 99 | "lastModified": "2016-04-22T19:48:42.690Z", 100 | "created": "2016-04-21T21:02:50.583Z", 101 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 102 | "deletePreserved": true, 103 | "disabled": false, 104 | "required": false, 105 | "fieldOptions": [], 106 | "description": "" 107 | }, { 108 | "_id": "57193ffa2aa1f3ff5e205b5c", 109 | "fieldValue": "no", 110 | "fieldType": "textfield", 111 | "title": "Can we get the link to your LinkedIn profile?", 112 | "lastModified": "2016-04-22T19:48:42.690Z", 113 | "created": "2016-04-21T21:02:50.583Z", 114 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 115 | "deletePreserved": true, 116 | "disabled": false, 117 | "required": false, 118 | "fieldOptions": [], 119 | "description": "" 120 | }, { 121 | "lastModified": "2016-04-22T23:02:46.025Z", 122 | "title": "Now, please read the following statement: \"Finding the \"Aha!\" moment on the customer journey is the first and most important job of a growth hacker\" What do you think of it?", 123 | "fieldType": "radio", 124 | "fieldValue": "", 125 | "_id": "571940472aa1f3ff5e205b60", 126 | "created": "2016-04-21T21:04:07.678Z", 127 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 128 | "deletePreserved": false, 129 | "disabled": false, 130 | "required": false, 131 | "fieldOptions": [{ 132 | "option_id": 60612, 133 | "option_title": "Option 0", 134 | "option_value": "1 (disagree)", 135 | "_id": "571940632aa1f3ff5e205b61" 136 | }, { 137 | "option_id": 46890, 138 | "option_title": "Option 60612", 139 | "option_value": "2", 140 | "_id": "571940642aa1f3ff5e205b62" 141 | }, { 142 | "option_id": 14519, 143 | "option_title": "Option 46890", 144 | "option_value": "3", 145 | "_id": "5719406c2aa1f3ff5e205b63" 146 | }, { 147 | "option_id": 13374, 148 | "option_title": "Option 14519", 149 | "option_value": "4", 150 | "_id": "5719406f2aa1f3ff5e205b64" 151 | }, { 152 | "option_id": 88666, 153 | "option_title": "Option 13374", 154 | "option_value": "5", 155 | "_id": "571940722aa1f3ff5e205b65" 156 | }, { 157 | "option_id": 74204, 158 | "option_title": "Option 88666", 159 | "option_value": "6 (agree)", 160 | "_id": "571940822aa1f3ff5e205b66" 161 | }], 162 | "description": "" 163 | }, { 164 | "lastModified": "2016-04-22T23:02:46.019Z", 165 | "title": "In this cross-functional role, you’ll be optimizing our users' journey across all stages of our marketing funnel.", 166 | "fieldType": "statement", 167 | "fieldValue": "", 168 | "_id": "57193f562aa1f3ff5e205b58", 169 | "created": "2016-04-21T21:00:06.998Z", 170 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 171 | "deletePreserved": false, 172 | "disabled": false, 173 | "required": true, 174 | "fieldOptions": [], 175 | "description": "" 176 | }, { 177 | "lastModified": "2016-04-22T23:02:46.021Z", 178 | "title": "What about your ability to get things done quickly?", 179 | "fieldType": "rating", 180 | "fieldValue": 1, 181 | "_id": "571940332aa1f3ff5e205b5f", 182 | "created": "2016-04-21T21:03:12.644Z", 183 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 184 | "deletePreserved": false, 185 | "disabled": false, 186 | "required": true, 187 | "ratingOptions": { 188 | "shape": "Star", 189 | "steps": 5 190 | }, 191 | "description": "" 192 | }, { 193 | "lastModified": "2016-04-22T23:02:46.021Z", 194 | "title": "Can you tell us more about your choice?", 195 | "fieldType": "textarea", 196 | "fieldValue": "", 197 | "_id": "571940932aa1f3ff5e205b67", 198 | "created": "2016-04-21T21:05:23.928Z", 199 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 200 | "deletePreserved": false, 201 | "disabled": false, 202 | "required": false, 203 | "fieldOptions": [], 204 | "description": "" 205 | }, { 206 | "lastModified": "2016-04-22T23:02:46.023Z", 207 | "title": "What growth hack have you done that you're most proud of?", 208 | "fieldType": "textarea", 209 | "fieldValue": "", 210 | "_id": "571940b12aa1f3ff5e205b68", 211 | "created": "2016-04-21T21:05:23.928Z", 212 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 213 | "deletePreserved": false, 214 | "disabled": false, 215 | "required": false, 216 | "fieldOptions": [], 217 | "description": "" 218 | }, { 219 | "lastModified": "2016-04-22T23:02:46.023Z", 220 | "title": "Now, some quick reasoning test questions...", 221 | "fieldType": "statement", 222 | "fieldValue": "", 223 | "_id": "571940c22aa1f3ff5e205b69", 224 | "created": "2016-04-21T21:06:10.235Z", 225 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 226 | "deletePreserved": false, 227 | "disabled": false, 228 | "required": true, 229 | "fieldOptions": [], 230 | "description": "" 231 | }, { 232 | "lastModified": "2016-04-22T23:02:46.025Z", 233 | "title": "Two students took an exam. One of them achieved 9 marks more than the other and his marks were 56% of the sum of both of their marks. What marks did they obtain?", 234 | "fieldType": "radio", 235 | "fieldValue": "", 236 | "_id": "571940ea2aa1f3ff5e205b6a", 237 | "created": "2016-04-21T21:06:50.729Z", 238 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 239 | "deletePreserved": false, 240 | "disabled": false, 241 | "required": true, 242 | "fieldOptions": [{ 243 | "option_id": 45860, 244 | "option_title": "Option 0", 245 | "option_value": "42 and 33", 246 | "_id": "571941022aa1f3ff5e205b6b" 247 | }, { 248 | "option_id": 84531, 249 | "option_title": "Option 45860", 250 | "option_value": "41 and 32", 251 | "_id": "571941032aa1f3ff5e205b6c" 252 | }, { 253 | "option_id": 88832, 254 | "option_title": "Option 84531", 255 | "option_value": "39 and 30", 256 | "_id": "5719410d2aa1f3ff5e205b6d" 257 | }, { 258 | "option_id": 39666, 259 | "option_title": "Option 88832", 260 | "option_value": "43 and 34", 261 | "_id": "571941172aa1f3ff5e205b6e" 262 | }], 263 | "description": "" 264 | }, { 265 | "lastModified": "2016-04-22T23:02:46.026Z", 266 | "title": "Agnes, Pedro, Robert, Xavi, Santi and David are sitting in a row. Santi and David are in the centre. Agnes and Pedro are at the ends. Robert is sitting to the left of Agnes. Who is to the right of Pedro?", 267 | "fieldType": "radio", 268 | "fieldValue": "", 269 | "_id": "5719412c2aa1f3ff5e205b6f", 270 | "created": "2016-04-21T21:06:50.729Z", 271 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 272 | "deletePreserved": false, 273 | "disabled": false, 274 | "required": true, 275 | "fieldOptions": [{ 276 | "option_id": 45860, 277 | "option_title": "Option 0", 278 | "option_value": "Agnes", 279 | "_id": "571941022aa1f3ff5e205b6b" 280 | }, { 281 | "option_id": 84531, 282 | "option_title": "Option 45860", 283 | "option_value": "Santi", 284 | "_id": "571941032aa1f3ff5e205b6c" 285 | }, { 286 | "option_id": 88832, 287 | "option_title": "Option 84531", 288 | "option_value": "Xavi", 289 | "_id": "5719410d2aa1f3ff5e205b6d" 290 | }, { 291 | "option_id": 39666, 292 | "option_title": "Option 88832", 293 | "option_value": "David", 294 | "_id": "571941172aa1f3ff5e205b6e" 295 | }], 296 | "description": "" 297 | }, { 298 | "lastModified": "2016-04-22T23:02:46.024Z", 299 | "title": "What makes you want to work at Cloud Metrics?", 300 | "fieldType": "textarea", 301 | "fieldValue": "", 302 | "_id": "571941572aa1f3ff5e205b70", 303 | "created": "2016-04-21T21:08:39.654Z", 304 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 305 | "deletePreserved": false, 306 | "disabled": false, 307 | "required": true, 308 | "fieldOptions": [], 309 | "description": "" 310 | }, { 311 | "lastModified": "2016-04-22T23:02:46.025Z", 312 | "title": "Finally, what annual salary ($) are you looking for?", 313 | "fieldType": "textfield", 314 | "fieldValue": "", 315 | "_id": "571941672aa1f3ff5e205b71", 316 | "created": "2016-04-21T21:08:55.492Z", 317 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 318 | "deletePreserved": false, 319 | "disabled": false, 320 | "required": false, 321 | "fieldOptions": [], 322 | "description": "" 323 | }, { 324 | "lastModified": "2016-04-22T23:02:46.025Z", 325 | "title": "Email2", 326 | "fieldType": "email", 327 | "fieldValue": "", 328 | "_id": "571a80045b53e2c651f28804", 329 | "created": "2016-04-22T19:48:20.733Z", 330 | "validFieldTypes": ["textfield", "date", "email", "link", "legal", "url", "textarea", "statement", "welcome", "thankyou", "file", "dropdown", "scale", "rating", "radio", "checkbox", "hidden", "yes_no", "natural", "number"], 331 | "deletePreserved": false, 332 | "disabled": false, 333 | "required": true, 334 | "fieldOptions": [], 335 | "description": "" 336 | }], 337 | "language": "english" 338 | }; 339 | 340 | $scope.endPoint = "https://admin.tellform.com/forms/"+$scope.myform._id; 341 | 342 | }); -------------------------------------------------------------------------------- /dist/template.js: -------------------------------------------------------------------------------- 1 | angular.module('angular-tellform.templates', []).run(['$templateCache', function($templateCache) { 2 | $templateCache.put("modules/forms/base/views/directiveViews/field/date.html", 3 | "
\n" + 5 | "
\n" + 6 | "

\n" + 7 | " \n" + 8 | " {{index+1}}\n" + 9 | " \n" + 10 | " \n" + 11 | " {{field.title}}\n" + 12 | " {{ 'OPTIONAL' | translate }}\n" + 13 | "

\n" + 14 | "

\n" + 15 | " {{field.description}}\n" + 16 | "

\n" + 17 | "
\n" + 18 | "
\n" + 19 | "
\n" + 20 | " \n" + 33 | "
\n" + 34 | "
\n" + 35 | "
\n" + 36 | ""); 37 | $templateCache.put("modules/forms/base/views/directiveViews/field/dropdown.html", 38 | "
0\">\n" + 40 | "
\n" + 41 | "

\n" + 42 | " \n" + 43 | " {{index+1}}\n" + 44 | " \n" + 45 | " \n" + 46 | " {{field.title}}\n" + 47 | " {{ 'OPTIONAL' | translate }}\n" + 48 | "

\n" + 49 | "

\n" + 50 | " {{field.description}}\n" + 51 | "

\n" + 52 | "
\n" + 53 | "
\n" + 54 | " \n" + 64 | " \n" + 65 | " \n" + 66 | " \n" + 68 | " \n" + 69 | " \n" + 70 | " \n" + 71 | "
\n" + 72 | "
\n" + 73 | "
\n" + 74 | ""); 75 | $templateCache.put("modules/forms/base/views/directiveViews/field/file.html", 76 | "
\n" + 77 | "\n" + 78 | "
\n" + 79 | "

\n" + 80 | " \n" + 81 | " {{index+1}}\n" + 82 | " \n" + 83 | " \n" + 84 | " {{field.title}}\n" + 85 | " {{ 'OPTIONAL' | translate }}\n" + 86 | "

\n" + 87 | "
\n" + 88 | "
\n" + 89 | "
\n" + 90 | "
\n" + 91 | " \n" + 92 | "
\n" + 93 | " {{field.file.originalname}}\n" + 94 | "
\n" + 95 | "
\n" + 96 | "
\n" + 97 | " \n" + 102 | "\n" + 103 | " \n" + 107 | "\n" + 108 | "
\n" + 109 | " \n" + 110 | " {{ UPLOAD_FILE | translate }}\n" + 111 | "
\n" + 112 | "
\n" + 113 | "
\n" + 114 | "
\n" + 115 | "
\n" + 116 | ""); 117 | $templateCache.put("modules/forms/base/views/directiveViews/field/hidden.html", 118 | "\n" + 119 | ""); 120 | $templateCache.put("modules/forms/base/views/directiveViews/field/legal.html", 121 | "
\n" + 124 | "
\n" + 125 | "

\n" + 126 | " \n" + 127 | " {{index+1}}\n" + 128 | " \n" + 129 | " \n" + 130 | " {{field.title}}\n" + 131 | " {{ 'OPTIONAL' | translate }}\n" + 132 | "

\n" + 133 | "
\n" + 134 | "

{{field.description}}

\n" + 135 | "
\n" + 136 | "
\n" + 137 | "
\n" + 140 | " \n" + 156 | " \n" + 171 | "
\n" + 172 | "
\n" + 173 | "
\n" + 174 | "
\n" + 175 | ""); 176 | $templateCache.put("modules/forms/base/views/directiveViews/field/natural.html", 177 | "
\n" + 178 | "

{{field.title}} *(required)

\n" + 179 | "
\n" + 180 | " \n" + 187 | "
\n" + 188 | "
\n" + 189 | "
\n" + 190 | " \n" + 191 | "
\n" + 192 | "
\n" + 193 | ""); 194 | $templateCache.put("modules/forms/base/views/directiveViews/field/password.html", 195 | "
\n" + 196 | "

{{field.title}} *(required)

\n" + 197 | "
\n" + 198 | " \n" + 199 | "
\n" + 200 | "
\n" + 201 | ""); 202 | $templateCache.put("modules/forms/base/views/directiveViews/field/radio.html", 203 | "
0\">\n" + 207 | "
\n" + 208 | "

\n" + 209 | " \n" + 210 | " {{index+1}}\n" + 211 | " \n" + 212 | " \n" + 213 | " {{field.title}}\n" + 214 | " {{ 'OPTIONAL' | translate }}\n" + 215 | "

\n" + 216 | "

\n" + 217 | " {{field.description}}\n" + 218 | "

\n" + 219 | "
\n" + 220 | "
\n" + 221 | "\n" + 222 | "
\n" + 223 | " \n" + 240 | "
\n" + 241 | "
\n" + 242 | "
\n" + 243 | "
\n" + 244 | ""); 245 | $templateCache.put("modules/forms/base/views/directiveViews/field/rating.html", 246 | "
\n" + 248 | "
\n" + 249 | "

\n" + 250 | " \n" + 251 | " {{index+1}}\n" + 252 | " \n" + 253 | " \n" + 254 | " {{field.title}}\n" + 255 | " {{ 'OPTIONAL' | translate }}\n" + 256 | "

\n" + 257 | "

\n" + 258 | " {{field.description}}\n" + 259 | "

\n" + 260 | "
\n" + 261 | "
\n" + 262 | "\n" + 263 | " \n" + 277 | " \n" + 278 | "
\n" + 279 | "
\n" + 280 | ""); 281 | $templateCache.put("modules/forms/base/views/directiveViews/field/statement.html", 282 | "
\n" + 286 | "
\n" + 287 | "
\n" + 288 | "

{{field.title}}

\n" + 289 | "

\n" + 290 | " {{field.description}}\n" + 291 | "

\n" + 292 | "
\n" + 293 | "
\n" + 294 | "

{{field.description}}

\n" + 295 | "
\n" + 296 | "
\n" + 297 | " \n" + 303 | "
\n" + 304 | "
\n" + 305 | "
\n" + 306 | ""); 307 | $templateCache.put("modules/forms/base/views/directiveViews/field/textarea.html", 308 | "
\n" + 309 | "
\n" + 310 | "

\n" + 311 | " \n" + 312 | " {{index+1}}\n" + 313 | " \n" + 314 | " \n" + 315 | " {{field.title}}\n" + 316 | " {{ 'OPTIONAL' | translate }}\n" + 317 | "

\n" + 318 | " {{ 'NEWLINE' | translate }}\n" + 319 | "

\n" + 320 | " {{field.description}}\n" + 321 | "

\n" + 322 | "
\n" + 323 | "
\n" + 324 | " Press SHIFT+ENTER to add a newline\n" + 325 | " \n" + 337 | "
\n" + 338 | "
\n" + 339 | "\n" + 340 | "
\n" + 341 | "
\n" + 343 | " \n" + 350 | "
\n" + 351 | " \n" + 352 | " {{ 'ENTER' | translate }}\n" + 353 | " \n" + 354 | "
\n" + 355 | "
\n" + 356 | "
\n" + 357 | ""); 358 | $templateCache.put("modules/forms/base/views/directiveViews/field/textfield.html", 359 | "
\n" + 361 | "
\n" + 362 | "

\n" + 363 | " \n" + 364 | " {{index+1}}\n" + 365 | " \n" + 366 | " \n" + 367 | "\n" + 368 | " {{field.title}}\n" + 369 | "\n" + 370 | " \n" + 371 | " ({{ 'OPTIONAL' | translate }})\n" + 372 | " \n" + 373 | "

\n" + 374 | "\n" + 375 | "

\n" + 376 | " {{field.description}}\n" + 377 | "

\n" + 378 | "
\n" + 379 | "
\n" + 380 | " \n" + 396 | "
\n" + 397 | "
\n" + 398 | "
\n" + 399 | " \n" + 400 | " Error:\n" + 401 | " {{ 'ERROR_EMAIL_INVALID' | translate }} \n" + 402 | " {{ 'ERROR_NOT_A_NUMBER' | translate }} \n" + 403 | " {{ 'ERROR_URL_INVALID' | translate }} \n" + 404 | "
\n" + 405 | "
\n" + 406 | "
\n" + 407 | "
\n" + 408 | "
\n" + 410 | " \n" + 417 | "
\n" + 418 | " \n" + 419 | " {{ 'ENTER' | translate }}\n" + 420 | " \n" + 421 | "
\n" + 422 | "
\n" + 423 | "
\n" + 424 | ""); 425 | $templateCache.put("modules/forms/base/views/directiveViews/field/yes_no.html", 426 | "
\n" + 430 | "
\n" + 431 | "

\n" + 432 | " \n" + 433 | " {{index+1}}\n" + 434 | " \n" + 435 | " \n" + 436 | " {{field.title}}\n" + 437 | " \n" + 438 | " {{ 'OPTIONAL' | translate }}\n" + 439 | " \n" + 440 | "

\n" + 441 | "

\n" + 442 | " {{field.description}}\n" + 443 | "

\n" + 444 | "
\n" + 445 | "\n" + 446 | "
\n" + 447 | "
\n" + 448 | " \n" + 465 | "
\n" + 466 | "\n" + 467 | "
\n" + 468 | " \n" + 485 | "
\n" + 486 | "
\n" + 487 | "
\n" + 488 | "
\n" + 489 | ""); 490 | $templateCache.put("modules/forms/base/views/directiveViews/form/submit-form.client.view.html", 491 | "
\n" + 492 | "\n" + 493 | "\n" + 494 | "\n" + 495 | "
\n" + 498 | "
\n" + 499 | "
\n" + 500 | "

\n" + 501 | "{{myform.startPage.introTitle}}\n" + 502 | "

\n" + 503 | "
\n" + 504 | "
\n" + 505 | "

\n" + 506 | "{{myform.startPage.introParagraph}}\n" + 507 | "

\n" + 508 | "
\n" + 509 | "
\n" + 510 | "\n" + 511 | "
\n" + 512 | "\n" + 518 | "
\n" + 519 | "
\n" + 520 | "

\n" + 521 | "\n" + 529 | "

\n" + 530 | "
\n" + 531 | "
\n" + 532 | "\n" + 533 | "\n" + 534 | "
\n" + 536 | "
\n" + 537 | "
\n" + 540 | "\n" + 541 | "
\n" + 547 | "\n" + 548 | " \n" + 549 | " \n" + 550 | "
\n" + 551 | "\n" + 552 | "\n" + 553 | "
\n" + 554 | "
\n" + 555 | "\n" + 556 | "\n" + 557 | "
\n" + 561 | "\n" + 562 | "
\n" + 565 | " {{ 'COMPLETING_NEEDED' | translate:translateAdvancementData }}\n" + 566 | "
\n" + 567 | "\n" + 568 | " \n" + 580 | "\n" + 581 | " \n" + 589 | "\n" + 590 | "
\n" + 591 | " \n" + 592 | " {{ 'ENTER' | translate }}\n" + 593 | " \n" + 594 | "
\n" + 595 | "
\n" + 596 | "\n" + 597 | "
\n" + 599 | "
\n" + 600 | "
\n" + 601 | "
\n" + 602 | "

{{ 'ADVANCEMENT' | translate:translateAdvancementData }}

\n" + 603 | "
\n" + 604 | "
\n" + 605 | " \n" + 612 | " \n" + 619 | "
\n" + 620 | " \n" + 626 | " \n" + 632 | "
\n" + 633 | "
\n" + 634 | "
\n" + 635 | "
\n" + 636 | "
\n" + 637 | "
\n" + 638 | "\n" + 639 | "\n" + 640 | "\n" + 656 | ""); 657 | $templateCache.put("modules/forms/base/views/submit-form.client.view.html", 658 | "
\n" + 659 | " \n" + 660 | "
\n" + 661 | "\n" + 662 | ""); 663 | }]); 664 | --------------------------------------------------------------------------------