added diff to update

This commit is contained in:
David Baldwynn 2016-08-26 15:34:29 -07:00
commit 0a74598894
13 changed files with 311 additions and 287 deletions

View file

@ -12,6 +12,7 @@ var mongoose = require('mongoose'),
fs = require('fs-extra'),
async = require('async'),
path = require('path'),
diff = require('deep-diff'),
_ = require('lodash');
/**
@ -69,74 +70,6 @@ exports.uploadPDF = function(req, res, next) {
}
};
/**
* Upload PDF
*/
/*
exports.uploadSubmissionFile = function(req, res, next) {
console.log('inside uploadPDF');
// console.log('\n\nProperty Descriptor\n-----------');
// console.log(Object.getOwnPropertyDescriptor(req.files.file, 'path'));
console.log(req.files);
if(req.files){
var file, _user, _path;
for(var i=0; i<req.files.length; i++){
file = req.files[i];
_user = req.user;
_path = file.path;
if (file.size === 0) {
return next(new Error('File uploaded is EMPTY'));
}else if(file.size > 100000000){
return next(new Error('File uploaded exceeds MAX SIZE of 100MB'));
}else {
fs.exists(_path, function(exists) {
//If file exists move to user's form directory
if(exists) {
var newDestination = config.tmpUploadPath+_user.username;
var stat = null;
try {
stat = fs.statSync(newDestination);
} catch (err) {
fs.mkdirSync(newDestination);
}
if (stat && !stat.isDirectory()) {
console.log('Directory cannot be created');
return next(new Error('Directory cannot be created because an inode of a different type exists at "' + newDestination + '"'));
}
console.log(path.join(newDestination, pdfFile.filename));
fs.move(pdfFile.path, path.join(newDestination, pdfFile.filename), function (err) {
if (err) {
return next(new Error(err.message));
}
pdfFile.path = path.join(newDestination, pdfFile.filename);
console.log(pdfFile.filename + ' uploaded to ' + pdfFile.path);
res.json(pdfFile);
});
} else {
return next(new Error('Did NOT get your file!'));
}
});
}
}
}else {
return next(new Error('Uploaded files were NOT detected'));
}
};
*/
/**
* Delete a forms submissions
*/
@ -302,10 +235,19 @@ exports.read = function(req, res) {
*/
exports.update = function(req, res) {
var form = req.form;
/*
delete req.body.form.__v;
delete req.body.form._id;
*/
//Unless we have 'admin' priviledges, updating form admin is disabled
if(req.body.changes){
var formChanges = req.body.changes;
formChanges.forEach(function (change) {
diff.applyChange(form, true, change);
});
} else {
//Unless we have 'admin' privileges, updating form admin is disabled
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
//Do this so we can create duplicate fields
@ -316,8 +258,9 @@ exports.update = function(req, res) {
delete field._id;
}
}
form = _.extend(form, req.body.form);
}
form.save(function(err, form) {
if (err) {

View file

@ -36,8 +36,9 @@
"js-yaml": "^3.6.1",
"angular-ui-select": "https://github.com/whitef0x0/ui-select.git#compiled",
"angular-translate": "~2.11.0",
"ng-device-detector": "~3.0.1",
"ng-translate": "*"
"ng-device-detector": "^3.0.1",
"ng-translate": "*",
"deep-diff": "^0.3.4"
},
"resolutions": {
"angular-bootstrap": "^0.14.0",

View file

@ -35,6 +35,7 @@
"connect-mongo": "~0.8.2",
"consolidate": "~0.13.1",
"cookie-parser": "~1.4.0",
"deep-diff": "^0.3.4",
"dotenv": "^2.0.0",
"email-verification": "~0.4.1",
"envfile": "^2.0.1",

View file

@ -1788,7 +1788,7 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
};
// Update existing Form
$scope.update = $rootScope.update = function(updateImmediately, cb){
$scope.update = $rootScope.update = function(updateImmediately, diffChanges, cb){
var continueUpdate = true;
if(!updateImmediately){
@ -1801,7 +1801,9 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
if(!updateImmediately){ $rootScope.saveInProgress = true; }
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
console.log(diffChanges);
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, { changes: diffChanges })
.then(function(response){
$rootScope.myform = $scope.myform = response.data;
// console.log(response.data);
@ -1954,7 +1956,6 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
$rootScope.finishedRender = false;
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
// console.log('hello');
$rootScope.finishedRender = false;
});
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
@ -1974,13 +1975,11 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return false;
};
var debounceSave = function () {
$rootScope.saveInProgress = true;
var debounceSave = function (diffChanges) {
$rootScope[$attrs.autoSaveCallback](true,
$rootScope[$attrs.autoSaveCallback](true, diffChanges,
function(err){
if(!err){
//console.log('\n\nForm data persisted -- setting pristine flag');
$formCtrl.$setPristine();
$formCtrl.$setUntouched();
}else{
@ -1992,12 +1991,10 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
//Update/Save Form if any Form fields are Dirty and Touched
$scope.$watch(function(newValue, oldValue) {
//console.log('introParagraphStartPage.$dirty: '+$scope.editForm.introParagraphStartPage.$dirty);
//console.log('introParagraphStartPage.$touched: '+$scope.editForm.introParagraphStartPage.$touched);
if($rootScope.finishedRender && $scope.anyDirtyAndTouched($scope.editForm) && !$rootScope.saveInProgress){
//console.log('Form saving started');
debounceSave();
//console.log('introParagraphStartPage.$dirty AFTER: '+$scope.editForm.introParagraphStartPage.$dirty);
delete newValue.visible_form_fields;
debounceSave(DeepDiff.diff(oldValue, newValue));
}
});
@ -2011,7 +2008,6 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
var changedFields = !_.isEqual(oldValue.form_fields,newValue.form_fields) || !_.isEqual(oldValue.startPage, newValue.startPage);
var changedFieldMap = false;
if(oldValue.hasOwnProperty('plugins.oscarhost.settings.fieldMap')){
changedFieldMap = !!oldValue.plugins.oscarhost.settings.fieldMap && !_.isEqual(oldValue.plugins.oscarhost.settings.fieldMap,newValue.plugins.oscarhost.settings.fieldMap);
@ -2039,7 +2035,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
}
//Save form ONLY IF rendering is finished, form_fields have been changed AND currently not save in progress
if( $rootScope.finishedRender && ((changedFields && !$formCtrl.$dirty) || changedFieldMap) && !$rootScope.saveInProgress) {
if( $rootScope.finishedRender && (changedFields && !$formCtrl.$dirty) && !$rootScope.saveInProgress) {
if(savePromise) {
$timeout.cancel(savePromise);
@ -2047,7 +2043,14 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
}
savePromise = $timeout(function() {
debounceSave();
$rootScope.saveInProgress = true;
console.log(newValue);
console.log(oldValue);
delete newValue.visible_form_fields;
delete newValue.visible_form_fields;
var _diff = DeepDiff.diff(oldValue, newValue);
debounceSave(_diff);
});
}
//If we are finished rendering then form saving should be finished
@ -2169,7 +2172,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
},
controller: ["$scope", function($scope){
console.log($scope.myform);
var field_ids = _($scope.myform.form_fields).pluck('_id');
for(var i=0; i<field_ids.length; i++){
$scope.myform.plugins.oscarhost.settings.fieldMap[field_ids[i]] = null;
@ -2268,7 +2270,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
}
}
var newField = {
title: fieldTitle,
title: fieldTitle + ' ' + $scope.myform.form_fields.length+1,
fieldType: fieldType,
fieldValue: '',
required: true,
@ -2285,7 +2287,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
});
}
if(modifyForm){
//Add newField to form_fields array
$scope.myform.form_fields.push(newField);
@ -2854,23 +2855,25 @@ angular.module('forms').directive('fieldDirective', ['$http', '$compile', '$root
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
switch(scope.field.fieldType){
case 'textfield':
scope.field.input_type = 'text';
scope.input_type = 'text';
break;
case 'email':
scope.field.input_type = 'email';
scope.field.placeholder = 'joesmith@example.com';
scope.input_type = 'email';
scope.placeholder = 'joesmith@example.com';
break;
case 'number':
scope.field.input_type = 'text';
scope.field.validateRegex = /^-?\d+$/;
scope.input_type = 'text';
scope.validateRegex = /^-?\d+$/;
break;
default:
scope.field.input_type = 'url';
scope.field.placeholder = 'http://example.com';
scope.input_type = 'url';
scope.placeholder = 'http://example.com';
break;
}
fieldType = 'textfield';
}
console.log(scope.input_type);
var template = getTemplateUrl(fieldType);
element.html(template).show();
var output = $compile(element.contents())(scope);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -6,9 +6,9 @@ var __indexOf = [].indexOf || function(item) {
if (i in this && this[i] === item) return i;
}
return -1;
};
};
angular.module('view-form').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields',
angular.module('forms').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields',
function($http, $compile, $rootScope, $templateCache, supportedFields) {
var getTemplateUrl = function(fieldType) {
@ -83,26 +83,27 @@ angular.module('view-form').directive('fieldDirective', ['$http', '$compile', '$
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
switch(scope.field.fieldType){
case 'textfield':
scope.field.input_type = 'text';
scope.input_type = 'text';
break;
case 'email':
scope.field.input_type = 'email';
scope.field.placeholder = 'joesmith@example.com';
scope.input_type = 'email';
scope.placeholder = 'joesmith@example.com';
break;
case 'number':
scope.field.input_type = 'text';
scope.field.validateRegex = /^-?\d+$/;
scope.input_type = 'text';
scope.validateRegex = /^-?\d+$/;
break;
default:
scope.field.input_type = 'url';
scope.field.placeholder = 'http://example.com';
scope.input_type = 'url';
scope.placeholder = 'http://example.com';
break;
}
fieldType = 'textfield';
}
var template = getTemplateUrl(fieldType);
element.html(template).show();
var output = $compile(element.contents())(scope);
}
};
}]);
}]);

View file

@ -21,9 +21,9 @@
<div class="col-xs-12 field-input">
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
name="{{field.fieldType}}{{index}}"
type="{{field.input_type}}"
ng-pattern="field.validateRegex"
placeholder="{{field.placeholder}}"
type="{{input_type}}"
ng-pattern="validateRegex"
placeholder="{{placeholder}}"
ng-class="{ 'no-border': !!field.fieldValue }"
class="focusOn text-field-input"
ng-model="field.fieldValue"

View file

@ -17,8 +17,6 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
$scope.formURL = "/#!/forms/" + $scope.myform._id;
console.log($scope.myform);
$scope.actualFormURL = window.location.protocol + '//' + $scope.myform.admin.username + '.' + window.location.host + "/#!/forms/" + $scope.myform._id;
@ -106,7 +104,7 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
};
// Update existing Form
$scope.update = $rootScope.update = function(updateImmediately, cb){
$scope.update = $rootScope.update = function(updateImmediately, diffChanges, cb){
refreshFrame();
var continueUpdate = true;
@ -120,7 +118,7 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
if(!updateImmediately){ $rootScope.saveInProgress = true; }
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, { changes: diffChanges })
.then(function(response){
$rootScope.myform = $scope.myform = response.data;
// console.log(response.data);

View file

@ -32,7 +32,6 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
$rootScope.finishedRender = false;
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
// console.log('hello');
$rootScope.finishedRender = false;
});
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
@ -52,13 +51,11 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return false;
};
var debounceSave = function () {
$rootScope.saveInProgress = true;
var debounceSave = function (diffChanges) {
$rootScope[$attrs.autoSaveCallback](true,
$rootScope[$attrs.autoSaveCallback](true, diffChanges,
function(err){
if(!err){
//console.log('\n\nForm data persisted -- setting pristine flag');
$formCtrl.$setPristine();
$formCtrl.$setUntouched();
}else{
@ -70,12 +67,10 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
//Update/Save Form if any Form fields are Dirty and Touched
$scope.$watch(function(newValue, oldValue) {
//console.log('introParagraphStartPage.$dirty: '+$scope.editForm.introParagraphStartPage.$dirty);
//console.log('introParagraphStartPage.$touched: '+$scope.editForm.introParagraphStartPage.$touched);
if($rootScope.finishedRender && $scope.anyDirtyAndTouched($scope.editForm) && !$rootScope.saveInProgress){
//console.log('Form saving started');
debounceSave();
//console.log('introParagraphStartPage.$dirty AFTER: '+$scope.editForm.introParagraphStartPage.$dirty);
delete newValue.visible_form_fields;
debounceSave(DeepDiff.diff(oldValue, newValue));
}
});
@ -89,7 +84,6 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
var changedFields = !_.isEqual(oldValue.form_fields,newValue.form_fields) || !_.isEqual(oldValue.startPage, newValue.startPage);
var changedFieldMap = false;
if(oldValue.hasOwnProperty('plugins.oscarhost.settings.fieldMap')){
changedFieldMap = !!oldValue.plugins.oscarhost.settings.fieldMap && !_.isEqual(oldValue.plugins.oscarhost.settings.fieldMap,newValue.plugins.oscarhost.settings.fieldMap);
@ -117,7 +111,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
}
//Save form ONLY IF rendering is finished, form_fields have been changed AND currently not save in progress
if( $rootScope.finishedRender && ((changedFields && !$formCtrl.$dirty) || changedFieldMap) && !$rootScope.saveInProgress) {
if( $rootScope.finishedRender && (changedFields && !$formCtrl.$dirty) && !$rootScope.saveInProgress) {
if(savePromise) {
$timeout.cancel(savePromise);
@ -125,7 +119,12 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
}
savePromise = $timeout(function() {
debounceSave();
$rootScope.saveInProgress = true;
delete newValue.visible_form_fields;
delete newValue.visible_form_fields;
var _diff = DeepDiff.diff(oldValue, newValue);
debounceSave(_diff);
});
}
//If we are finished rendering then form saving should be finished

View file

@ -10,7 +10,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
},
controller: function($scope){
console.log($scope.myform);
var field_ids = _($scope.myform.form_fields).pluck('_id');
for(var i=0; i<field_ids.length; i++){
$scope.myform.plugins.oscarhost.settings.fieldMap[field_ids[i]] = null;
@ -109,7 +108,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
}
}
var newField = {
title: fieldTitle,
title: fieldTitle + ' ' + $scope.myform.form_fields.length+1,
fieldType: fieldType,
fieldValue: '',
required: true,
@ -126,7 +125,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
});
}
if(modifyForm){
//Add newField to form_fields array
$scope.myform.form_fields.push(newField);

View file

@ -83,23 +83,24 @@ angular.module('forms').directive('fieldDirective', ['$http', '$compile', '$root
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
switch(scope.field.fieldType){
case 'textfield':
scope.field.input_type = 'text';
scope.input_type = 'text';
break;
case 'email':
scope.field.input_type = 'email';
scope.field.placeholder = 'joesmith@example.com';
scope.input_type = 'email';
scope.placeholder = 'joesmith@example.com';
break;
case 'number':
scope.field.input_type = 'text';
scope.field.validateRegex = /^-?\d+$/;
scope.input_type = 'text';
scope.validateRegex = /^-?\d+$/;
break;
default:
scope.field.input_type = 'url';
scope.field.placeholder = 'http://example.com';
scope.input_type = 'url';
scope.placeholder = 'http://example.com';
break;
}
fieldType = 'textfield';
}
var template = getTemplateUrl(fieldType);
element.html(template).show();
var output = $compile(element.contents())(scope);

View file

@ -21,9 +21,9 @@
<div class="col-xs-12 field-input">
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
name="{{field.fieldType}}{{index}}"
type="{{field.input_type}}"
ng-pattern="field.validateRegex"
placeholder="{{field.placeholder}}"
type="{{input_type}}"
ng-pattern="validateRegex"
placeholder="{{placeholder}}"
ng-class="{ 'no-border': !!field.fieldValue }"
class="focusOn text-field-input"
ng-model="field.fieldValue"
@ -47,7 +47,72 @@
</div>
</div>
<div>
<div class="btn btn-lg btn-default hidden-xs"
<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-xs-6 col-sm-3" style="margin-top:0.2em">
<small style="color:#ddd; font-size:70%">
{{ 'ENTER' | translate }}
</small>
</div>
</div>
</div>
<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"
ng-focus="setActiveField(field._id, index, true)"
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.validateRegex"> {{ '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 || forms.myForm.{{field.fieldType}}{{$index}}.$invalid"
ng-style="{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"