1
0

Merge branch 'publicFormImprovments' of github.com:whitef0x0/tellform into speed_improvements

This commit is contained in:
David Baldwynn 2017-10-07 04:23:59 -04:00
commit 1a155e9ef1
27 changed files with 341 additions and 269 deletions

View File

@ -164,7 +164,7 @@ var readForRender = exports.readForRender = function(req, res) {
delete newForm.__v;
delete newForm.created;
if(!newForm.startPage.showStart){
if(newForm.startPage && !newForm.startPage.showStart){
delete newForm.startPage;
}
@ -175,20 +175,31 @@ var readForRender = exports.readForRender = function(req, res) {
* Update a form
*/
exports.update = function(req, res) {
var form = req.form;
var updatedForm = req.body.form;
if(form.form_fields === undefined){
form.form_fields = [];
}
delete updatedForm.__v;
delete updatedForm.created;
if(form.analytics === undefined){
form.analytics = {
visitors: [],
gaCode: ''
}
}
if (req.body.changes) {
var formChanges = req.body.changes;
formChanges.forEach(function (change) {
diff.applyChange(form, true, change);
diff.applyChange(form._doc, true, change);
});
} else {
//Unless we have 'admin' privileges, updating form admin is disabled
delete updatedForm.__v;
delete updatedForm.created;
//Unless we have 'admin' privileges, updating the form's admin is disabled
if(updatedForm && req.user.roles.indexOf('admin') === -1) {
delete updatedForm.admin;
}
@ -200,7 +211,7 @@ exports.update = function(req, res) {
//Do this so we can create duplicate fields
var checkForValidId = new RegExp('^[0-9a-fA-F]{24}$');
for(var i=0; i<req.body.form.form_fields.length; i++){
for(var i=0; i < req.body.form.form_fields.length; i++){
var field = req.body.form.form_fields[i];
if(!checkForValidId.exec(field._id+'')){
delete field._id;

View File

@ -76,8 +76,7 @@ function BaseFieldSchema(){
},
title: {
type: String,
trim: true,
required: 'Field Title cannot be blank'
trim: true
},
description: {
type: String,
@ -106,7 +105,6 @@ function BaseFieldSchema(){
},
fieldType: {
type: String,
required: true,
enum: [
'textfield',
'date',

View File

@ -5,7 +5,8 @@
*/
var mongoose = require('mongoose'),
errorHandler = require('../controllers/errors.server.controller'),
Form = mongoose.model('Form');
Form = mongoose.model('Form'),
request = require('request');
// Create the chat configuration
module.exports = function (io, socket) {
@ -50,12 +51,25 @@ module.exports = function (io, socket) {
visitorsData[current_socket.id] = data;
visitorsData[current_socket.id].socketId = current_socket.id;
visitorsData[current_socket.id].isSaved = false;
if (data.isSubmitted && !data.isSaved) {
visitorsData[current_socket.id].isSaved = true;
saveVisitorData(data, function() {
current_socket.disconnect(true);
});
}
visitorsData[current_socket.id].ipAddr = current_socket.conn.transport.socket._socket.remoteAddress;
console.log(current_socket);
request('https://freegeoip.net/json/'+current_socket.conn.transport.socket._socket.remoteAddress, (error, response, body)=> {
console.log(body);
var geoData = body;
visitorsData[current_socket.id].geoLocation = {
city: geoData.city,
country: geoData.country_name
}
if (data.isSubmitted && !data.isSaved) {
visitorsData[current_socket.id].isSaved = true;
saveVisitorData(data, function() {
current_socket.disconnect(true);
});
}
});
});
current_socket.on('disconnect', function() {

View File

@ -76,11 +76,6 @@
<script src="/static/lib/jquery/dist/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).on("load", function() {
$(".loader").fadeOut("slow");
});
</script>
<link rel="stylesheet" href="/static/lib/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="/static/lib/bootstrap/dist/css/bootstrap.min.css">

View File

@ -94,6 +94,7 @@
"prerender-node": "^2.2.1",
"random-js": "^1.0.8",
"raven": "^0.9.0",
"request": "^2.83.0",
"socket.io": "^1.4.6",
"socket.io-redis": "^1.0.0",
"swig": "~1.4.1",

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,9 @@ angular.module('view-form').controller('SubmitFormController', [
'$scope', '$rootScope', '$state', '$translate', 'myForm',
function($scope, $rootScope, $state, $translate, myForm) {
$scope.myform = myForm;
$(".loader").fadeOut("slow");
document.body.style.background = myForm.design.colors.backgroundColor;
$translate.use(myForm.language);
}
]);

View File

@ -25,7 +25,7 @@ angular.module('view-form').directive('onEnterKey', ['$rootScope', function($roo
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
$element.bind('keydown keypress', function(event) {
$element.bind('keyup keypress', function(event) {
var keyCode = event.which || event.keyCode;
@ -65,6 +65,8 @@ angular.module('view-form').directive('onEnterKey', ['$rootScope', function($roo
var keyCode = event.which || event.keyCode;
if(keyCode === 9 && event.shiftKey) {
console.log('onTabAndShiftKey');
event.preventDefault();
$rootScope.$apply(function() {
$rootScope.$eval($attrs.onTabAndShiftKey);

View File

@ -9,8 +9,8 @@ jsep.addBinaryOp('!begins', 10);
jsep.addBinaryOp('ends', 10);
jsep.addBinaryOp('!ends', 10);
angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'SendVisitorData', '$translate',
function ($http, TimeCounter, $filter, $rootScope, SendVisitorData, $translate) {
angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'SendVisitorData', '$translate', '$timeout',
function ($http, TimeCounter, $filter, $rootScope, SendVisitorData, $translate, $timeout) {
return {
templateUrl: 'form_modules/forms/base/views/directiveViews/form/submit-form.client.view.html',
restrict: 'E',
@ -19,7 +19,8 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
ispreview: '='
},
controller: function($document, $window, $scope){
$scope.noscroll = false;
var NOSCROLL = false;
var FORM_ACTION_ID = 'submit_field';
$scope.forms = {};
//Don't start timer if we are looking at a design preview
@ -59,43 +60,6 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
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;
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);
}
$scope.$apply();
}
};
/*
** Field Controls
*/
@ -163,35 +127,46 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
throw new Error('current active field is null');
}
if($scope.selected._id === 'submit_field') {
if($scope.selected._id === FORM_ACTION_ID) {
return $scope.myform.form_fields.length - 1;
}
return $scope.selected.index;
};
$scope.isActiveField = function(field){
if($scope.selected._id === field._id) {
return true
}
return false;
};
$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);
if($scope.selected === null || (!field_id && field_index === null) ) {
return;
}
if(!field_id){
field_id = $scope.myform.visible_form_fields[field_index]._id;
} else if(field_index === null){
field_index = $scope.myform.visible_form_fields.length
$scope.selected._id = field_id;
$scope.selected.index = field_index;
if(!field_index){
for(var i=0; i<$scope.myform.visible_form_fields.length; i++){
for(var i=0; i < $scope.myform.visible_form_fields.length; i++){
var currField = $scope.myform.visible_form_fields[i];
if(field_id === currField._id){
$scope.selected.index = i;
if(currField['_id'] == field_id){
field_index = i;
break;
}
}
}
if($scope.selected._id === field_id){
return;
}
$scope.selected._id = field_id;
$scope.selected.index = field_index;
var nb_valid = $filter('formValidity')($scope.myform);
$scope.translateAdvancementData = {
done: nb_valid,
@ -200,10 +175,10 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
};
if(animateScroll){
$scope.noscroll=true;
NOSCROLL=true;
setTimeout(function() {
$document.scrollToElement(angular.element('.activeField'), -10, 200).then(function() {
$scope.noscroll = false;
NOSCROLL = false;
setTimeout(function() {
if (document.querySelectorAll('.activeField .focusOn').length) {
//Handle default case
@ -218,54 +193,109 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
});
});
});
} 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 if (document.querySelectorAll('.activeField input')[0]){
document.querySelectorAll('.activeField input')[0].focus();
}
});
}
//Only send analytics data if form has not been submitted
if(!$scope.myform.submitted){
SendVisitorData.send($scope.myform, getActiveField(), TimeCounter.getTimeElapsed());
}
}
};
$rootScope.nextField = $scope.nextField = function(){
var currField = $scope.myform.visible_form_fields[$scope.selected.index];
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);
}
$scope.$watch('selected.index', function(oldValue, newValue){
if(oldValue !== newValue && newValue < $scope.myform.form_fields.length){
//Only send analytics data if form has not been submitted
if(!$scope.myform.submitted){
console.log('SendVisitorData.send()');
SendVisitorData.send($scope.myform, newValue, TimeCounter.getTimeElapsed());
}
}
}
});
//Fire event when window is scrolled
$window.onscroll = function(){
if(!NOSCROLL){
var scrollTop = $(window).scrollTop();
var elemBox = document.getElementsByClassName('activeField')[0].getBoundingClientRect();
var fieldTop = elemBox.top;
var fieldBottom = elemBox.bottom;
var field_id, field_index;
var elemHeight = $('.activeField').height();
var submitSectionHeight = $('.form-actions').height();
var maxScrollTop = $(document).height() - $(window).height();
var fieldWrapperHeight = $('form_fields').height();
var selector = 'form > .field-directive:nth-of-type(' + String($scope.myform.visible_form_fields.length - 1)+ ')'
var fieldDirectiveHeight = $(selector).height()
var scrollPosition = maxScrollTop - submitSectionHeight - fieldDirectiveHeight*1.2;
var fractionToJump = 0.9;
//Focus on field above submit form button
if($scope.selected.index === $scope.myform.visible_form_fields.length){
if(scrollTop < scrollPosition){
field_index = $scope.selected.index-1;
$scope.setActiveField(null, field_index, false);
}
}
//Focus on submit form button
else if($scope.selected.index === $scope.myform.visible_form_fields.length-1 && scrollTop > scrollPosition){
field_index = $scope.selected.index+1;
$scope.setActiveField(FORM_ACTION_ID, field_index, false);
}
//If we scrolled bellow the current field, move to next field
else if(fieldBottom < elemHeight * fractionToJump && $scope.selected.index < $scope.myform.visible_form_fields.length-1 ){
field_index = $scope.selected.index+1;
$scope.setActiveField(null, field_index, false);
}
//If we scrolled above the current field, move to prev field
else if ( $scope.selected.index !== 0 && fieldTop > elemHeight * fractionToJump) {
field_index = $scope.selected.index-1;
$scope.setActiveField(null, field_index, false);
}
}
$scope.$apply();
};
$rootScope.nextField = $scope.nextField = function(){
if($scope.selected && $scope.selected.index > -1){
if($scope.selected._id !== FORM_ACTION_ID){
var currField = $scope.myform.visible_form_fields[$scope.selected.index];
//Jump to logicJump's destination if it is true
if(currField.logicJump && currField.logicJump.jumpTo && evaluateLogicJump(currField)){
$scope.setActiveField(currField.logicJump.jumpTo, null, true);
} else if($scope.selected.index < $scope.myform.visible_form_fields.length-1){
$scope.setActiveField(null, $scope.selected.index+1, true);
} else {
$scope.setActiveField(FORM_ACTION_ID, null, true);
}
} else {
//If we are at the submit actions page, go to the first field
$rootScope.setActiveField(null, 0, true);
}
} else {
//If selected is not defined go to the first field
$rootScope.setActiveField(null, 0, true);
}
};
$rootScope.prevField = $scope.prevField = function(){
console.log('prevField');
console.log($scope.selected);
var selected_index = $scope.selected.index - 1;
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);
$scope.setActiveField(null, selected_index, true);
}
};
$rootScope.goToInvalid = $scope.goToInvalid = function() {
var field_id = $('.row.field-directive .ng-invalid.focusOn, .row.field-directive .ng-untouched.focusOn:not(.ng-valid)').first().parents('.row.field-directive').first().attr('data-id');
$scope.setActiveField(field_id, null, true);
};
/*
** Form Display Functions
*/
@ -276,10 +306,6 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
}
};
$rootScope.goToInvalid = $scope.goToInvalid = function() {
document.querySelectorAll('.ng-invalid.focusOn')[0].focus();
};
var getDeviceData = function(){
var md = new MobileDetect(window.navigator.userAgent);
var deviceType = 'other';
@ -320,6 +346,10 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
};
$rootScope.submitForm = $scope.submitForm = function() {
if($scope.forms.myForm.$invalid){
$scope.goToInvalid();
return;
}
var _timeElapsed = TimeCounter.stopClock();
$scope.loading = true;

View File

@ -16,6 +16,7 @@
<div class="col-xs-12 field-input">
<div class="control-group input-append">
<input class="focusOn"
ng-focus="setActiveField(field._id, null, false)"
ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
ng-class="{ 'no-border': !!field.fieldValue }"
ui-date="dateOptions"

View File

@ -15,6 +15,7 @@
</div>
<div class="col-xs-12 field-input">
<ui-select ng-model="field.fieldValue"
ng-focus="setActiveField(field._id, null, false)"
theme="selectize"
search-enabled="true"
search-by="option_value"

View File

@ -26,6 +26,7 @@
{{$index+1}}
</div>
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
ng-focus="setActiveField(field._id, null, false)"
type="radio" class="focusOn"
value="{{option.option_value}}"
ng-model="field.fieldValue"

View File

@ -12,7 +12,7 @@
<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">
<button class="btn focusOn"
ng-style="{'font-size': '1.3em', 'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"
ng-click="nextField()">
{{ 'CONTINUE' | translate }}

View File

@ -16,6 +16,7 @@
<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-focus="setActiveField(field._id, null, false)"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-class="{ 'no-border': !!field.fieldValue }"

View File

@ -26,6 +26,7 @@
placeholder="{{placeholder}}"
ng-class="{ 'no-border': !!field.fieldValue }"
class="focusOn text-field-input"
ng-focus="setActiveField(field._id, null, false)"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
value="field.fieldValue"
@ -45,7 +46,7 @@
</div>
</div>
<div>
<div class="btn btn-lg btn-default"
<div class="btn btn-lg btn-default" ng-disabled="!field.fieldValue || field.$invalid"
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}"

View File

@ -28,6 +28,7 @@
<input type="radio" value="true"
class="focusOn"
style="opacity: 0; margin-left: 0px;"
ng-focus="setActiveField(field._id, null, false)"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
@ -46,6 +47,7 @@
<input type="radio" value="false"
style="opacity:0; margin-left:0px;"
ng-focus="setActiveField(field._id, null, false)"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"

View File

@ -1,16 +1,13 @@
<section class="overlay submitform" ng-if="!ispreview && (loading || (!myform.submitted && !myform.startPage.showStart))"></section>
<section class="overlay previewform submitform" ng-if="ispreview && (loading || (!myform.submitted && !myform.startPage.showStart))"></section>
<!-- Start Page View -->
<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;" ng-style="{'color': form.design.colors.questionColor}">
<h1 style="font-weight: 400; nont-size: 25px;" ng-style="{'color': myform.design.colors.questionColor}">
{{myform.startPage.introTitle}}
</h1>
</div>
<div class="col-xs-10 col-xs-offset-1 text-center" style="overflow-wrap: break-word;">
<p style="font-weight: 100; font-size: 16px;" ng-style="{'color': form.design.colors.questionColor}">
<p style="font-weight: 100; font-size: 16px;" ng-style="{'color': myform.design.colors.questionColor}">
{{myform.startPage.introParagraph}}
</p>
</div>
@ -37,42 +34,46 @@
</div>
<!-- Form Fields View -->
<div class="form-fields" ng-show="!myform.submitted && !myform.startPage.showStart" ng-style="{ 'border-color': myform.design.colors.buttonTextColor }">
<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 class="row form-field-wrapper">
<form name="forms.myForm" novalidate class="submission-form">
<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>
<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-top: 30vh; height: 100vh; margin-left: 1%; margin-right: 1%;"
on-tab-and-shift-key="prevField()"
on-tab-key="nextField()"
on-enter-key="submitForm()">
<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-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>
</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">

View File

@ -0,0 +1,12 @@
<script>
$(".loader").fadeOut("slow");
</script>
<section class="public-form auth sigin-view valign-wrapper">
<div class="row valign">
<h3 class="col-md-12 text-center">404 - Form Does not Exist </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 does not exist. Sorry about that!
</div>
</div>
</section>

View File

@ -1,4 +1,7 @@
<section class="auth sigin-view valign-wrapper">
<script>
$(".loader").fadeOut("slow");
</script>
<section class="public-form 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">

View File

@ -1,4 +1,4 @@
<section class="public-form" ng-style="{ 'background-color': myform.design.colors.backgroundColor }">
<section class="public-form">
<submit-form-directive myform="myform"></submit-form-directive>
</section>

View File

@ -27,7 +27,11 @@ angular.module('view-form').config(['$stateProvider',
}).
state('unauthorizedFormAccess', {
url: '/forms/unauthorized',
templateUrl: '/static/form_modules/forms/base/views/form-unauthorized.client.view.html',
templateUrl: '/static/form_modules/forms/base/views/form-unauthorized.client.view.html'
})
.state('formNotFound', {
url: '*path',
templateUrl: '/static/form_modules/forms/base/views/form-not-found.client.view.html'
});
}
]);

View File

@ -28,18 +28,6 @@
deviceType = 'desktop';
}
$.ajaxSetup( { 'async': false } );
var geoData = $.getJSON('https://freegeoip.net/json/').responseJSON;
$.ajaxSetup( { 'async': true } );
if(!geoData){
geoData = {
ip: '',
city: '',
country_name: ''
};
}
// Create a new message object
var visitorData = {
referrer: document.referrer,
@ -49,11 +37,8 @@
timeElapsed: timeElapsed,
language: lang,
deviceType: deviceType,
ipAddr: geoData.ip,
geoLocation: {
city: geoData.city,
country: geoData.country_name
}
ipAddr: null,
geoLocation: null
};
Socket.emit('form-visitor-data', visitorData);

View File

@ -16,6 +16,7 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$windo
$scope.animationsEnabled = true;
$scope.myform = myForm;
$rootScope.saveInProgress = false;
$scope.oldForm = _.cloneDeep($scope.myform);
CurrentForm.setForm($scope.myform);
@ -42,13 +43,23 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$windo
}
};
$scope.tabData = [
$scope.tabData = [
{
heading: $filter('translate')('CONFIGURE_TAB'),
templateName: 'configure'
}
];
$scope.designTabActive = false
$scope.deactivateDesignTab = function(){
$scope.designTabActive = false
}
$scope.activateDesignTab = function(){
$scope.designTabActive = true
}
$scope.setForm = function(form){
$scope.myform = form;
};
@ -102,16 +113,20 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$windo
}
};
// Update existing Form
$scope.update = $rootScope.update = function(updateImmediately, data, isDiffed, refreshAfterUpdate, cb){
refreshFrame();
$scope.updateDesign = function(updateImmediately, data, shouldDiff, refreshAfterUpdate){
$scope.update(updateImmediately, data, shouldDiff, refreshAfterUpdate, function(){
refreshFrame();
});
}
// Update existing Form
$scope.update = $rootScope.update = function(updateImmediately, data, shouldDiff, refreshAfterUpdate, cb){
var continueUpdate = true;
if(!updateImmediately){
continueUpdate = !$rootScope.saveInProgress;
}
//Update form **if we are not currently updating** or if **shouldUpdateNow flag is set**
//Update form **if we are not in the middle of an update** or if **shouldUpdateNow flag is set**
if(continueUpdate) {
var err = null;
@ -119,11 +134,24 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$windo
$rootScope.saveInProgress = true;
}
if (isDiffed) {
if (shouldDiff) {
//Do this so we can create duplicate fields
var checkForValidId = new RegExp('^[0-9a-fA-F]{24}$');
for(var i=0; i < $scope.myform.form_fields.length; i++){
var field = $scope.myform.form_fields[i];
if(!checkForValidId.exec(field._id+'')){
delete $scope.myform.form_fields[i]._id;
delete $scope.myform.form_fields[i].id;
}
}
var data = DeepDiff.diff($scope.oldForm, $scope.myform);
$scope.updatePromise = $http.put('/forms/' + $scope.myform._id, {changes: data})
.then(function (response) {
if (refreshAfterUpdate) {
$rootScope.myform = $scope.myform = response.data;
$scope.oldForm = _.cloneDeep($scope.myform);
}
}).catch(function (response) {
err = response.data;
@ -146,6 +174,22 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$windo
delete dataToSend.submissions;
}
if(dataToSend.visible_form_fields){
delete dataToSend.visible_form_fields;
}
if(dataToSend.analytics){
delete dataToSend.analytics.visitors;
delete dataToSend.analytics.fields;
delete dataToSend.analytics.submissions;
delete dataToSend.analytics.views;
delete dataToSend.analytics.conversionRate;
}
delete dataToSend.created;
delete dataToSend.lastModified;
delete dataToSend.__v;
$scope.updatePromise = $http.put('/forms/' + $scope.myform._id, {form: dataToSend})
.then(function (response) {
if (refreshAfterUpdate) {

View File

@ -1,3 +1,4 @@
'use strict';
angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormFields', '$uibModal',
@ -23,7 +24,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
forceHelperSize: true,
forcePlaceholderSize: true,
update: function(e, ui) {
$scope.update(false, $scope.myform, false, false, function(err){
$scope.update(false, $scope.myform, true, false, function(err){
});
},
};
@ -129,7 +130,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
$scope.saveField = function(){
$scope.myform.form_fields.push(curr_field);
$scope.$parent.update(false, $scope.$parent.myform, false, true, function(){
$scope.$parent.update(false, $scope.$parent.myform, true, true, function(){
$uibModalInstance.close();
});
};
@ -184,7 +185,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
};
$scope.saveStartPage = function(){
$scope.$parent.update(false, $scope.$parent.myform, false, true, function(){
$scope.$parent.update(false, $scope.$parent.myform, true, true, function(){
$uibModalInstance.close();
});
};
@ -196,7 +197,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
};
/*
** EditStartPageModal Functions
** EditEndPageModal Functions
*/
$scope.openEditEndPageModal = function(){
$scope.editEndPageModal = $uibModal.open({
@ -239,7 +240,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
};
$scope.saveEndPage = function(){
$scope.$parent.update(false, $scope.$parent.myform, false, true, function(){
$scope.$parent.update(false, $scope.$parent.myform, true, true, function(){
$uibModalInstance.close();
});
};

View File

@ -59,16 +59,16 @@
<div class="row">
<div class="col-xs-12">
<uib-tabset active="activePill" vertical="true" type="pills">
<uib-tab index="0" heading="{{ 'CREATE_TAB' | translate }}">
<uib-tab index="0" heading="{{ 'CREATE_TAB' | translate }}" select="deactivateDesignTab()">
<edit-form-directive myform="myform"></edit-form-directive>
</uib-tab>
<uib-tab ng-repeat="tab in tabData" index="{{$index+1}}" heading="{{tab.heading}}">
<uib-tab ng-repeat="tab in tabData" index="{{$index+1}}" heading="{{tab.heading}}" select="deactivateDesignTab()">
<div class='row' data-ng-include="'/static/modules/forms/admin/views/adminTabs/'+tab.templateName+'.html'"></div>
</uib-tab>
<uib-tab index="2" heading="{{ 'ANALYZE_TAB' | translate }}">
<uib-tab index="2" heading="{{ 'ANALYZE_TAB' | translate }}" select="deactivateDesignTab()">
<edit-submissions-form-directive myform="myform" user="myform.admin"></edit-submissions-form-directive>
</uib-tab>
<uib-tab ng-if="tabData" heading="{{ 'SHARE_TAB' | translate }}" index="{{tabData.length}}">
<uib-tab ng-if="tabData" heading="{{ 'SHARE_TAB' | translate }}" index="{{tabData.length}}" select="deactivateDesignTab()">
<div class="config-form">
<div class="row">
<div class="col-sm-12">
@ -114,7 +114,8 @@
</div>
</div>
</uib-tab>
<uib-tab ng-if="tabData && myform.form_fields.length" heading="{{ 'DESIGN_TAB' | translate }}" index="{{tabData.length}}+1">
<uib-tab class="design-tab" ng-if="tabData && myform.form_fields.length" heading="{{ 'DESIGN_TAB' | translate }}" index="{{tabData.length}}+1"
select="activateDesignTab()">
<div class="config-form design container">
<div class="row">
<div class="col-sm-4 col-xs-12">
@ -175,7 +176,7 @@
</div>
</div>
</div>
<div class="col-sm-8 hidden-xs">
<div class="col-sm-8 hidden-xs" ng-if="designTabActive">
<div class="public-form" ng-style="{ 'background-color': myform.design.colors.backgroundColor }">
<iframe id="iframe" ng-if="!!formURL" ng-src="{{formURL | trustSrc}}" style="border: none; box-shadow: 0px 0px 10px 0px grey; overflow: hidden; height: 400px; width: 90%; position: absolute;"></iframe>
</div>
@ -184,7 +185,7 @@
<div class="row">
<div class="col-sm-offset-4 col-sm-2">
<button class="btn btn-signup btn-rounded" type="button" ng-click="update(false, myform, false, false, null)"><i class="icon-arrow-left icon-white"></i>{{ 'SAVE_CHANGES' | translate }}</button>
<button class="btn btn-signup btn-rounded" type="button" ng-click="updateDesign(false, myform, false, false)"><i class="icon-arrow-left icon-white"></i>{{ 'SAVE_CHANGES' | translate }}</button>
</div>
<div class="col-sm-1">
<button class="btn btn-secondary btn-rounded" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i>{{ 'CANCEL' | translate }}</button>

View File

@ -11,37 +11,34 @@
.public-form input, .public-form textarea {
background-color: #000000;
background-color: rgba(0,0,0,0);
border: 2px dashed #ddd!important;
border-width: 0px;
}
.public-form input:focus, .public-form textarea:focus {
border: 2px dashed #ddd!important;
.public-form input.ng-untouched, .public-form textarea.ng-untouched {
border-width: 0 0 2px 0;
border-color: rgba(246, 255, 181, 0.4);
outline: 0;
}
/*.public-form input.no-border.ng-invalid, .public-form textarea.no-border {
border-color: none;
}*/
.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:focus, .public-form textarea:focus {
border-width: 0 0 2px 0;
border-color: rgba(246, 255, 181, 0.4);
outline: 0;
}
.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;*/
.public-form input.ng-dirty, .public-form textarea.ng-dirty {
border-width: 0;
}
.public-form input.empty, .public-form textarea.empty {
border-width: 0 0 2px 0;
border-color: rgba(246, 255, 181, 0.4);
}
section.content p.breakwords {
word-break: break-all;
}
.public-form .btn {
border: 1px solid #c6c6c6;
}
.public-form .btn[type='submit'] {
font-size: 1.5em;
padding: 0.35em 1.2em 0.35em 1.2em;
@ -142,7 +139,7 @@ form .row.field {
form .row.field > .field-title {
margin-top:0.5em;
font-size:1.2em;
padding-bottom: 1.8em;
padding-bottom: 0.5em;
width: inherit;
}
form .row.field > .field-input {
@ -243,15 +240,12 @@ form .row.field {
}
/* Styles for form list view (/forms) */
section.public-form {
padding: 0 10% 0 10%;
}
section.public-form .form-submitted {
height: 100vh;
section.public-form field-directive .btn.btn-lg.btn-default {
background: none;
}
section.public-form .btn {
border: 1px solid;
section.public-form field-directive .btn[disabled]{
display: none;
}
.form-item {
@ -330,42 +324,16 @@ section.public-form .btn {
top:0;
}
/*Modal overlay (for lightbox effect)*/
.overlay {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: #000;
background-color: rgba(0,0,0,0.5);
z-index: 10;
}
.overlay.submitform {
background-color: #fff;
background-color: rgba(256,256,256,0.8);
.field-directive {
opacity: 0.2;
padding: 2.5% 10% 2.5% 10%;
}
.field-directive {
z-index: 9;
padding: 10% 10% 10% 0;
border: 25px transparent solid;
position: relative;
.form-field-wrapper .form-actions.activeField, .field-directive.activeField {
opacity: 1;
}
.activeField {
z-index: 11;
position: relative;
background-color: transparent;
}
.activeField.field-directive {
display: inline-block;
border-radius: 7px;
width: 100%;
border: 25px transparent solid;
}
.activeField input {
background-color: transparent;
}
h3.forms-list-title {
color: #3FA2F7;
font-weight: 600;

View File

@ -60,22 +60,13 @@
var newFakeModal = function(){
var result = {
opened: true,
result: {
then: function(confirmCallback, cancelCallback) {
//Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
this.confirmCallBack = confirmCallback;
this.cancelCallback = cancelCallback;
}
},
close: function( item ) {
//The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
this.opened = false;
this.result.confirmCallBack( item );
},
dismiss: function( type ) {
//The user clicked cancel on the modal dialog, call the stored cancel callback
this.opened = false;
this.result.cancelCallback( type );
}
};
return result;
@ -173,7 +164,6 @@
beforeEach(inject(function($uibModal) {
var modal = newFakeModal();
spyOn($uibModal, 'open').and.returnValue(modal);
//spyOn($uibModal, 'close').and.callFake(modal.close());
}));
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).