2016-06-20 22:35:41 +00:00
'use strict' ;
// Init the application configuration module for AngularJS application
var ApplicationConfiguration = ( function ( ) {
// Init module configuration options
2017-03-28 00:08:45 +00:00
var applicationModuleName = 'TellForm-Form' ;
2017-04-11 07:10:36 +00:00
var applicationModuleVendorDependencies = [ 'duScroll' , 'ui.select' , 'ngSanitize' , 'vButton' , 'ngResource' , 'TellForm-Form.form_templates' , 'ui.router' , 'ui.bootstrap' , 'pascalprecht.translate' ] ;
2016-06-20 22:35:41 +00:00
// Add a new vertical module
var registerModule = function ( moduleName , dependencies ) {
// Create angular module
angular . module ( moduleName , dependencies || [ ] ) ;
// Add the module to the AngularJS configuration file
angular . module ( applicationModuleName ) . requires . push ( moduleName ) ;
} ;
return {
applicationModuleName : applicationModuleName ,
applicationModuleVendorDependencies : applicationModuleVendorDependencies ,
registerModule : registerModule
} ;
} ) ( ) ;
'use strict' ;
//Start by defining the main module and adding the module dependencies
angular . module ( ApplicationConfiguration . applicationModuleName , ApplicationConfiguration . applicationModuleVendorDependencies ) ;
// Setting HTML5 Location Mode
angular . module ( ApplicationConfiguration . applicationModuleName ) . config ( [ '$locationProvider' ,
function ( $locationProvider ) {
$locationProvider . hashPrefix ( '!' ) ;
}
] ) ;
//Permission Constants
angular . module ( ApplicationConfiguration . applicationModuleName ) . constant ( 'APP_PERMISSIONS' , {
2017-03-27 20:32:06 +00:00
viewAdminSettings : 'viewAdminSettings' ,
editAdminSettings : 'editAdminSettings' ,
editForm : 'editForm' ,
viewPrivateForm : 'viewPrivateForm'
2016-06-20 22:35:41 +00:00
} ) ;
//User Role constants
angular . module ( ApplicationConfiguration . applicationModuleName ) . constant ( 'USER_ROLES' , {
2017-03-27 20:32:06 +00:00
admin : 'admin' ,
normal : 'user' ,
superuser : 'superuser'
2016-06-20 22:35:41 +00:00
} ) ;
//form url
angular . module ( ApplicationConfiguration . applicationModuleName ) . constant ( 'FORM_URL' , '/forms/:formId' ) ;
//Then define the init function for starting up the application
angular . element ( document ) . ready ( function ( ) {
//Fixing facebook bug with redirect
if ( window . location . hash === '#_=_' ) window . location . hash = '#!' ;
//Then init the app
angular . bootstrap ( document , [ ApplicationConfiguration . applicationModuleName ] ) ;
} ) ;
2017-08-02 22:30:12 +00:00
angular . module ( 'TellForm-Form.form_templates' , [ ] ) . run ( [ '$templateCache' , function ( $templateCache ) {
2017-07-26 20:41:53 +00:00
"use strict" ;
$templateCache . put ( "form_modules/forms/base/views/form-unauthorized.client.view.html" ,
2017-07-27 02:53:02 +00:00
"<section class=\"auth sigin-view valign-wrapper\"><div class=\"row valign\"><h3 class=\"col-md-12 text-center\">Not Authorized to Access Form</h3><div class=\"col-md-4 col-md-offset-4\"><div class=\"col-md-12 text-center\" style=\"padding-bottom: 50px\">The form you are trying to access is currently private and not accesible publically.<br>If you are the owner of the form, you can set it to \"Public\" in the \"Configuration\" panel in the form admin.</div></div></div></section>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/submit-form.client.view.html" ,
"<section class=public-form ng-style=\"{ 'background-color': myform.design.colors.backgroundColor }\"><submit-form-directive myform=myform></submit-form-directive></section><script ng-if=myform.analytics.gaCode>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n" +
" (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n" +
" m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n" +
" })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');\n" +
"\n" +
" ga('create', '{{myform.analytics.gaCode}}', 'auto');\n" +
" ga('send', 'pageview');</script>" ) ;
$templateCache . put ( "form_modules/forms/base/views/directiveViews/entryPage/startPage.html" ,
"<div class=\"field row text-center\"><div class=\"col-xs-12 text-center\"><h1>{{pageData.introTitle}}</h1></div><div class=\"col-xs-10 col-xs-offset-1 text-left\"><p style=color:#ddd>{{pageData.introParagraph}}</p></div></div><div class=\"row form-actions\" style=\"padding-bottom:3em; padding-left: 1em; padding-right: 1em\"><p ng-repeat=\"button in pageData.buttons\" class=text-center style=display:inline><button class=\"btn btn-info\" type=button ng-style=\"{'background-color':button.bgColor, 'color':button.color}\"><a href={{button.url}} style=\"font-size: 1.6em; text-decoration: none; color: inherit\">{{button.text}}</a></button></p></div><div class=\"row form-actions\"><p class=\"col-xs-3 col-xs-offset-3 text-center\"><button class=\"btn btn-info\" type=button><a ng-click=exitpageData() style=\"color:white; font-size: 1.6em; text-decoration: none\">{{ 'CONTINUE_FORM' | translate }}</a></button></p></div>" ) ;
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/date.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"field row\" ng-click=\"setActiveField(field._id, index, true)\"><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=\"!field.required && !field.fieldValue\">{{ 'OPTIONAL' | translate }}</span></h3><p class=col-xs-12><small>{{field.description}}</small></p></div><div class=\"col-xs-12 field-input\"><div class=\"control-group input-append\"><input class=focusOn ng-style=\"{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}\" ng-class=\"{ 'no-border': !!field.fieldValue }\" ui-date=dateOptions ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-disabled=field.disabled placeholder=MM/DD/YYYY on-tab-key=nextField() on-tab-and-shift-key=prevField() ng-change=$root.nextField()></div></div></div>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/dropdown.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"field row dropdown\" ng-if=\"field.fieldOptions.length > 0\"><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>{{ 'OPTIONAL' | translate }}</span></h3><p class=col-xs-12><small>{{field.description}}</small></p></div><div class=\"col-xs-12 field-input\"><ui-select ng-model=field.fieldValue theme=selectize search-enabled=true search-by=option_value set-search-to-answer=true ng-required=field.required ng-disabled=field.disabled on-tab-and-shift-key=prevField() on-tab-key=nextField() ng-change=$root.nextField()><ui-select-match placeholder=\"Type or select an option\"></ui-select-match><ui-select-choices repeat=\"option in field.fieldOptions | filter: $select.search\" ng-class=\"{'active': option.option_value === field.fieldValue }\"><span ng-bind-html=\"option.option_value | highlight: $select.search\"></span></ui-select-choices></ui-select></div></div><br>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/hidden.html" ,
"<input ng-focus=\"setActiveField(field._id, index, true)\" ng-style=\"{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}\" type=hidden ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" value={{field.fieldValue}} ng-disabled=field.disabled>" ) ;
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/legal.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"field row radio legal\" on-enter-or-tab-key=nextField() on-tab-and-shift-key=prevField() key-to-truthy key-char-truthy=y key-char-falsey=n field=field on-valid-key=nextField()><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>{{ 'OPTIONAL' | translate }}</span></h3><br><p class=col-xs-12>{{field.description}}</p></div><div class=\"col-xs-12 field-input container\"><div class=row-fluid><label class=\"btn col-md-5 col-xs-12\" ng-class=\"{activeBtn: field.fieldValue == 'true'}\"><input class=focusOn ng-style=\"{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}\" type=radio value=true ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-disabled=field.disabled ng-change=\"nextField()\"><div class=letter style=float:left>Y</div><span>{{ 'LEGAL_ACCEPT' | translate }}</span></label><label class=\"btn col-md-5 col-md-offset-1 col-xs-12\" ng-class=\"{activeBtn: field.fieldValue == 'false'}\"><input class=focusOn ng-style=\"{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}\" type=radio value=false ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-disabled=field.disabled ng-change=\"nextField()\"><div class=letter style=float:left>N</div><span>{{ 'LEGAL_NO_ACCEPT' | translate }}</span></label></div></div></div><br>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/radio.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"field row radio\" on-enter-or-tab-key=nextField() key-to-option field=field ng-if=\"field.fieldOptions.length > 0\"><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>{{ 'OPTIONAL' | translate }}</span></h3><p class=col-xs-12><small>{{field.description}}</small></p></div><div class=\"col-xs-12 field-input\"><div ng-repeat=\"option in field.fieldOptions\" class=row-fluid><label class=\"btn col-md-4 col-xs-12 col-sm-12\" style=\"margin: 0.5em; padding-left:30px\" ng-class=\"{activeBtn: field.fieldValue == field.fieldOptions[$index].option_value}\"><div class=letter style=float:left>{{$index+1}}</div><input ng-style=\"{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}\" type=radio class=focusOn value={{option.option_value}} ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-disabled=field.disabled ng-change=\"$root.nextField()\"> <span ng-bind=option.option_value></span></label></div></div></div><br>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/rating.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"textfield field row\" on-enter-or-tab-key=nextField()><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>{{ 'OPTIONAL' | translate }}</span></h3><p class=col-xs-12><small>{{field.description}}</small></p></div><div class=\"col-xs-12 field-input\"><input-stars max={{field.ratingOptions.steps}} ng-init=\"field.fieldValue = 1\" on-shape-click=true on-star-click=nextField() icon-full={{field.ratingOptions.shape}} icon-base=\"fa fa-3x\" icon-empty={{field.ratingOptions.shape}} ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-disabled=field.disabled on-enter-or-tab-key=nextField() on-tab-and-shift-key=prevField() class=\"angular-input-stars focusOn\"></input-stars></div></div>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/statement.html" ,
2017-08-02 21:45:49 +00:00
"<div class=\"statement field row\" on-enter-or-tab-key=nextField() on-tab-and-shift-key=prevField()><div class=\"row field-title field-title\"><div class=col-xs-1><i class=\"fa fa-quote-left fa-1\"></i></div><h2 class=\"text-left col-xs-9\">{{field.title}}</h2><p class=col-xs-12><small>{{field.description}}</small></p></div><div class=\"row field-title field-input\"><p class=col-xs-12 ng-if=field.description.length>{{field.description}}</p><br><div class=\"col-xs-offset-1 col-xs-11\"><button class=\"btn focusOn\">ng-style=\"{'font-size': '1.3em', 'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}\" ng-click=\"nextField()\"> {{ 'CONTINUE' | translate }}</button></div></div></div>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/textarea.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"field row\" ng-click=\"setActiveField(field._id, index, true)\"><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>{{ 'OPTIONAL' | translate }}</span></h3><small>{{ 'NEWLINE' | translate }}</small><p><small>{{field.description}}</small></p></div><div class=\"col-xs-12 field-input\"><small style=font-size:0.6em>Press SHIFT+ENTER to add a newline</small><textarea class=\"textarea focusOn\" type=text ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-class=\"{ 'no-border': !!field.fieldValue }\" value={{field.fieldValue}} ng-required=field.required ng-disabled=field.disabled on-enter-or-tab-key=nextField() on-tab-and-shift-key=prevField() style=\"border: none; border-left: lightgrey dashed 2px\">\n" +
2017-07-26 20:41:53 +00:00
" </textarea></div></div><div><div class=\"btn btn-lg btn-default col-xs-12 col-sm-4 hidden-xs\" style=\"padding: 4px; margin-top:8px; background: rgba(255,255,255,0.5)\"><button ng-disabled=\"!field.fieldValue || forms.myForm.{{field.fieldType}}{{$index}}.$invalid\" ng-style=\"{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}\" ng-click=$root.nextField() class=\"btn col-sm-5 col-xs-5\">{{ 'OK' | translate }} <i class=\"fa fa-check\"></i></button><div class=\"col-sm-3 col-xs-6\" style=margin-top:0.2em><small style=\"color:#ddd; font-size:70%\">{{ 'ENTER' | translate }}</small></div></div></div>" ) ;
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/textfield.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"textfield field row\" ng-click=\"setActiveField(field._id, index, true)\"><div class=\"col-xs-12 field-title row-fluid\" ng-style=\"{'color': design.colors.questionColor}\"><h3 class=col-xs-12><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>({{ 'OPTIONAL' | translate }})</span></h3><p class=col-xs-12><small>{{field.description}}</small></p></div><div class=\"col-xs-12 field-input\"><input ng-style=\"{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}\" name={{field.fieldType}}{{index}} type={{input_type}} ng-pattern=validateRegex placeholder={{placeholder}} ng-class=\"{ 'no-border': !!field.fieldValue }\" class=\"focusOn text-field-input\" ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" value=field.fieldValue on-enter-or-tab-key=nextField() on-tab-and-shift-key=prevField() ng-required=field.required ng-disabled=field.disabled aria-describedby=\"inputError2Status\"></div><div class=col-xs-12><div ng-show=\"forms.myForm.{{field.fieldType}}{{index}}.$invalid && !!forms.myForm.{{field.fieldType}}{{index}}.$viewValue \" class=\"alert alert-danger\" role=alert><span class=\"glyphicon glyphicon-exclamation-sign\" aria-hidden=true></span> <span class=sr-only>Error:</span> <span ng-if=\"field.fieldType == 'email'\">{{ 'ERROR_EMAIL_INVALID' | translate }}</span> <span ng-if=\"field.fieldType == 'number'\">{{ 'ERROR_NOT_A_NUMBER' | translate }}</span> <span ng-if=\"field.fieldType == 'link'\">{{ 'ERROR_URL_INVALID' | translate }}</span></div></div></div><div><div class=\"btn btn-lg btn-default col-xs-12 col-sm-4 hidden-xs\" style=\"padding: 4px; margin-top:8px; background: rgba(255,255,255,0.5)\"><button ng-disabled=\"!field.fieldValue || field.$invalid\" ng-style=\"{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}\" ng-click=nextField() class=\"btn col-sm-5 col-xs-5\">{{ 'OK' | translate }} <i class=\"fa fa-check\"></i></button><div class=\"col-xs-6 col-sm-3\" style=margin-top:0.2em><small style=\"color:#ddd; font-size:70%\">{{ 'ENTER' | translate }}</small></div></div></div>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/field/yes_no.html" ,
2017-08-02 22:30:12 +00:00
"<div class=\"field row radio\" ng-click=\"setActiveField(field._id, index, true)\" on-tab-and-shift-key=prevField() key-to-truthy key-char-truthy=y key-char-falsey=n field=field on-valid-key=nextField() ng-show=!field.disabled><div class=\"col-xs-12 field-title\" ng-style=\"{'color': design.colors.questionColor}\"><h3 class=row><small class=field-number>{{index+1}} <i class=\"fa fa-angle-double-right\" aria-hidden=true></i></small> {{field.title}} <span class=required-error ng-show=!field.required>{{ 'OPTIONAL' | translate }}</span></h3><p class=row>{{field.description}}</p></div><div class=\"col-xs-12 field-input\"><div class=row><label class=\"btn btn-default col-md-2 col-sm-3 col-xs-7\" style=\"background: rgba(0,0,0,0.1); text-align:left\"><input type=radio value=true class=focusOn style=\"opacity: 0; margin-left: 0px\" ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-change=\"nextField()\"><div class=letter>{{ 'Y' | translate }}</div><span>{{ 'YES' | translate }}</span> <i ng-show=\"field.fieldValue === 'true'\" class=\"fa fa-check\" aria-hidden=true></i></label></div><div class=row style=\"margin-top: 10px\"><label class=\"btn btn-default col-md-2 col-sm-3 col-xs-7\" style=\"background: rgba(0,0,0,0.1); text-align:left\"><input type=radio value=false style=\"opacity:0; margin-left:0px\" ng-model=field.fieldValue ng-model-options=\"{ debounce: 250 }\" ng-required=field.required ng-change=\"nextField()\"><div class=letter>{{ 'N' | translate }}</div><span>{{ 'NO' | translate }}</span> <i ng-show=\"field.fieldValue === 'false'\" class=\"fa fa-check\" aria-hidden=true></i></label></div></div></div><br>" ) ;
2017-07-26 20:41:53 +00:00
$templateCache . put ( "form_modules/forms/base/views/directiveViews/form/submit-form.client.view.html" ,
"<section class=\"overlay submitform\" ng-if=\"loading || (!myform.submitted && !myform.startPage.showStart)\"></section><div ng-show=\"!myform.submitted && myform.startPage.showStart\" class=form-submitted style=\"padding-top: 35vh\"><div class=row><div class=\"col-xs-12 text-center\" style=\"overflow-wrap: break-word\"><h1 style=\"font-weight: 400; nont-size: 25px\">{{myform.startPage.introTitle}}</h1></div><div class=\"col-xs-10 col-xs-offset-1 text-center\" style=\"overflow-wrap: break-word\"><p style=\"color: grey; font-weight: 100; font-size: 16px\">{{myform.startPage.introParagraph}}</p></div></div><div class=\"row form-actions text-center\" style=\"padding: 5px 25px 5px 25px\"><button ng-click=exitStartPage() class=btn type=button ng-style=\"{'background-color':myform.design.colors.buttonColor, 'color':myform.design.colors.buttonTextColor}\"><span style=\"font-size: 1.6em\">{{myform.startPage.introButtonText}}</span></button></div><div class=\"row form-actions\" style=\"padding-bottom:3em; padding-left: 1em; padding-right: 1em\"><p ng-repeat=\"button in myform.startPage.buttons\" class=text-center style=display:inline><button class=btn style=\"background-color:rgb(156, 226, 235)\" type=button ng-style=\"{'background-color':button.bgColor, 'color':button.color}\"><a href={{button.url}} style=\"font-size: 1.6em; text-decoration: none\" ng-style=\"{'color':button.color}\">{{button.text}}</a></button></p></div></div><div class=form-fields ng-show=\"!myform.submitted && !myform.startPage.showStart\" ng-style=\"{ 'border-color': myform.design.colors.buttonTextColor }\"><div class=row><form name=forms.myForm novalidate class=\"submission-form col-sm-12 col-md-offset-1 col-md-10\"><div ng-repeat=\"field in myform.form_fields\" ng-if=!field.deletePreserved data-index={{$index}} data-id={{field._id}} ng-class=\"{activeField: selected._id == field._id }\" class=\"row field-directive\"><field-directive field=field design=myform.design index=$index forms=forms></field-directive></div></form></div><div class=\"row form-actions\" id=submit_field ng-class=\"{activeField: selected._id == 'submit_field' }\" ng-style=\"{ 'background-color':myform.design.colors.buttonColor}\" style=\"border-top: 1px solid #ddd; margin-right: -13%; margin-left: -13%; margin-top: 30vh; height: 100vh\"><div class=\"col-xs-12 text-left\" style=\"background-color:#990000; color:white\" ng-if=forms.myForm.$invalid>{{ 'COMPLETING_NEEDED' | translate:translateAdvancementData }}</div><button ng-if=!forms.myForm.$invalid class=\"Button btn col-sm-2 col-xs-8 focusOn\" v-busy=loading v-busy-label=\"Please wait\" v-pressable ng-disabled=\"loading || forms.myForm.$invalid\" ng-click=submitForm() on-enter-key=submitForm() on-enter-key-disabled=\"loading || forms.myForm.$invalid\" ng-style=\"{'background-color':myform.design.colors.buttonColor, 'color':myform.design.colors.buttonTextColor}\" style=\"font-size: 1.6em; margin-left: 1em; margin-top: 1em\">{{ 'SUBMIT' | translate }}</button> <button ng-if=forms.myForm.$invalid class=\"Button btn col-sm-2 col-xs-8 focusOn\" ng-click=goToInvalid() on-enter-key=goToInvalid() on-enter-key-disabled=!forms.myForm.$invalid style=\"font-size: 1.6em; margin-left: 1em; margin-top: 1em; background-color:#990000; color:white\">{{ 'REVIEW' | translate }}</button><div class=\"col-sm-2 hidden-xs\" style=\"font-size: 75%; margin-top:3.25em\"><small>{{ 'ENTER' | translate }}</small></div></div><section ng-if=!myform.hideFooter class=\"navbar navbar-fixed-bottom\" ng-style=\"{ 'background-color':myform.design.colors.buttonColor, 'padding-top': '15px', 'border-top': '2px '+ myform.design.colors.buttonTextColor +' solid', 'color':myform.design.colors.buttonTextColor}\"><div class=container-fluid><div class=row><div class=\"col-sm-5 col-md-6 col-xs-5\" ng-show=!myform.submitted><p class=lead>{{ 'ADVANCEMENT' | translate:translateAdvancementData }}</p></div><div class=\"col-md-6 col-md-offset-0 col-sm-offset-2 col-sm-3 col-xs-offset-1 col-xs-6 row\"><div class=\"col-md-4 col-md-offset-2 hidden-sm hidden-xs\" > < a href = / # ! / f o r m s c l a s s = b t n
} ] ) ;
2016-06-20 22:35:41 +00:00
'use strict' ;
// Use Application configuration module to register a new module
ApplicationConfiguration . registerModule ( 'view-form' , [
2017-04-11 07:10:36 +00:00
'ngFileUpload' , 'ui.date' , 'angular-input-stars'
2016-08-23 21:45:59 +00:00
] ) ;
2016-06-20 22:35:41 +00:00
'use strict' ;
angular . module ( 'view-form' ) . config ( [ '$translateProvider' , function ( $translateProvider ) {
$translateProvider . translations ( 'english' , {
FORM _SUCCESS : 'Form entry successfully submitted!' ,
REVIEW : 'Review' ,
BACK _TO _FORM : 'Go back to Form' ,
EDIT _FORM : 'Edit this TellForm' ,
CREATE _FORM : 'Create this TellForm' ,
ADVANCEMENT : '{{done}} out of {{total}} answered' ,
CONTINUE _FORM : 'Continue to Form' ,
REQUIRED : 'required' ,
COMPLETING _NEEDED : '{{answers_not_completed}} answer(s) need completing' ,
OPTIONAL : 'optional' ,
ERROR _EMAIL _INVALID : 'Please enter a valid email address' ,
ERROR _NOT _A _NUMBER : 'Please enter valid numbers only' ,
ERROR _URL _INVALID : 'Please a valid url' ,
OK : 'OK' ,
ENTER : 'press ENTER' ,
YES : 'Yes' ,
NO : 'No' ,
NEWLINE : 'press SHIFT+ENTER to create a newline' ,
CONTINUE : 'Continue' ,
LEGAL _ACCEPT : 'I accept' ,
LEGAL _NO _ACCEPT : 'I don’ t accept' ,
DELETE : 'Delete' ,
CANCEL : 'Cancel' ,
SUBMIT : 'Submit' ,
UPLOAD _FILE : 'Upload your File' ,
} ) ;
$translateProvider . preferredLanguage ( 'english' )
. fallbackLanguage ( 'english' )
. useSanitizeValueStrategy ( 'escape' ) ;
} ] ) ;
'use strict' ;
angular . module ( 'view-form' ) . config ( [ '$translateProvider' , function ( $translateProvider ) {
$translateProvider . translations ( 'french' , {
FORM _SUCCESS : 'Votre formulaire a été enregistré!' ,
REVIEW : 'Incomplet' ,
BACK _TO _FORM : 'Retourner au formulaire' ,
EDIT _FORM : 'Éditer le Tellform' ,
CREATE _FORM : 'Créer un TellForm' ,
ADVANCEMENT : '{{done}} complétés sur {{total}}' ,
CONTINUE _FORM : 'Aller au formulaire' ,
REQUIRED : 'obligatoire' ,
COMPLETING _NEEDED : '{{answers_not_completed}} réponse(s) doive(nt) être complétée(s)' ,
OPTIONAL : 'facultatif' ,
ERROR _EMAIL _INVALID : 'Merci de rentrer une adresse mail valide' ,
ERROR _NOT _A _NUMBER : 'Merce de ne rentrer que des nombres' ,
ERROR _URL _INVALID : 'Merci de rentrer une url valide' ,
OK : 'OK' ,
ENTER : 'presser ENTRÉE' ,
YES : 'Oui' ,
NO : 'Non' ,
NEWLINE : 'presser SHIFT+ENTER pour créer une nouvelle ligne' ,
CONTINUE : 'Continuer' ,
LEGAL _ACCEPT : 'J’ accepte' ,
LEGAL _NO _ACCEPT : 'Je n’ accepte pas' ,
DELETE : 'Supprimer' ,
CANCEL : 'Réinitialiser' ,
SUBMIT : 'Enregistrer' ,
UPLOAD _FILE : 'Envoyer un fichier' ,
Y : 'O' ,
N : 'N' ,
} ) ;
} ] ) ;
'use strict' ;
angular . module ( 'view-form' ) . config ( [ '$translateProvider' , function ( $translateProvider ) {
$translateProvider . translations ( 'german' , {
FORM _SUCCESS : 'Ihre Angaben wurden gespeichert.' ,
REVIEW : 'Unvollständig' ,
BACK _TO _FORM : 'Zurück zum Formular' ,
EDIT _FORM : '' ,
CREATE _FORM : '' ,
ADVANCEMENT : '{{done}} von {{total}} beantwortet' ,
CONTINUE _FORM : 'Zum Formular' ,
REQUIRED : 'verpflichtend' ,
COMPLETING _NEEDED : 'Es fehlen/fehtl noch {{answers_not_completed}} Antwort(en)' ,
OPTIONAL : 'fakultativ' ,
ERROR _EMAIL _INVALID : 'Bitte gültige Mailadresse eingeben' ,
ERROR _NOT _A _NUMBER : 'Bitte nur Zahlen eingeben' ,
ERROR _URL _INVALID : 'Bitte eine gültige URL eingeben' ,
OK : 'Okay' ,
ENTER : 'Eingabetaste drücken' ,
YES : 'Ja' ,
NO : 'Nein' ,
NEWLINE : 'Für eine neue Zeile SHIFT+ENTER drücken' ,
CONTINUE : 'Weiter' ,
LEGAL _ACCEPT : 'I accept' ,
LEGAL _NO _ACCEPT : 'I don’ t accept' ,
DELETE : 'Entfernen' ,
CANCEL : 'Canceln' ,
SUBMIT : 'Speichern' ,
UPLOAD _FILE : 'Datei versenden' ,
Y : 'J' ,
N : 'N' ,
} ) ;
} ] ) ;
'use strict' ;
angular . module ( 'view-form' ) . config ( [ '$translateProvider' , function ( $translateProvider ) {
$translateProvider . translations ( 'italian' , {
FORM _SUCCESS : 'Il formulario è stato inviato con successo!' ,
REVIEW : 'Incompleto' ,
BACK _TO _FORM : 'Ritorna al formulario' ,
EDIT _FORM : '' ,
CREATE _FORM : '' ,
ADVANCEMENT : '{{done}} su {{total}} completate' ,
CONTINUE _FORM : 'Vai al formulario' ,
REQUIRED : 'obbligatorio' ,
COMPLETING _NEEDED : '{{answers_not_completed}} risposta/e deve/ono essere completata/e' ,
OPTIONAL : 'opzionale' ,
ERROR _EMAIL _INVALID : 'Si prega di inserire un indirizzo email valido' ,
ERROR _NOT _A _NUMBER : 'Si prega di inserire solo numeri' ,
ERROR _URL _INVALID : 'Grazie per inserire un URL valido' ,
OK : 'OK' ,
ENTER : 'premere INVIO' ,
YES : 'Sì' ,
NO : 'No' ,
NEWLINE : 'premere SHIFT+INVIO per creare una nuova linea' ,
CONTINUE : 'Continua' ,
LEGAL _ACCEPT : 'I accept' ,
LEGAL _NO _ACCEPT : 'I don’ t accept' ,
DELETE : 'Cancella' ,
CANCEL : 'Reset' ,
SUBMIT : 'Registra' ,
UPLOAD _FILE : 'Invia un file' ,
Y : 'S' ,
N : 'N' ,
} ) ;
} ] ) ;
'use strict' ;
angular . module ( 'view-form' ) . config ( [ '$translateProvider' , function ( $translateProvider ) {
$translateProvider . translations ( 'spanish' , {
FORM _SUCCESS : '¡El formulario ha sido enviado con éxito!' ,
REVIEW : 'Revisar' ,
BACK _TO _FORM : 'Regresar al formulario' ,
EDIT _FORM : '' ,
CREATE _FORM : '' ,
ADVANCEMENT : '{{done}} de {{total}} contestadas' ,
CONTINUE _FORM : 'Continuar al formulario' ,
REQUIRED : 'Información requerida' ,
COMPLETING _NEEDED : '{{answers_not_completed}} respuesta(s) necesita(n) ser completada(s)' ,
OPTIONAL : 'Opcional' ,
ERROR _EMAIL _INVALID : 'Favor de proporcionar un correo electrónico válido' ,
ERROR _NOT _A _NUMBER : 'Por favor, introduzca sólo números válidos' ,
ERROR _URL _INVALID : 'Favor de proporcionar un url válido' ,
OK : 'OK' ,
ENTER : 'pulse INTRO' ,
YES : 'Si' ,
NO : 'No' ,
NEWLINE : 'presione SHIFT+INTRO para crear una nueva línea' ,
CONTINUE : 'Continuar' ,
2017-07-20 23:09:21 +00:00
LEGAL _ACCEPT : 'Yo acepto' ,
LEGAL _NO _ACCEPT : 'Yo no acepto' ,
2016-06-20 22:35:41 +00:00
DELETE : 'Eliminar' ,
CANCEL : 'Cancelar' ,
SUBMIT : 'Registrar' ,
UPLOAD _FILE : 'Cargar el archivo' ,
Y : 'S' ,
N : 'N'
} ) ;
} ] ) ;
'use strict' ;
// Setting up route
angular . module ( 'view-form' ) . config ( [ '$stateProvider' ,
function ( $stateProvider ) {
// Forms state routing
$stateProvider .
state ( 'submitForm' , {
url : '/forms/:formId' ,
templateUrl : '/static/form_modules/forms/base/views/submit-form.client.view.html' ,
resolve : {
Forms : 'Forms' ,
2017-07-25 22:08:25 +00:00
myForm : [ "Forms" , "$q" , "$state" , "$stateParams" , function ( Forms , $q , $state , $stateParams ) {
var deferred = $q . defer ( ) ;
console . log ( Forms . get ( { formId : $stateParams . formId } ) . $promise ) ;
return Forms . get ( { formId : $stateParams . formId } ) . $promise . then ( function ( data ) {
console . log ( data ) ;
return data ;
} , function ( reason ) {
console . log ( reason ) ;
$state . go ( 'unauthorizedFormAccess' ) ;
return deferred . reject ( { redirectTo : 'unauthorizedFormAccess' } ) ;
} ) ;
//return Forms.get({formId: $stateParams.formId}).$promise;
2016-06-20 22:35:41 +00:00
} ]
} ,
controller : 'SubmitFormController' ,
controllerAs : 'ctrl'
2017-07-25 22:08:25 +00:00
} ) .
state ( 'unauthorizedFormAccess' , {
url : '/forms/unauthorized' ,
2017-07-26 20:41:53 +00:00
templateUrl : '/static/form_modules/forms/base/views/form-unauthorized.client.view.html' ,
2017-07-25 22:08:25 +00:00
} ) ;
}
2016-06-20 22:35:41 +00:00
] ) ;
( function ( ) {
'use strict' ;
// Create the SendVisitorData service
angular
. module ( 'view-form' )
. factory ( 'SendVisitorData' , SendVisitorData ) ;
SendVisitorData . $inject = [ 'Socket' , '$state' ] ;
function SendVisitorData ( Socket , $state ) {
// Create a controller method for sending visitor data
function send ( form , lastActiveIndex , timeElapsed ) {
2016-11-09 19:04:47 +00:00
var lang = window . navigator . userLanguage || window . navigator . language ;
lang = lang . slice ( 0 , 2 ) ;
var userAgentString = navigator . userAgent ;
var md = new MobileDetect ( userAgentString ) ;
var deviceType = 'other' ;
if ( md . tablet ( ) ) {
deviceType = 'tablet' ;
} else if ( md . mobile ( ) ) {
deviceType = 'mobile' ;
2017-03-06 21:45:11 +00:00
} else if ( ! md . is ( 'bot' ) ) {
2016-11-09 19:04:47 +00:00
deviceType = 'desktop' ;
}
2016-11-09 19:20:50 +00:00
2017-07-20 23:09:21 +00:00
$ . ajaxSetup ( { 'async' : false } ) ;
2017-03-10 19:26:07 +00:00
var geoData = $ . getJSON ( 'https://freegeoip.net/json/' ) . responseJSON ;
2017-07-20 23:09:21 +00:00
$ . ajaxSetup ( { 'async' : true } ) ;
2016-11-09 19:04:47 +00:00
2017-03-27 20:32:06 +00:00
if ( ! geoData ) {
geoData = {
ip : '' ,
city : '' ,
country _name : ''
2017-07-20 23:09:21 +00:00
} ;
2017-03-27 20:32:06 +00:00
}
2016-06-20 22:35:41 +00:00
// Create a new message object
var visitorData = {
referrer : document . referrer ,
isSubmitted : form . submitted ,
formId : form . _id ,
lastActiveField : form . form _fields [ lastActiveIndex ] . _id ,
2016-11-09 19:04:47 +00:00
timeElapsed : timeElapsed ,
language : lang ,
deviceType : deviceType ,
2017-03-06 21:45:11 +00:00
ipAddr : geoData . ip ,
geoLocation : {
city : geoData . city ,
country : geoData . country _name
}
2016-06-20 22:35:41 +00:00
} ;
Socket . emit ( 'form-visitor-data' , visitorData ) ;
}
function init ( ) {
// Make sure the Socket is connected
if ( ! Socket . socket ) {
Socket . connect ( ) ;
}
}
var service = {
send : send
} ;
init ( ) ;
return service ;
}
} ( ) ) ;
'use strict' ;
angular . module ( 'view-form' ) . directive ( 'keyToOption' , function ( ) {
return {
restrict : 'A' ,
scope : {
field : '='
} ,
link : function ( $scope , $element , $attrs , $select ) {
$element . bind ( 'keydown keypress' , function ( event ) {
var keyCode = event . which || event . keyCode ;
var index = parseInt ( String . fromCharCode ( keyCode ) ) - 1 ;
//console.log($scope.field);
if ( index < $scope . field . fieldOptions . length ) {
event . preventDefault ( ) ;
$scope . $apply ( function ( ) {
$scope . field . fieldValue = $scope . field . fieldOptions [ index ] . option _value ;
} ) ;
}
} ) ;
}
} ;
} ) ;
'use strict' ;
angular . module ( 'view-form' ) . directive ( 'keyToTruthy' , [ '$rootScope' , function ( $rootScope ) {
return {
restrict : 'A' ,
scope : {
2017-08-02 21:45:49 +00:00
field : '=' ,
nextField : '&'
2016-06-20 22:35:41 +00:00
} ,
link : function ( $scope , $element , $attrs ) {
$element . bind ( 'keydown keypress' , function ( event ) {
var keyCode = event . which || event . keyCode ;
var truthyKeyCode = $attrs . keyCharTruthy . charCodeAt ( 0 ) - 32 ;
var falseyKeyCode = $attrs . keyCharFalsey . charCodeAt ( 0 ) - 32 ;
2017-08-02 21:45:49 +00:00
console . log ( $scope ) ;
if ( keyCode === truthyKeyCode ) {
2016-06-20 22:35:41 +00:00
event . preventDefault ( ) ;
$scope . $apply ( function ( ) {
$scope . field . fieldValue = 'true' ;
2017-08-02 21:45:49 +00:00
if ( $attrs . onValidKey ) {
$scope . $root . $eval ( $attrs . onValidKey ) ;
}
2016-06-20 22:35:41 +00:00
} ) ;
} else if ( keyCode === falseyKeyCode ) {
event . preventDefault ( ) ;
$scope . $apply ( function ( ) {
$scope . field . fieldValue = 'false' ;
2017-08-02 21:45:49 +00:00
if ( $attrs . onValidKey ) {
$scope . $root . $eval ( $attrs . onValidKey ) ;
}
} ) ;
2016-06-20 22:35:41 +00:00
}
} ) ;
}
} ;
} ] ) ;
'use strict' ;
// Configuring the Forms drop-down menus
angular . module ( 'view-form' )
. filter ( 'formValidity' , function ( ) {
return function ( formObj ) {
if ( formObj && formObj . form _fields && formObj . visible _form _fields ) {
//get keys
var formKeys = Object . keys ( formObj ) ;
//we only care about things that don't start with $
var fieldKeys = formKeys . filter ( function ( key ) {
return key [ 0 ] !== '$' ;
} ) ;
var fields = formObj . form _fields ;
var valid _count = fields . filter ( function ( field ) {
2017-07-27 05:22:58 +00:00
if ( typeof field === 'object' && field . fieldType !== 'rating' && field . fieldType !== 'statement' ) {
2016-06-20 22:35:41 +00:00
return ! ! ( field . fieldValue ) ;
2017-07-27 05:22:58 +00:00
} else if ( field . fieldType === 'rating' ) {
return true ;
2016-06-20 22:35:41 +00:00
}
} ) . length ;
return valid _count - ( formObj . form _fields . length - formObj . visible _form _fields . length ) ;
}
return 0 ;
} ;
} ) ;
angular . module ( 'view-form' ) . value ( 'supportedFields' , [
'textfield' ,
'textarea' ,
'date' ,
'dropdown' ,
'hidden' ,
'password' ,
'radio' ,
'legal' ,
'statement' ,
'rating' ,
'yes_no' ,
'number' ,
'natural'
] ) ;
2017-03-06 21:45:11 +00:00
angular . module ( 'view-form' ) . constant ( 'VIEW_FORM_URL' , '/forms/:formId/render' ) ;
2016-06-20 22:35:41 +00:00
'use strict' ;
// SubmitForm controller
angular . module ( 'view-form' ) . controller ( 'SubmitFormController' , [
'$scope' , '$rootScope' , '$state' , '$translate' , 'myForm' ,
function ( $scope , $rootScope , $state , $translate , myForm ) {
$scope . myform = myForm ;
2017-07-25 22:08:25 +00:00
$translate . use ( myForm . language ) ;
2016-06-20 22:35:41 +00:00
}
] ) ;
'use strict' ;
angular . module ( 'view-form' ) . directive ( 'fieldIconDirective' , function ( ) {
return {
template : '<i class="{{typeIcon}}"></i>' ,
restrict : 'E' ,
scope : {
typeName : '@'
} ,
controller : [ "$scope" , function ( $scope ) {
var iconTypeMap = {
'textfield' : 'fa fa-pencil-square-o' ,
'dropdown' : 'fa fa-th-list' ,
'date' : 'fa fa-calendar' ,
'checkbox' : 'fa fa-check-square-o' ,
'radio' : 'fa fa-dot-circle-o' ,
'email' : 'fa fa-envelope-o' ,
'textarea' : 'fa fa-pencil-square' ,
'legal' : 'fa fa-legal' ,
'file' : 'fa fa-cloud-upload' ,
'rating' : 'fa fa-star-half-o' ,
'link' : 'fa fa-link' ,
'scale' : 'fa fa-sliders' ,
'stripe' : 'fa fa-credit-card' ,
'statement' : 'fa fa-quote-left' ,
'yes_no' : 'fa fa-toggle-on' ,
'number' : 'fa fa-slack'
} ;
$scope . typeIcon = iconTypeMap [ $scope . typeName ] ;
} ]
} ;
} ) ;
'use strict' ;
// coffeescript's for in loop
var _ _indexOf = [ ] . indexOf || function ( item ) {
2016-10-07 15:31:15 +00:00
for ( var i = 0 , l = this . length ; i < l ; i ++ ) {
if ( i in this && this [ i ] === item ) return i ;
}
return - 1 ;
} ;
2016-06-20 22:35:41 +00:00
angular . module ( 'view-form' ) . directive ( 'fieldDirective' , [ '$http' , '$compile' , '$rootScope' , '$templateCache' , 'supportedFields' ,
2016-10-07 15:31:15 +00:00
function ( $http , $compile , $rootScope , $templateCache , supportedFields ) {
var getTemplateUrl = function ( fieldType ) {
var type = fieldType ;
var supported _fields = [
'textfield' ,
'textarea' ,
'date' ,
'dropdown' ,
'hidden' ,
'password' ,
'radio' ,
'legal' ,
'statement' ,
'rating' ,
'yes_no' ,
'number' ,
'natural'
] ;
2017-03-28 00:08:45 +00:00
var templateUrl = 'form_modules/forms/base/views/directiveViews/field/' ;
2016-10-07 15:31:15 +00:00
if ( _ _indexOf . call ( supportedFields , type ) >= 0 ) {
templateUrl = templateUrl + type + '.html' ;
}
return $templateCache . get ( templateUrl ) ;
} ;
2016-06-20 22:35:41 +00:00
2016-10-07 15:31:15 +00:00
return {
template : '<div>{{field.title}}</div>' ,
restrict : 'E' ,
scope : {
field : '=' ,
required : '&' ,
design : '=' ,
index : '=' ,
forms : '='
} ,
link : function ( scope , element ) {
2017-03-28 00:08:45 +00:00
2016-10-07 15:31:15 +00:00
$rootScope . chooseDefaultOption = scope . chooseDefaultOption = function ( type ) {
if ( type === 'yes_no' ) {
scope . field . fieldValue = 'true' ;
} else if ( type === 'rating' ) {
scope . field . fieldValue = 0 ;
} else if ( scope . field . fieldType === 'radio' ) {
console . log ( scope . field ) ;
scope . field . fieldValue = scope . field . fieldOptions [ 0 ] . option _value ;
console . log ( scope . field . fieldValue ) ;
} else if ( type === 'legal' ) {
scope . field . fieldValue = 'true' ;
$rootScope . nextField ( ) ;
}
} ;
2017-08-02 20:33:52 +00:00
scope . nextField = $rootScope . nextField ;
2016-10-07 15:31:15 +00:00
scope . setActiveField = $rootScope . setActiveField ;
2016-06-20 22:35:41 +00:00
2016-10-07 15:31:15 +00:00
//Set format only if field is a date
if ( scope . field . fieldType === 'date' ) {
scope . dateOptions = {
changeYear : true ,
changeMonth : true ,
altFormat : 'mm/dd/yyyy' ,
yearRange : '1900:-0' ,
defaultDate : 0
} ;
2016-06-20 22:35:41 +00:00
}
2016-10-07 15:31:15 +00:00
var fieldType = scope . field . fieldType ;
if ( scope . field . fieldType === 'number' || scope . field . fieldType === 'textfield' || scope . field . fieldType === 'email' || scope . field . fieldType === 'link' ) {
switch ( scope . field . fieldType ) {
case 'textfield' :
scope . input _type = 'text' ;
break ;
case 'email' :
scope . input _type = 'email' ;
scope . placeholder = 'joesmith@example.com' ;
break ;
case 'number' :
scope . input _type = 'text' ;
scope . validateRegex = /^-?\d+$/ ;
break ;
default :
scope . input _type = 'url' ;
scope . placeholder = 'http://example.com' ;
break ;
}
fieldType = 'textfield' ;
2016-06-20 22:35:41 +00:00
}
2016-10-07 15:31:15 +00:00
var template = getTemplateUrl ( fieldType ) ;
element . html ( template ) . show ( ) ;
var output = $compile ( element . contents ( ) ) ( scope ) ;
2016-06-20 22:35:41 +00:00
}
2016-10-07 15:31:15 +00:00
} ;
} ] ) ;
2016-06-20 22:35:41 +00:00
'use strict' ;
//TODO: DAVID: Need to refactor this
angular . module ( 'view-form' ) . directive ( 'onEnterKey' , [ '$rootScope' , function ( $rootScope ) {
return {
restrict : 'A' ,
link : function ( $scope , $element , $attrs ) {
$element . bind ( 'keydown keypress' , function ( event ) {
var keyCode = event . which || event . keyCode ;
var onEnterKeyDisabled = false ;
if ( $attrs . onEnterKeyDisabled !== null ) onEnterKeyDisabled = $attrs . onEnterKeyDisabled ;
if ( keyCode === 13 && ! event . shiftKey && ! onEnterKeyDisabled ) {
event . preventDefault ( ) ;
$rootScope . $apply ( function ( ) {
$rootScope . $eval ( $attrs . onEnterKey ) ;
} ) ;
}
} ) ;
}
} ;
} ] ) . directive ( 'onTabKey' , [ '$rootScope' , function ( $rootScope ) {
return {
restrict : 'A' ,
link : function ( $scope , $element , $attrs ) {
$element . bind ( 'keydown keypress' , function ( event ) {
var keyCode = event . which || event . keyCode ;
if ( keyCode === 9 && ! event . shiftKey ) {
event . preventDefault ( ) ;
$rootScope . $apply ( function ( ) {
$rootScope . $eval ( $attrs . onTabKey ) ;
} ) ;
}
} ) ;
}
} ;
} ] ) . directive ( 'onEnterOrTabKey' , [ '$rootScope' , function ( $rootScope ) {
return {
restrict : 'A' ,
link : function ( $scope , $element , $attrs ) {
$element . bind ( 'keydown keypress' , function ( event ) {
var keyCode = event . which || event . keyCode ;
if ( ( keyCode === 13 || keyCode === 9 ) && ! event . shiftKey ) {
event . preventDefault ( ) ;
$rootScope . $apply ( function ( ) {
$rootScope . $eval ( $attrs . onEnterOrTabKey ) ;
} ) ;
}
} ) ;
}
} ;
} ] ) . directive ( 'onTabAndShiftKey' , [ '$rootScope' , function ( $rootScope ) {
return {
restrict : 'A' ,
link : function ( $scope , $element , $attrs ) {
$element . bind ( 'keydown keypress' , function ( event ) {
var keyCode = event . which || event . keyCode ;
if ( keyCode === 9 && event . shiftKey ) {
event . preventDefault ( ) ;
$rootScope . $apply ( function ( ) {
$rootScope . $eval ( $attrs . onTabAndShiftKey ) ;
} ) ;
}
} ) ;
}
} ;
} ] ) ;
'use strict' ;
angular . module ( 'view-form' ) . directive ( 'onFinishRender' , [ "$rootScope" , "$timeout" , function ( $rootScope , $timeout ) {
return {
restrict : 'A' ,
link : function ( scope , element , attrs ) {
//Don't do anything if we don't have a ng-repeat on the current element
if ( ! element . attr ( 'ng-repeat' ) && ! element . attr ( 'data-ng-repeat' ) ) {
return ;
}
var broadcastMessage = attrs . onFinishRender || 'ngRepeat' ;
if ( scope . $first && ! scope . $last ) {
scope . $evalAsync ( function ( ) {
$rootScope . $broadcast ( broadcastMessage + ' Started' ) ;
} ) ;
} else if ( scope . $last ) {
scope . $evalAsync ( function ( ) {
// console.log(broadcastMessage+'Finished');
$rootScope . $broadcast ( broadcastMessage + ' Finished' ) ;
} ) ;
}
}
} ;
} ] ) ;
'use strict' ;
2016-10-07 15:31:15 +00:00
//FIXME: Should find an appropriate place for this
//Setting up jsep
2017-07-20 23:09:21 +00:00
jsep . addBinaryOp ( 'contains' , 10 ) ;
jsep . addBinaryOp ( '!contains' , 10 ) ;
jsep . addBinaryOp ( 'begins' , 10 ) ;
jsep . addBinaryOp ( '!begins' , 10 ) ;
jsep . addBinaryOp ( 'ends' , 10 ) ;
jsep . addBinaryOp ( '!ends' , 10 ) ;
2016-06-20 22:35:41 +00:00
angular . module ( 'view-form' ) . directive ( 'submitFormDirective' , [ '$http' , 'TimeCounter' , '$filter' , '$rootScope' , 'SendVisitorData' ,
function ( $http , TimeCounter , $filter , $rootScope , SendVisitorData ) {
return {
2017-03-28 00:08:45 +00:00
templateUrl : 'form_modules/forms/base/views/directiveViews/form/submit-form.client.view.html' ,
2016-06-20 22:35:41 +00:00
restrict : 'E' ,
scope : {
myform : '='
} ,
controller : [ "$document" , "$window" , "$scope" , function ( $document , $window , $scope ) {
$scope . noscroll = false ;
$scope . forms = { } ;
2017-03-06 21:45:11 +00:00
TimeCounter . restartClock ( ) ;
2016-06-20 22:35:41 +00:00
2017-07-27 05:22:58 +00:00
var form _fields _count = $scope . myform . visible _form _fields . filter ( function ( field ) {
if ( field . fieldType === 'statement' ) {
2016-06-20 22:35:41 +00:00
return false ;
}
return true ;
} ) . length ;
2017-07-27 05:22:58 +00:00
var nb _valid = $filter ( 'formValidity' ) ( $scope . myform ) ;
$scope . translateAdvancementData = {
done : nb _valid ,
total : form _fields _count ,
answers _not _completed : form _fields _count - nb _valid
} ;
2016-06-20 22:35:41 +00:00
$scope . reloadForm = function ( ) {
//Reset Form
$scope . myform . submitted = false ;
$scope . myform . form _fields = _ . chain ( $scope . myform . visible _form _fields ) . map ( function ( field ) {
field . fieldValue = '' ;
return field ;
} ) . value ( ) ;
$scope . loading = false ;
$scope . error = '' ;
$scope . selected = {
_id : '' ,
index : 0
} ;
$scope . setActiveField ( $scope . myform . visible _form _fields [ 0 ] . _id , 0 , false ) ;
//Reset Timer
TimeCounter . restartClock ( ) ;
} ;
//Fire event when window is scrolled
$window . onscroll = function ( ) {
$scope . scrollPos = document . body . scrollTop || document . documentElement . scrollTop || 0 ;
var elemBox = document . getElementsByClassName ( 'activeField' ) [ 0 ] . getBoundingClientRect ( ) ;
$scope . fieldTop = elemBox . top ;
$scope . fieldBottom = elemBox . bottom ;
//console.log($scope.forms.myForm);
var field _id ;
var field _index ;
if ( ! $scope . noscroll ) {
//Focus on submit button
if ( $scope . selected . index === $scope . myform . visible _form _fields . length - 1 && $scope . fieldBottom < 200 ) {
field _index = $scope . selected . index + 1 ;
field _id = 'submit_field' ;
$scope . setActiveField ( field _id , field _index , false ) ;
}
//Focus on field above submit button
else if ( $scope . selected . index === $scope . myform . visible _form _fields . length ) {
if ( $scope . fieldTop > 200 ) {
field _index = $scope . selected . index - 1 ;
field _id = $scope . myform . visible _form _fields [ field _index ] . _id ;
$scope . setActiveField ( field _id , field _index , false ) ;
}
} else if ( $scope . fieldBottom < 0 ) {
field _index = $scope . selected . index + 1 ;
field _id = $scope . myform . visible _form _fields [ field _index ] . _id ;
$scope . setActiveField ( field _id , field _index , false ) ;
} else if ( $scope . selected . index !== 0 && $scope . fieldTop > 0 ) {
field _index = $scope . selected . index - 1 ;
field _id = $scope . myform . visible _form _fields [ field _index ] . _id ;
$scope . setActiveField ( field _id , field _index , false ) ;
}
//console.log('$scope.selected.index: '+$scope.selected.index);
//console.log('scroll pos: '+$scope.scrollPos+' fieldTop: '+$scope.fieldTop+' fieldBottom: '+$scope.fieldBottom);
$scope . $apply ( ) ;
}
} ;
/ *
* * Field Controls
* /
2016-08-23 21:45:59 +00:00
var evaluateLogicJump = function ( field ) {
var logicJump = field . logicJump ;
2016-10-07 15:31:15 +00:00
if ( logicJump . expressionString && logicJump . valueB && field . fieldValue ) {
var parse _tree = jsep ( logicJump . expressionString ) ;
var left , right ;
if ( parse _tree . left . name === 'field' ) {
left = field . fieldValue ;
2017-07-20 23:09:21 +00:00
right = logicJump . valueB ;
2016-10-07 15:31:15 +00:00
} else {
left = logicJump . valueB ;
right = field . fieldValue ;
}
if ( field . fieldType === 'number' || field . fieldType === 'scale' || field . fieldType === 'rating' ) {
switch ( parse _tree . operator ) {
case '==' :
return ( parseInt ( left ) === parseInt ( right ) ) ;
case '!==' :
return ( parseInt ( left ) !== parseInt ( right ) ) ;
case '>' :
return ( parseInt ( left ) > parseInt ( right ) ) ;
case '>=' :
return ( parseInt ( left ) > parseInt ( right ) ) ;
case '<' :
return ( parseInt ( left ) < parseInt ( right ) ) ;
case '<=' :
return ( parseInt ( left ) <= parseInt ( right ) ) ;
default :
return false ;
}
} else {
switch ( parse _tree . operator ) {
case '==' :
return ( left === right ) ;
case '!==' :
return ( left !== right ) ;
case 'contains' :
return ( left . indexOf ( right ) > - 1 ) ;
case '!contains' :
2017-07-20 23:09:21 +00:00
/* jshint -W018 */
2016-10-07 15:31:15 +00:00
return ! ( left . indexOf ( right ) > - 1 ) ;
case 'begins' :
return left . startsWith ( right ) ;
case '!begins' :
return ! left . startsWith ( right ) ;
case 'ends' :
return left . endsWith ( right ) ;
case '!ends' :
return left . endsWith ( right ) ;
default :
return false ;
}
}
2016-08-23 21:45:59 +00:00
}
} ;
2016-06-20 22:35:41 +00:00
var getActiveField = function ( ) {
if ( $scope . selected === null ) {
console . error ( 'current active field is null' ) ;
throw new Error ( 'current active field is null' ) ;
}
if ( $scope . selected . _id === 'submit_field' ) {
return $scope . myform . form _fields . length - 1 ;
}
2017-07-20 23:09:21 +00:00
return $scope . selected . index ;
2016-06-20 22:35:41 +00:00
} ;
$scope . setActiveField = $rootScope . setActiveField = function ( field _id , field _index , animateScroll ) {
if ( $scope . selected === null || $scope . selected . _id === field _id ) {
//console.log('not scrolling');
//console.log($scope.selected);
return ;
}
//console.log('field_id: '+field_id);
//console.log('field_index: '+field_index);
//console.log($scope.selected);
$scope . selected . _id = field _id ;
$scope . selected . index = field _index ;
2016-08-23 21:45:59 +00:00
if ( ! field _index ) {
2016-10-07 15:31:15 +00:00
for ( var i = 0 ; i < $scope . myform . visible _form _fields . length ; i ++ ) {
var currField = $scope . myform . visible _form _fields [ i ] ;
2017-07-20 23:09:21 +00:00
if ( field _id === currField . _id ) {
2016-08-23 21:45:59 +00:00
$scope . selected . index = i ;
break ;
}
}
}
2016-06-20 22:35:41 +00:00
var nb _valid = $filter ( 'formValidity' ) ( $scope . myform ) ;
$scope . translateAdvancementData = {
done : nb _valid ,
total : form _fields _count ,
answers _not _completed : form _fields _count - nb _valid
} ;
if ( animateScroll ) {
$scope . noscroll = true ;
setTimeout ( function ( ) {
$document . scrollToElement ( angular . element ( '.activeField' ) , - 10 , 200 ) . then ( function ( ) {
$scope . noscroll = false ;
setTimeout ( function ( ) {
if ( document . querySelectorAll ( '.activeField .focusOn' ) . length ) {
//Handle default case
document . querySelectorAll ( '.activeField .focusOn' ) [ 0 ] . focus ( ) ;
} else if ( document . querySelectorAll ( '.activeField input' ) . length ) {
//Handle case for rating input
document . querySelectorAll ( '.activeField input' ) [ 0 ] . focus ( ) ;
} else {
//Handle case for dropdown input
document . querySelectorAll ( '.activeField .selectize-input' ) [ 0 ] . focus ( ) ;
}
} ) ;
} ) ;
} ) ;
} else {
setTimeout ( function ( ) {
if ( document . querySelectorAll ( '.activeField .focusOn' ) [ 0 ] ) {
//FIXME: DAVID: Figure out how to set focus without scroll movement in HTML Dom
document . querySelectorAll ( '.activeField .focusOn' ) [ 0 ] . focus ( ) ;
} else {
document . querySelectorAll ( '.activeField input' ) [ 0 ] . focus ( ) ;
}
} ) ;
}
SendVisitorData . send ( $scope . myform , getActiveField ( ) , TimeCounter . getTimeElapsed ( ) ) ;
} ;
$rootScope . nextField = $scope . nextField = function ( ) {
2016-08-23 21:45:59 +00:00
var currField = $scope . myform . visible _form _fields [ $scope . selected . index ] ;
2016-10-07 15:31:15 +00:00
2016-08-23 21:45:59 +00:00
if ( $scope . selected && $scope . selected . index > - 1 ) {
//Jump to logicJump's destination if it is true
if ( currField . logicJump && evaluateLogicJump ( currField ) ) {
$rootScope . setActiveField ( currField . logicJump . jumpTo , null , true ) ;
} else {
var selected _index , selected _id ;
if ( $scope . selected . index < $scope . myform . visible _form _fields . length - 1 ) {
selected _index = $scope . selected . index + 1 ;
selected _id = $scope . myform . visible _form _fields [ selected _index ] . _id ;
$rootScope . setActiveField ( selected _id , selected _index , true ) ;
} else if ( $scope . selected . index === $scope . myform . visible _form _fields . length - 1 ) {
selected _index = $scope . selected . index + 1 ;
selected _id = 'submit_field' ;
$rootScope . setActiveField ( selected _id , selected _index , true ) ;
}
}
2016-06-20 22:35:41 +00:00
}
2016-08-23 21:45:59 +00:00
2016-06-20 22:35:41 +00:00
} ;
$rootScope . prevField = $scope . prevField = function ( ) {
if ( $scope . selected . index > 0 ) {
var selected _index = $scope . selected . index - 1 ;
var selected _id = $scope . myform . visible _form _fields [ selected _index ] . _id ;
$scope . setActiveField ( selected _id , selected _index , true ) ;
}
} ;
/ *
* * Form Display Functions
* /
$scope . exitStartPage = function ( ) {
$scope . myform . startPage . showStart = false ;
if ( $scope . myform . visible _form _fields . length > 0 ) {
$scope . selected . _id = $scope . myform . visible _form _fields [ 0 ] . _id ;
}
} ;
$rootScope . goToInvalid = $scope . goToInvalid = function ( ) {
document . querySelectorAll ( '.ng-invalid.focusOn' ) [ 0 ] . focus ( ) ;
} ;
2017-03-06 21:45:11 +00:00
var getDeviceData = function ( ) {
var md = new MobileDetect ( window . navigator . userAgent ) ;
var deviceType = 'other' ;
if ( md . tablet ( ) ) {
deviceType = 'tablet' ;
} else if ( md . mobile ( ) ) {
deviceType = 'mobile' ;
} else if ( ! md . is ( 'bot' ) ) {
deviceType = 'desktop' ;
}
return {
type : deviceType ,
name : window . navigator . platform
2017-07-20 23:09:21 +00:00
} ;
2017-03-06 21:45:11 +00:00
} ;
var getIpAndGeo = function ( ) {
//Get Ip Address and GeoLocation Data
2017-07-20 23:09:21 +00:00
$ . ajaxSetup ( { 'async' : false } ) ;
2017-03-10 19:26:07 +00:00
var geoData = $ . getJSON ( 'https://freegeoip.net/json/' ) . responseJSON ;
2017-07-20 23:09:21 +00:00
$ . ajaxSetup ( { 'async' : true } ) ;
2017-03-06 21:45:11 +00:00
2017-07-27 02:53:02 +00:00
if ( ! geoData || ! geoData . ip ) {
geoData = {
ip : 'Adblocker'
} ;
}
2017-03-06 21:45:11 +00:00
return {
ipAddr : geoData . ip ,
geoLocation : {
City : geoData . city ,
Country : geoData . country _name
}
2017-07-20 23:09:21 +00:00
} ;
2017-03-06 21:45:11 +00:00
} ;
2016-06-20 22:35:41 +00:00
$rootScope . submitForm = $scope . submitForm = function ( ) {
var _timeElapsed = TimeCounter . stopClock ( ) ;
$scope . loading = true ;
var form = _ . cloneDeep ( $scope . myform ) ;
2017-03-06 21:45:11 +00:00
var deviceData = getDeviceData ( ) ;
form . device = deviceData ;
var geoData = getIpAndGeo ( ) ;
form . ipAddr = geoData . ipAddr ;
form . geoLocation = geoData . geoLocation ;
console . log ( geoData ) ;
2016-06-20 22:35:41 +00:00
2017-03-06 21:45:11 +00:00
form . timeElapsed = _timeElapsed ;
2016-06-20 22:35:41 +00:00
form . percentageComplete = $filter ( 'formValidity' ) ( $scope . myform ) / $scope . myform . visible _form _fields . length * 100 ;
delete form . visible _form _fields ;
for ( var i = 0 ; i < $scope . myform . form _fields . length ; i ++ ) {
if ( $scope . myform . form _fields [ i ] . fieldType === 'dropdown' && ! $scope . myform . form _fields [ i ] . deletePreserved ) {
$scope . myform . form _fields [ i ] . fieldValue = $scope . myform . form _fields [ i ] . fieldValue . option _value ;
}
}
setTimeout ( function ( ) {
$scope . submitPromise = $http . post ( '/forms/' + $scope . myform . _id , form )
2017-07-20 23:09:21 +00:00
. success ( function ( data , status ) {
2016-06-20 22:35:41 +00:00
$scope . myform . submitted = true ;
$scope . loading = false ;
SendVisitorData . send ( $scope . myform , getActiveField ( ) , _timeElapsed ) ;
} )
. error ( function ( error ) {
$scope . loading = false ;
console . error ( error ) ;
$scope . error = error . message ;
} ) ;
} , 500 ) ;
} ;
//Reload our form
2017-07-20 23:09:21 +00:00
$scope . reloadForm ( ) ;
2016-06-20 22:35:41 +00:00
} ]
} ;
}
] ) ;
'use strict' ;
//Forms service used for communicating with the forms REST endpoints
angular . module ( 'view-form' ) . service ( 'CurrentForm' ,
function ( ) {
//Private variables
var _form = { } ;
//Public Methods
this . getForm = function ( ) {
return _form ;
} ;
this . setForm = function ( form ) {
_form = form ;
} ;
}
) ;
'use strict' ;
//Forms service used for communicating with the forms REST endpoints
2017-03-06 21:45:11 +00:00
angular . module ( 'view-form' ) . factory ( 'Forms' , [ '$resource' , 'VIEW_FORM_URL' ,
function ( $resource , VIEW _FORM _URL ) {
return $resource ( VIEW _FORM _URL , {
2016-06-20 22:35:41 +00:00
formId : '@_id'
} , {
'get' : {
method : 'GET' ,
transformResponse : function ( data , header ) {
var form = angular . fromJson ( data ) ;
form . visible _form _fields = _ . filter ( form . form _fields , function ( field ) {
return ( field . deletePreserved === false ) ;
} ) ;
return form ;
}
} ,
'update' : {
method : 'PUT'
} ,
'save' : {
method : 'POST'
}
} ) ;
}
] ) ;
( function ( ) {
'use strict' ;
// Create the Socket.io wrapper service
function Socket ( $timeout , $window ) {
2017-07-31 21:30:55 +00:00
var service ;
2016-06-20 22:35:41 +00:00
// Connect to Socket.io server
function connect ( url ) {
service . socket = io ( url , { 'transports' : [ 'websocket' , 'polling' ] } ) ;
}
// Wrap the Socket.io 'emit' method
function emit ( eventName , data ) {
if ( service . socket ) {
service . socket . emit ( eventName , data ) ;
}
}
// Wrap the Socket.io 'on' method
function on ( eventName , callback ) {
if ( service . socket ) {
service . socket . on ( eventName , function ( data ) {
$timeout ( function ( ) {
callback ( data ) ;
} ) ;
} ) ;
}
}
// Wrap the Socket.io 'removeListener' method
function removeListener ( eventName ) {
if ( service . socket ) {
service . socket . removeListener ( eventName ) ;
}
}
2017-07-31 21:30:55 +00:00
2017-07-20 23:09:21 +00:00
service = {
connect : connect ,
emit : emit ,
on : on ,
removeListener : removeListener ,
socket : null
} ;
2017-07-31 21:30:55 +00:00
console . log ( $window . socketUrl ) ;
2017-07-20 23:09:21 +00:00
var url = '' ;
if ( $window . socketUrl && $window . socketPort ) {
url = window . location . protocol + '//' + $window . socketUrl + ':' + $window . socketPort ;
2017-07-31 21:30:55 +00:00
} else if ( $window . socketUrl ) {
2017-07-20 23:09:21 +00:00
url = window . location . protocol + '//' + $window . socketUrl ;
} else if ( $window . socketPort ) {
url = window . location . protocol + '//' + window . location . hostname + ':' + $window . socketPort ;
} else {
url = window . location . protocol + '//' + window . location . hostname ;
}
connect ( url ) ;
return service ;
2016-06-20 22:35:41 +00:00
}
2017-07-31 21:30:55 +00:00
2017-07-20 23:09:21 +00:00
angular
. module ( 'view-form' )
. factory ( 'Socket' , Socket ) ;
Socket . $inject = [ '$timeout' , '$window' ] ;
2016-06-20 22:35:41 +00:00
} ( ) ) ;
'use strict' ;
angular . module ( 'view-form' ) . service ( 'TimeCounter' , [
function ( ) {
2017-07-20 23:09:21 +00:00
var _startTime , _endTime = null ;
2016-06-20 22:35:41 +00:00
this . timeSpent = 0 ;
this . restartClock = function ( ) {
_startTime = Date . now ( ) ;
_endTime = null ;
// console.log('Clock Started');
} ;
this . getTimeElapsed = function ( ) {
if ( _startTime ) {
return Math . abs ( Date . now ( ) . valueOf ( ) - _startTime . valueOf ( ) ) / 1000 ;
}
} ;
this . stopClock = function ( ) {
if ( _startTime && _endTime === null ) {
_endTime = Date . now ( ) ;
this . timeSpent = Math . abs ( _endTime . valueOf ( ) - _startTime . valueOf ( ) ) / 1000 ;
this . _startTime = this . _endTime = null ;
return this . timeSpent ;
}
2017-07-20 23:09:21 +00:00
return new Error ( 'Clock has not been started' ) ;
2016-06-20 22:35:41 +00:00
} ;
this . clockStarted = function ( ) {
return ! ! this . _startTime ;
} ;
}
] ) ;