This commit is contained in:
Sam 2016-05-19 18:48:43 +02:00
commit 64781a42c2
41 changed files with 603 additions and 283 deletions

View File

@ -90,13 +90,15 @@ Edit the 'env' config in gruntfile.js to make sure your .env file is being used.
To run development version:
```$ grunt default```
Set ```NODE_ENV=development``` in .env file
```$ grunt````
To run production version:
```$ grunt production```
Set ```NODE_ENV=development``` in .env file
```$ grunt````
Your application should run on port 3000, so in your browser just go to [http://localhost:3000](http://localhost:3000)
Your application should run on port 3000 or the port you specified in your .env file, so in your browser just go to [http://localhost:3000](http://localhost:3000)
## Testing Your Application
@ -149,3 +151,16 @@ After you've generated the key and certificate, place them in the *config/sslcer
## Credits
Inspired/built off the great work of the [MeanJS team](https://github.com/mean/).
## Mentions on the Web
[t3n.de](http://t3n.de/news/open-source-alternative-typeform-tellform-707295/)
[BootCSS Expo](http://expo.bootcss.com/)
[Product Hunt](https://www.producthunt.com/tech/tellform)
[Hacker News Post](https://news.ycombinator.com/item?id=11711095)
[Reddit Posts](https://www.reddit.com/domain/tellform.com/)

View File

@ -362,13 +362,11 @@ exports.list = function(req, res) {
* Form middleware
*/
exports.formByID = function(req, res, next, id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(400).send({
message: 'Form is invalid'
});
}
else {
} else {
Form.findById(id).populate('admin').exec(function(err, form) {
if (err) {
return next(err);

View File

@ -29,10 +29,14 @@ module.exports = function(app) {
app.route('/upload/pdf')
.post(users.requiresLogin, upload.single('file'), forms.uploadPDF);
//TODO: Need to finish this
//TODO: Need to finish this for file upload field
//app.route('/forms/:formId([a-zA-Z0-9]+)/upload')
// .post(forms.uploadSubmissionFile);
app.route('/forms')
.get(users.requiresLogin, forms.list)
.post(users.requiresLogin, forms.create);
app.route('/forms/:formId([a-zA-Z0-9]+)')
.get(forms.read)
.post(forms.createSubmission)

View File

@ -27,6 +27,7 @@ module.exports = function(app) {
// Setting up the users authentication api
if(!config.signupDisabled) {
console.log('signupDisabled');
app.route('/auth/signup').post(users.signup);
}
app.route('/auth/signin').post(users.signin);

View File

@ -100,16 +100,10 @@
<script type="text/javascript" src="http://{{request.hostname}}:35729/livereload.js"></script>
{% endif %}
<script src="https://cdn.ravenjs.com/2.3.0/angular/raven.min.js"></script>
<script>
/*Raven.config('http://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2', {
// Raven settings
})
.setUser({
"id": "SERVER_RENDERED_ID",
"email": "SERVER_RENDERED_EMAIL"
})
.install()
*/
Raven.config('http://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install();
</script>
<!-- [if lt IE 9]>

View File

@ -23,7 +23,6 @@
"lodash": "~3.10.0",
"angular-ui-sortable": "~0.13.4",
"angular-permission": "~1.1.0",
"angular-input-stars": "*",
"file-saver.js": "~1.20150507.2",
"angular-bootstrap-colorpicker": "~3.0.19",
"angular-ui-router-tabs": "~1.7.0",
@ -31,12 +30,14 @@
"ui-select": "angular-ui-select#^0.16.1",
"angular-sanitize": "^1.5.3",
"v-button": "^1.1.1",
"angular-busy": "^4.1.3"
"angular-busy": "^4.1.3",
"angular-input-stars": "https://github.com/whitef0x0/angular-input-stars.git#master",
"raven-js": "^3.0.4",
"tableExport.jquery.plugin": "^1.5.1"
},
"resolutions": {
"angular-bootstrap": "^0.14.0",
"angular": "1.4.x",
"ng-file-upload": "^12.0.4"
"angular": "1.4.x"
},
"overrides": {
"BOWER-PACKAGE": {

2
config/env/all.js vendored
View File

@ -12,7 +12,7 @@ module.exports = {
reCAPTCHA_Key: process.env.reCAPTCHA_KEY || '',
signupDisabled: false ? (!process.env.SIGNUP_DISABLED || !process.env.SIGNUP_DISABLED === 'false') : true,
signupDisabled: !!process.env.SIGNUP_DISABLED,
baseUrl: '',
tempUserCollection: 'temporary_users',

View File

@ -3,7 +3,7 @@
module.exports = {
baseUrl: process.env.BASE_URL || 'http://localhost:3000',
db: {
uri: 'mongodb://'+(process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost')+'/mean-dev',
uri: 'mongodb://localhost/mean',
options: {
user: '',
pass: ''

View File

@ -54,6 +54,8 @@ module.exports = {
from: process.env.MAILER_FROM || 'no-reply@dev.tellform.com',
options: {
service: process.env.MAILER_SERVICE_PROVIDER || '',
secure: false,
requireTLS: true,
auth: {
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''

View File

@ -9,7 +9,7 @@ module.exports = {
pass: process.env.MONGOLAB_PASS || ''
}
},
port: process.env.PORT || 4545,
port: process.env.PORT || 4545,
log: {
// Can specify one of 'combined', 'common', 'dev', 'short', 'tiny'
format: 'combined',
@ -55,6 +55,7 @@ module.exports = {
from: process.env.MAILER_FROM || 'no-reply@tellform.com',
options: {
service: process.env.MAILER_SERVICE_PROVIDER || '',
ssl: true,
auth: {
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''

View File

@ -15,13 +15,13 @@ angular.module(ApplicationConfiguration.applicationModuleName).constant('APP_PER
viewAdminSettings: 'viewAdminSettings',
editAdminSettings: 'editAdminSettings',
editForm: 'editForm',
viewPrivateForm: 'viewPrivateForm',
viewPrivateForm: 'viewPrivateForm'
});
//User Role constants
angular.module(ApplicationConfiguration.applicationModuleName).constant('USER_ROLES', {
admin: 'admin',
normal: 'user',
superuser: 'superuser',
superuser: 'superuser'
});
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams',
@ -35,8 +35,10 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope'
$state.previous = fromState;
//console.log('toState: '+toState.name);
var statesToIgnore = ['home', 'signin', 'resendVerifyEmail', 'verify', 'signup', 'signup-success', 'forgot', 'reset-invalid', 'reset', 'reset-success'];
//Redirect to listForms if user is authenticated
if(toState.name === 'home' || toState.name === 'signin' || toState.name === 'resendVerifyEmail' || toState.name === 'verify' || toState.name === 'signup' || toState.name === 'signup-success'){
if(statesToIgnore.indexOf(toState.name) > 0){
if(Auth.isAuthenticated()){
event.preventDefault(); // stop current execution
//console.log('go to forms');
@ -45,7 +47,7 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope'
}
//Redirect to 'signup' route if user is not authenticated
else if(toState.name !== 'access_denied' && !Auth.isAuthenticated() && toState.name !== 'submitForm'){
//console.log('go to signup');
console.log('go to signup');
event.preventDefault(); // stop current execution
$state.go('listForms'); // go to listForms page
}
@ -71,9 +73,9 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope'
//console.log(permissions);
if( (permissions != null) ){
if( !authenticator.canAccess(permissions) ){
event.preventDefault();
//console.log('access denied');
$state.go('access_denied');
event.preventDefault();
//console.log('access denied');
$state.go('access_denied');
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -155,6 +155,10 @@ form .accordion-edit {
z-index: 99!important;
}
form .row.field .field-number {
margin-right: 0.5em;
}
/* Styles for form submission view (/forms/:formID) */
form .row.field {
padding: 1em 0 0 0;
@ -313,6 +317,7 @@ div.config-form .row.field {
.admin-form .panel-heading {
background-color: #f1f1f1;
position: relative!important;
}
.admin-form .panel-heading:hover {
background-color: #fff;

View File

@ -4,14 +4,14 @@
function removeDateFieldsFunc(o) {
var clone = _.clone(o);
function eachObject(v,k){
if(k === 'lastModified' || k === 'created'){
delete clone[i][k];
}
}
for(var i=0; i<clone.length; i++){
_.each(clone[i], eachObject);
_.each(clone[i], eachObject);
}
return clone;
}
@ -19,7 +19,7 @@ function removeDateFieldsFunc(o) {
_.mixin({ removeDateFields : removeDateFieldsFunc });
angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', function($rootScope, $timeout) {
return {
require: ['^form'],
restrict: 'AE',
@ -58,24 +58,24 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
$rootScope[$attrs.autoSaveCallback](true,
function(err){
if(!err){
console.log('\n\nForm data persisted -- setting pristine flag');
$formCtrl.$setPristine();
$formCtrl.$setUntouched();
//console.log('\n\nForm data persisted -- setting pristine flag');
$formCtrl.$setPristine();
$formCtrl.$setUntouched();
}else{
console.error('Error form data NOT persisted');
console.error(err);
}
});
});
};
//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);
//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');
//console.log('Form saving started');
debounceSave();
console.log('introParagraphStartPage.$dirty AFTER: '+$scope.editForm.introParagraphStartPage.$dirty);
//console.log('introParagraphStartPage.$dirty AFTER: '+$scope.editForm.introParagraphStartPage.$dirty);
}
});
@ -99,7 +99,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
if( (!newValue && !oldValue) || !oldValue ){
return;
}
// console.log('Autosaving');
// console.log('\n\n----------');
// console.log('!$dirty: '+ !$formCtrl.$dirty );
@ -112,7 +112,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
// console.log(oldValue.form_fields);
// console.log(newValue.form_fields);
if(oldValue.form_fields.length === 0) {
if(oldValue.form_fields.length === 0) {
$rootScope.finishedRender = true;
}
@ -124,9 +124,9 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = null;
}
savePromise = $timeout(function() {
debounceSave();
});
savePromise = $timeout(function() {
debounceSave();
});
}
//If we are finished rendering then form saving should be finished
else if($rootScope.finishedRender && $rootScope.saveInProgress){
@ -137,5 +137,5 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
});
}
};
}]);

View File

@ -16,6 +16,17 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
/*
** Initialize scope with variables
*/
//Setup UI-Sortable
$scope.sortableOptions = {
appendTo: '.dropzone',
cursorAt: { top: -155 },
forceHelperSize: true,
forcePlaceholderSize: true
};
console.log($scope.sortableOptions);
//Populate AddField with all available form field types
$scope.addField = {};
$scope.addField.types = FormFields.types;

View File

@ -108,10 +108,16 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
'csv': 'csv'
};
var blob = new Blob([document.getElementById('table-submission-data').innerHTM], {
console.log($scope.table.rows);
angular.element('#table-submission-data').tableExport({type: type, escape:false});
/*
var blob = new Blob([$scope.table.rows], {
type: 'application/'+fileMIMETypeMap[type]+';charset=utf-8'
});
saveAs(blob, $scope.myform.title+'_sumbissions_export_'+Date.now()+'.'+type);
*/
};
}

View File

@ -0,0 +1,28 @@
'use strict';
angular.module('forms').directive('keyToOption', function(){
return {
restrict: 'A',
scope: {
field: '='
},
link: function($scope, $element, $attrs) {
$element.bind('keydown keypress', function(event) {
console.log('keypress');
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;
});
}
});
}
};
});

View File

@ -0,0 +1,30 @@
'use strict';
angular.module('forms').directive('keyToTruthy', ['$rootScope', function($rootScope){
return {
restrict: 'A',
scope: {
field: '='
},
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;
if(keyCode === truthyKeyCode ) {
event.preventDefault();
$scope.$apply(function() {
$scope.field.fieldValue = 'true';
});
}else if(keyCode === falseyKeyCode){
event.preventDefault();
$scope.$apply(function() {
$scope.field.fieldValue = 'false';
});
}
});
}
};
}]);

View File

@ -6,12 +6,11 @@ angular.module('forms').directive('onEnterKey', ['$rootScope', function($rootSco
link: function($scope, $element, $attrs) {
$element.bind('keydown keypress', function(event) {
var keyCode = event.which || event.keyCode;
if(keyCode === 13) {
if(keyCode === 13 && !event.shiftKey) {
event.preventDefault();
$rootScope.$apply(function() {
$rootScope.$eval($attrs.onEnterKey);
});
event.preventDefault();
}
});
}

View File

@ -89,8 +89,8 @@ angular.module('forms').directive('submitFormDirective', ['$http', 'TimeCounter'
//console.log($scope.selected);
return;
}
//console.log('field_id: '+field_id);
//console.log('field_index: '+field_index);
console.log('field_id: '+field_id);
console.log('field_index: '+field_index);
//console.log($scope.selected);
$scope.selected._id = field_id;
@ -99,11 +99,18 @@ angular.module('forms').directive('submitFormDirective', ['$http', 'TimeCounter'
if(animateScroll){
$scope.noscroll=true;
setTimeout(function() {
$document.scrollToElement(angular.element('.activeField'), -10, 200).then(function(){
$scope.noscroll = false;
document.querySelectorAll('.activeField .focusOn')[0].focus();
$document.scrollToElement(angular.element('.activeField'), -10, 200).then(function() {
$scope.noscroll = false;
setTimeout(function() {
if (document.querySelectorAll('.activeField .focusOn')[0]) {
console.log(document.querySelectorAll('.activeField .focusOn')[0]);
document.querySelectorAll('.activeField .focusOn')[0].focus();
} else {
document.querySelectorAll('.activeField input')[0].focus();
}
});
});
}, 20);
});
}
};
@ -117,6 +124,7 @@ angular.module('forms').directive('submitFormDirective', ['$http', 'TimeCounter'
selected_id = $scope.myform.form_fields[selected_index]._id;
$rootScope.setActiveField(selected_id, selected_index, true);
} else if($scope.selected.index === $scope.myform.form_fields.length-1) {
console.log('Second last element');
selected_index = $scope.selected.index+1;
selected_id = 'submit_field';
$rootScope.setActiveField(selected_id, selected_index, true);
@ -141,7 +149,11 @@ angular.module('forms').directive('submitFormDirective', ['$http', 'TimeCounter'
}
};
$scope.submitForm = function() {
$scope.goToInvalid = function() {
document.querySelectorAll('.ng-invalid.focusOn')[0].focus();
};
$scope.submitForm = function() {
var _timeElapsed = TimeCounter.stopClock();
$scope.loading = true;
var form = _.cloneDeep($scope.myform);
@ -166,11 +178,8 @@ angular.module('forms').directive('submitFormDirective', ['$http', 'TimeCounter'
}, 500);
};
//Load our form when the page is ready
//angular.element(document).ready(function() {
$scope.reloadForm();
//});
//Reload our form
$scope.reloadForm();
}
};
}

View File

@ -43,7 +43,7 @@
</div>
<div class="col-xs-1 col-sm-2">
<small class="pull-right">
<a class="btn btn-default view-form-btn" href="/#!/forms/{{myform._id}}">
<a class="btn btn-default view-form-btn" href="/#!/forms/{{myform._id}}" ng-if="myform.form_fields.length">
<span class="hidden-xs hidden-sm">
View
<span ng-show="myform.isLive">
@ -75,4 +75,4 @@
</div>
</div>
</section>
</section>

View File

@ -1,21 +1,29 @@
<div class="field row" ng-click="setActiveField(field._id, index, true)">
<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>{{index}}</small>
<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</span>
</h3>
</div>
<div class="col-xs-12 field-input">
<div class="control-group input-append">
<input ng-focus="setActiveField(field._id, index, true)"
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">
<input ng-focus="setActiveField(field._id, index, true)"
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-enter-key="nextField()"
ng-change="$root.nextField()">
</div>
</div>
</div>

View File

@ -1,7 +1,12 @@
<div class="field row dropdown" ng-click="setActiveField(field._id, index, true)" ng-if="field.fieldOptions.length > 0">
<div class="field row dropdown"
ng-click="setActiveField(field._id, index, true)"
ng-if="field.fieldOptions.length > 0">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}">
<h3>
<small>{{index}}</small>
<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</span>
</h3>
@ -12,13 +17,12 @@
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
ng-disabled="field.disabled"
ng-focus="setActiveField(field._id, index, true)">
ng-change="$root.nextField()">
<ui-select-match placeholder="Type or select an option">
{{$select.selected.option_value}}
</ui-select-match>
<ui-select-choices
repeat="option in field.fieldOptions | filter: $select.search"
ng-class="{'active': option.option_value === field.fieldValue }">
<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>

View File

@ -1,7 +1,14 @@
<div class="field row" ng-if="form.autofillPDFs" ng-click="setActiveField(field._id, index, true)">
<div class="col-sm-4 field-title">
<h5>{{field.title}} <span class="required-error" ng-show="field.required && field.fieldValue == 0">(* required)</span></h5>
</div>
<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</span>
</h3>
</div>
<div class="col-sm-8 field-input">
<div class="input-group ">
<div tabindex="-1" class="form-control file-caption">

View File

@ -1,38 +1,49 @@
<div class="field row radio legal"
ng-click="setActiveField(field._id, index, true)"
on-enter-key="chooseDefaultOption('legal')">
on-enter-key="nextField()"
key-to-truthy key-char-truthy="y" key-char-falsey="n" field="field">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}">
<h3>{{field.title}} <span class="required-error" ng-show="!field.required">optional</span></h3>
<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</span>
</h3>
<br>
<p style="color:#ddd;">{{field.description}}</p>
</div>
<div class="col-xs-12 field-input container">
<div class="row-fluid">
<label class="btn col-xs-5"
<label class="btn col-md-5 col-xs-12"
ng-class="{activeBtn: field.fieldValue == 'true'}">
<input ng-focus="setActiveField(field._id, index, true)"
class="focusOn"
<input class="focusOn"
ng-focus="setActiveField(field._id, index, true)"
ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
type="radio"
value="true"
type="radio" value="true"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
ng-change="$root.nextField()"
ng-disabled="field.disabled"/>
ng-disabled="field.disabled"
ng-change="$root.nextField()"/>
<div class="letter" style="float:left">
Y
</div>
<span> I accept </span>
</label>
<label class="btn col-xs-5 col-xs-offset-1"
<label class="btn col-md-5 col-md-offset-1 col-xs-12"
ng-class="{activeBtn: field.fieldValue == 'false'}">
<input ng-focus="setActiveField(field._id, index, true)"
ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
type="radio"
value="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-select="$root.nextField()"
ng-disabled="field.disabled"/>
ng-required="field.required"
ng-disabled="field.disabled"
ng-change="$root.nextField()"/>
<div class="letter" style="float:left">
N
</div>
<span>I don't accept </span>
</label>
</div>

View File

@ -1,17 +1,30 @@
<div class="field row radio"
ng-click="setActiveField(field._id, index, true)"
ng-if="field.fieldOptions.length > 0"
on-enter-key="chooseDefaultOption()">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}"><h3><small>{{index}}</small>{{field.title}} <span class="required-error" ng-show="!field.required">optional</span></h3></div>
on-enter-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</span>
</h3>
</div>
<div class="col-xs-12 field-input">
<div ng-repeat="option in field.fieldOptions" class="row-fluid">
<label class="btn col-xs-4"
style="margin: 0.5em; padding-left:30px"
ng-click="$root.nextField()"
<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}">
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
<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-focus="setActiveField(field._id, index, true)"
value="{{option.option_value}}"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"

View File

@ -1,24 +1,27 @@
<div class="textfield field row"
ng-click="setActiveField(field._id, index, true)"
on-enter-key="chooseDefaultOption('rating')">
on-enter-key="nextField()">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}">
<h3>
<small>{{index}}</small>
<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</span>
</h3>
</div>
<div class="col-xs-12 field-input">
<input-stars max="5" ng-focus="setActiveField(field._id, index, true)"
icon-full="fa-star"
icon-base="fa fa-3x"
icon-empty="fa-star-o"
ng-init="field.fieldValue = 1"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
ng-disabled="field.disabled"
class="angular-input-stars focusOn">
<input-stars max="5"
ng-init="field.fieldValue = 1"
on-star-click="$root.nextField()"
icon-full="fa-star"
icon-base="fa fa-3x"
icon-empty="fa-star-o"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
ng-disabled="field.disabled"
class="angular-input-stars focusOn">
</input-stars>
</div>
</div>

View File

@ -1,5 +1,6 @@
<div class="statement field row"
on-enter-key="$root.nextField()">
on-enter-key="$root.nextField()"
ng-focus="setActiveField(field._id, index, true)">
<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>

View File

@ -1,34 +1,44 @@
<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>{{index}}</small>{{field.title}} <span class="required-error" ng-show="!field.required">optional</span></h3></div>
<div class="col-xs-12 field-input">
<textarea class="textarea" type="text"
ng-model="field.fieldValue"
ng-model-options="{ debounce: 250 }"
ng-class="{ 'no-border': !!field.fieldValue }"
value="{{field.fieldValue}}"
class="focusOn"
ng-required="field.required"
ng-disabled="field.disabled"
ng-focus="setActiveField(field._id, index, true)">
</textarea>
</div>
<div class="field row" ng-click="setActiveField(field._id, index, true)"
ng-focus="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</span>
</h3>
<small>press SHIFT+ENTER to create a newline</small>
</div>
<div class="col-xs-12 field-input">
<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"
ng-focus="setActiveField(field._id, index, true)"
on-enter-key="nextField()">
</textarea>
</div>
</div>
<div class="col-xs-12 row">
<div class="btn btn-lg btn-default row-fluid"
style="padding: 4px; margin-top:8px; background: rgba(255,255,255,0.5)">
<button ng-disabled="!field.fieldValue"
ng-click="$root.nextField()"
ng-style="{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"
class="btn col-sm-5 col-xs-5">
OK <i class="fa fa-check"></i>
</button>
<div>
<div class="btn btn-lg btn-default col-xs-12 col-sm-4"
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 <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%">
press ENTER
</small>
</div>
</div>
<small style="color:#ddd; font-size:70%">
press ENTER
</small>
</div>
</div>
</div>

View File

@ -1,7 +1,14 @@
<div class="textfield field row" ng-click="setActiveField(field._id, index, true)">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}">
<div class="textfield field row"
ng-click="setActiveField(field._id, index, true)">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}">
<h3>
<small>{{index}}</small>{{field.title}}
<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)
</span>
@ -34,8 +41,8 @@
</div>
</div>
</div>
<div class="col-xs-12 row">
<div class="btn btn-lg btn-default row-fluid"
<div>
<div class="btn btn-lg btn-default col-xs-12 col-sm-4"
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}"
@ -44,7 +51,7 @@
OK <i class="fa fa-check"></i>
</button>
<div class="col-sm-3 col-xs-6" style="margin-top:0.2em">
<div class="col-xs-6 col-sm-3" style="margin-top:0.2em">
<small style="color:#ddd; font-size:70%">
press ENTER
</small>

View File

@ -1,10 +1,16 @@
<div class="field row radio" ng-click="setActiveField(field._id, index, true)"
on-enter-key="chooseDefaultOption('yes_no')">
<div class="field row radio"
ng-click="setActiveField(field._id, index, true)"
on-enter-key="nextField()"
key-to-truthy key-char-truthy="y" key-char-falsey="n" field="field">
<div class="col-xs-12 field-title" ng-style="{'color': design.colors.questionColor}">
<h3 class="row">
<small>{{index}}</small>{{field.title}}
<span class="required-error" ng-show="field.required && !field.fieldValue">
*(required)
<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
</span>
</h3>
<p class="row">
@ -14,7 +20,7 @@
<div class="col-xs-12 field-input">
<div class="row">
<label class="btn btn-default col-md-2 col-sm-3 col-xs-4"
<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"
@ -34,7 +40,7 @@
</div>
<div class="row" style="margin-top: 10px;">
<label class="btn btn-default col-md-2 col-sm-3 col-xs-4"
<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"

View File

@ -4,7 +4,7 @@
<div class="row add-field-title">
<h3 class="col-md-12 hidden-sm hidden-xs">Click to Add New Field</h3>
<h4 class="col-sm-12 hidden-xs hidden-md hidden-lg">Add New Field</h5>
<h4 class="col-sm-12 hidden-xs hidden-md hidden-lg">Add New Field</h4>
<h5 class="col-sm-12 hidden-sm hidden-md hidden-lg">Add Field</h5>
</div>
<div class="panel-group row" class="draggable" ng-model="addField.types">
@ -163,10 +163,16 @@
</div>
<div class="row">
<div class="col-sm-12 col-md-8 dropzoneContainer">
<accordion close-others="accordion.oneAtATime" ui-sortable="dropzone" ng-model="myform.form_fields" class="dropzone">
<accordion-group data-ng-repeat="field in myform.form_fields track by field._id" is-open="accordion[$index].isOpen" on-finish-render="editFormFields" ng-if="!field.deletePreserved">
<accordion close-others="accordion.oneAtATime"
ui-sortable="sortableOptions"
ng-model="myform.form_fields"
class="dropzone">
<accordion-group ng-repeat="field in myform.form_fields track by field._id"
is-open="accordion[$index].isOpen"
on-finish-render="editFormFields"
ng-if="!field.deletePreserved">
<accordion-heading>
<div class="handle">

View File

@ -7,7 +7,7 @@
</button>
</div>
<div class="col-xs-2 col-xs-offset-4 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('xls')">
<button class="btn btn-default" ng-click="exportSubmissions('xml')">
<small>Export to Excel</small>
</button>
</div>
@ -103,4 +103,4 @@
</table>
</div>
</div>
</div>
</div>

View File

@ -41,43 +41,60 @@ ng-style="{'color':button.color}">
<!-- Form Fields View -->
<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 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-click="setActiveField('submit_field', myform.form_fields.length)"
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%; padding-bottom: 50vh;">
<button ng-focus="setActiveField('submit_field', myform.form_fields.length)"
class="Button btn col-sm-2 col-xs-4"
v-busy="loading" v-busy-label="Please wait" v-pressable
ng-disabled="loading || forms.myForm.$invalid"
ng-click="submitForm()"
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
</button>
<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%; padding-bottom: 100vh;">
<div class="col-sm-2 col-xs-6" style="font-size: 75%; margin-top:2.5em">
<small>
press ENTER
</small>
</div>
<div class="col-xs-12 text-left"
style="background-color:#990000; color:white;"
ng-if="forms.myForm.$invalid">
{{form_fields_count - (myform | formValidity)}} answer(s) need completing
</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"
ng-click="submitForm()"
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
</button>
<button ng-if="forms.myForm.$invalid"
class="Button btn col-sm-2 col-xs-8"
ng-click="goToInvalid()"
style="font-size: 1.6em; margin-left: 1em; margin-top: 1em; background-color:#990000; color:white">
Review
</button>
<div class="col-sm-2 hidden-xs" style="font-size: 75%; margin-top:3.25em">
<small>
press ENTER
</small>
</div>
</div>
<section ng-if="!myform.hideFooter" class="navbar navbar-fixed-bottom"
@ -101,14 +118,14 @@ press ENTER
Edit this TellForm
</a>
</div>
<div class="col-md-4 col-sm-10 col-md-offset-0 col-sm-offset-2 col-xs-12">
<button class="btn btn-lg" id="focusDownButton"
<div class="col-md-4 col-sm-10 col-md-offset-0 col-sm-offset-2 col-xs-12 row">
<button class="btn btn-lg col-xs-6" id="focusDownButton"
ng-style="{'background-color':myform.design.colors.buttonColor, 'color':myform.design.colors.buttonTextColor}"
ng-click="nextField()"
ng-disabled="selected.index > myform.form_fields.length-1">
<i class="fa fa-chevron-down"></i>
</button>
<button class="btn btn-info btn-lg" id="focusUpButton"
<button class="btn btn-lg col-xs-6" id="focusUpButton"
ng-style="{'background-color':myform.design.colors.buttonColor, 'color':myform.design.colors.buttonTextColor}"
ng-click="prevField()"
ng-disabled="selected.index == 0">
@ -127,10 +144,10 @@ press ENTER
style="padding-top: 5vh;">
<div class="field row text-center">
<div class="col-xs-6 col-xs-offset-3 text-center">Form entry successfully submitted!</div>
<div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 text-center">Form entry successfully submitted!</div>
</div>
<div class="row form-actions">
<p class="text-center col-xs-4 col-xs-offset-4">
<p class="text-center">
<button ng-click="reloadForm()" class="btn" type="button"
ng-style="{'background-color':myform.design.colors.buttonColor, 'color':myform.design.colors.buttonTextColor}">
<span style="font-size: 1.6em;"> Go back to Form</span>

View File

@ -10,6 +10,7 @@ angular.module('users').config(['$httpProvider',
if(response.config.url !== '/users/me'){
console.log('intercepted rejection of ', response.config.url, response.status);
if (response.status === 401) {
console.log($location.path());
// save the current location so that login can redirect back
$location.nextAfterLogin = $location.path();
$location.path('/signin');
@ -23,4 +24,4 @@ angular.module('users').config(['$httpProvider',
}
};
});
}]);
}]);

View File

@ -13,15 +13,16 @@ angular.module('users').config(['$stateProvider',
$timeout(deferred.resolve);
}
else {
Auth.currentUser = User.getCurrent(function() {
Auth.login();
$timeout(deferred.resolve());
},
function() {
Auth.logout();
$timeout(deferred.reject());
$state.go('signin', {reload: true});
});
Auth.currentUser = User.getCurrent(
function() {
Auth.login();
$timeout(deferred.resolve());
},
function() {
Auth.logout();
$timeout(deferred.reject());
$state.go('signin', {reload: true});
});
}
return deferred.promise;
@ -82,15 +83,20 @@ angular.module('users').config(['$stateProvider',
url: '/access_denied',
templateUrl: 'modules/users/views/authentication/access-denied.client.view.html'
}).
state('resendVerifyEmail', {
url: '/verify',
templateUrl: 'modules/users/views/verify/resend-verify-email.client.view.html'
}).
state('verify', {
resolve: {
isDisabled: checkSignupDisabled
},
url: '/verify/:token',
templateUrl: 'modules/users/views/verify/verify-account.client.view.html'
}).
state('resendVerifyEmail', {
resolve: {
isDisabled: checkSignupDisabled
},
url: '/verify',
templateUrl: 'modules/users/views/verify/resend-verify-email.client.view.html'
}).
state('forgot', {
url: '/password/forgot',
templateUrl: 'modules/users/views/password/forgot-password.client.view.html'

View File

@ -33,14 +33,14 @@
<input type="password" id="password" name="password" class="form-control" data-ng-model="credentials.password" placeholder="Password">
</div>
<div class="forgot-password">
<a href="/#!/password/forgot">Forgot your password?</a>
<a ui-sref="forgot">Forgot your password?</a>
</div>
<div class="text-center form-group">
<button class="btn btn-primary" ng-click="signin()">Sign in</button>
<span ng-hide="$root.signupDisabled">
&nbsp; or&nbsp;
<a href="/#!/signup">Sign up</a
<a ui-sref="signup">Sign up</a
</span>
</div>

View File

@ -26,11 +26,11 @@
</h2>
<br><br>
<p>Before you continue, make sure to check your email for our verification. If you don't receive it within 24h drop us a line at <a href="mail:hi@tellform.com">hi@TellForm.com</a></p>
<p>Before you continue, make sure to check your email for our verification. If you don't receive it within 24h drop us a line at <a href="mail:polydaic@gmail.com">polydaic@gmail.com</a></p>
<div class="text-center form-group">
<button type="submit" class="btn btn-large btn-primary">
<a href="/#!/" style="color: white; text-decoration: none;">Continue</a>
</button>
</div>
</div>
</section>
</section>

View File

@ -30,7 +30,7 @@
<h2>
A verification email has been sent to {{username}}.<br>But your account is still <b>not activated yet</b>
</h2>
<p>Check your email and click on the activation link to activate your account. If you have any questions drop us a line at <a href="mail:hi@TellForm.com">hi@TellForm.com</a></p>
<p>Check your email and click on the activation link to activate your account. If you have any questions drop us a line at <a href="mail:polydaic@gmail.com">polydaic@gmail.com</a></p>
<div class="text-center form-group">
<button type="submit" class="btn btn-large btn-primary">
<a href="/#!/" style="color:white;">Continue</a>
@ -38,4 +38,4 @@
</div>
</div>
</section>
</section>
</section>