Merge branch 'stage' of github.com:whitef0x0/tellform into stage
Conflicts: README.md app/models/form_submission.server.model.js public/dist/application.min.js public/dist/form-application.min.js
This commit is contained in:
commit
e88234dad5
|
@ -1,4 +1,4 @@
|
||||||
TellForm
|
[<img src="/" width="250px">](https://digitalocean.com/)
|
||||||
========
|
========
|
||||||
|
|
||||||
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UY555MCBZM722)
|
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UY555MCBZM722)
|
||||||
|
@ -14,8 +14,8 @@ TellForm is an *opensource alternative to TypeForm* built ontop of nodejs that c
|
||||||
[See examples here](https://tellform.com/examples)
|
[See examples here](https://tellform.com/examples)
|
||||||
|
|
||||||
####Sponsored by
|
####Sponsored by
|
||||||
[<img src="https://upload.wikimedia.org/wikipedia/en/thumb/f/ff/DigitalOcean_logo.svg/1024px-DigitalOcean_logo.svg.png" width="250px">](https://digitalocean.com/)
|
[<img src="https://www.digitalocean.com/assets/media/logos-badges/png/DO_Logo_Horizontal_Blue-3db19536.png" width="250px">](https://digitalocean.com/)
|
||||||
[<img src="https://raw.githubusercontent.com/docker-library/docs/831b07a52f9ff6577c915afc41af8158725829f4/sentry/logo.png" width="250px">](https://getsentry.com/)
|
[<img src="https://a0wx592cvgzripj.global.ssl.fastly.net/_static/780f0361d74cc3da6680cfa4f855336a/getsentry/images/branding/png/sentry-horizontal-black.png" width="250px">](https://getsentry.com/)
|
||||||
[<img src="https://dka575ofm4ao0.cloudfront.net/assets/base/logos/common-aececb0b4319b8fb61ac5b47a6983f96.png" width="250px">](https://statuspage.io/)
|
[<img src="https://dka575ofm4ao0.cloudfront.net/assets/base/logos/common-aececb0b4319b8fb61ac5b47a6983f96.png" width="250px">](https://statuspage.io/)
|
||||||
[<img src="http://bcsrq.com/wp-content/uploads/2014/04/StickerMuleLogo300.png" width="250px">](https://stickermule.com/)
|
[<img src="http://bcsrq.com/wp-content/uploads/2014/04/StickerMuleLogo300.png" width="250px">](https://stickermule.com/)
|
||||||
[<img src="https://app.sparkpost.com/assets/images/sparkpost-logo-color.svg" width="250px">](https://sparkpost.com/)
|
[<img src="https://app.sparkpost.com/assets/images/sparkpost-logo-color.svg" width="250px">](https://sparkpost.com/)
|
||||||
|
@ -50,6 +50,8 @@ Before you start, make sure you have
|
||||||
1. Redis installed and running at 127.0.0.1:6379
|
1. Redis installed and running at 127.0.0.1:6379
|
||||||
2. MongoDB installed and running at 127.0.0.1:27017 (OR specify the host and port in config/env/all)
|
2. MongoDB installed and running at 127.0.0.1:27017 (OR specify the host and port in config/env/all)
|
||||||
|
|
||||||
|
Also make sure to install DNS Masq or equivalent if running it locally on your computer (look at dns_masq_setup_osx for instructions on OSX)
|
||||||
|
|
||||||
Install dependencies first.
|
Install dependencies first.
|
||||||
```bash
|
```bash
|
||||||
$ npm install
|
$ npm install
|
||||||
|
|
|
@ -13,11 +13,19 @@ exports.index = function(req, res) {
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.form = function(req, res) {
|
exports.form = function(req, res) {
|
||||||
//Allow form to be embeded
|
//Allow form to be embedded
|
||||||
res.removeHeader('X-Frame-Options');
|
res.set('X-Frame-Options', 'GOFORIT');
|
||||||
|
|
||||||
res.render('form', {
|
res.render('form', {
|
||||||
user: req.user || null,
|
user: req.user || null,
|
||||||
request: req
|
request: req
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.redoc = function(req, res) {
|
||||||
|
res.render('redoc', {
|
||||||
|
request: req
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ var mongoose = require('mongoose'),
|
||||||
fs = require('fs-extra'),
|
fs = require('fs-extra'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
|
diff = require('deep-diff'),
|
||||||
_ = require('lodash');
|
_ = 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
|
* Delete a forms submissions
|
||||||
*/
|
*/
|
||||||
|
@ -185,8 +118,6 @@ exports.createSubmission = function(req, res) {
|
||||||
percentageComplete: req.body.percentageComplete
|
percentageComplete: req.body.percentageComplete
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!!form.plugins.oscarhost.baseUrl) submission.hasPlugins.oscarhost = true;
|
|
||||||
|
|
||||||
if(form.pdf) submission.pdf = form.pdf;
|
if(form.pdf) submission.pdf = form.pdf;
|
||||||
|
|
||||||
//Save submitter's IP Address
|
//Save submitter's IP Address
|
||||||
|
@ -256,23 +187,27 @@ exports.listSubmissions = function(req, res) {
|
||||||
* Create a new form
|
* Create a new form
|
||||||
*/
|
*/
|
||||||
exports.create = function(req, res) {
|
exports.create = function(req, res) {
|
||||||
|
|
||||||
|
|
||||||
|
if(!req.body.form){
|
||||||
|
console.log(err);
|
||||||
|
return res.status(400).send({
|
||||||
|
message: "Invalid Input"
|
||||||
|
});
|
||||||
|
}
|
||||||
var form = new Form(req.body.form);
|
var form = new Form(req.body.form);
|
||||||
|
|
||||||
form.admin = req.user._id;
|
form.admin = req.user._id;
|
||||||
console.log('Create a new form');
|
|
||||||
console.log(form);
|
|
||||||
console.log(req.body.form);
|
|
||||||
console.log(req.user);
|
|
||||||
|
|
||||||
form.save(function(err) {
|
form.save(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res.status(400).send({
|
return res.status(405).send({
|
||||||
message: errorHandler.getErrorMessage(err)
|
message: errorHandler.getErrorMessage(err)
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
res.json(form);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.json(form);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -280,10 +215,7 @@ exports.create = function(req, res) {
|
||||||
* Show the current form
|
* Show the current form
|
||||||
*/
|
*/
|
||||||
exports.read = function(req, res) {
|
exports.read = function(req, res) {
|
||||||
var validUpdateTypes= Form.schema.path('plugins.oscarhost.settings.updateType').enumValues;
|
|
||||||
|
|
||||||
var newForm = req.form.toJSON({virtuals : true});
|
var newForm = req.form.toJSON({virtuals : true});
|
||||||
newForm.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes;
|
|
||||||
|
|
||||||
if (req.userId) {
|
if (req.userId) {
|
||||||
if(req.form.admin._id+'' === req.userId+''){
|
if(req.form.admin._id+'' === req.userId+''){
|
||||||
|
@ -294,7 +226,6 @@ exports.read = function(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return res.json(newForm);
|
return res.json(newForm);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,27 +233,33 @@ exports.read = function(req, res) {
|
||||||
*/
|
*/
|
||||||
exports.update = function(req, res) {
|
exports.update = function(req, res) {
|
||||||
var form = req.form;
|
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){
|
||||||
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
|
console.log('SENDING DIFFS\n\n\n');
|
||||||
|
var formChanges = req.body.changes;
|
||||||
|
|
||||||
//Do this so we can create duplicate fields
|
formChanges.forEach(function (change) {
|
||||||
var checkForValidId = new RegExp('^[0-9a-fA-F]{24}$');
|
diff.applyChange(form, true, change);
|
||||||
for(var i=0; i<req.body.form.form_fields.length; i++){
|
});
|
||||||
var field = req.body.form.form_fields[i];
|
} else {
|
||||||
if(!checkForValidId.exec(field._id+'')){
|
//Unless we have 'admin' privileges, updating form admin is disabled
|
||||||
delete field._id;
|
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
|
||||||
|
|
||||||
|
//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++){
|
||||||
|
var field = req.body.form.form_fields[i];
|
||||||
|
if(!checkForValidId.exec(field._id+'')){
|
||||||
|
delete field._id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
form = _.extend(form, req.body.form);
|
||||||
}
|
}
|
||||||
|
|
||||||
form = _.extend(form, req.body.form);
|
|
||||||
|
|
||||||
form.save(function(err, form) {
|
form.save(function(err, form) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res.status(400).send({
|
res.status(405).send({
|
||||||
message: errorHandler.getErrorMessage(err)
|
message: errorHandler.getErrorMessage(err)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -382,7 +319,7 @@ exports.formByID = function(req, res, next, id) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
} else if (form === undefined || form === null) {
|
} else if (form === undefined || form === null) {
|
||||||
res.status(400).send({
|
res.status(404).send({
|
||||||
message: 'Form not found'
|
message: 'Form not found'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ var _ = require('lodash'),
|
||||||
config = require('../../../config/config'),
|
config = require('../../../config/config'),
|
||||||
nodemailer = require('nodemailer'),
|
nodemailer = require('nodemailer'),
|
||||||
crypto = require('crypto'),
|
crypto = require('crypto'),
|
||||||
User = mongoose.model('User');
|
User = mongoose.model('User'),
|
||||||
|
tokgen = require("../../libs/tokenGenerator");
|
||||||
|
|
||||||
|
|
||||||
var nev = require('email-verification')(mongoose);
|
var nev = require('email-verification')(mongoose);
|
||||||
|
|
||||||
|
@ -99,6 +101,7 @@ exports.resendVerificationEmail = function(req, res, next){
|
||||||
* Signup
|
* Signup
|
||||||
*/
|
*/
|
||||||
exports.signup = function(req, res) {
|
exports.signup = function(req, res) {
|
||||||
|
debugger;
|
||||||
|
|
||||||
// For security measures we remove the roles from the req.body object
|
// For security measures we remove the roles from the req.body object
|
||||||
delete req.body.roles;
|
delete req.body.roles;
|
||||||
|
@ -172,7 +175,6 @@ exports.signin = function(req, res, next) {
|
||||||
*/
|
*/
|
||||||
exports.signout = function(req, res) {
|
exports.signout = function(req, res) {
|
||||||
req.logout();
|
req.logout();
|
||||||
//res.redirect('/');
|
|
||||||
return res.status(200).send('You have successfully logged out.');
|
return res.status(200).send('You have successfully logged out.');
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -304,3 +306,43 @@ exports.removeOAuthProvider = function(req, res, next) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Generate API Key for User */
|
||||||
|
exports.generateAPIKey = function(req, res) {
|
||||||
|
if (!req.isAuthenticated()){
|
||||||
|
return res.status(400).send({
|
||||||
|
message: 'User is not Authorized'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
User.findById(req.user.id)
|
||||||
|
.exec( function(err, user) {
|
||||||
|
if (err) return res.status(400).send(err);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return res.status(400).send({
|
||||||
|
message: 'User does not Exist'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
user.apiKey = tokgen();
|
||||||
|
|
||||||
|
user.save(function(err, _user) {
|
||||||
|
if (err) {
|
||||||
|
return res.status(400).send({
|
||||||
|
message: errorHandler.getErrorMessage(err)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var newUser = _user.toObject();
|
||||||
|
delete newUser.salt;
|
||||||
|
delete newUser.__v;
|
||||||
|
delete newUser.passwordHash;
|
||||||
|
delete newUser.provider;
|
||||||
|
|
||||||
|
console.log(newUser);
|
||||||
|
return res.json(newUser);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -23,7 +23,9 @@ exports.userByID = function (req, res, next, id) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
} else if (!user) {
|
} else if (!user) {
|
||||||
return next(new Error('Failed to load User ' + id));
|
return res.status(404).send({
|
||||||
|
message: 'User does not exist'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
req.profile = user;
|
req.profile = user;
|
||||||
|
|
|
@ -27,13 +27,13 @@ exports.update = function(req, res) {
|
||||||
|
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(400).send({
|
return res.status(500).send({
|
||||||
message: errorHandler.getErrorMessage(err)
|
message: errorHandler.getErrorMessage(err)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
req.login(user, function(err) {
|
req.login(user, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.status(400).send(err);
|
res.status(500).send(err);
|
||||||
} else {
|
} else {
|
||||||
res.json(user);
|
res.json(user);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ exports.update = function(req, res) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(400).send({
|
res.status(401).send({
|
||||||
message: 'User is not signed in'
|
message: 'User is not signed in'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
8
app/libs/tokenGenerator.js
Normal file
8
app/libs/tokenGenerator.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let TokenGenerator = require("uuid-token-generator");
|
||||||
|
let tokgen = new TokenGenerator(256, TokenGenerator.BASE62);
|
||||||
|
|
||||||
|
module.exports = function() {
|
||||||
|
return tokgen.generate();
|
||||||
|
};
|
|
@ -92,11 +92,6 @@ var FormSchema = new Schema({
|
||||||
default: 'en',
|
default: 'en',
|
||||||
required: 'Form must have a language'
|
required: 'Form must have a language'
|
||||||
},
|
},
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
|
|
||||||
analytics:{
|
analytics:{
|
||||||
gaCode: {
|
gaCode: {
|
||||||
type: String
|
type: String
|
||||||
|
@ -146,18 +141,10 @@ var FormSchema = new Schema({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
isGenerated: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isLive: {
|
isLive: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
autofillPDFs: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
|
|
||||||
design: {
|
design: {
|
||||||
colors:{
|
colors:{
|
||||||
|
@ -187,57 +174,7 @@ var FormSchema = new Schema({
|
||||||
default: '#333'
|
default: '#333'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
font: String,
|
font: String
|
||||||
backgroundImage: { type: Schema.Types.Mixed }
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: {
|
|
||||||
oscarhost: {
|
|
||||||
baseUrl: {
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
lookupField: {
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'Field'
|
|
||||||
},
|
|
||||||
updateType: {
|
|
||||||
type: String,
|
|
||||||
enum: ['upsert', 'force_add', 'force_update', 'fetch'],
|
|
||||||
},
|
|
||||||
fieldMap: {
|
|
||||||
type: Schema.Types.Mixed,
|
|
||||||
},
|
|
||||||
validUpdateTypes: {
|
|
||||||
type: [String]
|
|
||||||
},
|
|
||||||
validFields : {
|
|
||||||
type: [String],
|
|
||||||
default: [
|
|
||||||
'address',
|
|
||||||
'city',
|
|
||||||
'email',
|
|
||||||
'firstName',
|
|
||||||
'hin',
|
|
||||||
'lastName',
|
|
||||||
'phone',
|
|
||||||
'postal',
|
|
||||||
'province',
|
|
||||||
'sex',
|
|
||||||
'spokenLanguage',
|
|
||||||
'title',
|
|
||||||
'DOB']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
auth: {
|
|
||||||
user: {
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
pass: {
|
|
||||||
type: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -367,11 +304,6 @@ FormSchema.pre('save', function (next) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, function(cb) {
|
}, function(cb) {
|
||||||
//DAVID: TODO: Make this so we don't have to update the validFields property ever save
|
|
||||||
if (that.plugins.oscarhost.hasOwnProperty('baseUrl')) {
|
|
||||||
var validUpdateTypes = mongoose.model('Form').schema.path('plugins.oscarhost.settings.updateType').enumValues;
|
|
||||||
that.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes;
|
|
||||||
}
|
|
||||||
return cb(null);
|
return cb(null);
|
||||||
},
|
},
|
||||||
function(cb) {
|
function(cb) {
|
||||||
|
@ -489,12 +421,18 @@ FormSchema.pre('save', function (next) {
|
||||||
else return cb();
|
else return cb();
|
||||||
},
|
},
|
||||||
function(cb) {
|
function(cb) {
|
||||||
|
var hasIds = true;
|
||||||
if(that.isModified('form_fields') && that.form_fields && _original){
|
for(var i=0; i<that.form_fields.length; i++){
|
||||||
|
if(!that.form_fields.hasOwnProperty('_id')){
|
||||||
|
hasIds = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(that.isModified('form_fields') && that.form_fields && _original && hasIds){
|
||||||
|
|
||||||
var old_form_fields = _original.form_fields,
|
var old_form_fields = _original.form_fields,
|
||||||
new_ids = _.map(_.pluck(that.form_fields, '_id'), function(id){ return ''+id;}),
|
new_ids = _.map(_.pluck(that.form_fields, 'id'), function(id){ return ''+id;}),
|
||||||
old_ids = _.map(_.pluck(old_form_fields, '_id'), function(id){ return ''+id;}),
|
old_ids = _.map(_.pluck(old_form_fields, 'id'), function(id){ return ''+id;}),
|
||||||
deletedIds = getDeletedIndexes(old_ids, new_ids);
|
deletedIds = getDeletedIndexes(old_ids, new_ids);
|
||||||
|
|
||||||
//Preserve fields that have at least one submission
|
//Preserve fields that have at least one submission
|
||||||
|
|
|
@ -7,7 +7,8 @@ var mongoose = require('mongoose'),
|
||||||
util = require('util'),
|
util = require('util'),
|
||||||
mUtilities = require('mongoose-utilities'),
|
mUtilities = require('mongoose-utilities'),
|
||||||
_ = require('lodash'),
|
_ = require('lodash'),
|
||||||
Schema = mongoose.Schema;
|
Schema = mongoose.Schema,
|
||||||
|
LogicJumpSchema = require('./logic_jump.server.model');
|
||||||
|
|
||||||
var FieldOptionSchema = new Schema({
|
var FieldOptionSchema = new Schema({
|
||||||
option_id: {
|
option_id: {
|
||||||
|
@ -77,10 +78,7 @@ function BaseFieldSchema(){
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
logicJump: {
|
logicJump: LogicJumpSchema,
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'LogicJump'
|
|
||||||
},
|
|
||||||
|
|
||||||
ratingOptions: {
|
ratingOptions: {
|
||||||
type: RatingFieldSchema,
|
type: RatingFieldSchema,
|
||||||
|
@ -162,6 +160,7 @@ FormFieldSchema.pre('validate', function(next) {
|
||||||
|
|
||||||
if(this.ratingOptions && this.ratingOptions.steps && this.ratingOptions.shape){
|
if(this.ratingOptions && this.ratingOptions.steps && this.ratingOptions.shape){
|
||||||
error.errors.ratingOptions = new mongoose.Error.ValidatorError({path: 'ratingOptions', message: 'ratingOptions is only allowed for type \'rating\' fields.', type: 'notvalid', value: this.ratingOptions});
|
error.errors.ratingOptions = new mongoose.Error.ValidatorError({path: 'ratingOptions', message: 'ratingOptions is only allowed for type \'rating\' fields.', type: 'notvalid', value: this.ratingOptions});
|
||||||
|
console.error(error);
|
||||||
return(next(error));
|
return(next(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,8 +182,9 @@ FormFieldSchema.pre('validate', function(next) {
|
||||||
|
|
||||||
//If field is multiple choice check that it has field
|
//If field is multiple choice check that it has field
|
||||||
if(this.fieldType !== 'dropdown' && this.fieldType !== 'radio' && this.fieldType !== 'checkbox'){
|
if(this.fieldType !== 'dropdown' && this.fieldType !== 'radio' && this.fieldType !== 'checkbox'){
|
||||||
if(!this.fieldOptions || this.fieldOptions.length !== 0){
|
if(this.fieldOptions && this.fieldOptions.length > 0){
|
||||||
error.errors.ratingOptions = new mongoose.Error.ValidatorError({path:'fieldOptions', message: 'fieldOptions are only allowed for type dropdown, checkbox or radio fields.', type: 'notvalid', value: this.ratingOptions});
|
error.errors.ratingOptions = new mongoose.Error.ValidatorError({path:'fieldOptions', message: 'fieldOptions are only allowed for type dropdown, checkbox or radio fields.', type: 'notvalid', value: this.ratingOptions});
|
||||||
|
console.error(error);
|
||||||
return(next(error));
|
return(next(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,13 +192,18 @@ FormFieldSchema.pre('validate', function(next) {
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//LogicJump Save
|
||||||
|
FormFieldSchema.pre('save', function(next) {
|
||||||
|
if(this.logicJump && this.logicJump.fieldA){
|
||||||
|
if(this.logicJump.jumpTo = '') delete this.logicJump.jumpTo;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
//Submission fieldValue correction
|
//Submission fieldValue correction
|
||||||
FormFieldSchema.pre('save', function(next) {
|
FormFieldSchema.pre('save', function(next) {
|
||||||
|
|
||||||
if(this.fieldType === 'dropdown' && this.isSubmission){
|
if(this.fieldType === 'dropdown' && this.isSubmission){
|
||||||
//console.log(this);
|
|
||||||
this.fieldValue = this.fieldValue.option_value;
|
this.fieldValue = this.fieldValue.option_value;
|
||||||
//console.log(this.fieldValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
|
|
|
@ -159,88 +159,7 @@ FormSubmissionSchema.pre('save', function (next) {
|
||||||
// console.log(_form);
|
// console.log(_form);
|
||||||
// console.log('should push to api');
|
// console.log('should push to api');
|
||||||
// console.log( (!this.oscarDemoNum && !!_form.plugins.oscarhost.baseUrl && !!_form.plugins.oscarhost.settings.fieldMap) );
|
// console.log( (!this.oscarDemoNum && !!_form.plugins.oscarhost.baseUrl && !!_form.plugins.oscarhost.settings.fieldMap) );
|
||||||
if (!this.oscarDemoNum && _form.plugins.oscarhost.baseUrl && _form.plugins.oscarhost.settings.fieldMap) {
|
return next();
|
||||||
console.log('OSCARHOST API HOOK');
|
|
||||||
var url_login = _form.plugins.oscarhost.baseUrl + '/LoginService?wsdl',
|
|
||||||
url_demo = _form.plugins.oscarhost.baseUrl + '/DemographicService?wsdl';
|
|
||||||
|
|
||||||
var args_login = {arg0: config.oscarhost.auth.user, arg1: config.oscarhost.auth.pass};
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
ignoredNamespaces: {
|
|
||||||
namespaces: ['targetNamespace', 'typedNamespace'],
|
|
||||||
override: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// console.log(self.form_fields);
|
|
||||||
|
|
||||||
//Generate demographics from hashmap
|
|
||||||
var generateDemo = function (formFields, conversionMap, demographicsTemplate) {
|
|
||||||
console.log('generating Demo fields');
|
|
||||||
console.log(conversionMap);
|
|
||||||
var _generatedDemo = {}, currField, propertyName;
|
|
||||||
|
|
||||||
for (var y = 0; y < formFields.length; y++) {
|
|
||||||
currField = formFields[y];
|
|
||||||
propertyName = conversionMap[currField._id];
|
|
||||||
|
|
||||||
if (demographicsTemplate.hasOwnProperty(conversionMap[currField._id])) {
|
|
||||||
_generatedDemo[propertyName] = currField.fieldValue + '';
|
|
||||||
} else if (propertyName === 'DOB') {
|
|
||||||
var date = new Date(currField.fieldValue);
|
|
||||||
_generatedDemo.dateOfBirth = date.getDate() + '';
|
|
||||||
_generatedDemo.yearOfBirth = date.getFullYear() + '';
|
|
||||||
_generatedDemo.monthOfBirth = date.getMonth() + '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var currDate = new Date();
|
|
||||||
var dateString = currDate.toISOString().split('T')[0] + ' ' + currDate.toISOString().split('T')[1].slice(0, 8);
|
|
||||||
_generatedDemo.lastUpdateDate = currDate.toISOString();
|
|
||||||
return _generatedDemo;
|
|
||||||
};
|
|
||||||
|
|
||||||
var submissionDemographic = generateDemo(self.form_fields, _form.plugins.oscarhost.settings.fieldMap, newDemoTemplate);
|
|
||||||
|
|
||||||
console.log(submissionDemographic);
|
|
||||||
async.waterfall([
|
|
||||||
function (callback) {
|
|
||||||
//Authenticate with API
|
|
||||||
soap.createClient(url_login, options, function (err, client) {
|
|
||||||
client.login(args_login, function (err, result) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
console.log('SOAP authenticated');
|
|
||||||
return callback(null, result.return);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
function (security_obj, callback) {
|
|
||||||
//Force Add Demographic
|
|
||||||
if (_form.plugins.oscarhost.settings.updateType === 'force_add') {
|
|
||||||
soap.createClient(url_demo, options, function (err, client) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
client.setSecurity(new OscarSecurity(security_obj.securityId, security_obj.securityTokenKey));
|
|
||||||
|
|
||||||
client.addDemographic({arg0: submissionDemographic}, function (err, result) {
|
|
||||||
console.log('FORCE ADDING DEMOGRAPHIC \n');
|
|
||||||
// console.log(result.return);
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
], function (err, result) {
|
|
||||||
if (err) return next(err);
|
|
||||||
|
|
||||||
self.oscarDemoNum = parseInt(result.return, 10);
|
|
||||||
console.log('self.oscarDemoNum: ' + self.oscarDemoNum);
|
|
||||||
return next();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return next();
|
return next();
|
||||||
|
|
|
@ -6,76 +6,76 @@
|
||||||
var mongoose = require('mongoose'),
|
var mongoose = require('mongoose'),
|
||||||
Schema = mongoose.Schema,
|
Schema = mongoose.Schema,
|
||||||
_ = require('lodash'),
|
_ = require('lodash'),
|
||||||
math = require('math');
|
math = require('mathjs');
|
||||||
|
|
||||||
|
var schemaOptions = {
|
||||||
var BooleanExpressionSchema = new Schema({
|
toObject: {
|
||||||
expressionString: {
|
virtuals: true
|
||||||
type: String,
|
|
||||||
},
|
},
|
||||||
result: {
|
toJSON: {
|
||||||
type: Boolean,
|
virtuals: true
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
BooleanExpressionSchema.methods.evaluate = function(){
|
|
||||||
if(this.expressionString){
|
|
||||||
//Get headNode
|
|
||||||
var headNode = math.parse(this.expressionString);
|
|
||||||
var expressionScope = {};
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
//Create scope
|
|
||||||
headNode.traverse(function (node, path, parent) {
|
|
||||||
if(node.type === 'SymbolNode'){
|
|
||||||
|
|
||||||
mongoose.model('Field')
|
|
||||||
.findOne({_id: node.name}).exec(function(err, field){
|
|
||||||
if(err) {
|
|
||||||
console.log(err);
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!!_.parseInt(field.fieldValue)){
|
|
||||||
that.expressionScope[node.name] = _.parseInt(field.fieldValue);
|
|
||||||
}else {
|
|
||||||
that.expressionScope[node.name] = field.fieldValue;
|
|
||||||
}
|
|
||||||
console.log('_id: '+node.name);
|
|
||||||
console.log('value: '+that.expressionScope[node.name]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var code = headNode.compile();
|
|
||||||
var result = code.eval(expressionScope);
|
|
||||||
|
|
||||||
this.result = result;
|
|
||||||
return result;
|
|
||||||
}else{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mongoose.model('BooleanExpression', BooleanExpressionSchema);
|
|
||||||
/**
|
|
||||||
* Form Schema
|
|
||||||
*/
|
|
||||||
var LogicJumpSchema = new Schema({
|
var LogicJumpSchema = new Schema({
|
||||||
created: {
|
expressionString: {
|
||||||
type: Date,
|
type: String,
|
||||||
default: Date.now
|
enum: [
|
||||||
|
'field == static',
|
||||||
|
'field != static',
|
||||||
|
'field > static',
|
||||||
|
'field >= static',
|
||||||
|
'field <= static',
|
||||||
|
'field < static',
|
||||||
|
'field contains static',
|
||||||
|
'field !contains static',
|
||||||
|
'field begins static',
|
||||||
|
'field !begins static',
|
||||||
|
'field ends static',
|
||||||
|
'field !ends static',
|
||||||
|
]
|
||||||
},
|
},
|
||||||
lastModified: {
|
fieldA: {
|
||||||
type: Date,
|
|
||||||
},
|
|
||||||
|
|
||||||
BooleanExpression: {
|
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'BooleanExpression'
|
ref: 'FormField'
|
||||||
},
|
},
|
||||||
|
valueB: {
|
||||||
|
type: Schema.Types.String
|
||||||
|
},
|
||||||
|
jumpTo: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: 'FormField'
|
||||||
|
}
|
||||||
|
}, schemaOptions);
|
||||||
|
|
||||||
});
|
/*
|
||||||
|
IS EQUAL TO statement
|
||||||
|
|
||||||
|
var scope = {
|
||||||
|
a: val1,
|
||||||
|
b: val2
|
||||||
|
};
|
||||||
|
|
||||||
|
math.eval('a == b', scope);
|
||||||
|
|
||||||
|
IS NOT EQUAL TO statement
|
||||||
|
var scope = {
|
||||||
|
a: val1,
|
||||||
|
b: val2
|
||||||
|
};
|
||||||
|
|
||||||
|
math.eval('a !== b', scope);
|
||||||
|
|
||||||
|
BEGINS WITH statement
|
||||||
|
|
||||||
|
ENDS WITH statement
|
||||||
|
|
||||||
|
CONTAINS statement
|
||||||
|
|
||||||
|
DOES NOT CONTAIN statement
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
mongoose.model('LogicJump', LogicJumpSchema);
|
mongoose.model('LogicJump', LogicJumpSchema);
|
||||||
|
|
||||||
|
module.exports = LogicJumpSchema;
|
||||||
|
|
|
@ -75,6 +75,7 @@ var UserSchema = new Schema({
|
||||||
type: String,
|
type: String,
|
||||||
unique: true,
|
unique: true,
|
||||||
required: false,
|
required: false,
|
||||||
|
lowercase: true,
|
||||||
trim: true
|
trim: true
|
||||||
},
|
},
|
||||||
passwordHash: {
|
passwordHash: {
|
||||||
|
@ -119,7 +120,13 @@ var UserSchema = new Schema({
|
||||||
resetPasswordExpires: {
|
resetPasswordExpires: {
|
||||||
type: Date
|
type: Date
|
||||||
},
|
},
|
||||||
token: String
|
token: String,
|
||||||
|
apiKey: {
|
||||||
|
type: String,
|
||||||
|
unique: true,
|
||||||
|
index: true,
|
||||||
|
sparse: true
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
UserSchema.virtual('displayName').get(function () {
|
UserSchema.virtual('displayName').get(function () {
|
||||||
|
|
|
@ -7,10 +7,11 @@ var forms = require('../../app/controllers/forms.server.controller'),
|
||||||
core = require('../../app/controllers/core.server.controller');
|
core = require('../../app/controllers/core.server.controller');
|
||||||
|
|
||||||
module.exports = function(app) {
|
module.exports = function(app) {
|
||||||
// Root routing
|
// Core routing
|
||||||
app.route('/').get(core.index);
|
app.route('/').get(core.index);
|
||||||
app.route('/subdomain/([a-zA-Z0-9]+)/').get(core.form);
|
|
||||||
app.route('/subdomain/*/forms/:formId([a-zA-Z0-9]+)')
|
app.route('/subdomain/api/').get(core.redoc);
|
||||||
.get(forms.read)
|
app.route('/subdomain/:userSlug((?!api$)[A-Za-z0-9]+)/').get(core.form);
|
||||||
|
app.route('/subdomain/:userSlug((?!api$)[A-Za-z0-9]+)/forms/:formId([a-zA-Z0-9]+)').get(forms.read)
|
||||||
.post(forms.createSubmission);
|
.post(forms.createSubmission);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
var users = require('../../app/controllers/users.server.controller'),
|
var users = require('../../app/controllers/users.server.controller'),
|
||||||
forms = require('../../app/controllers/forms.server.controller'),
|
forms = require('../../app/controllers/forms.server.controller'),
|
||||||
multer = require('multer'),
|
multer = require('multer'),
|
||||||
config = require('../../config/config');
|
config = require('../../config/config'),
|
||||||
|
auth = require('../../config/passport_helpers');
|
||||||
|
|
||||||
// Setting the pdf upload route and folder
|
// Setting the pdf upload route and folder
|
||||||
var storage = multer.diskStorage({
|
var storage = multer.diskStorage({
|
||||||
|
@ -27,21 +28,21 @@ var upload = multer({
|
||||||
module.exports = function(app) {
|
module.exports = function(app) {
|
||||||
// Form Routes
|
// Form Routes
|
||||||
app.route('/upload/pdf')
|
app.route('/upload/pdf')
|
||||||
.post(users.requiresLogin, upload.single('file'), forms.uploadPDF);
|
.post(auth.isAuthenticatedOrApiKey, upload.single('file'), forms.uploadPDF);
|
||||||
|
|
||||||
app.route('/forms')
|
app.route('/forms')
|
||||||
.get(users.requiresLogin, forms.list)
|
.get(auth.isAuthenticatedOrApiKey, forms.list)
|
||||||
.post(users.requiresLogin, forms.create);
|
.post(auth.isAuthenticatedOrApiKey, forms.create);
|
||||||
|
|
||||||
app.route('/forms/:formId([a-zA-Z0-9]+)')
|
app.route('/forms/:formId([a-zA-Z0-9]+)')
|
||||||
.get(forms.read)
|
.get(forms.read)
|
||||||
.post(forms.createSubmission)
|
.post(forms.createSubmission)
|
||||||
.put(users.requiresLogin, forms.hasAuthorization, forms.update)
|
.put(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.update)
|
||||||
.delete(users.requiresLogin, forms.hasAuthorization, forms.delete);
|
.delete(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.delete);
|
||||||
|
|
||||||
app.route('/forms/:formId([a-zA-Z0-9]+)/submissions')
|
app.route('/forms/:formId([a-zA-Z0-9]+)/submissions')
|
||||||
.get(users.requiresLogin, forms.hasAuthorization, forms.listSubmissions)
|
.get(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.listSubmissions)
|
||||||
.delete(users.requiresLogin, forms.hasAuthorization, forms.deleteSubmissions);
|
.delete(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.deleteSubmissions);
|
||||||
|
|
||||||
// Finish by binding the form middleware
|
// Finish by binding the form middleware
|
||||||
app.param('formId', forms.formByID);
|
app.param('formId', forms.formByID);
|
||||||
|
|
|
@ -3,16 +3,17 @@
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
var passport = require('passport');
|
var passport = require('passport'),
|
||||||
var config = require('../../config/config');
|
config = require('../../config/config'),
|
||||||
|
auth = require('../../config/passport_helpers');
|
||||||
|
|
||||||
module.exports = function(app) {
|
module.exports = function(app) {
|
||||||
// User Routes
|
// User Routes
|
||||||
var users = require('../../app/controllers/users.server.controller');
|
var users = require('../../app/controllers/users.server.controller');
|
||||||
|
|
||||||
// Setting up the users profile api
|
// Setting up the users profile api
|
||||||
app.route('/users/me').get(users.requiresLogin, users.getUser);
|
app.route('/users/me').get(auth.isAuthenticatedOrApiKey, users.getUser);
|
||||||
app.route('/users').put(users.requiresLogin, users.update);
|
app.route('/users').put(auth.isAuthenticatedOrApiKey, users.update);
|
||||||
app.route('/users/accounts').delete(users.requiresLogin, users.removeOAuthProvider);
|
app.route('/users/accounts').delete(users.requiresLogin, users.removeOAuthProvider);
|
||||||
|
|
||||||
// Setting up the users account verification api
|
// Setting up the users account verification api
|
||||||
|
@ -32,6 +33,8 @@ module.exports = function(app) {
|
||||||
app.route('/auth/signin').post(users.signin);
|
app.route('/auth/signin').post(users.signin);
|
||||||
app.route('/auth/signout').get(users.signout);
|
app.route('/auth/signout').get(users.signout);
|
||||||
|
|
||||||
|
app.route('/auth/genkey').get(users.requiresLogin, users.generateAPIKey);
|
||||||
|
|
||||||
// // Setting the facebook oauth routes
|
// // Setting the facebook oauth routes
|
||||||
// app.route('/auth/facebook').get(passport.authenticate('facebook', {
|
// app.route('/auth/facebook').get(passport.authenticate('facebook', {
|
||||||
// scope: ['email']
|
// scope: ['email']
|
||||||
|
|
|
@ -55,12 +55,8 @@ module.exports = function (io, socket) {
|
||||||
// a user has visited our page - add them to the visitorsData object
|
// a user has visited our page - add them to the visitorsData object
|
||||||
socket.on('form-visitor-data', function(data) {
|
socket.on('form-visitor-data', function(data) {
|
||||||
|
|
||||||
console.log('\n\nuser has visited our page');
|
|
||||||
|
|
||||||
visitorsData[socket.id] = data;
|
visitorsData[socket.id] = data;
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
if (data.isSubmitted) {
|
if (data.isSubmitted) {
|
||||||
saveVisitorData(data, function () {
|
saveVisitorData(data, function () {
|
||||||
console.log('\n\n user submitted form');
|
console.log('\n\n user submitted form');
|
||||||
|
|
|
@ -150,13 +150,6 @@ describe('FormSubmission Model Unit Tests:', function() {
|
||||||
beforeEach(function(done){
|
beforeEach(function(done){
|
||||||
|
|
||||||
var myFieldMap = {};
|
var myFieldMap = {};
|
||||||
myFieldMap[myForm.form_fields[0]._id+''] = 'firstName';
|
|
||||||
myFieldMap[myForm.form_fields[1]._id+''] = 'lastName';
|
|
||||||
myFieldMap[myForm.form_fields[2]._id+''] = 'sex';
|
|
||||||
myFieldMap[myForm.form_fields[3]._id+''] = 'DOB';
|
|
||||||
myFieldMap[myForm.form_fields[4]._id+''] = 'phone';
|
|
||||||
|
|
||||||
myForm.plugins.oscarhost.settings.fieldMap = myFieldMap;
|
|
||||||
|
|
||||||
myForm.save(function(err, form){
|
myForm.save(function(err, form){
|
||||||
if(err) done(err);
|
if(err) done(err);
|
||||||
|
@ -175,49 +168,6 @@ describe('FormSubmission Model Unit Tests:', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// it('should add Patient to OscarHost EMR after save', function(done){
|
|
||||||
// var url_login = myForm.plugins.oscarhost.baseUrl+'/LoginService?wsdl',
|
|
||||||
// url_demo = myForm.plugins.oscarhost.baseUrl+'/DemographicService?wsdl',
|
|
||||||
// args_login = {arg0: config.oscarhost.auth.user, arg1: config.oscarhost.auth.pass};
|
|
||||||
|
|
||||||
// var options = {
|
|
||||||
// ignoredNamespaces: {
|
|
||||||
// namespaces: ['targetNamespace', 'typedNamespace'],
|
|
||||||
// override: true
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// async.waterfall([
|
|
||||||
// function (callback) {
|
|
||||||
// //Authenticate with API
|
|
||||||
// soap.createClient(url_login, options, function(err, client) {
|
|
||||||
// client.login(args_login, function (err, result) {
|
|
||||||
// if(err) callback(err);
|
|
||||||
// callback(null, result.return);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
|
|
||||||
// function (security_obj, callback) {
|
|
||||||
// soap.createClient(url_demo, options, function(err, client) {
|
|
||||||
// client.setSecurity(new OscarSecurity(security_obj.securityId, security_obj.securityTokenKey) );
|
|
||||||
|
|
||||||
// client.getDemographic({ arg0: oscar_demo_num }, function (err, result) {
|
|
||||||
// if(err) callback(err);
|
|
||||||
// callback(null, result);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
|
|
||||||
// ], function(err, result) {
|
|
||||||
// if(err) done(err);
|
|
||||||
|
|
||||||
// should.exist(result);
|
|
||||||
// console.log(result.return);
|
|
||||||
|
|
||||||
// done();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Method Find', function(){
|
describe('Method Find', function(){
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>{{title}}</title>
|
<title>{{title}} Form</title>
|
||||||
|
|
||||||
<!-- General META -->
|
<!-- General META -->
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
@ -61,11 +61,11 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body ng-cloak>
|
<body ng-cloak>
|
||||||
<div class="github-fork-ribbon-wrapper right-bottom hidden-xs">
|
<!--<div class="github-fork-ribbon-wrapper right-bottom hidden-xs">
|
||||||
<div class="github-fork-ribbon">
|
<div class="github-fork-ribbon">
|
||||||
<a href="https://github.com/whitef0x0/tellform">Fork me on GitHub</a>
|
<a href="https://github.com/whitef0x0/tellform">Fork me on GitHub</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>-->
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<section ui-view></section>
|
<section ui-view></section>
|
||||||
</section>
|
</section>
|
||||||
|
|
94
app/views/redoc.server.view.html
Normal file
94
app/views/redoc.server.view.html
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>{{title}}</title>
|
||||||
|
|
||||||
|
<!-- General META -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
|
||||||
|
<!-- Semantic META -->
|
||||||
|
<meta name="keywords" content="{{keywords}}">
|
||||||
|
<meta name="description" content="{{description}}">
|
||||||
|
|
||||||
|
<!-- Facebook META -->
|
||||||
|
<meta property="og:site_name" content="{{title}}">
|
||||||
|
<meta property="og:title" content="{{title}}">
|
||||||
|
<meta property="og:description" content="{{description}}">
|
||||||
|
<meta property="og:url" content="{{url}}">
|
||||||
|
<meta property="og:image" content="/img/brand/logo.png">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
<!-- Twitter META -->
|
||||||
|
<meta name="twitter:title" content="{{title}}">
|
||||||
|
<meta name="twitter:description" content="{{description}}">
|
||||||
|
<meta name="twitter:url" content="{{url}}">
|
||||||
|
<meta name="twitter:image" content="/img/brand/logo.png">
|
||||||
|
|
||||||
|
<!-- Fav Icon -->
|
||||||
|
<link href="/static/modules/core/img/brand/favicon.ico" rel="shortcut icon" type="image/x-icon">
|
||||||
|
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,900'>
|
||||||
|
|
||||||
|
<!--Bower CSS dependencies-->
|
||||||
|
|
||||||
|
<!-- end Bower CSS dependencies-->
|
||||||
|
|
||||||
|
<!--Application CSS Files-->
|
||||||
|
{% for cssFile in cssFiles %}
|
||||||
|
<link rel="stylesheet" href="{{cssFile}}">
|
||||||
|
{% endfor %}
|
||||||
|
<!-- end Application CSS Files-->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- HTML5 Shim -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<redoc spec-url='/static/swagger.json'></redoc>
|
||||||
|
<script src="https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"> </script>
|
||||||
|
|
||||||
|
<!--Bower JS dependencies-->
|
||||||
|
{% for bowerJSFile in bowerJSFiles %}
|
||||||
|
<script type="text/javascript" src="{{bowerJSFile}}"></script>
|
||||||
|
{% endfor %}
|
||||||
|
<!-- end Bower JS dependencies-->
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.8/angular-strap.min.js"></script>
|
||||||
|
|
||||||
|
{% if process.env.NODE_ENV === 'development' %}
|
||||||
|
|
||||||
|
<script src="https://cdn.ravenjs.com/2.3.0/angular/raven.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- [if lt IE 9]>
|
||||||
|
<section class="browsehappy jumbotron hide">
|
||||||
|
<h1>Hello there!</h1>
|
||||||
|
<p>You are using an old browser which we unfortunately do not support.</p>
|
||||||
|
<p>Please <a href="http://browsehappy.com/">click here</a> to update your browser before using the website.</p>
|
||||||
|
<p><a href="http://browsehappy.com" class="btn btn-primary btn-lg" role="button">Yes, upgrade my browser!</a></p>
|
||||||
|
</section>
|
||||||
|
<![endif] -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||||
|
|
||||||
|
ga('create', '{{google_analytics_id}}', 'auto');
|
||||||
|
ga('send', 'pageview');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -36,8 +36,12 @@
|
||||||
"js-yaml": "^3.6.1",
|
"js-yaml": "^3.6.1",
|
||||||
"angular-ui-select": "https://github.com/whitef0x0/ui-select.git#compiled",
|
"angular-ui-select": "https://github.com/whitef0x0/ui-select.git#compiled",
|
||||||
"angular-translate": "~2.11.0",
|
"angular-translate": "~2.11.0",
|
||||||
"ng-device-detector": "~3.0.1",
|
"ng-device-detector": "^3.0.1",
|
||||||
"ng-translate": "*"
|
"ng-translate": "*",
|
||||||
|
"deep-diff": "^0.3.4",
|
||||||
|
"mathjs": "^3.4.1",
|
||||||
|
"jsep": "^0.3.1",
|
||||||
|
"ngclipboard": "^1.1.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"angular-bootstrap": "^0.14.0",
|
"angular-bootstrap": "^0.14.0",
|
||||||
|
|
|
@ -31,7 +31,7 @@ if( fs.existsSync('./config/env/api_keys.js') ){
|
||||||
exports,
|
exports,
|
||||||
require('./env/api_keys')
|
require('./env/api_keys')
|
||||||
);
|
);
|
||||||
}else {
|
} else {
|
||||||
module.exports = exports;
|
module.exports = exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
config/env/all.js
vendored
2
config/env/all.js
vendored
|
@ -14,7 +14,7 @@ module.exports = {
|
||||||
|
|
||||||
reCAPTCHA_Key: process.env.reCAPTCHA_KEY || '',
|
reCAPTCHA_Key: process.env.reCAPTCHA_KEY || '',
|
||||||
|
|
||||||
signupDisabled: !!process.env.SIGNUP_DISABLED,
|
signupDisabled: (process.env.SIGNUP_DISABLED === "TRUE"),
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
tempUserCollection: 'temporary_users',
|
tempUserCollection: 'temporary_users',
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@ module.exports = function(db) {
|
||||||
var subdomains = req.subdomains;
|
var subdomains = req.subdomains;
|
||||||
var host = req.hostname;
|
var host = req.hostname;
|
||||||
|
|
||||||
|
|
||||||
if(subdomains.slice(0, 4).join('.')+'' === '1.0.0.127'){
|
if(subdomains.slice(0, 4).join('.')+'' === '1.0.0.127'){
|
||||||
subdomains = subdomains.slice(4);
|
subdomains = subdomains.slice(4);
|
||||||
}
|
}
|
||||||
|
@ -81,18 +80,38 @@ module.exports = function(db) {
|
||||||
if (!subdomains.length) return next();
|
if (!subdomains.length) return next();
|
||||||
|
|
||||||
var urlPath = url.parse(req.url).path.split('/');
|
var urlPath = url.parse(req.url).path.split('/');
|
||||||
if(urlPath.indexOf('static')){
|
if(urlPath.indexOf('static') > -1){
|
||||||
|
//console.log("STATIC FILE\n\n\n\n");
|
||||||
urlPath.splice(1,1);
|
urlPath.splice(1,1);
|
||||||
req.root = 'https://' + config.baseUrl + urlPath.join('/');
|
req.root = 'https://' + config.baseUrl + urlPath.join('/');
|
||||||
|
console.log(req.root);
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(subdomains.indexOf('stage') || subdomains.indexOf('admin')){
|
if(urlPath.indexOf('users') > -1 && urlPath.indexOf('me') > -1){
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(subdomains.indexOf('stage') > -1 || subdomains.indexOf('admin') > -1){
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(req.subdomains.reverse()[0]);
|
||||||
|
//console.log("is api subdomain: "+ (subdomains.indexOf("api") > -1));
|
||||||
|
//console.log(req.url);
|
||||||
|
if(subdomains.indexOf('api') > -1){
|
||||||
|
// rebuild url
|
||||||
|
path += 'api' + req.url;
|
||||||
|
console.log(req.url);
|
||||||
|
// TODO: check path and query strings are preserved
|
||||||
|
// reassign url
|
||||||
|
req.url = path;
|
||||||
|
console.log(req.url);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
User.findOne({username: req.subdomains.reverse()[0]}).exec(function (err, user) {
|
User.findOne({username: req.subdomains.reverse()[0]}).exec(function (err, user) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
req.subdomains = null;
|
req.subdomains = null;
|
||||||
|
@ -113,10 +132,13 @@ module.exports = function(db) {
|
||||||
|
|
||||||
// TODO: check path and query strings are preserved
|
// TODO: check path and query strings are preserved
|
||||||
// reassign url
|
// reassign url
|
||||||
|
console.log("path: "+path);
|
||||||
req.url = path;
|
req.url = path;
|
||||||
|
|
||||||
req.userId = user._id;
|
req.userId = user._id;
|
||||||
|
|
||||||
|
console.log('\n\n\ngot subdomain: '+ req.subdomains.reverse()[0]);
|
||||||
|
|
||||||
// Q.E.D.
|
// Q.E.D.
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
54
config/passport_helpers.js
Normal file
54
config/passport_helpers.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var config = require("./config");
|
||||||
|
var passport = require("passport");
|
||||||
|
|
||||||
|
var User = require('mongoose').model('User');
|
||||||
|
|
||||||
|
module.exports.isAuthenticatedOrApiKey = function isAuthenticated(req, res, next) {
|
||||||
|
debugger;
|
||||||
|
if (req.isAuthenticated()) {
|
||||||
|
return next();
|
||||||
|
} else {
|
||||||
|
// Try authenticate with API KEY
|
||||||
|
if (req.headers.apikey || req.query.apikey || req.body.apikey) {
|
||||||
|
passport.authenticate("localapikey", function (err, user, info) {
|
||||||
|
if (err)
|
||||||
|
return res.sendStatus(500);
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
return res.status(401).send(info.message || "");
|
||||||
|
|
||||||
|
req.login(user, function(err) {
|
||||||
|
if (err) return res.sendStatus(500);
|
||||||
|
|
||||||
|
req.user = user;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
})(req, res, next);
|
||||||
|
} else {
|
||||||
|
return res.sendStatus(401);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports.hasRole = function hasRole(roleRequired) {
|
||||||
|
if (!roleRequired)
|
||||||
|
throw new Error("Required role needs to be set");
|
||||||
|
|
||||||
|
return function(req, res, next) {
|
||||||
|
return module.exports.isAuthenticated(req, res, function() {
|
||||||
|
if (req.user && req.user.roles && req.user.roles.indexOf(roleRequired) !== -1)
|
||||||
|
next();
|
||||||
|
else
|
||||||
|
res.sendStatus(403);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.hasAdminRole = function hasAdminRole() {
|
||||||
|
return module.exports.hasRole("admin");
|
||||||
|
};
|
||||||
|
|
25
config/strategies/apikey.js
Normal file
25
config/strategies/apikey.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var passport = require("passport");
|
||||||
|
var LocalAPIKeyStrategy = require("passport-localapikey-update").Strategy;
|
||||||
|
var User = require('mongoose').model('User');
|
||||||
|
|
||||||
|
module.exports = function() {
|
||||||
|
passport.use(new LocalAPIKeyStrategy({
|
||||||
|
passReqToCallback : true
|
||||||
|
}, function(req, apiKey, done) {
|
||||||
|
return User.findOne({
|
||||||
|
"apiKey": apiKey
|
||||||
|
}, function(err, user) {
|
||||||
|
if (err)
|
||||||
|
return done(err);
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
return done(null, false, {
|
||||||
|
message: "Unknown API Key"
|
||||||
|
});
|
||||||
|
|
||||||
|
return done(null, user);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
};
|
40
dns_masq_setup_osx.md
Normal file
40
dns_masq_setup_osx.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# wildcard DNS in localhost development
|
||||||
|
- install [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html)
|
||||||
|
```
|
||||||
|
$ brew install dnsmasq
|
||||||
|
...
|
||||||
|
$ cp /usr/local/opt/dnsmasq/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf
|
||||||
|
```
|
||||||
|
- edit `/usr/local/etc/dnsmasq.conf`
|
||||||
|
```
|
||||||
|
address=/local/127.0.0.1
|
||||||
|
```
|
||||||
|
- start **dnsmasq**
|
||||||
|
```
|
||||||
|
$ sudo brew services start dnsmasq
|
||||||
|
```
|
||||||
|
- any time we change `dnsmasq.conf` we have to re-start **dnsmasq**:
|
||||||
|
```
|
||||||
|
$ sudo launchctl stop homebrew.mxcl.dnsmasq
|
||||||
|
$ sudo launchctl start homebrew.mxcl.dnsmasq
|
||||||
|
```
|
||||||
|
- For OS X to _resolve_ requests from `*.local` to **localhost** we need to add a _resolver_:
|
||||||
|
```
|
||||||
|
$ sudo mkdir /etc/resolver
|
||||||
|
$ sudo touch /etc/resolver/local
|
||||||
|
```
|
||||||
|
- edit `/etc/resolver/local`
|
||||||
|
```
|
||||||
|
nameserver 127.0.0.1
|
||||||
|
```
|
||||||
|
- re-start the computer to enable the _resolver_
|
||||||
|
|
||||||
|
===
|
||||||
|
**REFERENCES**
|
||||||
|
|
||||||
|
- [Using Dnsmasq for local development on OS X - Passing Curiosity](https://passingcuriosity.com/2013/dnsmasq-dev-osx/)
|
||||||
|
- [Using Dnsmasq Configure Wildcard DNS Record on Mac | Ri Xu Online](https://xuri.me/2014/12/13/using-dnsmasq-configure-wildcard-dns-record-on-mac.html)
|
||||||
|
- [unix - In my /etc/hosts/ file on Linux/OSX, how do I do a wildcard subdomain? - Server Fault](http://serverfault.com/questions/118378/in-my-etc-hosts-file-on-linux-osx-how-do-i-do-a-wildcard-subdomain)
|
||||||
|
- [hostname - Wildcard in /etc/hosts file - Unix & Linux Stack Exchange](http://unix.stackexchange.com/questions/3352/wildcard-in-etc-hosts-file)
|
||||||
|
- [Mac OS Lion - Wildcard subdomain virtual host - Stack Overflow](http://stackoverflow.com/questions/9562059/mac-os-lion-wildcard-subdomain-virtual-host)
|
||||||
|
- [How to put wildcard entry into /etc/hosts? - Stack Overflow](http://stackoverflow.com/questions/20446930/how-to-put-wildcard-entry-into-etc-hosts)
|
|
@ -1,140 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions name="DemographicWsService" targetNamespace="http://ws.oscarehr.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws.oscarehr.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<wsdl:types>
|
|
||||||
<xs:schema elementFormDefault="unqualified" targetNamespace="http://ws.oscarehr.org/" version="1.0" xmlns:tns="http://ws.oscarehr.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<xs:element name="getDemographic" type="tns:getDemographic"/>
|
|
||||||
<xs:element name="getDemographicByMyOscarUserName" type="tns:getDemographicByMyOscarUserName"/>
|
|
||||||
<xs:element name="getDemographicByMyOscarUserNameResponse" type="tns:getDemographicByMyOscarUserNameResponse"/>
|
|
||||||
<xs:element name="getDemographicResponse" type="tns:getDemographicResponse"/>
|
|
||||||
<xs:complexType name="getDemographic">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element minOccurs="0" name="arg0" type="xs:int"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="getDemographicResponse">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element minOccurs="0" name="return" type="tns:demographicTransfer"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType final="extension restriction" name="demographicTransfer">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="activeCount" type="xs:int"/>
|
|
||||||
<xs:element minOccurs="0" name="address" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="alias" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="anonymous" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="chartNo" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="children" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="citizenship" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="city" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="dateJoined" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="dateOfBirth" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="demographicNo" type="xs:int"/>
|
|
||||||
<xs:element minOccurs="0" name="displayName" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="effDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="email" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="endDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="familyDoctor" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="firstName" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="hcRenewDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="hcType" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="headRecord" type="xs:int"/>
|
|
||||||
<xs:element minOccurs="0" name="hin" type="xs:string"/>
|
|
||||||
<xs:element name="hsAlertCount" type="xs:int"/>
|
|
||||||
<xs:element minOccurs="0" name="lastName" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="lastUpdateDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="lastUpdateUser" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="links" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="monthOfBirth" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="myOscarUserName" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="officialLanguage" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="patientStatus" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="patientStatusDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="pcnIndicator" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="phone" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="phone2" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="postal" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="previousAddress" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="providerNo" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="province" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="rosterDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="rosterStatus" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="rosterTerminationDate" type="xs:dateTime"/>
|
|
||||||
<xs:element minOccurs="0" name="rosterTerminationReason" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="sex" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="sexDesc" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="sin" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="sourceOfIncome" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="spokenLanguage" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="title" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="ver" type="xs:string"/>
|
|
||||||
<xs:element minOccurs="0" name="yearOfBirth" type="xs:string"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="getDemographicByMyOscarUserName">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element minOccurs="0" name="arg0" type="xs:string"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="getDemographicByMyOscarUserNameResponse">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element minOccurs="0" name="return" type="tns:demographicTransfer"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:schema>
|
|
||||||
</wsdl:types>
|
|
||||||
<wsdl:message name="getDemographicByMyOscarUserNameResponse">
|
|
||||||
<wsdl:part element="tns:getDemographicByMyOscarUserNameResponse" name="parameters">
|
|
||||||
</wsdl:part>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message name="getDemographicByMyOscarUserName">
|
|
||||||
<wsdl:part element="tns:getDemographicByMyOscarUserName" name="parameters">
|
|
||||||
</wsdl:part>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message name="getDemographicResponse">
|
|
||||||
<wsdl:part element="tns:getDemographicResponse" name="parameters">
|
|
||||||
</wsdl:part>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message name="getDemographic">
|
|
||||||
<wsdl:part element="tns:getDemographic" name="parameters">
|
|
||||||
</wsdl:part>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:portType name="DemographicWs">
|
|
||||||
<wsdl:operation name="getDemographic">
|
|
||||||
<wsdl:input message="tns:getDemographic" name="getDemographic">
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output message="tns:getDemographicResponse" name="getDemographicResponse">
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation name="getDemographicByMyOscarUserName">
|
|
||||||
<wsdl:input message="tns:getDemographicByMyOscarUserName" name="getDemographicByMyOscarUserName">
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output message="tns:getDemographicByMyOscarUserNameResponse" name="getDemographicByMyOscarUserNameResponse">
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
</wsdl:portType>
|
|
||||||
<wsdl:binding name="DemographicWsServiceSoapBinding" type="tns:DemographicWs">
|
|
||||||
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
|
|
||||||
<wsdl:operation name="getDemographic">
|
|
||||||
<soap:operation soapAction="" style="document"/>
|
|
||||||
<wsdl:input name="getDemographic">
|
|
||||||
<soap:body use="literal"/>
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output name="getDemographicResponse">
|
|
||||||
<soap:body use="literal"/>
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation name="getDemographicByMyOscarUserName">
|
|
||||||
<soap:operation soapAction="" style="document"/>
|
|
||||||
<wsdl:input name="getDemographicByMyOscarUserName">
|
|
||||||
<soap:body use="literal"/>
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output name="getDemographicByMyOscarUserNameResponse">
|
|
||||||
<soap:body use="literal"/>
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
</wsdl:binding>
|
|
||||||
<wsdl:service name="DemographicWsService">
|
|
||||||
<wsdl:port binding="tns:DemographicWsServiceSoapBinding" name="DemographicWsPort">
|
|
||||||
<soap:address location="https://secure11.oscarhost.ca/kensington/ws/DemographicService"/>
|
|
||||||
</wsdl:port>
|
|
||||||
</wsdl:service>
|
|
||||||
</wsdl:definitions>
|
|
File diff suppressed because one or more lines are too long
|
@ -1,108 +0,0 @@
|
||||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.oscarehr.org/">
|
|
||||||
<soapenv:Header/>
|
|
||||||
<soapenv:Body>
|
|
||||||
<ws:addDemographic>
|
|
||||||
<!--Optional:-->
|
|
||||||
<arg0>
|
|
||||||
<!-- <activeCount>1</activeCount>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<address>2286 Ottawa</address>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <alias>?</alias>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <anonymous>?</anonymous>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <chartNo>?</chartNo>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <children>?</children>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <citizenship>?</citizenship>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<city>West Vancouver</city>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <dateJoined></dateJoined>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<dateOfBirth>06</dateOfBirth>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <demographicNo>?</demographicNo>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<displayName>TestUserAddDemographic</displayName>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <effDate></effDate>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<email>polydaic@gmail.com</email>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <endDate></endDate>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <familyDoctor> </familyDoctor>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<firstName>TestUser</firstName>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <hcRenewDate></hcRenewDate>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <hcType></hcType>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <headRecord></headRecord>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <hin></hin>-->
|
|
||||||
<!-- <hsAlertCount>0</hsAlertCount>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<lastName>AddDemographic</lastName>
|
|
||||||
<!--Optional:-->
|
|
||||||
<lastUpdateDate>2015-10-01T18:39:46.817Z</lastUpdateDate>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <lastUpdateUser> </lastUpdateUser>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <links> </links>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<monthOfBirth>06</monthOfBirth>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <myOscarUserName> </myOscarUserName>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <officialLanguage> </officialLanguage>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <patientStatus> </patientStatus>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <patientStatusDate></patientStatusDate>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <pcnIndicator> </pcnIndicator>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<phone>6048786969</phone>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <phone2> </phone2>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<postal>V8V5S8</postal>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <previousAddress> </previousAddress>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <providerNo> </providerNo>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<province>BC</province>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <rosterDate></rosterDate>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <rosterStatus> </rosterStatus>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <rosterTerminationDate></rosterTerminationDate>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <rosterTerminationReason> </rosterTerminationReason>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<sex>M</sex>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <sexDesc> </sexDesc>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <sin> </sin>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <sourceOfIncome> </sourceOfIncome>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <spokenLanguage> </spokenLanguage>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<title>Mr.</title>
|
|
||||||
<!--Optional:-->
|
|
||||||
<!-- <ver> </ver>-->
|
|
||||||
<!--Optional:-->
|
|
||||||
<yearOfBirth>1994</yearOfBirth>
|
|
||||||
</arg0>
|
|
||||||
</ws:addDemographic>
|
|
||||||
</soapenv:Body>
|
|
||||||
</soapenv:Envelope>
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12
package.json
12
package.json
|
@ -24,6 +24,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^1.4.2",
|
"async": "^1.4.2",
|
||||||
|
"async-boolean-expression-evaluator": "^1.1.1",
|
||||||
"aws-sdk": "^2.3.9",
|
"aws-sdk": "^2.3.9",
|
||||||
"bcrypt": "^0.8.7",
|
"bcrypt": "^0.8.7",
|
||||||
"body-parser": "~1.14.1",
|
"body-parser": "~1.14.1",
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
"connect-mongo": "~0.8.2",
|
"connect-mongo": "~0.8.2",
|
||||||
"consolidate": "~0.13.1",
|
"consolidate": "~0.13.1",
|
||||||
"cookie-parser": "~1.4.0",
|
"cookie-parser": "~1.4.0",
|
||||||
|
"deep-diff": "^0.3.4",
|
||||||
"dotenv": "^2.0.0",
|
"dotenv": "^2.0.0",
|
||||||
"email-verification": "~0.4.1",
|
"email-verification": "~0.4.1",
|
||||||
"envfile": "^2.0.1",
|
"envfile": "^2.0.1",
|
||||||
|
@ -64,6 +66,7 @@
|
||||||
"lodash": "^2.4.1",
|
"lodash": "^2.4.1",
|
||||||
"main-bower-files": "~2.9.0",
|
"main-bower-files": "~2.9.0",
|
||||||
"math": "0.0.3",
|
"math": "0.0.3",
|
||||||
|
"mathjs": "^3.4.1",
|
||||||
"method-override": "~2.3.0",
|
"method-override": "~2.3.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mongoose": "~4.4.19",
|
"mongoose": "~4.4.19",
|
||||||
|
@ -81,6 +84,7 @@
|
||||||
"passport-google-oauth": "~0.2.0",
|
"passport-google-oauth": "~0.2.0",
|
||||||
"passport-linkedin": "~1.0.0",
|
"passport-linkedin": "~1.0.0",
|
||||||
"passport-local": "~1.0.0",
|
"passport-local": "~1.0.0",
|
||||||
|
"passport-localapikey-update": "^0.5.0",
|
||||||
"passport-twitter": "~1.0.2",
|
"passport-twitter": "~1.0.2",
|
||||||
"path-exists": "^2.1.0",
|
"path-exists": "^2.1.0",
|
||||||
"pdffiller": "~0.1.1",
|
"pdffiller": "~0.1.1",
|
||||||
|
@ -91,10 +95,14 @@
|
||||||
"socket.io": "^1.4.6",
|
"socket.io": "^1.4.6",
|
||||||
"socket.io-redis": "^1.0.0",
|
"socket.io-redis": "^1.0.0",
|
||||||
"swig": "~1.4.1",
|
"swig": "~1.4.1",
|
||||||
|
"uuid-token-generator": "^0.5.0",
|
||||||
"wildcard-subdomains": "github:whitef0x0/wildcard-subdomains"
|
"wildcard-subdomains": "github:whitef0x0/wildcard-subdomains"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"chromedriver": "^2.25.1",
|
||||||
"coveralls": "^2.11.4",
|
"coveralls": "^2.11.4",
|
||||||
|
"cross-spawn": "^5.0.0",
|
||||||
|
"del": "^2.2.2",
|
||||||
"glob": "^7.0.3",
|
"glob": "^7.0.3",
|
||||||
"grunt-execute": "^0.2.2",
|
"grunt-execute": "^0.2.2",
|
||||||
"grunt-mocha-istanbul": "^3.0.1",
|
"grunt-mocha-istanbul": "^3.0.1",
|
||||||
|
@ -111,10 +119,12 @@
|
||||||
"karma-ng-html2js-preprocessor": "^0.2.0",
|
"karma-ng-html2js-preprocessor": "^0.2.0",
|
||||||
"karma-phantomjs-launcher": "~0.2.1",
|
"karma-phantomjs-launcher": "~0.2.1",
|
||||||
"mailosaur": "^1.0.1",
|
"mailosaur": "^1.0.1",
|
||||||
"mocha": ">=1.20.0",
|
"mocha": "^3.1.2",
|
||||||
"mocha-lcov-reporter": "^1.0.0",
|
"mocha-lcov-reporter": "^1.0.0",
|
||||||
|
"nightwatch": "^0.9.8",
|
||||||
"node-mandrill": "^1.0.1",
|
"node-mandrill": "^1.0.1",
|
||||||
"phantomjs": "^1.9.18",
|
"phantomjs": "^1.9.18",
|
||||||
|
"selenium-server": "^3.0.1",
|
||||||
"should": "~7.1.1",
|
"should": "~7.1.1",
|
||||||
"supertest": "~1.2.0",
|
"supertest": "~1.2.0",
|
||||||
"supertest-session": "~2.0.1"
|
"supertest-session": "~2.0.1"
|
||||||
|
|
232
public/dist/application.js
vendored
232
public/dist/application.js
vendored
|
@ -180,7 +180,7 @@ ApplicationConfiguration.registerModule('core', ['users']);
|
||||||
// Use Application configuration module to register a new module
|
// Use Application configuration module to register a new module
|
||||||
ApplicationConfiguration.registerModule('forms', [
|
ApplicationConfiguration.registerModule('forms', [
|
||||||
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
||||||
'angular-input-stars', 'users'
|
'angular-input-stars', 'users', 'ngclipboard'
|
||||||
]);//, 'colorpicker.module' @TODO reactivate this module
|
]);//, 'colorpicker.module' @TODO reactivate this module
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -228,6 +228,10 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid
|
||||||
PREVIEW: 'Preview',
|
PREVIEW: 'Preview',
|
||||||
|
|
||||||
//Edit Form View
|
//Edit Form View
|
||||||
|
DISABLED: 'Disabled:',
|
||||||
|
YES: 'YES',
|
||||||
|
NO: 'NO',
|
||||||
|
ADD_LOGIC_JUMP: 'Add Logic Jump',
|
||||||
ADD_FIELD_LG: 'Click to Add New Field',
|
ADD_FIELD_LG: 'Click to Add New Field',
|
||||||
ADD_FIELD_MD: 'Add New Field',
|
ADD_FIELD_MD: 'Add New Field',
|
||||||
ADD_FIELD_SM: 'Add Field',
|
ADD_FIELD_SM: 'Add Field',
|
||||||
|
@ -549,11 +553,12 @@ angular.module('core').controller('HeaderController', ['$rootScope', '$scope', '
|
||||||
$rootScope.signupDisabled = $window.signupDisabled;
|
$rootScope.signupDisabled = $window.signupDisabled;
|
||||||
|
|
||||||
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
|
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
|
||||||
|
|
||||||
|
console.log(Auth.ensureHasCurrentUser(User));
|
||||||
$scope.authentication = $rootScope.authentication = Auth;
|
$scope.authentication = $rootScope.authentication = Auth;
|
||||||
|
|
||||||
$rootScope.languages = $scope.languages = ['en', 'fr', 'es', 'it', 'de'];
|
$rootScope.languages = $scope.languages = ['en', 'fr', 'es', 'it', 'de'];
|
||||||
|
|
||||||
console.log($locale.id);
|
|
||||||
//Set global app language
|
//Set global app language
|
||||||
if($scope.authentication.isAuthenticated()){
|
if($scope.authentication.isAuthenticated()){
|
||||||
$rootScope.language = $scope.user.language;
|
$rootScope.language = $scope.user.language;
|
||||||
|
@ -952,7 +957,7 @@ angular.module('forms').config(['$stateProvider',
|
||||||
// Create a controller method for sending visitor data
|
// Create a controller method for sending visitor data
|
||||||
function send(form, lastActiveIndex, timeElapsed) {
|
function send(form, lastActiveIndex, timeElapsed) {
|
||||||
// Create a new message object
|
// Create a new message object
|
||||||
var visitorData = {
|
/*var visitorData = {
|
||||||
referrer: document.referrer,
|
referrer: document.referrer,
|
||||||
isSubmitted: form.submitted,
|
isSubmitted: form.submitted,
|
||||||
formId: form._id,
|
formId: form._id,
|
||||||
|
@ -981,15 +986,15 @@ angular.module('forms').config(['$stateProvider',
|
||||||
}
|
}
|
||||||
console.log(visitorData.deviceType);
|
console.log(visitorData.deviceType);
|
||||||
Socket.emit('form-visitor-data', visitorData);
|
Socket.emit('form-visitor-data', visitorData);
|
||||||
});
|
});*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(){
|
function init(){
|
||||||
// Make sure the Socket is connected
|
// Make sure the Socket is connected
|
||||||
if (!Socket.socket) {
|
/*if (!Socket.socket) {
|
||||||
Socket.connect();
|
Socket.connect();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
var service = {
|
var service = {
|
||||||
|
@ -1267,6 +1272,7 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
|
||||||
|
|
||||||
angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User',
|
angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User',
|
||||||
function($scope, $stateParams, $state, User) {
|
function($scope, $stateParams, $state, User) {
|
||||||
|
|
||||||
$scope.error = '';
|
$scope.error = '';
|
||||||
|
|
||||||
// Submit forgotten password account id
|
// Submit forgotten password account id
|
||||||
|
@ -1303,11 +1309,13 @@ angular.module('users').controller('PasswordController', ['$scope', '$stateParam
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('users').controller('SettingsController', ['$scope', '$rootScope', '$http', '$state', 'Users',
|
angular.module('users').controller('SettingsController', ['$scope', '$rootScope', '$http', '$state', 'Users', 'Auth',
|
||||||
function($scope, $rootScope, $http, $state, Users) {
|
function($scope, $rootScope, $http, $state, Users, Auth) {
|
||||||
$scope.user = $rootScope.user;
|
|
||||||
|
$scope.user = Auth.currentUser;
|
||||||
|
|
||||||
// Check if there are additional accounts
|
// Check if there are additional accounts
|
||||||
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
|
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
|
||||||
|
@ -1317,6 +1325,10 @@ angular.module('users').controller('SettingsController', ['$scope', '$rootScope'
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function(){
|
||||||
|
$scope.user = Auth.currentUser;
|
||||||
|
};
|
||||||
|
|
||||||
// Check if provider is already in use with current user
|
// Check if provider is already in use with current user
|
||||||
$scope.isConnectedSocialAccount = function(provider) {
|
$scope.isConnectedSocialAccount = function(provider) {
|
||||||
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
|
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
|
||||||
|
@ -1371,6 +1383,7 @@ angular.module('users').controller('SettingsController', ['$scope', '$rootScope'
|
||||||
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('users').controller('VerifyController', ['$scope', '$state', '$rootScope', 'User', 'Auth', '$stateParams',
|
angular.module('users').controller('VerifyController', ['$scope', '$state', '$rootScope', 'User', 'Auth', '$stateParams',
|
||||||
|
@ -1697,8 +1710,21 @@ angular.module('core').config(['$translateProvider', function ($translateProvide
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// Forms controller
|
// Forms controller
|
||||||
angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$uibModal', 'myForm', '$filter',
|
angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$uibModal', 'myForm', '$filter', '$sce',
|
||||||
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $uibModal, myForm, $filter) {
|
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $uibModal, myForm, $filter, $sce) {
|
||||||
|
|
||||||
|
$scope.trustSrc = function(src) {
|
||||||
|
return $sce.trustAsResourceUrl(src);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Set active tab to Create
|
||||||
|
$scope.activePill = 0;
|
||||||
|
|
||||||
|
$scope.copied = false;
|
||||||
|
$scope.onCopySuccess = function(e) {
|
||||||
|
console.log("COPY SUCCESSFUL!");
|
||||||
|
$scope.copied = true;
|
||||||
|
};
|
||||||
|
|
||||||
$scope = $rootScope;
|
$scope = $rootScope;
|
||||||
$scope.animationsEnabled = true;
|
$scope.animationsEnabled = true;
|
||||||
|
@ -1707,24 +1733,34 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
|
||||||
|
|
||||||
CurrentForm.setForm($scope.myform);
|
CurrentForm.setForm($scope.myform);
|
||||||
|
|
||||||
$scope.formURL = $scope.myform.admin.username + '.tellform.com';
|
$scope.formURL = "/#!/forms/" + $scope.myform._id;
|
||||||
|
|
||||||
$scope.tabData = [
|
$scope.actualFormURL = window.location.protocol + '//' + $scope.myform.admin.username + '.' + window.location.host + "/#!/forms/" + $scope.myform._id;
|
||||||
{
|
|
||||||
|
|
||||||
|
var refreshFrame = $scope.refreshFrame = function(){
|
||||||
|
if(document.getElementById('iframe')) {
|
||||||
|
document.getElementById('iframe').contentWindow.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$scope.tabData = [
|
||||||
|
/*{
|
||||||
heading: $filter('translate')('CREATE_TAB'),
|
heading: $filter('translate')('CREATE_TAB'),
|
||||||
route: 'viewForm.create'
|
templateName: 'create'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: $filter('translate')('DESIGN_TAB'),
|
heading: $filter('translate')('DESIGN_TAB'),
|
||||||
route: 'viewForm.design'
|
templateName: 'design'
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
heading: $filter('translate')('CONFIGURE_TAB'),
|
heading: $filter('translate')('CONFIGURE_TAB'),
|
||||||
route: 'viewForm.configure'
|
templateName: 'configure'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: $filter('translate')('ANALYZE_TAB'),
|
heading: $filter('translate')('ANALYZE_TAB'),
|
||||||
route: 'viewForm.analyze'
|
templateName: 'analyze'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1788,7 +1824,8 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update existing Form
|
// Update existing Form
|
||||||
$scope.update = $rootScope.update = function(updateImmediately, cb){
|
$scope.update = $rootScope.update = function(updateImmediately, diffChanges, cb){
|
||||||
|
refreshFrame();
|
||||||
|
|
||||||
var continueUpdate = true;
|
var continueUpdate = true;
|
||||||
if(!updateImmediately){
|
if(!updateImmediately){
|
||||||
|
@ -1801,7 +1838,7 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
|
||||||
|
|
||||||
if(!updateImmediately){ $rootScope.saveInProgress = true; }
|
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){
|
.then(function(response){
|
||||||
$rootScope.myform = $scope.myform = response.data;
|
$rootScope.myform = $scope.myform = response.data;
|
||||||
// console.log(response.data);
|
// console.log(response.data);
|
||||||
|
@ -1954,7 +1991,6 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
|
||||||
|
|
||||||
$rootScope.finishedRender = false;
|
$rootScope.finishedRender = false;
|
||||||
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
|
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
|
||||||
// console.log('hello');
|
|
||||||
$rootScope.finishedRender = false;
|
$rootScope.finishedRender = false;
|
||||||
});
|
});
|
||||||
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
|
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
|
||||||
|
@ -1974,13 +2010,11 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var debounceSave = function () {
|
var debounceSave = function (diffChanges) {
|
||||||
$rootScope.saveInProgress = true;
|
|
||||||
|
|
||||||
$rootScope[$attrs.autoSaveCallback](true,
|
$rootScope[$attrs.autoSaveCallback](true, diffChanges,
|
||||||
function(err){
|
function(err){
|
||||||
if(!err){
|
if(!err){
|
||||||
//console.log('\n\nForm data persisted -- setting pristine flag');
|
|
||||||
$formCtrl.$setPristine();
|
$formCtrl.$setPristine();
|
||||||
$formCtrl.$setUntouched();
|
$formCtrl.$setUntouched();
|
||||||
}else{
|
}else{
|
||||||
|
@ -1990,56 +2024,48 @@ 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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Autosave Form when model (specified in $attrs.autoSaveWatch) changes
|
//Autosave Form when model (specified in $attrs.autoSaveWatch) changes
|
||||||
$scope.$watch($attrs.autoSaveWatch, function(newValue, oldValue) {
|
$scope.$watch($attrs.autoSaveWatch, function(newValue, oldValue) {
|
||||||
|
|
||||||
|
if( !newValue || !oldValue ) {
|
||||||
|
$rootScope.finishedRender = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
newValue = angular.copy(newValue);
|
newValue = angular.copy(newValue);
|
||||||
oldValue = angular.copy(oldValue);
|
oldValue = angular.copy(oldValue);
|
||||||
|
|
||||||
newValue.form_fields = _.removeDateFields(newValue.form_fields);
|
delete newValue.visible_form_fields;
|
||||||
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
|
delete oldValue.visible_form_fields;
|
||||||
|
newValue.form_fields = _.removeDateFields(newValue.form_fields);
|
||||||
|
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
|
||||||
|
|
||||||
var changedFields = !_.isEqual(oldValue.form_fields,newValue.form_fields) || !_.isEqual(oldValue.startPage, newValue.startPage);
|
var changedFields = !!DeepDiff.diff(oldValue, newValue) && DeepDiff.diff(oldValue, newValue).length > 0;
|
||||||
var changedFieldMap = false;
|
|
||||||
|
|
||||||
if(oldValue.hasOwnProperty('plugins.oscarhost.settings.fieldMap')){
|
//If our form is undefined, don't save form
|
||||||
changedFieldMap = !!oldValue.plugins.oscarhost.settings.fieldMap && !_.isEqual(oldValue.plugins.oscarhost.settings.fieldMap,newValue.plugins.oscarhost.settings.fieldMap);
|
if(!changedFields){
|
||||||
}
|
$rootScope.finishedRender = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//If our form is undefined, don't save form
|
if(oldValue.form_fields.length === 0) {
|
||||||
if( (!newValue && !oldValue) || !oldValue ){
|
$rootScope.finishedRender = true;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
//console.log('Autosaving');
|
||||||
|
//console.log('\n\n----------');
|
||||||
|
//console.log('!$dirty: '+ !$formCtrl.$dirty );
|
||||||
|
|
||||||
// console.log('Autosaving');
|
|
||||||
// console.log('\n\n----------');
|
|
||||||
// console.log('!$dirty: '+ !$formCtrl.$dirty );
|
|
||||||
// console.log('changedFields: '+changedFields);
|
|
||||||
// console.log('changedFieldMap: '+changedFieldMap);
|
// console.log('changedFieldMap: '+changedFieldMap);
|
||||||
// console.log('finishedRender: '+$rootScope.finishedRender);
|
//console.log('finishedRender: '+$rootScope.finishedRender);
|
||||||
// console.log('!saveInProgress: '+!$rootScope.saveInProgress);
|
//console.log('!saveInProgress: '+!$rootScope.saveInProgress);
|
||||||
// console.log('newValue: '+newValue);
|
// console.log('newValue: '+newValue);
|
||||||
// console.log('oldValue: '+oldValue);
|
// console.log('oldValue: '+oldValue);
|
||||||
// console.log(oldValue.form_fields);
|
// console.log(oldValue.form_fields);
|
||||||
// console.log(newValue.form_fields);
|
// console.log(newValue.form_fields);
|
||||||
|
|
||||||
if(oldValue.form_fields.length === 0) {
|
|
||||||
$rootScope.finishedRender = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Save form ONLY IF rendering is finished, form_fields have been changed AND currently not save in progress
|
//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) && !$rootScope.saveInProgress) {
|
||||||
|
|
||||||
if(savePromise) {
|
if(savePromise) {
|
||||||
$timeout.cancel(savePromise);
|
$timeout.cancel(savePromise);
|
||||||
|
@ -2047,7 +2073,12 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
|
||||||
}
|
}
|
||||||
|
|
||||||
savePromise = $timeout(function() {
|
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
|
//If we are finished rendering then form saving should be finished
|
||||||
|
@ -2164,16 +2195,12 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
return {
|
return {
|
||||||
templateUrl: 'modules/forms/admin/views/directiveViews/form/edit-form.client.view.html',
|
templateUrl: 'modules/forms/admin/views/directiveViews/form/edit-form.client.view.html',
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
|
transclude: true,
|
||||||
scope: {
|
scope: {
|
||||||
myform:'='
|
myform:'='
|
||||||
},
|
},
|
||||||
controller: ["$scope", function($scope){
|
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;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
** Initialize scope with variables
|
** Initialize scope with variables
|
||||||
*/
|
*/
|
||||||
|
@ -2222,24 +2249,24 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
//Populate local scope with rootScope methods/variables
|
//Populate local scope with rootScope methods/variables
|
||||||
$scope.update = $rootScope.update;
|
$scope.update = $rootScope.update;
|
||||||
|
|
||||||
//Many-to-many Select for Mapping OscarhostFields -> FormFields
|
// LOGIC JUMP METHODS
|
||||||
$scope.oscarFieldsLeft = function(field_id){
|
$scope.removeLogicJump = function (field_index) {
|
||||||
|
var currField = $scope.myform.form_fields[field_index];
|
||||||
|
currField.logicJump = {};
|
||||||
|
};
|
||||||
|
|
||||||
if($scope.myform && $scope.myform.plugins.oscarhost.settings.validFields.length > 0){
|
$scope.addNewLogicJump = function (field_index) {
|
||||||
if(!$scope.myform.plugins.oscarhost.settings.fieldMap) $scope.myform.plugins.oscarhost.settings.fieldMap = {};
|
var form_fields = $scope.myform.form_fields;
|
||||||
|
var currField = form_fields[field_index];
|
||||||
|
console.log(currField);
|
||||||
|
if (form_fields.length > 1 && currField._id) {
|
||||||
|
|
||||||
var oscarhostFields = $scope.myform.plugins.oscarhost.settings.validFields;
|
var newLogicJump = {
|
||||||
var currentFields = _($scope.myform.plugins.oscarhost.settings.fieldMap).invert().keys().value();
|
fieldA: currField._id
|
||||||
|
};
|
||||||
if( $scope.myform.plugins.oscarhost.settings.fieldMap.hasOwnProperty(field_id) ){
|
currField.logicJump = newLogicJump;
|
||||||
currentFields = _(currentFields).difference($scope.myform.plugins.oscarhost.settings.fieldMap[field_id]);
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
//Get all oscarhostFields that haven't been mapped to a formfield
|
|
||||||
return _(oscarhostFields).difference(currentFields).value();
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** FormFields (ui-sortable) drag-and-drop configuration
|
** FormFields (ui-sortable) drag-and-drop configuration
|
||||||
|
@ -2268,12 +2295,13 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var newField = {
|
var newField = {
|
||||||
title: fieldTitle,
|
title: fieldTitle + ' ' + $scope.myform.form_fields.length+1,
|
||||||
fieldType: fieldType,
|
fieldType: fieldType,
|
||||||
fieldValue: '',
|
fieldValue: '',
|
||||||
required: true,
|
required: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
deletePreserved: false
|
deletePreserved: false,
|
||||||
|
logicJump: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
if($scope.showAddOptions(newField)){
|
if($scope.showAddOptions(newField)){
|
||||||
|
@ -2285,7 +2313,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(modifyForm){
|
if(modifyForm){
|
||||||
//Add newField to form_fields array
|
//Add newField to form_fields array
|
||||||
$scope.myform.form_fields.push(newField);
|
$scope.myform.form_fields.push(newField);
|
||||||
|
@ -2294,15 +2321,11 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
};
|
};
|
||||||
|
|
||||||
// Delete particular field on button click
|
// Delete particular field on button click
|
||||||
$scope.deleteField = function (field_index){
|
$scope.deleteField = function (field_index) {
|
||||||
|
console.log($scope.myform.form_fields);
|
||||||
//Delete field from field map
|
|
||||||
var currFieldId = $scope.myform.form_fields[field_index]._id;
|
|
||||||
if($scope.myform.hasOwnProperty('plugins.oscarhost.baseUrl')) delete $scope.myform.plugins.oscarhost.settings.fieldMap[currFieldId];
|
|
||||||
|
|
||||||
//Delete field
|
|
||||||
$scope.myform.form_fields.splice(field_index, 1);
|
$scope.myform.form_fields.splice(field_index, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.duplicateField = function (field_index){
|
$scope.duplicateField = function (field_index){
|
||||||
var currField = _.cloneDeep($scope.myform.form_fields[field_index]);
|
var currField = _.cloneDeep($scope.myform.form_fields[field_index]);
|
||||||
currField._id = 'cloned'+_.uniqueId();
|
currField._id = 'cloned'+_.uniqueId();
|
||||||
|
@ -2408,10 +2431,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}]
|
}]
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -2493,7 +2513,6 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
|
||||||
|
|
||||||
var visitors = $scope.myform.analytics.visitors;
|
var visitors = $scope.myform.analytics.visitors;
|
||||||
|
|
||||||
console.log(visitors);
|
|
||||||
for(var i=0; i<visitors.length; i++){
|
for(var i=0; i<visitors.length; i++){
|
||||||
var visitor = visitors[i];
|
var visitor = visitors[i];
|
||||||
var deviceType = visitor.deviceType;
|
var deviceType = visitor.deviceType;
|
||||||
|
@ -2854,23 +2873,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'){
|
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
|
||||||
switch(scope.field.fieldType){
|
switch(scope.field.fieldType){
|
||||||
case 'textfield':
|
case 'textfield':
|
||||||
scope.field.input_type = 'text';
|
scope.input_type = 'text';
|
||||||
break;
|
break;
|
||||||
case 'email':
|
case 'email':
|
||||||
scope.field.input_type = 'email';
|
scope.input_type = 'email';
|
||||||
scope.field.placeholder = 'joesmith@example.com';
|
scope.placeholder = 'joesmith@example.com';
|
||||||
break;
|
break;
|
||||||
case 'number':
|
case 'number':
|
||||||
scope.field.input_type = 'text';
|
scope.input_type = 'text';
|
||||||
scope.field.validateRegex = /^-?\d+$/;
|
scope.validateRegex = /^-?\d+$/;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
scope.field.input_type = 'url';
|
scope.input_type = 'url';
|
||||||
scope.field.placeholder = 'http://example.com';
|
scope.placeholder = 'http://example.com';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fieldType = 'textfield';
|
fieldType = 'textfield';
|
||||||
}
|
}
|
||||||
|
|
||||||
var template = getTemplateUrl(fieldType);
|
var template = getTemplateUrl(fieldType);
|
||||||
element.html(template).show();
|
element.html(template).show();
|
||||||
var output = $compile(element.contents())(scope);
|
var output = $compile(element.contents())(scope);
|
||||||
|
@ -3330,7 +3350,8 @@ angular.module('users').config(['$translateProvider', function ($translateProvid
|
||||||
|
|
||||||
$translateProvider.translations('en', {
|
$translateProvider.translations('en', {
|
||||||
ACCESS_DENIED_TEXT: 'You need to be logged in to access this page',
|
ACCESS_DENIED_TEXT: 'You need to be logged in to access this page',
|
||||||
USERNAME_LABEL: 'Username or Email',
|
USERNAME_OR_EMAIL_LABEL: 'Username or Email',
|
||||||
|
USERNAME_LABEL: 'Username',
|
||||||
PASSWORD_LABEL: 'Password',
|
PASSWORD_LABEL: 'Password',
|
||||||
CURRENT_PASSWORD_LABEL: 'Current Password',
|
CURRENT_PASSWORD_LABEL: 'Current Password',
|
||||||
NEW_PASSWORD_LABEL: 'New Password',
|
NEW_PASSWORD_LABEL: 'New Password',
|
||||||
|
@ -3347,6 +3368,9 @@ angular.module('users').config(['$translateProvider', function ($translateProvid
|
||||||
SIGNIN_HEADER_TEXT: 'Sign in',
|
SIGNIN_HEADER_TEXT: 'Sign in',
|
||||||
|
|
||||||
SIGNUP_ERROR_TEXT: 'Couldn\'t complete registration due to errors',
|
SIGNUP_ERROR_TEXT: 'Couldn\'t complete registration due to errors',
|
||||||
|
ENTER_ACCOUNT_EMAIL: 'Enter your account email.',
|
||||||
|
RESEND_VERIFICATION_EMAIL: 'Resend Verification Email',
|
||||||
|
SAVE_CHANGES: 'Save Changes',
|
||||||
|
|
||||||
UPDATE_PROFILE_BTN: 'Update Profile',
|
UPDATE_PROFILE_BTN: 'Update Profile',
|
||||||
PROFILE_SAVE_SUCCESS: 'Profile saved successfully',
|
PROFILE_SAVE_SUCCESS: 'Profile saved successfully',
|
||||||
|
|
4
public/dist/application.min.css
vendored
4
public/dist/application.min.css
vendored
File diff suppressed because one or more lines are too long
6
public/dist/application.min.js
vendored
6
public/dist/application.min.js
vendored
File diff suppressed because one or more lines are too long
335
public/dist/form-application.js
vendored
335
public/dist/form-application.js
vendored
|
@ -176,7 +176,7 @@ angular.module('NodeForm.templates', []).run(['$templateCache', function($templa
|
||||||
ApplicationConfiguration.registerModule('view-form', [
|
ApplicationConfiguration.registerModule('view-form', [
|
||||||
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
||||||
'angular-input-stars', 'pascalprecht.translate'
|
'angular-input-stars', 'pascalprecht.translate'
|
||||||
]);//, 'colorpicker.module' @TODO reactivate this module
|
]);
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -612,110 +612,111 @@ angular.module('view-form').directive('fieldIconDirective', function() {
|
||||||
|
|
||||||
// coffeescript's for in loop
|
// coffeescript's for in loop
|
||||||
var __indexOf = [].indexOf || function(item) {
|
var __indexOf = [].indexOf || function(item) {
|
||||||
for (var i = 0, l = this.length; i < l; i++) {
|
for (var i = 0, l = this.length; i < l; i++) {
|
||||||
if (i in this && this[i] === item) return i;
|
if (i in this && this[i] === item) return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
angular.module('view-form').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields',
|
angular.module('view-form').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields',
|
||||||
function($http, $compile, $rootScope, $templateCache, supportedFields) {
|
function($http, $compile, $rootScope, $templateCache, supportedFields) {
|
||||||
|
|
||||||
var getTemplateUrl = function(fieldType) {
|
var getTemplateUrl = function(fieldType) {
|
||||||
var type = fieldType;
|
var type = fieldType;
|
||||||
|
|
||||||
var supported_fields = [
|
var supported_fields = [
|
||||||
'textfield',
|
'textfield',
|
||||||
'textarea',
|
'textarea',
|
||||||
'date',
|
'date',
|
||||||
'dropdown',
|
'dropdown',
|
||||||
'hidden',
|
'hidden',
|
||||||
'password',
|
'password',
|
||||||
'radio',
|
'radio',
|
||||||
'legal',
|
'legal',
|
||||||
'statement',
|
'statement',
|
||||||
'rating',
|
'rating',
|
||||||
'yes_no',
|
'yes_no',
|
||||||
'number',
|
'number',
|
||||||
'natural'
|
'natural'
|
||||||
];
|
];
|
||||||
|
|
||||||
var templateUrl = 'modules/forms/base/views/directiveViews/field/';
|
var templateUrl = 'modules/forms/base/views/directiveViews/field/';
|
||||||
|
|
||||||
if (__indexOf.call(supportedFields, type) >= 0) {
|
if (__indexOf.call(supportedFields, type) >= 0) {
|
||||||
templateUrl = templateUrl+type+'.html';
|
templateUrl = templateUrl+type+'.html';
|
||||||
}
|
|
||||||
return $templateCache.get(templateUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
template: '<div>{{field.title}}</div>',
|
|
||||||
restrict: 'E',
|
|
||||||
scope: {
|
|
||||||
field: '=',
|
|
||||||
required: '&',
|
|
||||||
design: '=',
|
|
||||||
index: '=',
|
|
||||||
forms: '='
|
|
||||||
},
|
|
||||||
link: function(scope, element) {
|
|
||||||
|
|
||||||
$rootScope.chooseDefaultOption = scope.chooseDefaultOption = function(type) {
|
|
||||||
if(type === 'yes_no'){
|
|
||||||
scope.field.fieldValue = 'true';
|
|
||||||
}else if(type === 'rating'){
|
|
||||||
scope.field.fieldValue = 0;
|
|
||||||
}else if(scope.field.fieldType === 'radio'){
|
|
||||||
console.log(scope.field);
|
|
||||||
scope.field.fieldValue = scope.field.fieldOptions[0].option_value;
|
|
||||||
console.log(scope.field.fieldValue);
|
|
||||||
}else if(type === 'legal'){
|
|
||||||
scope.field.fieldValue = 'true';
|
|
||||||
$rootScope.nextField();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.setActiveField = $rootScope.setActiveField;
|
|
||||||
|
|
||||||
//Set format only if field is a date
|
|
||||||
if(scope.field.fieldType === 'date'){
|
|
||||||
scope.dateOptions = {
|
|
||||||
changeYear: true,
|
|
||||||
changeMonth: true,
|
|
||||||
altFormat: 'mm/dd/yyyy',
|
|
||||||
yearRange: '1900:-0',
|
|
||||||
defaultDate: 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var fieldType = scope.field.fieldType;
|
|
||||||
|
|
||||||
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
|
|
||||||
switch(scope.field.fieldType){
|
|
||||||
case 'textfield':
|
|
||||||
scope.field.input_type = 'text';
|
|
||||||
break;
|
|
||||||
case 'email':
|
|
||||||
scope.field.input_type = 'email';
|
|
||||||
scope.field.placeholder = 'joesmith@example.com';
|
|
||||||
break;
|
|
||||||
case 'number':
|
|
||||||
scope.field.input_type = 'text';
|
|
||||||
scope.field.validateRegex = /^-?\d+$/;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scope.field.input_type = 'url';
|
|
||||||
scope.field.placeholder = 'http://example.com';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fieldType = 'textfield';
|
|
||||||
}
|
}
|
||||||
var template = getTemplateUrl(fieldType);
|
return $templateCache.get(templateUrl);
|
||||||
element.html(template).show();
|
};
|
||||||
var output = $compile(element.contents())(scope);
|
|
||||||
}
|
return {
|
||||||
};
|
template: '<div>{{field.title}}</div>',
|
||||||
}]);
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
field: '=',
|
||||||
|
required: '&',
|
||||||
|
design: '=',
|
||||||
|
index: '=',
|
||||||
|
forms: '='
|
||||||
|
},
|
||||||
|
link: function(scope, element) {
|
||||||
|
|
||||||
|
$rootScope.chooseDefaultOption = scope.chooseDefaultOption = function(type) {
|
||||||
|
if(type === 'yes_no'){
|
||||||
|
scope.field.fieldValue = 'true';
|
||||||
|
}else if(type === 'rating'){
|
||||||
|
scope.field.fieldValue = 0;
|
||||||
|
}else if(scope.field.fieldType === 'radio'){
|
||||||
|
console.log(scope.field);
|
||||||
|
scope.field.fieldValue = scope.field.fieldOptions[0].option_value;
|
||||||
|
console.log(scope.field.fieldValue);
|
||||||
|
}else if(type === 'legal'){
|
||||||
|
scope.field.fieldValue = 'true';
|
||||||
|
$rootScope.nextField();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.setActiveField = $rootScope.setActiveField;
|
||||||
|
|
||||||
|
//Set format only if field is a date
|
||||||
|
if(scope.field.fieldType === 'date'){
|
||||||
|
scope.dateOptions = {
|
||||||
|
changeYear: true,
|
||||||
|
changeMonth: true,
|
||||||
|
altFormat: 'mm/dd/yyyy',
|
||||||
|
yearRange: '1900:-0',
|
||||||
|
defaultDate: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldType = scope.field.fieldType;
|
||||||
|
|
||||||
|
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
|
||||||
|
switch(scope.field.fieldType){
|
||||||
|
case 'textfield':
|
||||||
|
scope.input_type = 'text';
|
||||||
|
break;
|
||||||
|
case 'email':
|
||||||
|
scope.input_type = 'email';
|
||||||
|
scope.placeholder = 'joesmith@example.com';
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
scope.input_type = 'text';
|
||||||
|
scope.validateRegex = /^-?\d+$/;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scope.input_type = 'url';
|
||||||
|
scope.placeholder = 'http://example.com';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fieldType = 'textfield';
|
||||||
|
}
|
||||||
|
|
||||||
|
var template = getTemplateUrl(fieldType);
|
||||||
|
element.html(template).show();
|
||||||
|
var output = $compile(element.contents())(scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -824,6 +825,42 @@ angular.module('view-form').directive('onFinishRender', ["$rootScope", "$timeout
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
//FIXME: Should find an appropriate place for this
|
||||||
|
//Setting up jsep
|
||||||
|
jsep.addBinaryOp("contains", 10);
|
||||||
|
jsep.addBinaryOp("!contains", 10);
|
||||||
|
jsep.addBinaryOp("begins", 10);
|
||||||
|
jsep.addBinaryOp("!begins", 10);
|
||||||
|
jsep.addBinaryOp("ends", 10);
|
||||||
|
jsep.addBinaryOp("!ends", 10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a 32 bit FNV-1a hash
|
||||||
|
* Found here: https://gist.github.com/vaiorabbit/5657561
|
||||||
|
* Ref.: http://isthe.com/chongo/tech/comp/fnv/
|
||||||
|
*
|
||||||
|
* @param {string} str the input value
|
||||||
|
* @param {boolean} [asString=false] set to true to return the hash value as
|
||||||
|
* 8-digit hex string instead of an integer
|
||||||
|
* @param {integer} [seed] optionally pass the hash of the previous chunk
|
||||||
|
* @returns {integer | string}
|
||||||
|
*/
|
||||||
|
function hashFnv32a(str, asString, seed) {
|
||||||
|
/*jshint bitwise:false */
|
||||||
|
var i, l,
|
||||||
|
hval = (seed === undefined) ? 0x811c9dc5 : seed;
|
||||||
|
|
||||||
|
for (i = 0, l = str.length; i < l; i++) {
|
||||||
|
hval ^= str.charCodeAt(i);
|
||||||
|
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
|
||||||
|
}
|
||||||
|
if( asString ){
|
||||||
|
// Convert to 8 digit hex string
|
||||||
|
return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
|
||||||
|
}
|
||||||
|
return hval >>> 0;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'SendVisitorData',
|
angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'SendVisitorData',
|
||||||
function ($http, TimeCounter, $filter, $rootScope, SendVisitorData) {
|
function ($http, TimeCounter, $filter, $rootScope, SendVisitorData) {
|
||||||
|
@ -916,6 +953,67 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||||
/*
|
/*
|
||||||
** Field Controls
|
** Field Controls
|
||||||
*/
|
*/
|
||||||
|
var evaluateLogicJump = function(field){
|
||||||
|
console.log('evaluateLogicJump');
|
||||||
|
console.log(field.fieldValue);
|
||||||
|
var logicJump = field.logicJump;
|
||||||
|
|
||||||
|
if (logicJump.expressionString && logicJump.valueB && field.fieldValue) {
|
||||||
|
var parse_tree = jsep(logicJump.expressionString);
|
||||||
|
var left, right;
|
||||||
|
|
||||||
|
console.log(parse_tree);
|
||||||
|
|
||||||
|
if(parse_tree.left.name === 'field'){
|
||||||
|
left = field.fieldValue;
|
||||||
|
right = logicJump.valueB
|
||||||
|
} else {
|
||||||
|
left = logicJump.valueB;
|
||||||
|
right = field.fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(field.fieldType === 'number' || field.fieldType === 'scale' || field.fieldType === 'rating'){
|
||||||
|
switch(parse_tree.operator) {
|
||||||
|
case '==':
|
||||||
|
return (parseInt(left) === parseInt(right));
|
||||||
|
case '!==':
|
||||||
|
return (parseInt(left) !== parseInt(right));
|
||||||
|
case '>':
|
||||||
|
return (parseInt(left) > parseInt(right));
|
||||||
|
case '>=':
|
||||||
|
return (parseInt(left) > parseInt(right));
|
||||||
|
case '<':
|
||||||
|
return (parseInt(left) < parseInt(right));
|
||||||
|
case '<=':
|
||||||
|
return (parseInt(left) <= parseInt(right));
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(parse_tree.operator) {
|
||||||
|
case '==':
|
||||||
|
return (left === right);
|
||||||
|
case '!==':
|
||||||
|
return (left !== right);
|
||||||
|
case 'contains':
|
||||||
|
return (left.indexOf(right) > -1);
|
||||||
|
case '!contains':
|
||||||
|
return !(left.indexOf(right) > -1);
|
||||||
|
case 'begins':
|
||||||
|
return left.startsWith(right);
|
||||||
|
case '!begins':
|
||||||
|
return !left.startsWith(right);
|
||||||
|
case 'ends':
|
||||||
|
return left.endsWith(right);
|
||||||
|
case '!ends':
|
||||||
|
return left.endsWith(right);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var getActiveField = function(){
|
var getActiveField = function(){
|
||||||
if($scope.selected === null){
|
if($scope.selected === null){
|
||||||
console.error('current active field is null');
|
console.error('current active field is null');
|
||||||
|
@ -941,6 +1039,15 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||||
|
|
||||||
$scope.selected._id = field_id;
|
$scope.selected._id = field_id;
|
||||||
$scope.selected.index = field_index;
|
$scope.selected.index = field_index;
|
||||||
|
if(!field_index){
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var nb_valid = $filter('formValidity')($scope.myform);
|
var nb_valid = $filter('formValidity')($scope.myform);
|
||||||
$scope.translateAdvancementData = {
|
$scope.translateAdvancementData = {
|
||||||
|
@ -983,20 +1090,26 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||||
};
|
};
|
||||||
|
|
||||||
$rootScope.nextField = $scope.nextField = function(){
|
$rootScope.nextField = $scope.nextField = function(){
|
||||||
//console.log('nextfield');
|
var currField = $scope.myform.visible_form_fields[$scope.selected.index];
|
||||||
//console.log($scope.selected.index);
|
|
||||||
//console.log($scope.myform.visible_form_fields.length-1);
|
if($scope.selected && $scope.selected.index > -1){
|
||||||
var selected_index, selected_id;
|
//Jump to logicJump's destination if it is true
|
||||||
if($scope.selected.index < $scope.myform.visible_form_fields.length-1){
|
if(currField.logicJump && evaluateLogicJump(currField)){
|
||||||
selected_index = $scope.selected.index+1;
|
$rootScope.setActiveField(currField.logicJump.jumpTo, null, true);
|
||||||
selected_id = $scope.myform.visible_form_fields[selected_index]._id;
|
} else {
|
||||||
$rootScope.setActiveField(selected_id, selected_index, true);
|
var selected_index, selected_id;
|
||||||
} else if($scope.selected.index === $scope.myform.visible_form_fields.length-1) {
|
if($scope.selected.index < $scope.myform.visible_form_fields.length-1){
|
||||||
//console.log('Second last element');
|
selected_index = $scope.selected.index+1;
|
||||||
selected_index = $scope.selected.index+1;
|
selected_id = $scope.myform.visible_form_fields[selected_index]._id;
|
||||||
selected_id = 'submit_field';
|
$rootScope.setActiveField(selected_id, selected_index, true);
|
||||||
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$rootScope.prevField = $scope.prevField = function(){
|
$rootScope.prevField = $scope.prevField = function(){
|
||||||
|
|
4
public/dist/form-application.min.js
vendored
4
public/dist/form-application.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -2,107 +2,108 @@
|
||||||
|
|
||||||
// coffeescript's for in loop
|
// coffeescript's for in loop
|
||||||
var __indexOf = [].indexOf || function(item) {
|
var __indexOf = [].indexOf || function(item) {
|
||||||
for (var i = 0, l = this.length; i < l; i++) {
|
for (var i = 0, l = this.length; i < l; i++) {
|
||||||
if (i in this && this[i] === item) return i;
|
if (i in this && this[i] === item) return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
angular.module('view-form').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields',
|
angular.module('view-form').directive('fieldDirective', ['$http', '$compile', '$rootScope', '$templateCache', 'supportedFields',
|
||||||
function($http, $compile, $rootScope, $templateCache, supportedFields) {
|
function($http, $compile, $rootScope, $templateCache, supportedFields) {
|
||||||
|
|
||||||
var getTemplateUrl = function(fieldType) {
|
var getTemplateUrl = function(fieldType) {
|
||||||
var type = fieldType;
|
var type = fieldType;
|
||||||
|
|
||||||
var supported_fields = [
|
var supported_fields = [
|
||||||
'textfield',
|
'textfield',
|
||||||
'textarea',
|
'textarea',
|
||||||
'date',
|
'date',
|
||||||
'dropdown',
|
'dropdown',
|
||||||
'hidden',
|
'hidden',
|
||||||
'password',
|
'password',
|
||||||
'radio',
|
'radio',
|
||||||
'legal',
|
'legal',
|
||||||
'statement',
|
'statement',
|
||||||
'rating',
|
'rating',
|
||||||
'yes_no',
|
'yes_no',
|
||||||
'number',
|
'number',
|
||||||
'natural'
|
'natural'
|
||||||
];
|
];
|
||||||
|
|
||||||
var templateUrl = 'modules/forms/base/views/directiveViews/field/';
|
var templateUrl = 'modules/forms/base/views/directiveViews/field/';
|
||||||
|
|
||||||
if (__indexOf.call(supportedFields, type) >= 0) {
|
if (__indexOf.call(supportedFields, type) >= 0) {
|
||||||
templateUrl = templateUrl+type+'.html';
|
templateUrl = templateUrl+type+'.html';
|
||||||
}
|
|
||||||
return $templateCache.get(templateUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
template: '<div>{{field.title}}</div>',
|
|
||||||
restrict: 'E',
|
|
||||||
scope: {
|
|
||||||
field: '=',
|
|
||||||
required: '&',
|
|
||||||
design: '=',
|
|
||||||
index: '=',
|
|
||||||
forms: '='
|
|
||||||
},
|
|
||||||
link: function(scope, element) {
|
|
||||||
|
|
||||||
$rootScope.chooseDefaultOption = scope.chooseDefaultOption = function(type) {
|
|
||||||
if(type === 'yes_no'){
|
|
||||||
scope.field.fieldValue = 'true';
|
|
||||||
}else if(type === 'rating'){
|
|
||||||
scope.field.fieldValue = 0;
|
|
||||||
}else if(scope.field.fieldType === 'radio'){
|
|
||||||
console.log(scope.field);
|
|
||||||
scope.field.fieldValue = scope.field.fieldOptions[0].option_value;
|
|
||||||
console.log(scope.field.fieldValue);
|
|
||||||
}else if(type === 'legal'){
|
|
||||||
scope.field.fieldValue = 'true';
|
|
||||||
$rootScope.nextField();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.setActiveField = $rootScope.setActiveField;
|
|
||||||
|
|
||||||
//Set format only if field is a date
|
|
||||||
if(scope.field.fieldType === 'date'){
|
|
||||||
scope.dateOptions = {
|
|
||||||
changeYear: true,
|
|
||||||
changeMonth: true,
|
|
||||||
altFormat: 'mm/dd/yyyy',
|
|
||||||
yearRange: '1900:-0',
|
|
||||||
defaultDate: 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var fieldType = scope.field.fieldType;
|
|
||||||
|
|
||||||
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
|
|
||||||
switch(scope.field.fieldType){
|
|
||||||
case 'textfield':
|
|
||||||
scope.field.input_type = 'text';
|
|
||||||
break;
|
|
||||||
case 'email':
|
|
||||||
scope.field.input_type = 'email';
|
|
||||||
scope.field.placeholder = 'joesmith@example.com';
|
|
||||||
break;
|
|
||||||
case 'number':
|
|
||||||
scope.field.input_type = 'text';
|
|
||||||
scope.field.validateRegex = /^-?\d+$/;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scope.field.input_type = 'url';
|
|
||||||
scope.field.placeholder = 'http://example.com';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fieldType = 'textfield';
|
|
||||||
}
|
}
|
||||||
var template = getTemplateUrl(fieldType);
|
return $templateCache.get(templateUrl);
|
||||||
element.html(template).show();
|
};
|
||||||
var output = $compile(element.contents())(scope);
|
|
||||||
}
|
return {
|
||||||
};
|
template: '<div>{{field.title}}</div>',
|
||||||
}]);
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
field: '=',
|
||||||
|
required: '&',
|
||||||
|
design: '=',
|
||||||
|
index: '=',
|
||||||
|
forms: '='
|
||||||
|
},
|
||||||
|
link: function(scope, element) {
|
||||||
|
|
||||||
|
$rootScope.chooseDefaultOption = scope.chooseDefaultOption = function(type) {
|
||||||
|
if(type === 'yes_no'){
|
||||||
|
scope.field.fieldValue = 'true';
|
||||||
|
}else if(type === 'rating'){
|
||||||
|
scope.field.fieldValue = 0;
|
||||||
|
}else if(scope.field.fieldType === 'radio'){
|
||||||
|
console.log(scope.field);
|
||||||
|
scope.field.fieldValue = scope.field.fieldOptions[0].option_value;
|
||||||
|
console.log(scope.field.fieldValue);
|
||||||
|
}else if(type === 'legal'){
|
||||||
|
scope.field.fieldValue = 'true';
|
||||||
|
$rootScope.nextField();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.setActiveField = $rootScope.setActiveField;
|
||||||
|
|
||||||
|
//Set format only if field is a date
|
||||||
|
if(scope.field.fieldType === 'date'){
|
||||||
|
scope.dateOptions = {
|
||||||
|
changeYear: true,
|
||||||
|
changeMonth: true,
|
||||||
|
altFormat: 'mm/dd/yyyy',
|
||||||
|
yearRange: '1900:-0',
|
||||||
|
defaultDate: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldType = scope.field.fieldType;
|
||||||
|
|
||||||
|
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
|
||||||
|
switch(scope.field.fieldType){
|
||||||
|
case 'textfield':
|
||||||
|
scope.input_type = 'text';
|
||||||
|
break;
|
||||||
|
case 'email':
|
||||||
|
scope.input_type = 'email';
|
||||||
|
scope.placeholder = 'joesmith@example.com';
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
scope.input_type = 'text';
|
||||||
|
scope.validateRegex = /^-?\d+$/;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scope.input_type = 'url';
|
||||||
|
scope.placeholder = 'http://example.com';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fieldType = 'textfield';
|
||||||
|
}
|
||||||
|
|
||||||
|
var template = getTemplateUrl(fieldType);
|
||||||
|
element.html(template).show();
|
||||||
|
var output = $compile(element.contents())(scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,5 +1,41 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
//FIXME: Should find an appropriate place for this
|
||||||
|
//Setting up jsep
|
||||||
|
jsep.addBinaryOp("contains", 10);
|
||||||
|
jsep.addBinaryOp("!contains", 10);
|
||||||
|
jsep.addBinaryOp("begins", 10);
|
||||||
|
jsep.addBinaryOp("!begins", 10);
|
||||||
|
jsep.addBinaryOp("ends", 10);
|
||||||
|
jsep.addBinaryOp("!ends", 10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a 32 bit FNV-1a hash
|
||||||
|
* Found here: https://gist.github.com/vaiorabbit/5657561
|
||||||
|
* Ref.: http://isthe.com/chongo/tech/comp/fnv/
|
||||||
|
*
|
||||||
|
* @param {string} str the input value
|
||||||
|
* @param {boolean} [asString=false] set to true to return the hash value as
|
||||||
|
* 8-digit hex string instead of an integer
|
||||||
|
* @param {integer} [seed] optionally pass the hash of the previous chunk
|
||||||
|
* @returns {integer | string}
|
||||||
|
*/
|
||||||
|
function hashFnv32a(str, asString, seed) {
|
||||||
|
/*jshint bitwise:false */
|
||||||
|
var i, l,
|
||||||
|
hval = (seed === undefined) ? 0x811c9dc5 : seed;
|
||||||
|
|
||||||
|
for (i = 0, l = str.length; i < l; i++) {
|
||||||
|
hval ^= str.charCodeAt(i);
|
||||||
|
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
|
||||||
|
}
|
||||||
|
if( asString ){
|
||||||
|
// Convert to 8 digit hex string
|
||||||
|
return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
|
||||||
|
}
|
||||||
|
return hval >>> 0;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'SendVisitorData',
|
angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCounter', '$filter', '$rootScope', 'SendVisitorData',
|
||||||
function ($http, TimeCounter, $filter, $rootScope, SendVisitorData) {
|
function ($http, TimeCounter, $filter, $rootScope, SendVisitorData) {
|
||||||
|
@ -92,6 +128,67 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||||
/*
|
/*
|
||||||
** Field Controls
|
** Field Controls
|
||||||
*/
|
*/
|
||||||
|
var evaluateLogicJump = function(field){
|
||||||
|
console.log('evaluateLogicJump');
|
||||||
|
console.log(field.fieldValue);
|
||||||
|
var logicJump = field.logicJump;
|
||||||
|
|
||||||
|
if (logicJump.expressionString && logicJump.valueB && field.fieldValue) {
|
||||||
|
var parse_tree = jsep(logicJump.expressionString);
|
||||||
|
var left, right;
|
||||||
|
|
||||||
|
console.log(parse_tree);
|
||||||
|
|
||||||
|
if(parse_tree.left.name === 'field'){
|
||||||
|
left = field.fieldValue;
|
||||||
|
right = logicJump.valueB
|
||||||
|
} else {
|
||||||
|
left = logicJump.valueB;
|
||||||
|
right = field.fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(field.fieldType === 'number' || field.fieldType === 'scale' || field.fieldType === 'rating'){
|
||||||
|
switch(parse_tree.operator) {
|
||||||
|
case '==':
|
||||||
|
return (parseInt(left) === parseInt(right));
|
||||||
|
case '!==':
|
||||||
|
return (parseInt(left) !== parseInt(right));
|
||||||
|
case '>':
|
||||||
|
return (parseInt(left) > parseInt(right));
|
||||||
|
case '>=':
|
||||||
|
return (parseInt(left) > parseInt(right));
|
||||||
|
case '<':
|
||||||
|
return (parseInt(left) < parseInt(right));
|
||||||
|
case '<=':
|
||||||
|
return (parseInt(left) <= parseInt(right));
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(parse_tree.operator) {
|
||||||
|
case '==':
|
||||||
|
return (left === right);
|
||||||
|
case '!==':
|
||||||
|
return (left !== right);
|
||||||
|
case 'contains':
|
||||||
|
return (left.indexOf(right) > -1);
|
||||||
|
case '!contains':
|
||||||
|
return !(left.indexOf(right) > -1);
|
||||||
|
case 'begins':
|
||||||
|
return left.startsWith(right);
|
||||||
|
case '!begins':
|
||||||
|
return !left.startsWith(right);
|
||||||
|
case 'ends':
|
||||||
|
return left.endsWith(right);
|
||||||
|
case '!ends':
|
||||||
|
return left.endsWith(right);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var getActiveField = function(){
|
var getActiveField = function(){
|
||||||
if($scope.selected === null){
|
if($scope.selected === null){
|
||||||
console.error('current active field is null');
|
console.error('current active field is null');
|
||||||
|
@ -117,6 +214,15 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||||
|
|
||||||
$scope.selected._id = field_id;
|
$scope.selected._id = field_id;
|
||||||
$scope.selected.index = field_index;
|
$scope.selected.index = field_index;
|
||||||
|
if(!field_index){
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var nb_valid = $filter('formValidity')($scope.myform);
|
var nb_valid = $filter('formValidity')($scope.myform);
|
||||||
$scope.translateAdvancementData = {
|
$scope.translateAdvancementData = {
|
||||||
|
@ -159,20 +265,26 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||||
};
|
};
|
||||||
|
|
||||||
$rootScope.nextField = $scope.nextField = function(){
|
$rootScope.nextField = $scope.nextField = function(){
|
||||||
//console.log('nextfield');
|
var currField = $scope.myform.visible_form_fields[$scope.selected.index];
|
||||||
//console.log($scope.selected.index);
|
|
||||||
//console.log($scope.myform.visible_form_fields.length-1);
|
if($scope.selected && $scope.selected.index > -1){
|
||||||
var selected_index, selected_id;
|
//Jump to logicJump's destination if it is true
|
||||||
if($scope.selected.index < $scope.myform.visible_form_fields.length-1){
|
if(currField.logicJump && evaluateLogicJump(currField)){
|
||||||
selected_index = $scope.selected.index+1;
|
$rootScope.setActiveField(currField.logicJump.jumpTo, null, true);
|
||||||
selected_id = $scope.myform.visible_form_fields[selected_index]._id;
|
} else {
|
||||||
$rootScope.setActiveField(selected_id, selected_index, true);
|
var selected_index, selected_id;
|
||||||
} else if($scope.selected.index === $scope.myform.visible_form_fields.length-1) {
|
if($scope.selected.index < $scope.myform.visible_form_fields.length-1){
|
||||||
//console.log('Second last element');
|
selected_index = $scope.selected.index+1;
|
||||||
selected_index = $scope.selected.index+1;
|
selected_id = $scope.myform.visible_form_fields[selected_index]._id;
|
||||||
selected_id = 'submit_field';
|
$rootScope.setActiveField(selected_id, selected_index, true);
|
||||||
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$rootScope.prevField = $scope.prevField = function(){
|
$rootScope.prevField = $scope.prevField = function(){
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
|
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
|
||||||
name="{{field.fieldType}}{{index}}"
|
name="{{field.fieldType}}{{index}}"
|
||||||
type="{{field.input_type}}"
|
type="{{input_type}}"
|
||||||
ng-pattern="field.validateRegex"
|
ng-pattern="validateRegex"
|
||||||
placeholder="{{field.placeholder}}"
|
placeholder="{{placeholder}}"
|
||||||
ng-class="{ 'no-border': !!field.fieldValue }"
|
ng-class="{ 'no-border': !!field.fieldValue }"
|
||||||
class="focusOn text-field-input"
|
class="focusOn text-field-input"
|
||||||
ng-model="field.fieldValue"
|
ng-model="field.fieldValue"
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
on-tab-and-shift-key="prevField()"
|
on-tab-and-shift-key="prevField()"
|
||||||
ng-required="field.required"
|
ng-required="field.required"
|
||||||
ng-disabled="field.disabled"
|
ng-disabled="field.disabled"
|
||||||
aria-describedby="inputError2Status">
|
aria-describedby="inputError2Status"/ >
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12">
|
<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">
|
<div ng-show="forms.myForm.{{field.fieldType}}{{index}}.$invalid && !!forms.myForm.{{field.fieldType}}{{index}}.$viewValue " class="alert alert-danger" role="alert">
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
style="padding: 4px; margin-top:8px; background: rgba(255,255,255,0.5)">
|
style="padding: 4px; margin-top:8px; background: rgba(255,255,255,0.5)">
|
||||||
<button ng-disabled="!field.fieldValue || forms.myForm.{{field.fieldType}}{{$index}}.$invalid"
|
<button ng-disabled="!field.fieldValue || forms.myForm.{{field.fieldType}}{{$index}}.$invalid"
|
||||||
ng-style="{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"
|
ng-style="{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"
|
||||||
ng-click="$root.nextField()"
|
ng-click="nextField()"
|
||||||
class="btn col-sm-5 col-xs-5">
|
class="btn col-sm-5 col-xs-5">
|
||||||
|
|
||||||
{{ 'OK' | translate }} <i class="fa fa-check"></i>
|
{{ 'OK' | translate }} <i class="fa fa-check"></i>
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
ApplicationConfiguration.registerModule('view-form', [
|
ApplicationConfiguration.registerModule('view-form', [
|
||||||
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
||||||
'angular-input-stars', 'pascalprecht.translate'
|
'angular-input-stars', 'pascalprecht.translate'
|
||||||
]);//, 'colorpicker.module' @TODO reactivate this module
|
]);
|
||||||
|
|
|
@ -6,11 +6,12 @@ angular.module('core').controller('HeaderController', ['$rootScope', '$scope', '
|
||||||
$rootScope.signupDisabled = $window.signupDisabled;
|
$rootScope.signupDisabled = $window.signupDisabled;
|
||||||
|
|
||||||
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
|
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
|
||||||
|
|
||||||
|
console.log(Auth.ensureHasCurrentUser(User));
|
||||||
$scope.authentication = $rootScope.authentication = Auth;
|
$scope.authentication = $rootScope.authentication = Auth;
|
||||||
|
|
||||||
$rootScope.languages = $scope.languages = ['en', 'fr', 'es', 'it', 'de'];
|
$rootScope.languages = $scope.languages = ['en', 'fr', 'es', 'it', 'de'];
|
||||||
|
|
||||||
console.log($locale.id);
|
|
||||||
//Set global app language
|
//Set global app language
|
||||||
if($scope.authentication.isAuthenticated()){
|
if($scope.authentication.isAuthenticated()){
|
||||||
$rootScope.language = $scope.user.language;
|
$rootScope.language = $scope.user.language;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
font-family: 'Source Sans Pro', sans-serif;
|
font-family: 'Source Sans Pro', sans-serif;
|
||||||
|
@ -10,12 +12,34 @@ body {
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Custom CSS for Buttons */
|
||||||
|
.btn-rounded {
|
||||||
|
border-radius: 100px;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 10px 28px;
|
||||||
|
margin: 0 2px;
|
||||||
|
margin-top: 1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: #DDDDDD;
|
||||||
|
color: #4c4c4c;
|
||||||
|
border: 2px #4c4c4c solid;
|
||||||
|
}
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background: #cacaca;
|
||||||
|
border-color: #cacaca;
|
||||||
|
}
|
||||||
|
|
||||||
/*Navbar Custom CSS*/
|
/*Navbar Custom CSS*/
|
||||||
.navbar {
|
.navbar {
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
|
padding: 10px 0 10px 0;
|
||||||
}
|
}
|
||||||
.navbar-inverse {
|
.navbar-inverse {
|
||||||
background-color:#588EB4;
|
background-color:#3FA2F7;
|
||||||
border: 0;
|
border: 0;
|
||||||
color: white!important;
|
color: white!important;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +57,7 @@ body {
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
}
|
}
|
||||||
.navbar-nav > li > a {
|
.navbar-nav > li > a {
|
||||||
|
padding-top: 20px;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.navbar-nav > li:hover, .navbar-nav > li.active {
|
.navbar-nav > li:hover, .navbar-nav > li.active {
|
||||||
|
|
|
@ -5,25 +5,11 @@
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="sr-only">Toggle navigation</span>
|
||||||
<span>{{ 'MENU_BTN' | translate }}</span>
|
<span>{{ 'MENU_BTN' | translate }}</span>
|
||||||
</button>
|
</button>
|
||||||
<a href="https://www.tellform.com/#!/" class="navbar-brand">
|
<a href="/#!/" class="navbar-brand">
|
||||||
<img src="/static/modules/core/img/logo_white.svg" height="100%">
|
<img src="/static/modules/core/img/logo_white.svg" height="100%">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<nav class="collapse navbar-collapse" collapse="!isCollapsed" role="navigation">
|
<nav class="collapse navbar-collapse" collapse="!isCollapsed" role="navigation">
|
||||||
<ul class="nav navbar-nav" data-ng-if="authentication.isAuthenticated()">
|
|
||||||
<li data-ng-repeat="item in menu.items | orderBy: 'position'" data-ng-if="item.shouldRender(authentication.isAuthenticated());" ng-switch="item.menuItemType" ui-route="{{item.uiRoute}}" class="{{item.menuItemClass}}" ng-class="{active: ($uiRoute)}" dropdown="item.menuItemType === 'dropdown'">
|
|
||||||
<a ng-switch-when="dropdown" class="dropdown-toggle" dropdown-toggle>
|
|
||||||
<span data-ng-bind="item.title"></span>
|
|
||||||
<b class="caret"></b>
|
|
||||||
</a>
|
|
||||||
<ul ng-switch-when="dropdown" class="dropdown-menu">
|
|
||||||
<li data-ng-repeat="subitem in item.items | orderBy: 'position'" data-ng-if="subitem.shouldRender(authentication.isAuthenticated());" ui-route="{{subitem.uiRoute}}" ng-class="{active: $uiRoute}">
|
|
||||||
<a href="/#!/{{subitem.link}}" data-ng-bind="subitem.title"></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<a ng-switch-default href="/#!/{{item.link}}" data-ng-bind="item.title"></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul class="nav navbar-nav navbar-right" data-ng-hide="authentication.isAuthenticated()">
|
<ul class="nav navbar-nav navbar-right" data-ng-hide="authentication.isAuthenticated()">
|
||||||
<li ng-hide="$root.signupDisabled" ui-route="/signup" ng-class="{active: $uiRoute}">
|
<li ng-hide="$root.signupDisabled" ui-route="/signup" ng-class="{active: $uiRoute}">
|
||||||
<a href="/#!/signup">{{ 'SIGNUP_TAB' | translate }}</a>
|
<a href="/#!/signup">{{ 'SIGNUP_TAB' | translate }}</a>
|
||||||
|
|
|
@ -39,6 +39,10 @@ angular.module('forms').config(['$translateProvider', function ($translateProvid
|
||||||
PREVIEW: 'Preview',
|
PREVIEW: 'Preview',
|
||||||
|
|
||||||
//Edit Form View
|
//Edit Form View
|
||||||
|
DISABLED: 'Disabled:',
|
||||||
|
YES: 'YES',
|
||||||
|
NO: 'NO',
|
||||||
|
ADD_LOGIC_JUMP: 'Add Logic Jump',
|
||||||
ADD_FIELD_LG: 'Click to Add New Field',
|
ADD_FIELD_LG: 'Click to Add New Field',
|
||||||
ADD_FIELD_MD: 'Add New Field',
|
ADD_FIELD_MD: 'Add New Field',
|
||||||
ADD_FIELD_SM: 'Add Field',
|
ADD_FIELD_SM: 'Add Field',
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// Forms controller
|
// Forms controller
|
||||||
angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$uibModal', 'myForm', '$filter',
|
angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$uibModal', 'myForm', '$filter', '$sce',
|
||||||
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $uibModal, myForm, $filter) {
|
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $uibModal, myForm, $filter, $sce) {
|
||||||
|
|
||||||
|
$scope.trustSrc = function(src) {
|
||||||
|
return $sce.trustAsResourceUrl(src);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Set active tab to Create
|
||||||
|
$scope.activePill = 0;
|
||||||
|
|
||||||
|
$scope.copied = false;
|
||||||
|
$scope.onCopySuccess = function(e) {
|
||||||
|
console.log("COPY SUCCESSFUL!");
|
||||||
|
$scope.copied = true;
|
||||||
|
};
|
||||||
|
|
||||||
$scope = $rootScope;
|
$scope = $rootScope;
|
||||||
$scope.animationsEnabled = true;
|
$scope.animationsEnabled = true;
|
||||||
|
@ -11,24 +24,34 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
|
||||||
|
|
||||||
CurrentForm.setForm($scope.myform);
|
CurrentForm.setForm($scope.myform);
|
||||||
|
|
||||||
$scope.formURL = $scope.myform.admin.username + '.tellform.com';
|
$scope.formURL = "/#!/forms/" + $scope.myform._id;
|
||||||
|
|
||||||
$scope.tabData = [
|
$scope.actualFormURL = window.location.protocol + '//' + $scope.myform.admin.username + '.' + window.location.host + "/#!/forms/" + $scope.myform._id;
|
||||||
{
|
|
||||||
|
|
||||||
|
var refreshFrame = $scope.refreshFrame = function(){
|
||||||
|
if(document.getElementById('iframe')) {
|
||||||
|
document.getElementById('iframe').contentWindow.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$scope.tabData = [
|
||||||
|
/*{
|
||||||
heading: $filter('translate')('CREATE_TAB'),
|
heading: $filter('translate')('CREATE_TAB'),
|
||||||
route: 'viewForm.create'
|
templateName: 'create'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: $filter('translate')('DESIGN_TAB'),
|
heading: $filter('translate')('DESIGN_TAB'),
|
||||||
route: 'viewForm.design'
|
templateName: 'design'
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
heading: $filter('translate')('CONFIGURE_TAB'),
|
heading: $filter('translate')('CONFIGURE_TAB'),
|
||||||
route: 'viewForm.configure'
|
templateName: 'configure'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: $filter('translate')('ANALYZE_TAB'),
|
heading: $filter('translate')('ANALYZE_TAB'),
|
||||||
route: 'viewForm.analyze'
|
templateName: 'analyze'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -92,7 +115,8 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update existing Form
|
// Update existing Form
|
||||||
$scope.update = $rootScope.update = function(updateImmediately, cb){
|
$scope.update = $rootScope.update = function(updateImmediately, diffChanges, cb){
|
||||||
|
refreshFrame();
|
||||||
|
|
||||||
var continueUpdate = true;
|
var continueUpdate = true;
|
||||||
if(!updateImmediately){
|
if(!updateImmediately){
|
||||||
|
@ -105,7 +129,7 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
|
||||||
|
|
||||||
if(!updateImmediately){ $rootScope.saveInProgress = true; }
|
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){
|
.then(function(response){
|
||||||
$rootScope.myform = $scope.myform = response.data;
|
$rootScope.myform = $scope.myform = response.data;
|
||||||
// console.log(response.data);
|
// console.log(response.data);
|
||||||
|
|
|
@ -32,7 +32,6 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
|
||||||
|
|
||||||
$rootScope.finishedRender = false;
|
$rootScope.finishedRender = false;
|
||||||
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
|
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
|
||||||
// console.log('hello');
|
|
||||||
$rootScope.finishedRender = false;
|
$rootScope.finishedRender = false;
|
||||||
});
|
});
|
||||||
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
|
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
|
||||||
|
@ -52,13 +51,11 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var debounceSave = function () {
|
var debounceSave = function (diffChanges) {
|
||||||
$rootScope.saveInProgress = true;
|
|
||||||
|
|
||||||
$rootScope[$attrs.autoSaveCallback](true,
|
$rootScope[$attrs.autoSaveCallback](true, diffChanges,
|
||||||
function(err){
|
function(err){
|
||||||
if(!err){
|
if(!err){
|
||||||
//console.log('\n\nForm data persisted -- setting pristine flag');
|
|
||||||
$formCtrl.$setPristine();
|
$formCtrl.$setPristine();
|
||||||
$formCtrl.$setUntouched();
|
$formCtrl.$setUntouched();
|
||||||
}else{
|
}else{
|
||||||
|
@ -68,56 +65,48 @@ 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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Autosave Form when model (specified in $attrs.autoSaveWatch) changes
|
//Autosave Form when model (specified in $attrs.autoSaveWatch) changes
|
||||||
$scope.$watch($attrs.autoSaveWatch, function(newValue, oldValue) {
|
$scope.$watch($attrs.autoSaveWatch, function(newValue, oldValue) {
|
||||||
|
|
||||||
|
if( !newValue || !oldValue ) {
|
||||||
|
$rootScope.finishedRender = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
newValue = angular.copy(newValue);
|
newValue = angular.copy(newValue);
|
||||||
oldValue = angular.copy(oldValue);
|
oldValue = angular.copy(oldValue);
|
||||||
|
|
||||||
newValue.form_fields = _.removeDateFields(newValue.form_fields);
|
delete newValue.visible_form_fields;
|
||||||
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
|
delete oldValue.visible_form_fields;
|
||||||
|
newValue.form_fields = _.removeDateFields(newValue.form_fields);
|
||||||
|
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
|
||||||
|
|
||||||
var changedFields = !_.isEqual(oldValue.form_fields,newValue.form_fields) || !_.isEqual(oldValue.startPage, newValue.startPage);
|
var changedFields = !!DeepDiff.diff(oldValue, newValue) && DeepDiff.diff(oldValue, newValue).length > 0;
|
||||||
var changedFieldMap = false;
|
|
||||||
|
|
||||||
if(oldValue.hasOwnProperty('plugins.oscarhost.settings.fieldMap')){
|
//If our form is undefined, don't save form
|
||||||
changedFieldMap = !!oldValue.plugins.oscarhost.settings.fieldMap && !_.isEqual(oldValue.plugins.oscarhost.settings.fieldMap,newValue.plugins.oscarhost.settings.fieldMap);
|
if(!changedFields){
|
||||||
}
|
$rootScope.finishedRender = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//If our form is undefined, don't save form
|
if(oldValue.form_fields.length === 0) {
|
||||||
if( (!newValue && !oldValue) || !oldValue ){
|
$rootScope.finishedRender = true;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
//console.log('Autosaving');
|
||||||
|
//console.log('\n\n----------');
|
||||||
|
//console.log('!$dirty: '+ !$formCtrl.$dirty );
|
||||||
|
|
||||||
// console.log('Autosaving');
|
|
||||||
// console.log('\n\n----------');
|
|
||||||
// console.log('!$dirty: '+ !$formCtrl.$dirty );
|
|
||||||
// console.log('changedFields: '+changedFields);
|
|
||||||
// console.log('changedFieldMap: '+changedFieldMap);
|
// console.log('changedFieldMap: '+changedFieldMap);
|
||||||
// console.log('finishedRender: '+$rootScope.finishedRender);
|
//console.log('finishedRender: '+$rootScope.finishedRender);
|
||||||
// console.log('!saveInProgress: '+!$rootScope.saveInProgress);
|
//console.log('!saveInProgress: '+!$rootScope.saveInProgress);
|
||||||
// console.log('newValue: '+newValue);
|
// console.log('newValue: '+newValue);
|
||||||
// console.log('oldValue: '+oldValue);
|
// console.log('oldValue: '+oldValue);
|
||||||
// console.log(oldValue.form_fields);
|
// console.log(oldValue.form_fields);
|
||||||
// console.log(newValue.form_fields);
|
// console.log(newValue.form_fields);
|
||||||
|
|
||||||
if(oldValue.form_fields.length === 0) {
|
|
||||||
$rootScope.finishedRender = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Save form ONLY IF rendering is finished, form_fields have been changed AND currently not save in progress
|
//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) && !$rootScope.saveInProgress) {
|
||||||
|
|
||||||
if(savePromise) {
|
if(savePromise) {
|
||||||
$timeout.cancel(savePromise);
|
$timeout.cancel(savePromise);
|
||||||
|
@ -125,7 +114,12 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
|
||||||
}
|
}
|
||||||
|
|
||||||
savePromise = $timeout(function() {
|
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
|
//If we are finished rendering then form saving should be finished
|
||||||
|
|
|
@ -5,16 +5,12 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
return {
|
return {
|
||||||
templateUrl: 'modules/forms/admin/views/directiveViews/form/edit-form.client.view.html',
|
templateUrl: 'modules/forms/admin/views/directiveViews/form/edit-form.client.view.html',
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
|
transclude: true,
|
||||||
scope: {
|
scope: {
|
||||||
myform:'='
|
myform:'='
|
||||||
},
|
},
|
||||||
controller: function($scope){
|
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;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
** Initialize scope with variables
|
** Initialize scope with variables
|
||||||
*/
|
*/
|
||||||
|
@ -63,24 +59,24 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
//Populate local scope with rootScope methods/variables
|
//Populate local scope with rootScope methods/variables
|
||||||
$scope.update = $rootScope.update;
|
$scope.update = $rootScope.update;
|
||||||
|
|
||||||
//Many-to-many Select for Mapping OscarhostFields -> FormFields
|
// LOGIC JUMP METHODS
|
||||||
$scope.oscarFieldsLeft = function(field_id){
|
$scope.removeLogicJump = function (field_index) {
|
||||||
|
var currField = $scope.myform.form_fields[field_index];
|
||||||
|
currField.logicJump = {};
|
||||||
|
};
|
||||||
|
|
||||||
if($scope.myform && $scope.myform.plugins.oscarhost.settings.validFields.length > 0){
|
$scope.addNewLogicJump = function (field_index) {
|
||||||
if(!$scope.myform.plugins.oscarhost.settings.fieldMap) $scope.myform.plugins.oscarhost.settings.fieldMap = {};
|
var form_fields = $scope.myform.form_fields;
|
||||||
|
var currField = form_fields[field_index];
|
||||||
|
console.log(currField);
|
||||||
|
if (form_fields.length > 1 && currField._id) {
|
||||||
|
|
||||||
var oscarhostFields = $scope.myform.plugins.oscarhost.settings.validFields;
|
var newLogicJump = {
|
||||||
var currentFields = _($scope.myform.plugins.oscarhost.settings.fieldMap).invert().keys().value();
|
fieldA: currField._id
|
||||||
|
};
|
||||||
if( $scope.myform.plugins.oscarhost.settings.fieldMap.hasOwnProperty(field_id) ){
|
currField.logicJump = newLogicJump;
|
||||||
currentFields = _(currentFields).difference($scope.myform.plugins.oscarhost.settings.fieldMap[field_id]);
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
//Get all oscarhostFields that haven't been mapped to a formfield
|
|
||||||
return _(oscarhostFields).difference(currentFields).value();
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** FormFields (ui-sortable) drag-and-drop configuration
|
** FormFields (ui-sortable) drag-and-drop configuration
|
||||||
|
@ -109,12 +105,13 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var newField = {
|
var newField = {
|
||||||
title: fieldTitle,
|
title: fieldTitle + ' ' + $scope.myform.form_fields.length+1,
|
||||||
fieldType: fieldType,
|
fieldType: fieldType,
|
||||||
fieldValue: '',
|
fieldValue: '',
|
||||||
required: true,
|
required: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
deletePreserved: false
|
deletePreserved: false,
|
||||||
|
logicJump: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
if($scope.showAddOptions(newField)){
|
if($scope.showAddOptions(newField)){
|
||||||
|
@ -126,7 +123,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(modifyForm){
|
if(modifyForm){
|
||||||
//Add newField to form_fields array
|
//Add newField to form_fields array
|
||||||
$scope.myform.form_fields.push(newField);
|
$scope.myform.form_fields.push(newField);
|
||||||
|
@ -135,15 +131,11 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
};
|
};
|
||||||
|
|
||||||
// Delete particular field on button click
|
// Delete particular field on button click
|
||||||
$scope.deleteField = function (field_index){
|
$scope.deleteField = function (field_index) {
|
||||||
|
console.log($scope.myform.form_fields);
|
||||||
//Delete field from field map
|
|
||||||
var currFieldId = $scope.myform.form_fields[field_index]._id;
|
|
||||||
if($scope.myform.hasOwnProperty('plugins.oscarhost.baseUrl')) delete $scope.myform.plugins.oscarhost.settings.fieldMap[currFieldId];
|
|
||||||
|
|
||||||
//Delete field
|
|
||||||
$scope.myform.form_fields.splice(field_index, 1);
|
$scope.myform.form_fields.splice(field_index, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.duplicateField = function (field_index){
|
$scope.duplicateField = function (field_index){
|
||||||
var currField = _.cloneDeep($scope.myform.form_fields[field_index]);
|
var currField = _.cloneDeep($scope.myform.form_fields[field_index]);
|
||||||
currField._id = 'cloned'+_.uniqueId();
|
currField._id = 'cloned'+_.uniqueId();
|
||||||
|
@ -249,10 +241,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -75,7 +75,6 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
|
||||||
|
|
||||||
var visitors = $scope.myform.analytics.visitors;
|
var visitors = $scope.myform.analytics.visitors;
|
||||||
|
|
||||||
console.log(visitors);
|
|
||||||
for(var i=0; i<visitors.length; i++){
|
for(var i=0; i<visitors.length; i++){
|
||||||
var visitor = visitors[i];
|
var visitor = visitors[i];
|
||||||
var deviceType = visitor.deviceType;
|
var deviceType = visitor.deviceType;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<div class="container" cg-busy="{promise:updatePromise,templateUrl:'modules/forms/admin/views/directiveViews/cgBusy/update-form-message-TypeB.html',message:'Updating form...', backdrop:false, wrapperClass:'.busy-updating-wrapper'}"></div>
|
<div class="container" cg-busy="{promise:updatePromise,templateUrl:'modules/forms/admin/views/directiveViews/cgBusy/update-form-message-TypeB.html',message:'Updating form...', backdrop:false, wrapperClass:'.busy-updating-wrapper'}"></div>
|
||||||
|
|
||||||
<section class="container admin-form">
|
<section class="admin-form">
|
||||||
|
|
||||||
<!-- Modal Delete Dialog Template -->
|
<!-- Modal Delete Dialog Template -->
|
||||||
<script type="text/ng-template" id="myModalContent.html">
|
<script type="text/ng-template" id="myModalContent.html">
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="page-header row-fluid" style="padding-bottom: 1em;">
|
<div class="page-header" style="padding-bottom: 1em;">
|
||||||
<div class="col-xs-10 col-sm-8">
|
<div class="col-xs-10 col-sm-8">
|
||||||
<h1 class="hidden-sm hidden-xs" data-ng-bind="myform.title" style="margin-bottom: 0px;"></h1>
|
<h1 class="hidden-sm hidden-xs" data-ng-bind="myform.title" style="margin-bottom: 0px;"></h1>
|
||||||
<h2 class="hidden-md hidden-lg" data-ng-bind="myform.title" style="margin-bottom: 0px;"></h2>
|
<h2 class="hidden-md hidden-lg" data-ng-bind="myform.title" style="margin-bottom: 0px;"></h2>
|
||||||
|
@ -45,19 +45,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-1 col-sm-2">
|
<div class="col-xs-1 col-sm-2">
|
||||||
<small class="pull-right">
|
<small class="pull-right">
|
||||||
<a class="btn btn-default view-form-btn" href="//{{formURL}}/#!/forms/{{myform._id}}">
|
<a class="btn btn-secondary view-form-btn" href="{{actualFormURL}}">
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ 'VIEW' | translate }}
|
{{ 'VIEW' | translate }}
|
||||||
<span ng-show="myform.isLive">
|
<span ng-show="myform.isLive">
|
||||||
{{ 'LIVE' | translate }}
|
{{ 'LIVE' | translate }}
|
||||||
</span>
|
</span>
|
||||||
<span ng-hide="myform.isLive">{{ 'PREVIEW' | translate }}</span> {{ 'FORM' | translate }}
|
<span ng-hide="myform.isLive">{{ 'PREVIEW' | translate }}</span>
|
||||||
</span>
|
|
||||||
<span class="hidden-xs hidden-md hidden-lg">
|
|
||||||
View
|
|
||||||
<span ng-if="myform.isLive">{{ 'LIVE' | translate }}</span>
|
|
||||||
<span ng-if="!myform.isLive">{{ 'PREVIEW' | translate }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
|
<!--<span class="hidden-xs hidden-md hidden-lg">-->
|
||||||
|
<!--View-->
|
||||||
|
<!--<span ng-if="myform.isLive">{{ 'LIVE' | translate }}</span>-->
|
||||||
|
<!--<span ng-if="!myform.isLive">{{ 'PREVIEW' | translate }}</span>-->
|
||||||
|
<!--</span>-->
|
||||||
<i class="status-light status-light-on fa fa-dot-circle-o" ng-if="myform.isLive"></i>
|
<i class="status-light status-light-on fa fa-dot-circle-o" ng-if="myform.isLive"></i>
|
||||||
<i class="status-light status-light-off fa fa-dot-circle-o" ng-if="!myform.isLive"></i>
|
<i class="status-light status-light-off fa fa-dot-circle-o" ng-if="!myform.isLive"></i>
|
||||||
</a>
|
</a>
|
||||||
|
@ -65,16 +65,133 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row-fluid">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<!-- <tabset> -->
|
<uib-tabset active="activePill" vertical="true" type="pills">
|
||||||
<tabs data="tabData"></tabs>
|
<uib-tab index="0" heading="{{ 'CREATE_TAB' | translate }}">
|
||||||
<!-- </tabset> -->
|
<edit-form-directive myform="myform"></edit-form-directive>
|
||||||
</div>
|
</uib-tab>
|
||||||
|
<uib-tab ng-repeat="tab in tabData" index="{{$index}}+1" heading="{{tab.heading}}">
|
||||||
|
<div class='row' data-ng-include="'/static/modules/forms/admin/views/adminTabs/'+tab.templateName+'.html'" onload="form_url = trustSrc(formURL)"></div>
|
||||||
|
</uib-tab>
|
||||||
|
<uib-tab ng-if="tabData" heading="Share" index="{{tabData.length}}">
|
||||||
|
<div class="config-form">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<uib-tabset active="activePill" vertical="true" type="pills">
|
||||||
|
<uib-tab index="0" heading="Share your Form">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
Your TellForm is permanently at this URL
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-8 form-input">
|
||||||
|
<span ngclipboard data-clipboard-target="#copyURL"> <input id="copyURL" ng-value="actualFormURL" class="form-control ng-pristine ng-untouched ng-valid"> </span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<button class="btn btn btn-secondary view-form-btn" ngclipboard data-clipboard-target="#copyURL">
|
||||||
|
Copy <i class="fa fa-clipboard" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</uib-tab>
|
||||||
|
<uib-tab index="1" heading="Embed your Form">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
Copy and Paste this to add your TellForm to your website
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-8 form-input">
|
||||||
|
<span ngclipboard data-clipboard-target="#copyEmbedded">
|
||||||
|
<textarea id="copyEmbedded" class="form-control ng-pristine ng-untouched ng-valid" style="min-height:200px; width:100%; background-color: #FFFFCC; color: #30313F;">
|
||||||
|
<!-- Change the width and height values to suit you best -->
|
||||||
|
<iframe id="iframe" ng-if="!!formURL" src="{{trustSrc(formURL)}}" style="width:100%;height:500px;"></iframe>
|
||||||
|
<div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;">Powered by<a href="https://www.tellform.com" style="color: #999" target="_blank">TellForm</a></div>
|
||||||
|
</textarea>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<button class="btn btn btn-secondary view-form-btn" ngclipboard data-clipboard-target="#copyEmbedded">
|
||||||
|
Copy <i class="fa fa-clipboard" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</uib-tab>
|
||||||
|
</uib-tabset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</uib-tab>
|
||||||
|
<uib-tab ng-if="tabData && myform.form_fields.length" heading="Design" index="{{tabData.length}}+1">
|
||||||
|
<div class="config-form design container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 col-sm-12 container">
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-5">
|
||||||
|
<h5>{{ 'BACKGROUND_COLOR' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
<div class="field-input col-sm-6">
|
||||||
|
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.backgroundColor" ng-style="{ 'background-color': myform.design.colors.backgroundColor }"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-12">
|
<div class="row field">
|
||||||
<ui-view></ui-view>
|
<div class="field-title col-sm-5">
|
||||||
</div>
|
<h5>{{ 'QUESTION_TEXT_COLOR' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-input col-sm-6">
|
||||||
|
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.questionColor" ng-style="{ 'background-color': myform.design.colors.questionColor }"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-5">
|
||||||
|
<h5>{{ 'ANSWER_TEXT_COLOR' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-input col-sm-6">
|
||||||
|
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.answerColor" ng-style="{ 'background-color': myform.design.colors.answerColor }"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-5">
|
||||||
|
<h5>{{ 'BTN_BACKGROUND_COLOR' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-input col-sm-6">
|
||||||
|
<input class="form-control" colorpicker="hex" type="text"
|
||||||
|
ng-model="myform.design.colors.buttonColor"
|
||||||
|
ng-style="{ 'background-color': myform.design.colors.buttonColor }"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-5">
|
||||||
|
<h5>{{ 'BTN_TEXT_COLOR' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-input col-sm-6">
|
||||||
|
<input class="form-control" colorpicker="hex" type="text"
|
||||||
|
ng-model="myform.design.colors.buttonTextColor"
|
||||||
|
ng-style="{ 'background-color': myform.design.colors.buttonTextColor }"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8 hide-md hide-lg">
|
||||||
|
<iframe id="iframe" ng-if="!!formURL" src="{{trustSrc(formURL)}}" style="border: none; box-shadow: 0px 0px 10px 0px grey; overflow: hidden; height: 400px; width: 90%; position: absolute;"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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, null)"><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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</uib-tab>
|
||||||
|
</uib-tabset>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,21 +1,12 @@
|
||||||
<div class="config-form design container">
|
<div class="config-form design container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 container">
|
<div class="col-md-4 col-sm-12 container">
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<h2 class="hidden-sm hidden-xs">{{ 'DESIGN_HEADER' | translate }}</h2>
|
|
||||||
<h3 class="hidden-lg hidden-md">{{ 'DESIGN_HEADER' | translate }}</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row field">
|
<div class="row field">
|
||||||
<div class="field-title col-sm-3">
|
<div class="field-title col-sm-3">
|
||||||
<h5>{{ 'BACKGROUND_COLOR' | translate }}</h5>
|
<h5>{{ 'BACKGROUND_COLOR' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field-input col-sm-6">
|
||||||
<div class="field-input col-sm-9">
|
<input ng-change="refreshIframe()" class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.backgroundColor" ng-style="{ 'background-color': myform.design.colors.backgroundColor }"/>
|
||||||
|
|
||||||
<input colorpicker="hex" type="text" ng-model="myform.design.colors.backgroundColor" ng-style="{ 'background-color': myform.design.colors.backgroundColor }"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -24,11 +15,8 @@
|
||||||
<h5>{{ 'QUESTION_TEXT_COLOR' | translate }}</h5>
|
<h5>{{ 'QUESTION_TEXT_COLOR' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-input col-sm-9">
|
<div class="field-input col-sm-6">
|
||||||
|
<input ng-change="refreshIframe()" class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.questionColor" ng-style="{ 'background-color': myform.design.colors.questionColor }"/>
|
||||||
<input colorpicker="hex" type="text" ng-model="myform.design.colors.questionColor" ng-style="{ 'background-color': myform.design.colors.questionColor }"/>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -37,8 +25,8 @@
|
||||||
<h5>{{ 'ANSWER_TEXT_COLOR' | translate }}</h5>
|
<h5>{{ 'ANSWER_TEXT_COLOR' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-input col-sm-9">
|
<div class="field-input col-sm-6">
|
||||||
<input colorpicker="hex" type="text" ng-model="myform.design.colors.answerColor" ng-style="{ 'background-color': myform.design.colors.answerColor }"/>
|
<input ng-change="refreshIframe()" class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.answerColor" ng-style="{ 'background-color': myform.design.colors.answerColor }"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -47,8 +35,8 @@
|
||||||
<h5>{{ 'BTN_BACKGROUND_COLOR' | translate }}</h5>
|
<h5>{{ 'BTN_BACKGROUND_COLOR' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-input col-sm-9">
|
<div class="field-input col-sm-6">
|
||||||
<input colorpicker="hex" type="text"
|
<input ng-change="refreshIframe()" class="form-control" colorpicker="hex" type="text"
|
||||||
ng-model="myform.design.colors.buttonColor"
|
ng-model="myform.design.colors.buttonColor"
|
||||||
ng-style="{ 'background-color': myform.design.colors.buttonColor }"/>
|
ng-style="{ 'background-color': myform.design.colors.buttonColor }"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,21 +46,24 @@
|
||||||
<h5>{{ 'BTN_TEXT_COLOR' | translate }}</h5>
|
<h5>{{ 'BTN_TEXT_COLOR' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-input col-sm-9">
|
<div class="field-input col-sm-6">
|
||||||
<input colorpicker="hex" type="text"
|
<input ng-change="refreshIframe()" class="form-control" colorpicker="hex" type="text"
|
||||||
ng-model="myform.design.colors.buttonTextColor"
|
ng-model="myform.design.colors.buttonTextColor"
|
||||||
ng-style="{ 'background-color': myform.design.colors.buttonTextColor }"/>
|
ng-style="{ 'background-color': myform.design.colors.buttonTextColor }"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-8 hide-md hide-lg">
|
||||||
|
<iframe refreshable="refreshDesign" ng-if="!!form_url" src="{{form_url}}" style="border: none; box-shadow: 0px 0px 10px 0px grey; overflow: hidden; height: 95vh; width: 90%; position: absolute;"></iframe>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-offset-4 col-sm-2">
|
<div class="col-sm-offset-4 col-sm-2">
|
||||||
<button class="btn btn-primary btn-large" type="button" ng-click="update(false, null)"><i class="icon-arrow-left icon-white"></i> Save Changes</button>
|
<button class="btn btn-signup btn-rounded" type="button" ng-click="update(false, null)"><i class="icon-arrow-left icon-white"></i>{{ 'SAVE_CHANGES' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
<button class="btn btn-default" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i> Cancel</button>
|
<button class="btn btn-secondary btn-rounded" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i>{{ 'CANCEL' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
<div class="config-form container">
|
<div class="config-form container">
|
||||||
<div class="row">
|
<!--<div class="row">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<!-- Settings -->
|
<h2 class="hidden-sm hidden-xs">{{ 'ADVANCED_SETTINGS' | translate }}</h2>
|
||||||
<div class="col-sm-12 container-fluid">
|
<h3 class="hidden-lg hidden-md">{{ 'ADVANCED_SETTINGS' | translate }}</h3>
|
||||||
<div class="row">
|
</div>
|
||||||
<div class="col-sm-12">
|
</div>-->
|
||||||
<h2 class="hidden-sm hidden-xs">{{ 'ADVANCED_SETTINGS' | translate }}</h2>
|
<!-- Settings -->
|
||||||
<h3 class="hidden-lg hidden-md">{{ 'ADVANCED_SETTINGS' | translate }}</h3>
|
<div class="row">
|
||||||
</div>
|
<div class="col-sm-offset-2 col-sm-4">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row field">
|
<div class="row field">
|
||||||
<div class="field-title col-sm-4">
|
<div class="field-title col-sm-12">
|
||||||
<h5>{{ 'FORM_NAME' | translate }}</h5>
|
<h5>{{ 'FORM_NAME' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-12">
|
||||||
<input type="text"
|
<input class="form-control"
|
||||||
|
type="text"
|
||||||
ng-model="myform.title"
|
ng-model="myform.title"
|
||||||
value="{{myform.title}}"
|
value="{{myform.title}}"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
|
@ -26,18 +25,18 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row field">
|
<div class="row field">
|
||||||
<div class="field-title col-sm-6">
|
<div class="field-title col-sm-12">
|
||||||
<h5>{{ 'FORM_STATUS' | translate }}</h5>
|
<h5>{{ 'FORM_STATUS' | translate }}</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-input col-sm-6">
|
<div class="field-input col-sm-12">
|
||||||
|
|
||||||
<label>
|
<label style="display: inline-block;">
|
||||||
<input type="radio" data-ng-value="true" ng-model="myform.isLive" ng-required="true" style="background-color:#33CC00;"/>
|
<input type="radio" data-ng-value="true" ng-model="myform.isLive" ng-required="true" style="background-color:#33CC00;"/>
|
||||||
<span>{{ 'PUBLIC' | translate }}</span>
|
<span>{{ 'PUBLIC' | translate }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label>
|
<label style="display: inline-block;">
|
||||||
<input type="radio" data-ng-value="false" ng-model="myform.isLive" ng-required="true" />
|
<input type="radio" data-ng-value="false" ng-model="myform.isLive" ng-required="true" />
|
||||||
<span>{{ 'PRIVATE' | translate }}</span>
|
<span>{{ 'PRIVATE' | translate }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -45,25 +44,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row field">
|
|
||||||
<div class="field-title col-sm-4">
|
|
||||||
<h5>{{ 'GA_TRACKING_CODE' | translate }}</h5>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="myform.analytics.gaCode"
|
|
||||||
value="{{myform.analytics.gaCode}}"
|
|
||||||
style="width: 100%;"
|
|
||||||
ng-minlength="4"
|
|
||||||
placeholder="UA-XXXXX-Y"
|
|
||||||
ng-pattern="/\bUA-\d{4,10}-\d{1,4}\b/">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row field">
|
<div class="row field">
|
||||||
<div class="col-xs-6 field-title">Language</div>
|
<div class="col-sm-12 field-title">Language</div>
|
||||||
<div class="col-xs-4 field-input">
|
<div class="col-sm-12 field-input">
|
||||||
<select ng-model="myform.language">
|
<select ng-model="myform.language">
|
||||||
<option ng-repeat="language in languages"
|
<option ng-repeat="language in languages"
|
||||||
ng-selected="language == myform.language"
|
ng-selected="language == myform.language"
|
||||||
|
@ -74,51 +57,69 @@
|
||||||
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
|
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row field">
|
|
||||||
<div class="field-title col-sm-6">
|
|
||||||
<h5>{{ 'DISPLAY_FOOTER' | translate }}</h5>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="field-input col-sm-6">
|
|
||||||
<label>
|
|
||||||
<input type="radio" data-ng-value="false" ng-model="myform.hideFooter" ng-required="true" />
|
|
||||||
<span>{{ 'YES' | translate }}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label>
|
|
||||||
<input type="radio" data-ng-value="true" ng-model="myform.hideFooter" ng-required="true" />
|
|
||||||
<span>{{ 'No' | translate }}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row field">
|
|
||||||
<div class="field-title col-sm-6">
|
|
||||||
<h5>Display Start Page?</h5>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="field-input col-sm-6">
|
|
||||||
|
|
||||||
<label>
|
|
||||||
<input type="radio" data-ng-value="true" ng-model="myform.startPage.showStart" ng-required="true" style="background-color:#33CC00;"/>
|
|
||||||
<span>{{ 'YES' | translate }}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label>
|
|
||||||
<input type="radio" data-ng-value="false" ng-model="myform.startPage.showStart" ng-required="true" />
|
|
||||||
<span>{{ 'NO' | translate }}</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-12">
|
||||||
|
<h5>{{ 'GA_TRACKING_CODE' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<input class="form-control"
|
||||||
|
type="text"
|
||||||
|
ng-model="myform.analytics.gaCode"
|
||||||
|
value="{{myform.analytics.gaCode}}"
|
||||||
|
style="width: 100%;"
|
||||||
|
ng-minlength="4"
|
||||||
|
placeholder="UA-XXXXX-Y"
|
||||||
|
ng-pattern="/\bUA-\d{4,10}-\d{1,4}\b/">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-12">
|
||||||
|
<h5>{{ 'DISPLAY_FOOTER' | translate }}</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-input col-sm-12">
|
||||||
|
<label style="display: inline-block;">
|
||||||
|
<input type="radio" data-ng-value="false" ng-model="myform.hideFooter" ng-required="true" />
|
||||||
|
<span>{{ 'YES' | translate }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label style="display: inline-block;">
|
||||||
|
<input type="radio" data-ng-value="true" ng-model="myform.hideFooter" ng-required="true" />
|
||||||
|
<span>{{ 'No' | translate }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row field">
|
||||||
|
<div class="field-title col-sm-12">
|
||||||
|
<h5>Display Start Page?</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-input col-sm-12">
|
||||||
|
|
||||||
|
<label style="display: inline-block;">
|
||||||
|
<input type="radio" data-ng-value="true" ng-model="myform.startPage.showStart" ng-required="true" style="background-color:#33CC00;"/>
|
||||||
|
<span>{{ 'YES' | translate }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label style="display: inline-block;">
|
||||||
|
<input type="radio" data-ng-value="false" ng-model="myform.startPage.showStart" ng-required="true" />
|
||||||
|
<span>{{ 'NO' | translate }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-offset-4 col-sm-2">
|
<div class="col-sm-offset-4 col-sm-2">
|
||||||
<button class="btn btn-primary btn-large" type="button" ng-click="update(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="update(false, null)"><i class="icon-arrow-left icon-white"></i>{{ 'SAVE_CHANGES' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
<button class="btn btn-default" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i>{{ 'CANCEL' | translate }}</button>
|
<button class="btn btn-secondary btn-rounded" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i>{{ 'CANCEL' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<form class="row container" name="editForm" auto-save-form auto-save-watch="myform" auto-save-callback="update">
|
<form class="row container" name="editForm" auto-save-form auto-save-watch="myform" auto-save-callback="update">
|
||||||
|
|
||||||
<!-- Add Fields Element -->
|
<!-- Add Fields Element -->
|
||||||
<div class="col-xs-2 col-sm-4 col-md-4 add-field">
|
<div class="col-xs-2 col-sm-4 add-field">
|
||||||
|
|
||||||
<div class="row add-field-title">
|
<div class="row add-field-title">
|
||||||
<h3 class="col-md-12 hidden-sm hidden-xs">{{ 'ADD_FIELD_LG' | translate }}</h3>
|
<h3 class="col-md-12 hidden-sm hidden-xs">{{ 'ADD_FIELD_LG' | translate }}</h3>
|
||||||
|
@ -249,7 +249,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="row" ng-show="showRatingOptions(field)"><br></div>
|
<div class="row" ng-show="showRatingOptions(field)"><br></div>
|
||||||
<div class="row" ng-if="showRatingOptions(field)">
|
<div class="row" ng-if="showRatingOptions(field)">
|
||||||
<div class="col-md-9 col-sm-9">{{ 'NUM_OF_STEPS' | translate }}</div>
|
<div class="col-md-9 col-sm-9">{{ 'NUM_OF_STEPS' | translate }}</div>
|
||||||
|
@ -293,7 +292,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4 col-xs-12 field-input">Disabled:</div>
|
<div class="col-md-4 col-xs-12 field-input">{{ 'DISABLED' | translate }}</div>
|
||||||
<div class="col-md-8 col-xs-12 field-input">
|
<div class="col-md-8 col-xs-12 field-input">
|
||||||
<label class="btn col-xs-5">
|
<label class="btn col-xs-5">
|
||||||
<input type="radio" ng-value="true"
|
<input type="radio" ng-value="true"
|
||||||
|
@ -309,6 +308,106 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row" ng-if="myform.form_fields.length > 1">
|
||||||
|
<h4> Logic Jump </h4>
|
||||||
|
</div>
|
||||||
|
<div class="row" ng-if="myform.form_fields.length > 1">
|
||||||
|
<div class="col-md-4 col-xs-12 field-input">{{ 'ADD_LOGIC_JUMP' | translate }}</div>
|
||||||
|
<div class="col-md-8 col-xs-12 field-input">
|
||||||
|
<label class="btn col-xs-5">
|
||||||
|
<input type="radio" ng-checked="!!myform.form_fields[$index].logicJump.fieldA"
|
||||||
|
name="logicJumpYes{{field._id}}" ng-click="addNewLogicJump($index)"/>
|
||||||
|
<span> {{ 'YES' | translate }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="btn col-xs-5 col-xs-offset-1">
|
||||||
|
<input type="radio" ng-checked="!myform.form_fields[$index].logicJump.fieldA"
|
||||||
|
name="logicJumpNo{{field._id}}" ng-click="removeLogicJump($index)"/>
|
||||||
|
<span> {{ 'NO' | translate }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row question" ng-if="myform.form_fields.length > 1 && myform.form_fields[$index].logicJump.fieldA">
|
||||||
|
<div class="col-md-4 col-sm-12">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
<b> If this field </b>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-sm-12">
|
||||||
|
<select style="width:100%" ng-model="field.logicJump.expressionString"
|
||||||
|
value="{{field.logicJump.expressionString}}"
|
||||||
|
name="logicjump_expressionString{{field._id}}">
|
||||||
|
<option value="field == static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
is equal to
|
||||||
|
</option>
|
||||||
|
<option value="field != static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
is not equal to
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="field > static" ng-if-start="field.fieldType === 'number' || field.fieldType === 'rating' || field.fieldType === 'number'">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
is greater than
|
||||||
|
</option>
|
||||||
|
<option value="field >= static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
is greater or equal than
|
||||||
|
</option>
|
||||||
|
<option value="field < static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
is smaller than
|
||||||
|
</option>
|
||||||
|
<option value="field <= static" ng-if-end>
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
is smaller or equal than
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="field contains static" ng-if-start="field.fieldType !== 'number' && field.fieldType !== 'rating' && field.fieldType !== 'number'">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
contains
|
||||||
|
</option>
|
||||||
|
<option value="field !contains static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
does not contain
|
||||||
|
</option>
|
||||||
|
<option value="field ends static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
ends with
|
||||||
|
</option>
|
||||||
|
<option value="field !ends static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
does not end with
|
||||||
|
</option>
|
||||||
|
<option value="field starts static">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
starts with
|
||||||
|
</option>
|
||||||
|
<option value="field !starts static" ng-if-end>
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
does not start with
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-sm-12">
|
||||||
|
<input type="text" ng-model="field.logicJump.valueB"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<!-- FIX ME: translate this -->
|
||||||
|
<b>Jumps to </b>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<select style="width:100%" ng-model="field.logicJump.jumpTo"
|
||||||
|
value="{{field.logicJump.jumpTo}}"
|
||||||
|
name="logicjump_jumpTo{{field._id}}">
|
||||||
|
<option ng-repeat="jump_field in myform.form_fields"
|
||||||
|
value="{{jump_field._id}}">
|
||||||
|
{{jump_field.title}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</accordion-group>
|
</accordion-group>
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<div class="submissions-table row container">
|
<div class="submissions-table container">
|
||||||
<div class="row text-center analytics">
|
<div class="row text-center analytics">
|
||||||
<div class="row col-xs-12 header-numbers">
|
<div class="col-xs-12 header-title">
|
||||||
Overview Analytics
|
|
||||||
</div>
|
|
||||||
<div class="row col-xs-12 header-title">
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{ 'TOTAL_VIEWS' | translate }}
|
{{ 'TOTAL_VIEWS' | translate }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +17,7 @@
|
||||||
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row col-xs-12 header-numbers">
|
<div class="col-xs-12 header-numbers">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{myform.analytics.views}}
|
{{myform.analytics.views}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,10 +34,7 @@
|
||||||
{{AverageTimeElapsed | secondsToDateTime | date:'mm:ss'}}
|
{{AverageTimeElapsed | secondsToDateTime | date:'mm:ss'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row col-xs-12 header-numbers">
|
<div class="col-xs-12 detailed-title">
|
||||||
Device Analytics
|
|
||||||
</div>
|
|
||||||
<div class="row col-xs-12 detailed-title">
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{ 'DESKTOP_AND_LAPTOP' | translate }}
|
{{ 'DESKTOP_AND_LAPTOP' | translate }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,7 +52,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-xs-12 detailed-row">
|
<div class="col-xs-12 detailed-row">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<div class="row header">
|
<div class="row header">
|
||||||
{{ 'UNIQUE_VISITS' | translate }}
|
{{ 'UNIQUE_VISITS' | translate }}
|
||||||
|
@ -96,7 +90,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-xs-12 detailed-row">
|
<div class="col-xs-12 detailed-row">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<div class="row header">
|
<div class="row header">
|
||||||
{{ 'RESPONSES' | translate }}
|
{{ 'RESPONSES' | translate }}
|
||||||
|
@ -134,7 +128,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-xs-12 detailed-row">
|
<div class="col-xs-12 detailed-row">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<div class="row header">
|
<div class="row header">
|
||||||
{{ 'COMPLETION_RATE' | translate }}
|
{{ 'COMPLETION_RATE' | translate }}
|
||||||
|
@ -172,7 +166,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-xs-12 detailed-row">
|
<div class="col-xs-12 detailed-row">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<div class="row header">
|
<div class="row header">
|
||||||
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
{{ 'AVERAGE_TIME_TO_COMPLETE' | translate }}
|
||||||
|
@ -210,10 +204,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-xs-12 text-center" style="font-size:5em;">
|
<div class="col-xs-12 field-title-row">
|
||||||
Field Analytics
|
|
||||||
</div>
|
|
||||||
<div class="row col-xs-12 field-title-row">
|
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<strong>{{ 'FIELD_TITLE' | translate }}</strong>
|
<strong>{{ 'FIELD_TITLE' | translate }}</strong>
|
||||||
|
@ -230,7 +221,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col-xs-12 field-detailed-row" ng-repeat="fieldStats in myform.analytics.fields">
|
<div class="col-xs-12 field-detailed-row" ng-repeat="fieldStats in myform.analytics.fields">
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
{{fieldStats.field.title}}
|
{{fieldStats.field.title}}
|
||||||
|
@ -247,9 +238,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="row col-xs-12 header-numbers text-center" style="font-size:5em;">
|
|
||||||
Responses Table
|
|
||||||
</div>
|
|
||||||
<div class="row table-tools">
|
<div class="row table-tools">
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-2">
|
||||||
<button class="btn btn-danger" ng-click="deleteSelectedSubmissions()" ng-disabled="!isAtLeastOneChecked();">
|
<button class="btn btn-danger" ng-click="deleteSelectedSubmissions()" ng-disabled="!isAtLeastOneChecked();">
|
||||||
|
|
|
@ -4,6 +4,13 @@
|
||||||
|
|
||||||
<section data-ng-controller="ListFormsController as ctrl" data-ng-init="findAll()" class="container">
|
<section data-ng-controller="ListFormsController as ctrl" data-ng-init="findAll()" class="container">
|
||||||
<br>
|
<br>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4 col-xs-offset-4">
|
||||||
|
<h3 class="text-center forms-list-title">
|
||||||
|
My Forms
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div ng-click="openCreateModal()" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item create-new">
|
<div ng-click="openCreateModal()" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item create-new">
|
||||||
<div class="title-row col-xs-12">
|
<div class="title-row col-xs-12">
|
||||||
|
@ -47,8 +54,8 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div data-ng-repeat="form in myforms"
|
<div data-ng-repeat="form in myforms"
|
||||||
ng-style="{ 'background-color': form.design.colors.backgroundColor, 'color': form.design.colors.answerColor }"
|
class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item container"
|
||||||
class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item container">
|
ng-class="{'paused': !form.isLive}">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
|
@ -58,21 +65,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<a data-ng-href="#!/forms/{{form._id}}/admin/create"
|
<a data-ng-href="#!/forms/{{form._id}}/admin/create"
|
||||||
ng-style="{ 'color': form.design.colors.answerColor }"
|
class="title-row col-xs-12">
|
||||||
class="title-row col-xs-12">
|
<h4 class="list-group-item-heading" data-ng-bind="form.title"></h4>
|
||||||
<h4 class="list-group-item-heading" data-ng-bind="form.title"></h4>
|
</a>
|
||||||
</a>
|
<div class="col-xs-12 responses-row">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row footer">
|
|
||||||
<div class="col-xs-12 details-row">
|
|
||||||
|
|
||||||
<small class="list-group-item-text">
|
<small class="list-group-item-text">
|
||||||
{{ 'CREATED_ON' | translate }}
|
<span> {{ form.submissions.length }} responses </span>
|
||||||
<span data-ng-bind="form.created | date:'shortDate'"></span>
|
</small>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<small ng-if="!form.isLive" class="list-group-item-text">
|
||||||
|
<span> Form Paused </span>
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
0
public/modules/forms/base/bower.json
Executable file → Normal file
0
public/modules/forms/base/bower.json
Executable file → Normal file
|
@ -1,3 +1,19 @@
|
||||||
|
/* Custom Tab CSS */
|
||||||
|
.nav.nav-pills.nav-stacked {
|
||||||
|
width: 16.66666667%;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
min-height: 1px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
div.tab-content {
|
||||||
|
width: 83.33333333%;
|
||||||
|
position: relative;
|
||||||
|
min-height: 1px;
|
||||||
|
float:left;
|
||||||
|
padding-top: 0!important;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-default.startPage {
|
.panel-default.startPage {
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
border-color: #a9a9a9;
|
border-color: #a9a9a9;
|
||||||
|
@ -302,6 +318,8 @@ div.config-form .row.field {
|
||||||
}
|
}
|
||||||
.admin-form .page-header {
|
.admin-form .page-header {
|
||||||
border: none;
|
border: none;
|
||||||
|
margin-top: none;
|
||||||
|
margin-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Styles for admin view tabs */
|
/*Styles for admin view tabs */
|
||||||
|
@ -419,16 +437,26 @@ section.public-form .btn {
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-item {
|
.form-item {
|
||||||
|
border-radius: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 6px inset #ccc;
|
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
/*width:100%;*/
|
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 215px;
|
height: 215px;
|
||||||
/*padding-bottom: 25%;*/
|
|
||||||
margin-bottom: 45px;
|
margin-bottom: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-item.paused {
|
||||||
|
background-color: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item.paused:hover {
|
||||||
|
background-color: darkred;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.form-item.create-new input[type='text']{
|
.form-item.create-new input[type='text']{
|
||||||
width: inherit;
|
width: inherit;
|
||||||
color:black;
|
color:black;
|
||||||
|
@ -436,17 +464,22 @@ section.public-form .btn {
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-item.create-new {
|
.form-item.create-new {
|
||||||
background-color: rgb(131,131,131);
|
background-color: #3FA2F7;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-item.create-new:hover {
|
||||||
|
background-color: #276496;
|
||||||
|
}
|
||||||
|
|
||||||
/*CREATE-NEW FORM MODAL*/
|
/*CREATE-NEW FORM MODAL*/
|
||||||
.form-item.create-new.new-form {
|
.form-item.create-new.new-form {
|
||||||
background-color: rgb(300,131,131);
|
background-color: rgb(300,131,131);
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
}
|
}
|
||||||
.form-item.create-new.new-form:hover {
|
.form-item.create-new.new-form:hover {
|
||||||
background-color: rgb(300,100,100);
|
background-color: #3079b5;
|
||||||
}
|
}
|
||||||
.form-item.new-form input[type='text'] {
|
.form-item.new-form input[type='text'] {
|
||||||
margin-top:0.2em;
|
margin-top:0.2em;
|
||||||
|
@ -513,10 +546,23 @@ section.public-form .btn {
|
||||||
.activeField input {
|
.activeField input {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
h3.forms-list-title {
|
||||||
|
color: #3FA2F7;
|
||||||
|
weight: 600;
|
||||||
|
margin-bottom: 3em;
|
||||||
|
}
|
||||||
|
.form-item {
|
||||||
|
color: #71AADD;
|
||||||
|
background-color: #E4F1FD;
|
||||||
|
}
|
||||||
|
.form-item:hover {
|
||||||
|
background-color: #3FA2F7;
|
||||||
|
color: #23527C;
|
||||||
|
}
|
||||||
|
|
||||||
.form-item:hover, .form-item.create-new:hover {
|
.form-item.create-new:hover {
|
||||||
border-bottom: 8px inset #ccc;
|
|
||||||
background-color: #d9d9d9;
|
background-color: #d9d9d9;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-item.create-new:hover {
|
.form-item.create-new:hover {
|
||||||
|
@ -529,15 +575,17 @@ section.public-form .btn {
|
||||||
left: 30%;
|
left: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-item .title-row{
|
.form-item .title-row {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
padding-top:3em;
|
padding-top:3em;
|
||||||
padding-bottom:3.65em;
|
padding-bottom:1em;
|
||||||
}
|
}
|
||||||
.form-item .title-row h4 {
|
.form-item .title-row h4 {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
}
|
}
|
||||||
|
.form-item .responses-row {
|
||||||
|
}
|
||||||
|
|
||||||
.form-item.create-new .title-row{
|
.form-item.create-new .title-row{
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -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'){
|
if(scope.field.fieldType === 'number' || scope.field.fieldType === 'textfield' || scope.field.fieldType === 'email' || scope.field.fieldType === 'link'){
|
||||||
switch(scope.field.fieldType){
|
switch(scope.field.fieldType){
|
||||||
case 'textfield':
|
case 'textfield':
|
||||||
scope.field.input_type = 'text';
|
scope.input_type = 'text';
|
||||||
break;
|
break;
|
||||||
case 'email':
|
case 'email':
|
||||||
scope.field.input_type = 'email';
|
scope.input_type = 'email';
|
||||||
scope.field.placeholder = 'joesmith@example.com';
|
scope.placeholder = 'joesmith@example.com';
|
||||||
break;
|
break;
|
||||||
case 'number':
|
case 'number':
|
||||||
scope.field.input_type = 'text';
|
scope.input_type = 'text';
|
||||||
scope.field.validateRegex = /^-?\d+$/;
|
scope.validateRegex = /^-?\d+$/;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
scope.field.input_type = 'url';
|
scope.input_type = 'url';
|
||||||
scope.field.placeholder = 'http://example.com';
|
scope.placeholder = 'http://example.com';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fieldType = 'textfield';
|
fieldType = 'textfield';
|
||||||
}
|
}
|
||||||
|
|
||||||
var template = getTemplateUrl(fieldType);
|
var template = getTemplateUrl(fieldType);
|
||||||
element.html(template).show();
|
element.html(template).show();
|
||||||
var output = $compile(element.contents())(scope);
|
var output = $compile(element.contents())(scope);
|
||||||
|
|
0
public/modules/forms/base/views/directiveViews/field/date.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/date.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/dropdown.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/dropdown.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/hidden.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/hidden.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/radio.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/radio.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/textarea.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/field/textarea.html
Executable file → Normal file
86
public/modules/forms/base/views/directiveViews/field/textfield.html
Executable file → Normal file
86
public/modules/forms/base/views/directiveViews/field/textfield.html
Executable file → Normal file
|
@ -1,8 +1,8 @@
|
||||||
<div class="textfield field row"
|
<div class="textfield field row"
|
||||||
ng-click="setActiveField(field._id, index, true)">
|
ng-click="setActiveField(field._id, index, true)">
|
||||||
<div class="col-xs-12 field-title row-fluid" ng-style="{'color': design.colors.questionColor}">
|
<div class="col-xs-12 field-title row-fluid" ng-style="{'color': design.colors.questionColor}">
|
||||||
<h3 class="col-xs-12">
|
<h3 class="col-xs-12">
|
||||||
<small class="field-number">
|
<small class="field-number">
|
||||||
{{index+1}}
|
{{index+1}}
|
||||||
<i class="fa fa-angle-double-right" aria-hidden="true"></i>
|
<i class="fa fa-angle-double-right" aria-hidden="true"></i>
|
||||||
</small>
|
</small>
|
||||||
|
@ -12,54 +12,54 @@
|
||||||
<span class="required-error" ng-show="!field.required">
|
<span class="required-error" ng-show="!field.required">
|
||||||
({{ 'OPTIONAL' | translate }})
|
({{ 'OPTIONAL' | translate }})
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<p class="col-xs-12">
|
<p class="col-xs-12">
|
||||||
<small>{{field.description}}</small>
|
<small>{{field.description}}</small>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
|
<input ng-style="{'color': design.colors.answerColor, 'border-color': design.colors.answerColor}"
|
||||||
name="{{field.fieldType}}{{index}}"
|
name="{{field.fieldType}}{{index}}"
|
||||||
type="{{field.input_type}}"
|
type="{{input_type}}"
|
||||||
ng-pattern="field.validateRegex"
|
ng-pattern="validateRegex"
|
||||||
placeholder="{{field.placeholder}}"
|
placeholder="{{placeholder}}"
|
||||||
ng-class="{ 'no-border': !!field.fieldValue }"
|
ng-class="{ 'no-border': !!field.fieldValue }"
|
||||||
class="focusOn text-field-input"
|
class="focusOn text-field-input"
|
||||||
ng-model="field.fieldValue"
|
ng-model="field.fieldValue"
|
||||||
ng-model-options="{ debounce: 250 }"
|
ng-model-options="{ debounce: 250 }"
|
||||||
value="field.fieldValue"
|
value="field.fieldValue"
|
||||||
ng-focus="setActiveField(field._id, index, true)"
|
ng-focus="setActiveField(field._id, index, true)"
|
||||||
on-enter-or-tab-key="nextField()"
|
on-enter-or-tab-key="nextField()"
|
||||||
on-tab-and-shift-key="prevField()"
|
on-tab-and-shift-key="prevField()"
|
||||||
ng-required="field.required"
|
ng-required="field.required"
|
||||||
ng-disabled="field.disabled"
|
ng-disabled="field.disabled"
|
||||||
aria-describedby="inputError2Status">
|
aria-describedby="inputError2Status">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12">
|
<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">
|
<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="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
|
||||||
<span class="sr-only">Error:</span>
|
<span class="sr-only">Error:</span>
|
||||||
<span ng-if="field.fieldType == 'email'"> {{ 'ERROR_EMAIL_INVALID' | translate }} </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.validateRegex"> {{ 'ERROR_NOT_A_NUMBER' | translate }} </span>
|
||||||
<span ng-if="field.fieldType == 'link'"> {{ 'ERROR_URL_INVALID' | translate }} </span>
|
<span ng-if="field.fieldType == 'link'"> {{ 'ERROR_URL_INVALID' | translate }} </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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)">
|
style="padding: 4px; margin-top:8px; background: rgba(255,255,255,0.5)">
|
||||||
<button ng-disabled="!field.fieldValue || forms.myForm.{{field.fieldType}}{{$index}}.$invalid"
|
<button ng-disabled="!field.fieldValue || forms.myForm.{{field.fieldType}}{{$index}}.$invalid"
|
||||||
ng-style="{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"
|
ng-style="{'background-color':design.colors.buttonColor, 'color':design.colors.buttonTextColor}"
|
||||||
ng-click="$root.nextField()"
|
ng-click="$root.nextField()"
|
||||||
class="btn col-sm-5 col-xs-5">
|
class="btn col-sm-5 col-xs-5">
|
||||||
|
|
||||||
{{ 'OK' | translate }} <i class="fa fa-check"></i>
|
{{ 'OK' | translate }} <i class="fa fa-check"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="col-xs-6 col-sm-3" 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%">
|
<small style="color:#ddd; font-size:70%">
|
||||||
{{ 'ENTER' | translate }}
|
{{ 'ENTER' | translate }}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
0
public/modules/forms/base/views/directiveViews/form/submit-form.client.view.html
Executable file → Normal file
0
public/modules/forms/base/views/directiveViews/form/submit-form.client.view.html
Executable file → Normal file
|
@ -13,7 +13,7 @@
|
||||||
// Create a controller method for sending visitor data
|
// Create a controller method for sending visitor data
|
||||||
function send(form, lastActiveIndex, timeElapsed) {
|
function send(form, lastActiveIndex, timeElapsed) {
|
||||||
// Create a new message object
|
// Create a new message object
|
||||||
var visitorData = {
|
/*var visitorData = {
|
||||||
referrer: document.referrer,
|
referrer: document.referrer,
|
||||||
isSubmitted: form.submitted,
|
isSubmitted: form.submitted,
|
||||||
formId: form._id,
|
formId: form._id,
|
||||||
|
@ -42,15 +42,15 @@
|
||||||
}
|
}
|
||||||
console.log(visitorData.deviceType);
|
console.log(visitorData.deviceType);
|
||||||
Socket.emit('form-visitor-data', visitorData);
|
Socket.emit('form-visitor-data', visitorData);
|
||||||
});
|
});*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(){
|
function init(){
|
||||||
// Make sure the Socket is connected
|
// Make sure the Socket is connected
|
||||||
if (!Socket.socket) {
|
/*if (!Socket.socket) {
|
||||||
Socket.connect();
|
Socket.connect();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
var service = {
|
var service = {
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
// Use Application configuration module to register a new module
|
// Use Application configuration module to register a new module
|
||||||
ApplicationConfiguration.registerModule('forms', [
|
ApplicationConfiguration.registerModule('forms', [
|
||||||
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
'ngFileUpload', 'ui.router.tabs', 'ui.date', 'ui.sortable',
|
||||||
'angular-input-stars', 'users'
|
'angular-input-stars', 'users', 'ngclipboard'
|
||||||
]);//, 'colorpicker.module' @TODO reactivate this module
|
]);//, 'colorpicker.module' @TODO reactivate this module
|
||||||
|
|
|
@ -4,7 +4,8 @@ angular.module('users').config(['$translateProvider', function ($translateProvid
|
||||||
|
|
||||||
$translateProvider.translations('en', {
|
$translateProvider.translations('en', {
|
||||||
ACCESS_DENIED_TEXT: 'You need to be logged in to access this page',
|
ACCESS_DENIED_TEXT: 'You need to be logged in to access this page',
|
||||||
USERNAME_LABEL: 'Username or Email',
|
USERNAME_OR_EMAIL_LABEL: 'Username or Email',
|
||||||
|
USERNAME_LABEL: 'Username',
|
||||||
PASSWORD_LABEL: 'Password',
|
PASSWORD_LABEL: 'Password',
|
||||||
CURRENT_PASSWORD_LABEL: 'Current Password',
|
CURRENT_PASSWORD_LABEL: 'Current Password',
|
||||||
NEW_PASSWORD_LABEL: 'New Password',
|
NEW_PASSWORD_LABEL: 'New Password',
|
||||||
|
@ -21,6 +22,9 @@ angular.module('users').config(['$translateProvider', function ($translateProvid
|
||||||
SIGNIN_HEADER_TEXT: 'Sign in',
|
SIGNIN_HEADER_TEXT: 'Sign in',
|
||||||
|
|
||||||
SIGNUP_ERROR_TEXT: 'Couldn\'t complete registration due to errors',
|
SIGNUP_ERROR_TEXT: 'Couldn\'t complete registration due to errors',
|
||||||
|
ENTER_ACCOUNT_EMAIL: 'Enter your account email.',
|
||||||
|
RESEND_VERIFICATION_EMAIL: 'Resend Verification Email',
|
||||||
|
SAVE_CHANGES: 'Save Changes',
|
||||||
|
|
||||||
UPDATE_PROFILE_BTN: 'Update Profile',
|
UPDATE_PROFILE_BTN: 'Update Profile',
|
||||||
PROFILE_SAVE_SUCCESS: 'Profile saved successfully',
|
PROFILE_SAVE_SUCCESS: 'Profile saved successfully',
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User',
|
angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User',
|
||||||
function($scope, $stateParams, $state, User) {
|
function($scope, $stateParams, $state, User) {
|
||||||
|
|
||||||
$scope.error = '';
|
$scope.error = '';
|
||||||
|
|
||||||
// Submit forgotten password account id
|
// Submit forgotten password account id
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('users').controller('SettingsController', ['$scope', '$rootScope', '$http', '$state', 'Users',
|
angular.module('users').controller('SettingsController', ['$scope', '$rootScope', '$http', '$state', 'Users', 'Auth',
|
||||||
function($scope, $rootScope, $http, $state, Users) {
|
function($scope, $rootScope, $http, $state, Users, Auth) {
|
||||||
$scope.user = $rootScope.user;
|
|
||||||
|
$scope.user = Auth.currentUser;
|
||||||
|
|
||||||
// Check if there are additional accounts
|
// Check if there are additional accounts
|
||||||
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
|
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
|
||||||
|
@ -12,6 +13,10 @@ angular.module('users').controller('SettingsController', ['$scope', '$rootScope'
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function(){
|
||||||
|
$scope.user = Auth.currentUser;
|
||||||
|
};
|
||||||
|
|
||||||
// Check if provider is already in use with current user
|
// Check if provider is already in use with current user
|
||||||
$scope.isConnectedSocialAccount = function(provider) {
|
$scope.isConnectedSocialAccount = function(provider) {
|
||||||
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
|
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
|
||||||
|
|
|
@ -6,7 +6,7 @@ section.auth {
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #1e5799; /* Old browsers */
|
background-color: #50B5C1; /* Old browsers */
|
||||||
background: -moz-linear-gradient(137deg, #50B5C1 0%, #6450A0 85%); /* FF3.6-15 */
|
background: -moz-linear-gradient(137deg, #50B5C1 0%, #6450A0 85%); /* FF3.6-15 */
|
||||||
background: -webkit-linear-gradient(137deg, #50B5C1 0%, #6450A0 85%); /* Chrome10-25,Safari5.1-6 */
|
background: -webkit-linear-gradient(137deg, #50B5C1 0%, #6450A0 85%); /* Chrome10-25,Safari5.1-6 */
|
||||||
background: linear-gradient(137deg, #50B5C1 0%, #6450A0 85%);
|
background: linear-gradient(137deg, #50B5C1 0%, #6450A0 85%);
|
||||||
|
@ -63,18 +63,31 @@ section.auth {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.auth .btn-signup {
|
|
||||||
|
.btn-rounded.btn-signup {
|
||||||
background-color: #FFD747;
|
background-color: #FFD747;
|
||||||
color: #896D0B;
|
color: #896D0B;
|
||||||
border: 2px #FFD747 solid;
|
border: 2px #FFD747 solid;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
section.auth .btn-signup:hover {
|
|
||||||
|
.btn-rounded.btn-signup:hover {
|
||||||
color: #FFD747;
|
color: #FFD747;
|
||||||
background-color: #896D0B;
|
background-color: #896D0B;
|
||||||
border: 2px #896D0B solid;
|
border: 2px #896D0B solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-rounded.btn-default {
|
||||||
|
background-color: transparent;
|
||||||
|
color: white;
|
||||||
|
border: 2px white solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-rounded.btn-default:focus, .btn-rounded.btn-default:hover {
|
||||||
|
color: #6450A0;
|
||||||
|
background-color: white;
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 992px) {
|
@media (min-width: 992px) {
|
||||||
.nav-users {
|
.nav-users {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -90,10 +103,12 @@ section.auth {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.form-control {
|
section.auth input.form-control {
|
||||||
border: none;
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.form-control {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: white;
|
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
padding: 30px 20px;
|
padding: 30px 20px;
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
<div class="col-md-4 col-md-offset-4">
|
<div class="col-md-4 col-md-offset-4">
|
||||||
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
||||||
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<form class="signin form-horizontal" autocomplete="off">
|
<form class="signin form-horizontal" autocomplete="off">
|
||||||
|
@ -33,14 +32,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<!--<label for="username">{{ 'USERNAME_LABEL' | translate }}</label>-->
|
<!--<label for="username">{{ 'USERNAME_LABEL' | translate }}</label>-->
|
||||||
<input type="text" id="username" name="username" class="form-control" data-ng-model="credentials.username" placeholder="{{ 'USERNAME_LABEL' | translate }}" ng-minlength="4">
|
<input type="text" id="username" name="username" class="form-control" data-ng-model="credentials.username" placeholder="{{ 'USERNAME_OR_EMAIL_LABEL' | translate }}" ng-minlength="4">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<!--<label for="password">{{ 'PASSWORD_LABEL' | translate }}</label>-->
|
<!--<label for="password">{{ 'PASSWORD_LABEL' | translate }}</label>-->
|
||||||
<input type="password" id="password" name="password" class="form-control" data-ng-model="credentials.password" placeholder="{{ 'PASSWORD_LABEL' | translate }}" ng-minlength="4">
|
<input type="password" id="password" name="password" class="form-control" data-ng-model="credentials.password" placeholder="{{ 'PASSWORD_LABEL' | translate }}" ng-minlength="4">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-signup" ng-click="signin()">{{ 'SIGNIN_BTN' | translate }}</button>
|
<button class="btn btn-signup btn-rounded btn-block" ng-click="signin()">{{ 'SIGNIN_BTN' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center forgot-password">
|
<div class="text-center forgot-password">
|
||||||
<a ui-sref="forgot">{{ 'FORGOT_PASSWORD_LINK' | translate }}</a>
|
<a ui-sref="forgot">{{ 'FORGOT_PASSWORD_LINK' | translate }}</a>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
<p>
|
<p>
|
||||||
<strong>{{ 'BEFORE_YOU_CONTINUE' | translate }}</strong> <a href="mail:polydaic@gmail.com">polydaic@gmail.com</a></p>
|
<strong>{{ 'BEFORE_YOU_CONTINUE' | translate }}</strong> <a href="mail:polydaic@gmail.com">polydaic@gmail.com</a></p>
|
||||||
<div class="text-center form-group">
|
<div class="text-center form-group">
|
||||||
<button type="submit" class="btn btn-large btn-primary">
|
<button type="submit" class="btn btn-primary btn-rounded">
|
||||||
<a href="/#!/" style="color: white; text-decoration: none;">Continue</a>
|
<a href="/#!/" style="color: white; text-decoration: none;">Continue</a>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,29 +30,6 @@
|
||||||
{{'SIGNUP_ERROR_TEXT' | translate}}: <br>
|
{{'SIGNUP_ERROR_TEXT' | translate}}: <br>
|
||||||
<strong data-ng-bind="error"></strong>
|
<strong data-ng-bind="error"></strong>
|
||||||
</div>
|
</div>
|
||||||
<!--<div class="form-group">
|
|
||||||
<label for="firstName">{{ 'FIRST_NAME_LABEL' | translate }}</label>
|
|
||||||
<input type="text" ng-pattern="/^[a-zA-Z0-9 \-.]*$/" required id="firstName" name="firstName" class="form-control" ng-model="credentials.firstName" placeholder="First Name">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="lastName">{{ 'LAST_NAME_LABEL' | translate }}</label>
|
|
||||||
<input type="text" ng-pattern="/^[a-zA-Z0-9 \-.]*$/" required id="lastName" name="lastName" class="form-control" ng-model="credentials.lastName" placeholder="Last Name">
|
|
||||||
</div>-->
|
|
||||||
<!--<div class="row form-group">
|
|
||||||
<div class="field-title">
|
|
||||||
<b>{{ 'LANGUAGE_LABEL' | translate }}</b>
|
|
||||||
</div>
|
|
||||||
<div class="field-input">
|
|
||||||
<select ng-model="user.language" required>
|
|
||||||
<option ng-repeat="language in languages"
|
|
||||||
ng-selected="language == user.language"
|
|
||||||
value="{{language}}">
|
|
||||||
{{language}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>-->
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<!--<label for="username">{{ 'USERNAME_LABEL' | translate }}</label>-->
|
<!--<label for="username">{{ 'USERNAME_LABEL' | translate }}</label>-->
|
||||||
<input type="text" id="username" name="username" class="form-control" ng-pattern="languageRegExp" ng-minlength="4" ng-model="credentials.username" placeholder="{{ 'USERNAME_LABEL' | translate }}" ng-minlength="4">
|
<input type="text" id="username" name="username" class="form-control" ng-pattern="languageRegExp" ng-minlength="4" ng-model="credentials.username" placeholder="{{ 'USERNAME_LABEL' | translate }}" ng-minlength="4">
|
||||||
|
@ -66,7 +43,7 @@
|
||||||
<input type="password" id="password" name="password" class="form-control" ng-model="credentials.password" placeholder="{{ 'PASSWORD_LABEL' | translate }}" ng-minlength="4">
|
<input type="password" id="password" name="password" class="form-control" ng-model="credentials.password" placeholder="{{ 'PASSWORD_LABEL' | translate }}" ng-minlength="4">
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center form-group">
|
<div class="text-center form-group">
|
||||||
<button type="submit" class="btn btn-signup">{{ 'SIGNUP_BTN' | translate }}</button>
|
<button type="submit" class="btn btn-signup btn-rounded btn-block">{{ 'SIGNUP_BTN' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
<section class="auth row" data-ng-controller="PasswordController">
|
<section class="auth valign-wrapper" data-ng-controller="PasswordController">
|
||||||
<h3 class="col-md-12 text-center">{{ 'PASSWORD_RESTORE_HEADER' | translate }}</h3>
|
<div class="row valign">
|
||||||
<p class="small text-center">{{ 'ENTER_YOUR_EMAIL' | translate }}</p>
|
<div class="col-md-4 col-md-offset-4">
|
||||||
<div class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6">
|
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
||||||
<form data-ng-submit="askForPasswordReset()" class="signin form-horizontal" autocomplete="off">
|
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
||||||
<fieldset>
|
</div>
|
||||||
<div class="form-group">
|
<div class="col-md-12">
|
||||||
<input type="text" id="username" name="username" class="form-control" data-ng-model="credentials.username" placeholder="{{ 'USERNAME_LABEL' | translate }}">
|
<form data-ng-submit="askForPasswordReset()" autocomplete="off">
|
||||||
</div>
|
<fieldset>
|
||||||
<div class="text-center form-group">
|
<div class="form-group">
|
||||||
<button type="submit" class="btn btn-primary">{{ 'UPDATE_PASSWORD_LABEL' | translate }}</button>
|
<input type="text" id="username" name="username" class="form-control" data-ng-model="credentials.username" placeholder="{{ 'USERNAME_OR_EMAIL_LABEL' | translate }}">
|
||||||
</div>
|
</div>
|
||||||
<div data-ng-show="error" class="text-center text-danger">
|
<div class="text-center form-group">
|
||||||
<strong>{{error}}</strong>
|
<button type="submit" class="btn btn-signup btn-rounded btn-block">{{ 'PASSWORD_RESTORE_HEADER' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div data-ng-show="success" class="text-center text-success">
|
<div data-ng-show="error" class="text-center text-danger">
|
||||||
<strong>{{success}}</strong>
|
<strong>{{error}}</strong>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
<div data-ng-show="success" class="text-center text-success">
|
||||||
</form>
|
<strong>{{success}}</strong>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<header data-ng-include="'/static/modules/core/views/header.client.view.html'"></header>
|
<header data-ng-include="'/static/modules/core/views/header.client.view.html'"></header>
|
||||||
|
|
||||||
<section class="row" data-ng-controller="SettingsController">
|
<section class="row" data-ng-controller="SettingsController">
|
||||||
<h3 class="col-xs-offset-1 col-xs-10 text-center">Edit your profile</h3>
|
<h2 class="col-xs-offset-1 col-xs-10 text-center">Edit your profile</h2>
|
||||||
<div class="col-xs-offset-3 col-xs-6">
|
<div class="col-xs-offset-3 col-xs-6">
|
||||||
<form name="userForm" data-ng-submit="updateUserProfile(userForm.$valid)" class="signin form-horizontal" autocomplete="off">
|
<form name="userForm" data-ng-submit="updateUserProfile(userForm.$valid)" class="signin form-horizontal" autocomplete="off">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
@ -15,18 +15,18 @@
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-xs-7 field-title">
|
<div class="col-xs-7 field-title">
|
||||||
<b>{{ 'FIRST_NAME_LABEL' | translate }}</b>
|
{{ 'FIRST_NAME_LABEL' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<input type="text" id="firstName" name="firstName" class="form-control" data-ng-model="user.firstName" placeholder="First Name" ng-pattern="/^[a-zA-Z0-9 \-.]*$/">
|
<input type="text" id="firstName" name="firstName" class="form-control" data-ng-model="user.firstName" ng-pattern="/^[\w0-9 \-.]*$/">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-xs-7 field-title">
|
<div class="col-xs-7 field-title">
|
||||||
<b>Last Name</b>
|
{{ 'LAST_NAME_LABEL' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<input type="text" id="lastName" name="lastName" class="form-control" data-ng-model="user.lastName" placeholder="Last Name" ng-pattern="/^[a-zA-Z0-9 \-.]*$/">
|
<input type="text" id="lastName" name="lastName" class="form-control" data-ng-model="user.lastName" ng-pattern="/^[\w0-9 \-.]*$/">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<div class="col-xs-7 field-title">
|
<div class="col-xs-7 field-title">
|
||||||
<b>{{ 'LANGUAGE_LABEL' | translate }}</b>
|
{{ 'LANGUAGE_LABEL' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<select ng-model="user.language" required>
|
<select ng-model="user.language" required>
|
||||||
|
@ -49,25 +49,28 @@
|
||||||
|
|
||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<div class="col-xs-7 field-title">
|
<div class="col-xs-7 field-title">
|
||||||
<b>Username</b>
|
{{ 'USERNAME_LABEL' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<input type="text" id="username" name="username" class="form-control" data-ng-model="user.username" placeholder="Username">
|
<input type="text" id="username" name="username" class="form-control" data-ng-model="user.username">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<div class="col-xs-7 field-title">
|
<div class="col-xs-7 field-title">
|
||||||
<b>{{ 'EMAIL_LABEL' | translate }}</b>
|
{{ 'EMAIL_LABEL' | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 field-input">
|
<div class="col-xs-12 field-input">
|
||||||
<input type="email" id="email" name="email" class="form-control" data-ng-model="user.email" placeholder="Email">
|
<input type="email" id="email" name="email" class="form-control" data-ng-model="user.email">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center form-group">
|
<div class="text-center form-group">
|
||||||
<button type="submit" class="btn btn-large btn-primary" style="font-size:1.6em;">
|
<button type="submit" class="btn btn-signup btn-rounded">
|
||||||
{{ 'SUBMIT_BTN' | translate }}
|
{{ 'SAVE_CHANGES' | translate }}
|
||||||
|
</button>
|
||||||
|
<button type="none" ng-click="cancel()" class="btn btn-rounded">
|
||||||
|
{{ 'CANCEL' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,45 @@
|
||||||
<section class="auth" data-ng-controller="VerifyController">
|
<section class="auth valign-wrapper" data-ng-controller="VerifyController">
|
||||||
<section ng-if="!isResetSent">
|
|
||||||
<h3 class="col-md-12 text-center">Resend your account verification email</h3>
|
<section class="row valign" ng-if="!isResetSent">
|
||||||
<p class="small text-center">Enter your account email.</p>
|
<div class="col-md-4 col-md-offset-4">
|
||||||
<div data-ng-show="error" class="text-center text-danger">
|
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
||||||
<strong>{{error}}</strong>
|
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6">
|
<div data-ng-show="error" class="text-center text-danger">
|
||||||
<form data-ng-submit="resendVerifyEmail()" class="signin form-horizontal" autocomplete="off">
|
<strong>{{error}}</strong>
|
||||||
<fieldset>
|
</div>
|
||||||
<div class="form-group">
|
<div class="col-md-12">
|
||||||
<input type="text" id="email" name="email" class="form-control" data-ng-model="credentials.email" placeholder="bob@example.com">
|
<form data-ng-submit="resendVerifyEmail()" class="signin form-horizontal" autocomplete="off">
|
||||||
</div>
|
<fieldset>
|
||||||
<div class="text-center form-group">
|
<div class="form-group">
|
||||||
<button type="submit" class="btn btn-primary" ng-click="resendVerifyEmail()">{{ 'SUBMIT_BTN' | translate }}</button>
|
<input type="text" id="email" name="email" class="form-control" data-ng-model="credentials.email" placeholder="{{ 'ENTER_ACCOUNT_EMAIL' | translate}}">
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
<div class="text-center form-group">
|
||||||
</form>
|
<button type="submit" class="btn btn-signup btn-rounded btn-block" ng-click="resendVerifyEmail()">{{ 'RESEND_VERIFICATION_EMAIL' | translate }}</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section ng-if="isResetSent">
|
<section class="row valign" ng-if="isResetSent">
|
||||||
<h3 class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6 text-center">Verification Email has been Sent </h3>
|
<div class="col-md-4 col-md-offset-4">
|
||||||
<div class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6">
|
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
||||||
<h2>
|
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
||||||
{{ 'VERIFICATION_EMAIL_SENT' | translate }} {{username}}.
|
</div>
|
||||||
<br> {{ 'NOT_ACTIVATED_YET' | translate }}
|
<h3 class="col-md-12 text-center">Verification Email has been Sent</h3>
|
||||||
</h2>
|
<div class="col-md-12">
|
||||||
<p> {{ 'CHECK_YOUR_EMAIL' | translate }} <a href="mail:polydaic@gmail.com">polydaic@gmail.com</a></p>
|
<h2>
|
||||||
<div class="text-center form-group">
|
{{ 'VERIFICATION_EMAIL_SENT' | translate }} {{username}}.
|
||||||
<button type="submit" class="btn btn-large btn-primary">
|
<br> {{ 'NOT_ACTIVATED_YET' | translate }}
|
||||||
|
</h2>
|
||||||
|
<p> {{ 'CHECK_YOUR_EMAIL' | translate }} <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 btn-rounded">
|
||||||
<a href="/#!/" style="color:white;">Continue</a>
|
<a href="/#!/" style="color:white;">Continue</a>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,14 +1,38 @@
|
||||||
<section class="auth" data-ng-controller="VerifyController" ng-init="validateVerifyToken()">
|
<section class="auth" data-ng-controller="VerifyController" ng-init="validateVerifyToken()">
|
||||||
|
|
||||||
<section class="row text-center" ng-if="isResetSent">
|
<section class="row text-center" ng-if="isResetSent">
|
||||||
<h3 class="col-md-12"></h3>
|
<div class="col-md-4 col-md-offset-4">
|
||||||
<a href="/#!/signin" class="col-md-12">{{ 'CONTINUE_TO_LOGIN' | translate }}</a>
|
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
||||||
|
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
||||||
|
</div>
|
||||||
|
<h3 class="col-md-12">
|
||||||
|
{{ 'VERIFY_SUCCESS' | translate }}
|
||||||
|
</h3>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<a href="/#!/signin" class="btn btn-signup btn-rounded btn-block">{{ 'CONTINUE_TO_LOGIN' | translate }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="row text-center" ng-if="!isResetSent">
|
<section class="row text-center" ng-if="!isResetSent">
|
||||||
<h3 class="col-md-12">{{ 'VERIFY_ERROR' | translate }}</h3>
|
<div class="col-md-4 col-md-offset-4">
|
||||||
<a href="/#!/verify" class="col-md-6">{{ 'REVERIFY_ACCOUNT_LINK' | translate }}</a>
|
<div class="col-md-12 text-center" style="padding-bottom: 50px;">
|
||||||
<a href="/#!/signin" class="col-md-6">{{ 'SIGNIN_BTN' | translate }}</a>
|
<img src="/static/modules/core/img/logo_white.svg" height="100px">
|
||||||
|
</div>
|
||||||
|
<h3 class="col-md-12">
|
||||||
|
{{ 'VERIFY_ERROR' | translate }}
|
||||||
|
</h3>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<a href="/#!/verify" class="btn btn-rounded btn-default">
|
||||||
|
{{ 'REVERIFY_ACCOUNT_LINK' | translate }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<a href="/#!/signin" class="btn btn-rounded btn-primary">
|
||||||
|
{{ 'SIGNIN_BTN' | translate }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
882
public/swagger.json
Normal file
882
public/swagger.json
Normal file
|
@ -0,0 +1,882 @@
|
||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "TellForm API",
|
||||||
|
"contact": {
|
||||||
|
"name": "TellForm Team",
|
||||||
|
"email": "team@tellform.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out how to host your own TellForm instance.",
|
||||||
|
"url": "https://github.com/whitef0x0/tellform"
|
||||||
|
},
|
||||||
|
"host": "api.tellform.com",
|
||||||
|
"basePath": "/",
|
||||||
|
"schemes": [
|
||||||
|
"http",
|
||||||
|
"https"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "form",
|
||||||
|
"description": "Everything about your Forms"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "user",
|
||||||
|
"description": "Everything about your Account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"securityDefinitions": {
|
||||||
|
"api_key": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "apikey",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/forms": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"form"
|
||||||
|
],
|
||||||
|
"summary": "Find all forms",
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "Missing Form Input"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Form is Invalid"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Form not Found"
|
||||||
|
},
|
||||||
|
"200": {
|
||||||
|
"description": "forms response",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/form/:form_id": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"form"
|
||||||
|
],
|
||||||
|
"summary": "Find form by ID",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "forms response",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Form"
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"x-expires": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"form"
|
||||||
|
],
|
||||||
|
"summary": "Create a new form",
|
||||||
|
"description": "Create and save a new form",
|
||||||
|
"operationId": "addForm",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "Form object that is to be created",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "Missing Form Input"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Form is Invalid"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Form not Found"
|
||||||
|
},
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-code-samples": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"form"
|
||||||
|
],
|
||||||
|
"summary": "Update an existing form",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "updateForm",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "form",
|
||||||
|
"description": "Form object that needs to be updated",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "Missing Form Input"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Form is Invalid"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Form not Found"
|
||||||
|
},
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Form"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-code-samples": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users/me": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve current User",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "getUser",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"500": {
|
||||||
|
"description": "Could not Update User"
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "User is not Signed in"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "User is not Authorized"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "User does not exsit"
|
||||||
|
},
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Update the current user",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "updateUser",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "User object that needs to be updated",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"500": {
|
||||||
|
"description": "Could not Update User"
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "User is not Signed in"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "User is not Authorized"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "User does not exsit"
|
||||||
|
},
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"api_key": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"x-code-samples": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"User": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"language",
|
||||||
|
"email",
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"firstName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "First name of User",
|
||||||
|
"example": "John"
|
||||||
|
},
|
||||||
|
"lastName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "First name of User",
|
||||||
|
"example": "Doe"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"en",
|
||||||
|
"fr",
|
||||||
|
"es",
|
||||||
|
"it",
|
||||||
|
"de"
|
||||||
|
],
|
||||||
|
"default": "en",
|
||||||
|
"required": "User must have a language",
|
||||||
|
"description": "Language of User (for internationalization)",
|
||||||
|
"example": "fr"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "email",
|
||||||
|
"required": "User email cannot be blank",
|
||||||
|
"unique": "true",
|
||||||
|
"description": "Email of User",
|
||||||
|
"example": "john.doe@somewhere.com"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"required": "Username cannot be blank",
|
||||||
|
"unique": "true",
|
||||||
|
"description": "Username of User",
|
||||||
|
"example": "johndoe"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"user",
|
||||||
|
"admin",
|
||||||
|
"superuser"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": [ "user" ],
|
||||||
|
"description": "Security Roles of User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lastModified": {
|
||||||
|
"type": "date",
|
||||||
|
"description": "Date that user was last modified",
|
||||||
|
"example": "2016-08-26T20:19:30.146Z"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date",
|
||||||
|
"description": "Date that user was created on",
|
||||||
|
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||||
|
},
|
||||||
|
"resetPasswordToken": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Reset password token of User",
|
||||||
|
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||||
|
},
|
||||||
|
"resetPasswordExpires": {
|
||||||
|
"type": "date",
|
||||||
|
"example": "2016-08-26T20:19:30.146Z",
|
||||||
|
"description": "Date that the User's password reset token expires"
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Verification token of User",
|
||||||
|
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||||
|
},
|
||||||
|
"apiKey": {
|
||||||
|
"type": "string",
|
||||||
|
"unique": true,
|
||||||
|
"index": true,
|
||||||
|
"sparse": true,
|
||||||
|
"description": "API Key of User",
|
||||||
|
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LogicJump": {
|
||||||
|
"expressionString": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"field == static",
|
||||||
|
"field != static",
|
||||||
|
"field > static",
|
||||||
|
"field >= static",
|
||||||
|
"field <= static",
|
||||||
|
"field < static",
|
||||||
|
"field contains static",
|
||||||
|
"field !contains static",
|
||||||
|
"field begins static",
|
||||||
|
"field !begins static",
|
||||||
|
"field ends static",
|
||||||
|
"field !ends static"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"fieldA": {
|
||||||
|
"$ref": "#/definitions/FormField"
|
||||||
|
},
|
||||||
|
"valueB": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"jumpTo": {
|
||||||
|
"$ref": "#/definitions/FormField"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FieldOption": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"option_id": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"option_title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"option_value": {
|
||||||
|
"type": "string",
|
||||||
|
"trim": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RatingField": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"steps": {
|
||||||
|
"type": "number",
|
||||||
|
"min": 1,
|
||||||
|
"max": 10
|
||||||
|
},
|
||||||
|
"shape": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Heart",
|
||||||
|
"Star",
|
||||||
|
"thumbs-up",
|
||||||
|
"thumbs-down",
|
||||||
|
"Circle",
|
||||||
|
"Square",
|
||||||
|
"Check Circle",
|
||||||
|
"Smile Outlined",
|
||||||
|
"Hourglass",
|
||||||
|
"bell",
|
||||||
|
"Paper Plane",
|
||||||
|
"Comment",
|
||||||
|
"Trash"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"validShapes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FormField": {
|
||||||
|
"required": [
|
||||||
|
"title",
|
||||||
|
"fieldType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"isSubmission": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether Field is part of a Submission or not",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"submissionId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "ID of Submission that this Field belongs to",
|
||||||
|
"example": "57bca0969ca8e18b825bcc2b"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"trim": true,
|
||||||
|
"required": "Field Title cannot be blank",
|
||||||
|
"description": "Description of Field",
|
||||||
|
"example": "Your Current University"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Description of Field",
|
||||||
|
"example": "Please do not use abbreviations for your school name"
|
||||||
|
},
|
||||||
|
"logicJump": {
|
||||||
|
"$ref": "#/definitions/FormField"
|
||||||
|
},
|
||||||
|
"ratingOptions": {
|
||||||
|
"type": "#/definitions/RatingField"
|
||||||
|
},
|
||||||
|
"fieldOptions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "FieldOption"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Specifies whether Field is required",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether Field is disabled",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"deletePreserved": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether Field should be preserved if it is deleted",
|
||||||
|
"example": false
|
||||||
|
},
|
||||||
|
"validFieldTypes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fieldType": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"enum": [
|
||||||
|
"textfield",
|
||||||
|
"date",
|
||||||
|
"email",
|
||||||
|
"link",
|
||||||
|
"legal",
|
||||||
|
"url",
|
||||||
|
"textarea",
|
||||||
|
"statement",
|
||||||
|
"welcome",
|
||||||
|
"thankyou",
|
||||||
|
"file",
|
||||||
|
"dropdown",
|
||||||
|
"scale",
|
||||||
|
"rating",
|
||||||
|
"radio",
|
||||||
|
"checkbox",
|
||||||
|
"hidden",
|
||||||
|
"yes_no",
|
||||||
|
"natural",
|
||||||
|
"stripe",
|
||||||
|
"number"
|
||||||
|
],
|
||||||
|
"description": "Type of Field",
|
||||||
|
"example": "textfield"
|
||||||
|
},
|
||||||
|
"fieldValue": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Value of Field",
|
||||||
|
"example": "University of British Columbia"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"VisitorData": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"referrer": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Referring site of Form Visitor",
|
||||||
|
"example": "http://google.com"
|
||||||
|
},
|
||||||
|
"lastActiveField": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "ID of Last Active Field",
|
||||||
|
"example": "57bca0969ca8e18b825bcc2b"
|
||||||
|
},
|
||||||
|
"timeElapsed": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Time Elasped for Visitor on Form (in seconds)",
|
||||||
|
"example": "333.33"
|
||||||
|
},
|
||||||
|
"isSubmitted": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Specifies whether user submitted form before leaving page",
|
||||||
|
"example": false
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Language of User using form",
|
||||||
|
"example": "en"
|
||||||
|
},
|
||||||
|
"ipAddr": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "IP Address of User",
|
||||||
|
"example": "324.332.322.333"
|
||||||
|
},
|
||||||
|
"deviceType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"desktop",
|
||||||
|
"phone",
|
||||||
|
"tablet",
|
||||||
|
"other"
|
||||||
|
],
|
||||||
|
"default": "other",
|
||||||
|
"description": "Device Type of User",
|
||||||
|
"example": "phone"
|
||||||
|
},
|
||||||
|
"userAgent": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "User Agent of User",
|
||||||
|
"example": "Mozilla/5.0 (Linux; <Android Version>; <Build Tag etc.>) AppleWebKit/<WebKit Rev> (KHTML, like Gecko) Chrome/<Chrome Rev> Mobile Safari/<WebKit Rev>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Button": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "url",
|
||||||
|
"description": "URL of Button Link",
|
||||||
|
"example": "http://you-are-awesome.com"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Angular Action fired during Button click",
|
||||||
|
"example": "openModal()"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Text of Button",
|
||||||
|
"example": "Go to HomePage"
|
||||||
|
},
|
||||||
|
"bgColor": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#5bc0de",
|
||||||
|
"description": "Background Color of Button (in hex)",
|
||||||
|
"example": "#5bc0de"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#ffffff",
|
||||||
|
"description": "Font Color of Button (in hex)",
|
||||||
|
"example": "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FormSubmission": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"language",
|
||||||
|
"admin",
|
||||||
|
"title"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"required": "Form Title cannot be blank"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"en",
|
||||||
|
"fr",
|
||||||
|
"es",
|
||||||
|
"it",
|
||||||
|
"de"
|
||||||
|
],
|
||||||
|
"default": "en",
|
||||||
|
"required": "Form must have a language"
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"$ref": "#/definitions/User",
|
||||||
|
},
|
||||||
|
"ipAddr": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"geoLocation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Country": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Region": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"City": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pdfFilePath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pdf": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
|
||||||
|
"timeElapsed": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"percentageComplete": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Form": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"language",
|
||||||
|
"admin",
|
||||||
|
"title"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"required": "Form Title cannot be blank",
|
||||||
|
"description": "Public Title of Form",
|
||||||
|
"example": "UBC CPSC221 Course Waitlist Form"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"en",
|
||||||
|
"fr",
|
||||||
|
"es",
|
||||||
|
"it",
|
||||||
|
"de"
|
||||||
|
],
|
||||||
|
"default": "en",
|
||||||
|
"required": "Form must have a language",
|
||||||
|
"description": "Language of Form",
|
||||||
|
"example": "en"
|
||||||
|
},
|
||||||
|
"analytics": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Analytics of Form",
|
||||||
|
"properties": {
|
||||||
|
"gaCode": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Analytics of Form",
|
||||||
|
"example": "UA-000000-01"
|
||||||
|
},
|
||||||
|
"visitors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "#/definitions/VisitorData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"form_fields": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "FormField"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"submissions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/FormSubmission"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"type": "User",
|
||||||
|
"description": "User that this Form belongs to"
|
||||||
|
},
|
||||||
|
"startPage": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"showStart": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether Form StarPage should be displayed",
|
||||||
|
"example": false
|
||||||
|
},
|
||||||
|
"introTitle": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Welcome to Form",
|
||||||
|
"description": "Title of Form's StartPage",
|
||||||
|
"example": "Welcome to our Awesome Form!"
|
||||||
|
},
|
||||||
|
"introParagraph": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Introduction paragraph for Form's StartPage.",
|
||||||
|
"example": "Welcome to our Awesome Form!"
|
||||||
|
},
|
||||||
|
"introButtonText": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Start",
|
||||||
|
"description": "StartPage Continue Button",
|
||||||
|
"example": "Continue"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
type: "Button"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hideFooter": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether to hide or show Form Footer",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"isLive": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Specifies whether form is Publically available or Private",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"design": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"colors": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"backgroundColor": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#fff",
|
||||||
|
"description": "Background color of Form",
|
||||||
|
"example": "#4c4c4c"
|
||||||
|
},
|
||||||
|
"questionColor": {
|
||||||
|
"type": "string",
|
||||||
|
"match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#333",
|
||||||
|
"description": "Question text font color (in hex)",
|
||||||
|
"example": "#fff"
|
||||||
|
},
|
||||||
|
"answerColor": {
|
||||||
|
"type": "string",
|
||||||
|
"match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#333",
|
||||||
|
"description": "Answer text font color (in hex)",
|
||||||
|
"example": "#f9f9f9"
|
||||||
|
},
|
||||||
|
"buttonColor": {
|
||||||
|
"type": "string",
|
||||||
|
"match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#fff",
|
||||||
|
"description": "Background color of Form Buttons (in hex)",
|
||||||
|
"example": "#555"
|
||||||
|
},
|
||||||
|
"buttonTextColor": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||||
|
"default": "#333",
|
||||||
|
"description": "Font color of Form Buttons (in hex)",
|
||||||
|
"example": "#fff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"font": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue