routable tabs in poll view for participation and evaluation
This commit is contained in:
parent
6bcf2fb088
commit
858b75e543
18 changed files with 892 additions and 723 deletions
|
@ -1,111 +1,11 @@
|
|||
import Ember from "ember";
|
||||
import EmberValidations from 'ember-validations';
|
||||
import moment from "moment";
|
||||
/* global jstz */
|
||||
|
||||
export default Ember.Controller.extend(EmberValidations.Mixin, {
|
||||
export default Ember.Controller.extend({
|
||||
encryption: Ember.inject.service(),
|
||||
encryptionKey: '',
|
||||
newUserName: '',
|
||||
queryParams: ['encryptionKey'],
|
||||
usersSorting: ['creationDate'],
|
||||
sortedUsers: Ember.computed.sort('model.users', 'usersSorting'),
|
||||
|
||||
actions: {
|
||||
addNewUser: function(){
|
||||
var newUser = {
|
||||
name: this.get('newUserName'),
|
||||
selections: []
|
||||
};
|
||||
var self = this;
|
||||
|
||||
// work-a-round cause value is not retrived otherwise
|
||||
this.get('newUserSelections').forEach(function(selection) {
|
||||
if(typeof selection.get('value') === 'string') {
|
||||
newUser.selections.pushObject(
|
||||
self.store.createFragment('selection', {
|
||||
label: selection.get('value')
|
||||
})
|
||||
);
|
||||
}
|
||||
else {
|
||||
newUser.selections.pushObject(
|
||||
self.store.createFragment('selection', {
|
||||
type: selection.get('value.type'),
|
||||
label: selection.get('value.label'),
|
||||
labelTranslation: selection.get('value.labelTranslation'),
|
||||
icon: selection.get('value.icon')
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// send new user to controller for saving
|
||||
this.send('saveNewUser', newUser);
|
||||
|
||||
// clear input fields
|
||||
this.set('newUserName', '');
|
||||
this.get('newUserSelections').forEach(function(selection){
|
||||
selection.set('value', '');
|
||||
});
|
||||
|
||||
// reset validation erros
|
||||
this.set('errors.newUserName', '');
|
||||
this.set('errors.everyOptionIsAnswered', '');
|
||||
|
||||
Ember.run.scheduleOnce('afterRender', this, function(){
|
||||
// recalculate fixedHeaders
|
||||
Ember.$('.user-selections-table').floatThead('reflow');
|
||||
});
|
||||
|
||||
Ember.run.scheduleOnce('afterRender', this, function(){
|
||||
// resize top scrollbars
|
||||
Ember.$('.top-scrollbar div').css('width', Ember.$('.user-selections-table').width() );
|
||||
Ember.$('.top-scrollbar-floatThead').css('width', Ember.$('.table-scroll').outerWidth() );
|
||||
Ember.$('.top-scrollbar-floatThead div').css('width', Ember.$('.user-selections-table').width() );
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* save a new user
|
||||
*/
|
||||
saveNewUser: function(user){
|
||||
var self = this;
|
||||
|
||||
// create new user record in store
|
||||
var newUser = this.store.createRecord('user', {
|
||||
name: user.name,
|
||||
creationDate: new Date(),
|
||||
poll: this.get('model'),
|
||||
selections: user.selections,
|
||||
version: this.buildInfo.semver
|
||||
});
|
||||
|
||||
// save new user
|
||||
newUser.save().catch(function(){
|
||||
// error: new user is not saved
|
||||
self.send('openModal', {
|
||||
template: 'save-retry',
|
||||
model: {
|
||||
record: newUser
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
submitNewUser: function(){
|
||||
var self = this;
|
||||
this.validate().then(function() {
|
||||
self.send('addNewUser');
|
||||
}).catch(function(){
|
||||
Ember.$.each(Ember.View.views, function(id, view) {
|
||||
if(view.isEasyForm) {
|
||||
view.focusOut();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
dateGroups: function() {
|
||||
// group dates only for find a date with times
|
||||
|
@ -189,242 +89,10 @@ export default Ember.Controller.extend(EmberValidations.Mixin, {
|
|||
return dates;
|
||||
}.property('model.options.@each', 'useLocalTimezone'),
|
||||
|
||||
/*
|
||||
* evaluates poll data
|
||||
* if free text answers are allowed evaluation is disabled
|
||||
*/
|
||||
evaluation: function() {
|
||||
// disable evaluation if answer type is free text
|
||||
if (this.get('model.answerType') === 'FreeText') {
|
||||
return [];
|
||||
}
|
||||
|
||||
var evaluation = [],
|
||||
options = [],
|
||||
lookup = [];
|
||||
|
||||
// init options array
|
||||
this.get('model.options').forEach(function(option, index){
|
||||
options[index] = 0;
|
||||
});
|
||||
|
||||
// init array of evalutation objects
|
||||
// create object for every possible answer
|
||||
this.get('model.answers').forEach(function(answer){
|
||||
evaluation.push({
|
||||
id: answer.label,
|
||||
label: answer.label,
|
||||
options: Ember.$.extend([], options)
|
||||
});
|
||||
});
|
||||
// create object for no answer if answers are not forced
|
||||
if (!this.get('model.forceAnswer')){
|
||||
evaluation.push({
|
||||
id: null,
|
||||
label: 'no answer',
|
||||
options: Ember.$.extend([], options)
|
||||
});
|
||||
}
|
||||
|
||||
// create lookup array
|
||||
evaluation.forEach(function(value, index){
|
||||
lookup[value.id] = index;
|
||||
});
|
||||
|
||||
// loop over all users
|
||||
this.get('model.users').forEach(function(user){
|
||||
// loop over all selections of the user
|
||||
user.get('selections').forEach(function(selection, optionindex){
|
||||
var answerindex;
|
||||
|
||||
// get answer index by lookup array
|
||||
if (typeof lookup[selection.value.label] === 'undefined') {
|
||||
answerindex = lookup[null];
|
||||
}
|
||||
else {
|
||||
answerindex = lookup[selection.value.label];
|
||||
}
|
||||
|
||||
// increment counter
|
||||
try {
|
||||
evaluation[answerindex]['options'][optionindex] = evaluation[answerindex]['options'][optionindex] + 1;
|
||||
} catch (e) {
|
||||
// ToDo: Throw an error
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return evaluation;
|
||||
}.property('model.users.@each'),
|
||||
|
||||
evaluationBestOptions: function() {
|
||||
var options = [],
|
||||
bestOptions = [],
|
||||
self = this;
|
||||
// can not evaluate answer type free text
|
||||
if(this.get('model.isFreeText')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
this.get('model.users').forEach(function(user){
|
||||
user.get('selections').forEach(function(selection, i){
|
||||
if(options.length - 1 < i) {
|
||||
options.push({
|
||||
answers: [],
|
||||
key: i,
|
||||
score: 0
|
||||
});
|
||||
}
|
||||
|
||||
if(typeof options[i].answers[selection.get('type')] === 'undefined') {
|
||||
options[i].answers[selection.get('type')] = 0;
|
||||
}
|
||||
options[i].answers[selection.get('type')]++;
|
||||
|
||||
switch (selection.get('type')) {
|
||||
case 'yes':
|
||||
options[i].score += 2;
|
||||
break;
|
||||
|
||||
case 'maybe':
|
||||
options[i].score += 1;
|
||||
break;
|
||||
|
||||
case 'no':
|
||||
options[i].score -= 2;
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
options.sort(function(a, b) {
|
||||
return a.score < b.score;
|
||||
});
|
||||
|
||||
bestOptions.push(
|
||||
options[0]
|
||||
);
|
||||
var i = 1;
|
||||
while(true) {
|
||||
if (
|
||||
typeof options[i] !== 'undefined' &&
|
||||
bestOptions[0].score === options[i].score
|
||||
) {
|
||||
bestOptions.push(
|
||||
options[i]
|
||||
);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
bestOptions.forEach(function(bestOption, i){
|
||||
if (self.get('model.isFindADate')) {
|
||||
bestOptions[i].title = self.get('dates')[bestOption.key].title;
|
||||
}
|
||||
else {
|
||||
bestOptions[i].title = self.get('model.options')[bestOption.key].title;
|
||||
}
|
||||
});
|
||||
|
||||
return bestOptions;
|
||||
}.property('model.users.@each'),
|
||||
|
||||
evaluationBestOptionsMultiple: function(){
|
||||
if (this.get('evaluationBestOptions.length') > 1) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}.property('evaluationBestOptions'),
|
||||
|
||||
evaluationLastParticipation: function(){
|
||||
return this.get('sortedUsers.lastObject.creationDate');
|
||||
}.property('sortedUsers.@each'),
|
||||
|
||||
evaluationParticipants: function(){
|
||||
return this.get('model.users.length');
|
||||
}.property('model.users.@each'),
|
||||
|
||||
/*
|
||||
* returns true if user has selected an answer for every option provided
|
||||
*/
|
||||
everyOptionIsAnswered: function(){
|
||||
try {
|
||||
var newUserSelections = this.get('newUserSelections'),
|
||||
allAnswered = true;
|
||||
|
||||
if (typeof newUserSelections === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
newUserSelections.forEach(function(item){
|
||||
if (Ember.isEmpty(item.value)) {
|
||||
allAnswered = false;
|
||||
}
|
||||
});
|
||||
|
||||
return allAnswered;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}.property('newUserSelections.@each.value'),
|
||||
|
||||
/*
|
||||
* calculate colspan for a row which should use all columns in table
|
||||
* used by evaluation row
|
||||
*/
|
||||
fullRowColspan: function(){
|
||||
return this.get('model.options.length') + 2;
|
||||
}.property('model.options.@each'),
|
||||
|
||||
isEvaluable: function() {
|
||||
if(
|
||||
!this.get('model.isFreeText') &&
|
||||
this.get('model.users.length') > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}.property('model.users.@each', 'model.isFreeText'),
|
||||
|
||||
/*
|
||||
* switch isValid state
|
||||
* is needed for disable submit button
|
||||
*/
|
||||
isNotValid: function(){
|
||||
return !this.get('isValid');
|
||||
}.property('isValid'),
|
||||
|
||||
// array to store selections of new user
|
||||
newUserSelections: function(){
|
||||
var newUserSelections = Ember.A(),
|
||||
options = this.get('model.options');
|
||||
|
||||
options.forEach(function(){
|
||||
var newSelection = Ember.Object.create({value: ''});
|
||||
newUserSelections.pushObject(newSelection);
|
||||
});
|
||||
|
||||
return newUserSelections;
|
||||
}.property('model.options'),
|
||||
|
||||
optionCount: function() {
|
||||
return this.get('model.options.length');
|
||||
}.property('model.options'),
|
||||
|
||||
pollUrl: function() {
|
||||
return window.location.href;
|
||||
}.property('currentPath', 'encryptionKey'),
|
||||
|
||||
|
||||
preventEncryptionKeyChanges: function() {
|
||||
if (
|
||||
!Ember.isEmpty(this.get('encryption.key')) &&
|
||||
|
@ -446,40 +114,5 @@ export default Ember.Controller.extend(EmberValidations.Mixin, {
|
|||
|
||||
useLocalTimezone: function() {
|
||||
return false;
|
||||
}.property(),
|
||||
|
||||
validations: {
|
||||
everyOptionIsAnswered: {
|
||||
/*
|
||||
* validate if every option is answered
|
||||
* if it's forced by poll settings (forceAnswer === true)
|
||||
*
|
||||
* using a computed property therefore which returns true / false
|
||||
* in combinatoin with acceptance validator
|
||||
*
|
||||
* ToDo: Show validation errors
|
||||
*/
|
||||
acceptance: {
|
||||
if: function(object){
|
||||
return object.get('model.forceAnswer');
|
||||
},
|
||||
message: Ember.I18n.t('poll.error.newUser.everyOptionIsAnswered')
|
||||
}
|
||||
},
|
||||
|
||||
newUserName: {
|
||||
presence: {
|
||||
message: Ember.I18n.t('poll.error.newUserName'),
|
||||
|
||||
/*
|
||||
* validate if a user name is given
|
||||
* if it's forced by poll settings (anonymousUser === false)
|
||||
*/
|
||||
unless: function(object){
|
||||
/* have in mind that anonymousUser is undefined on init */
|
||||
return object.get('model.anonymousUser');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.property()
|
||||
});
|
||||
|
|
194
app/controllers/poll/evaluation.js
Normal file
194
app/controllers/poll/evaluation.js
Normal file
|
@ -0,0 +1,194 @@
|
|||
import Ember from "ember";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
usersSorting: ['creationDate'],
|
||||
sortedUsers: Ember.computed.sort('pollController.model.users', 'usersSorting'),
|
||||
pollController: Ember.inject.controller('poll'),
|
||||
dates: Ember.computed.reads('pollController.dates'),
|
||||
dateGroups: Ember.computed.reads('pollController.dateGroups'),
|
||||
|
||||
/*
|
||||
* evaluates poll data
|
||||
* if free text answers are allowed evaluation is disabled
|
||||
*/
|
||||
evaluation: function() {
|
||||
// disable evaluation if answer type is free text
|
||||
if (this.get('model.answerType') === 'FreeText') {
|
||||
return [];
|
||||
}
|
||||
|
||||
var evaluation = [],
|
||||
options = [],
|
||||
lookup = [];
|
||||
|
||||
// init options array
|
||||
this.get('model.options').forEach(function(option, index){
|
||||
options[index] = 0;
|
||||
});
|
||||
|
||||
// init array of evalutation objects
|
||||
// create object for every possible answer
|
||||
this.get('model.answers').forEach(function(answer){
|
||||
evaluation.push({
|
||||
id: answer.label,
|
||||
label: answer.label,
|
||||
options: Ember.$.extend([], options)
|
||||
});
|
||||
});
|
||||
// create object for no answer if answers are not forced
|
||||
if (!this.get('model.forceAnswer')){
|
||||
evaluation.push({
|
||||
id: null,
|
||||
label: 'no answer',
|
||||
options: Ember.$.extend([], options)
|
||||
});
|
||||
}
|
||||
|
||||
// create lookup array
|
||||
evaluation.forEach(function(value, index){
|
||||
lookup[value.id] = index;
|
||||
});
|
||||
|
||||
// loop over all users
|
||||
this.get('model.users').forEach(function(user){
|
||||
// loop over all selections of the user
|
||||
user.get('selections').forEach(function(selection, optionindex){
|
||||
var answerindex;
|
||||
|
||||
// get answer index by lookup array
|
||||
if (typeof lookup[selection.value.label] === 'undefined') {
|
||||
answerindex = lookup[null];
|
||||
}
|
||||
else {
|
||||
answerindex = lookup[selection.value.label];
|
||||
}
|
||||
|
||||
// increment counter
|
||||
try {
|
||||
evaluation[answerindex]['options'][optionindex] = evaluation[answerindex]['options'][optionindex] + 1;
|
||||
} catch (e) {
|
||||
// ToDo: Throw an error
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return evaluation;
|
||||
}.property('model.users.@each'),
|
||||
|
||||
evaluationBestOptions: function() {
|
||||
var options = [],
|
||||
bestOptions = [],
|
||||
self = this;
|
||||
// can not evaluate answer type free text
|
||||
if(this.get('model.isFreeText')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
this.get('model.users').forEach(function(user){
|
||||
user.get('selections').forEach(function(selection, i){
|
||||
if(options.length - 1 < i) {
|
||||
options.push({
|
||||
answers: [],
|
||||
key: i,
|
||||
score: 0
|
||||
});
|
||||
}
|
||||
|
||||
if(typeof options[i].answers[selection.get('type')] === 'undefined') {
|
||||
options[i].answers[selection.get('type')] = 0;
|
||||
}
|
||||
options[i].answers[selection.get('type')]++;
|
||||
|
||||
switch (selection.get('type')) {
|
||||
case 'yes':
|
||||
options[i].score += 2;
|
||||
break;
|
||||
|
||||
case 'maybe':
|
||||
options[i].score += 1;
|
||||
break;
|
||||
|
||||
case 'no':
|
||||
options[i].score -= 2;
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
options.sort(function(a, b) {
|
||||
return a.score < b.score;
|
||||
});
|
||||
|
||||
bestOptions.push(
|
||||
options[0]
|
||||
);
|
||||
var i = 1;
|
||||
while(true) {
|
||||
if (
|
||||
typeof options[i] !== 'undefined' &&
|
||||
bestOptions[0].score === options[i].score
|
||||
) {
|
||||
bestOptions.push(
|
||||
options[i]
|
||||
);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
bestOptions.forEach(function(bestOption, i){
|
||||
if (self.get('model.isFindADate')) {
|
||||
bestOptions[i].title = self.get('dates')[bestOption.key].title;
|
||||
}
|
||||
else {
|
||||
bestOptions[i].title = self.get('model.options')[bestOption.key].title;
|
||||
}
|
||||
});
|
||||
|
||||
return bestOptions;
|
||||
}.property('model.users.@each'),
|
||||
|
||||
evaluationBestOptionsMultiple: function(){
|
||||
if (this.get('evaluationBestOptions.length') > 1) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}.property('evaluationBestOptions'),
|
||||
|
||||
evaluationLastParticipation: function(){
|
||||
return this.get('sortedUsers.lastObject.creationDate');
|
||||
}.property('sortedUsers.@each'),
|
||||
|
||||
evaluationParticipants: function(){
|
||||
return this.get('model.users.length');
|
||||
}.property('model.users.@each'),
|
||||
|
||||
/*
|
||||
* calculate colspan for a row which should use all columns in table
|
||||
* used by evaluation row
|
||||
*/
|
||||
fullRowColspan: function(){
|
||||
return this.get('model.options.length') + 2;
|
||||
}.property('model.options.@each'),
|
||||
|
||||
isEvaluable: function() {
|
||||
if(
|
||||
!this.get('model.isFreeText') &&
|
||||
this.get('model.users.length') > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}.property('model.users.@each', 'model.isFreeText'),
|
||||
|
||||
optionCount: function() {
|
||||
return this.get('model.options.length');
|
||||
}.property('model.options')
|
||||
});
|
197
app/controllers/poll/participation.js
Normal file
197
app/controllers/poll/participation.js
Normal file
|
@ -0,0 +1,197 @@
|
|||
import Ember from "ember";
|
||||
import EmberValidations from 'ember-validations';
|
||||
|
||||
export default Ember.Controller.extend(EmberValidations.Mixin, {
|
||||
dates: Ember.computed.reads('pollController.dates'),
|
||||
dateGroups: Ember.computed.reads('pollController.dateGroups'),
|
||||
encryption: Ember.inject.service(),
|
||||
newUserName: '',
|
||||
pollController: Ember.inject.controller('poll'),
|
||||
|
||||
actions: {
|
||||
addNewUser: function(){
|
||||
var newUser = {
|
||||
name: this.get('newUserName'),
|
||||
selections: []
|
||||
};
|
||||
var self = this;
|
||||
|
||||
// work-a-round cause value is not retrived otherwise
|
||||
this.get('newUserSelections').forEach(function(selection) {
|
||||
if(typeof selection.get('value') === 'string') {
|
||||
newUser.selections.pushObject(
|
||||
self.store.createFragment('selection', {
|
||||
label: selection.get('value')
|
||||
})
|
||||
);
|
||||
}
|
||||
else {
|
||||
newUser.selections.pushObject(
|
||||
self.store.createFragment('selection', {
|
||||
type: selection.get('value.type'),
|
||||
label: selection.get('value.label'),
|
||||
labelTranslation: selection.get('value.labelTranslation'),
|
||||
icon: selection.get('value.icon')
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// send new user to controller for saving
|
||||
this.send('saveNewUser', newUser);
|
||||
|
||||
// clear input fields
|
||||
this.set('newUserName', '');
|
||||
this.get('newUserSelections').forEach(function(selection){
|
||||
selection.set('value', '');
|
||||
});
|
||||
|
||||
// reset validation erros
|
||||
this.set('errors.newUserName', '');
|
||||
this.set('errors.everyOptionIsAnswered', '');
|
||||
|
||||
Ember.run.scheduleOnce('afterRender', this, function(){
|
||||
// recalculate fixedHeaders
|
||||
Ember.$('.user-selections-table').floatThead('reflow');
|
||||
});
|
||||
|
||||
Ember.run.scheduleOnce('afterRender', this, function(){
|
||||
// resize top scrollbars
|
||||
Ember.$('.top-scrollbar div').css('width', Ember.$('.user-selections-table').width() );
|
||||
Ember.$('.top-scrollbar-floatThead').css('width', Ember.$('.table-scroll').outerWidth() );
|
||||
Ember.$('.top-scrollbar-floatThead div').css('width', Ember.$('.user-selections-table').width() );
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* save a new user
|
||||
*/
|
||||
saveNewUser: function(user){
|
||||
var self = this;
|
||||
|
||||
// create new user record in store
|
||||
var newUser = this.store.createRecord('user', {
|
||||
name: user.name,
|
||||
creationDate: new Date(),
|
||||
poll: this.get('model'),
|
||||
selections: user.selections,
|
||||
version: this.buildInfo.semver
|
||||
});
|
||||
|
||||
// save new user
|
||||
newUser.save()
|
||||
.then(() => {
|
||||
this.transitionTo('poll.evaluation', this.get('model'), {
|
||||
queryParams: { encryptionKey: this.get('encryption.key') }
|
||||
});
|
||||
})
|
||||
.catch(function(){
|
||||
// error: new user is not saved
|
||||
self.send('openModal', {
|
||||
template: 'save-retry',
|
||||
model: {
|
||||
record: newUser
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
submitNewUser: function(){
|
||||
var self = this;
|
||||
this.validate().then(function() {
|
||||
self.send('addNewUser');
|
||||
}).catch(function(){
|
||||
Ember.$.each(Ember.View.views, function(id, view) {
|
||||
if(view.isEasyForm) {
|
||||
view.focusOut();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* returns true if user has selected an answer for every option provided
|
||||
*/
|
||||
everyOptionIsAnswered: function(){
|
||||
try {
|
||||
var newUserSelections = this.get('newUserSelections'),
|
||||
allAnswered = true;
|
||||
|
||||
if (typeof newUserSelections === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
newUserSelections.forEach(function(item){
|
||||
if (Ember.isEmpty(item.value)) {
|
||||
allAnswered = false;
|
||||
}
|
||||
});
|
||||
|
||||
return allAnswered;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}.property('newUserSelections.@each.value'),
|
||||
|
||||
/*
|
||||
* switch isValid state
|
||||
* is needed for disable submit button
|
||||
*/
|
||||
isNotValid: function(){
|
||||
return !this.get('isValid');
|
||||
}.property('isValid'),
|
||||
|
||||
// array to store selections of new user
|
||||
newUserSelections: function(){
|
||||
var newUserSelections = Ember.A(),
|
||||
options = this.get('model.options');
|
||||
|
||||
options.forEach(function(){
|
||||
var newSelection = Ember.Object.create({value: ''});
|
||||
newUserSelections.pushObject(newSelection);
|
||||
});
|
||||
|
||||
return newUserSelections;
|
||||
}.property('model.options'),
|
||||
|
||||
optionCount: function() {
|
||||
return this.get('model.options.length');
|
||||
}.property('model.options'),
|
||||
|
||||
validations: {
|
||||
everyOptionIsAnswered: {
|
||||
/*
|
||||
* validate if every option is answered
|
||||
* if it's forced by poll settings (forceAnswer === true)
|
||||
*
|
||||
* using a computed property therefore which returns true / false
|
||||
* in combinatoin with acceptance validator
|
||||
*
|
||||
* ToDo: Show validation errors
|
||||
*/
|
||||
acceptance: {
|
||||
if: function(object){
|
||||
return object.get('model.forceAnswer');
|
||||
},
|
||||
message: Ember.I18n.t('poll.error.newUser.everyOptionIsAnswered')
|
||||
}
|
||||
},
|
||||
|
||||
newUserName: {
|
||||
presence: {
|
||||
message: Ember.I18n.t('poll.error.newUserName'),
|
||||
|
||||
/*
|
||||
* validate if a user name is given
|
||||
* if it's forced by poll settings (anonymousUser === false)
|
||||
*/
|
||||
unless: function(object){
|
||||
/* have in mind that anonymousUser is undefined on init */
|
||||
return object.get('model.anonymousUser');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -6,7 +6,10 @@ var Router = Ember.Router.extend({
|
|||
});
|
||||
|
||||
Router.map(function(){
|
||||
this.route('poll', { path: '/poll/:poll_id' });
|
||||
this.resource('poll', { path: '/poll/:poll_id' }, function(){
|
||||
this.route('participation');
|
||||
this.route('evaluation');
|
||||
});
|
||||
this.resource('create', function(){
|
||||
this.route('meta');
|
||||
this.route('options');
|
||||
|
|
|
@ -11,6 +11,10 @@ export default Ember.Route.extend({
|
|||
}
|
||||
},
|
||||
|
||||
afterModel(poll) {
|
||||
this.transitionTo('poll.participation', poll, {queryParams: {encryptionKey: this.get('encryption.key')}});
|
||||
},
|
||||
|
||||
encryption: Ember.inject.service(),
|
||||
|
||||
model: function(params) {
|
||||
|
|
|
@ -18,216 +18,26 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<div class="table-scroll">
|
||||
<table class="user-selections-table table table-striped table-condensed">
|
||||
<thead>
|
||||
{{#if model.isDateTime}}
|
||||
<tr class="dateGroups">
|
||||
<th> </th>
|
||||
{{#each dateGroup in dateGroups}}
|
||||
<th {{bind-attr colspan="dateGroup.colspan"}}>
|
||||
{{formattedDate dateGroup.value}}
|
||||
</th>
|
||||
{{/each}}
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr>
|
||||
<th> </th>
|
||||
{{#if model.isFindADate}}
|
||||
{{#each date in dates}}
|
||||
<th>
|
||||
{{#if model.isDateTime}}
|
||||
{{formattedDate date.title format="LT" times=true}}
|
||||
{{else}}
|
||||
{{formattedDate date.title}}
|
||||
{{/if}}
|
||||
</th>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
{{#each option in model.options}}
|
||||
<th>
|
||||
{{option.title}}
|
||||
</th>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
<div class="box container-fluid">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
{{#link-to "poll.participation" model tagName='li' activeClass='active' class='participation'}}
|
||||
{{#link-to "poll.participation" model}}
|
||||
participation
|
||||
{{/link-to}}
|
||||
{{/link-to}}
|
||||
{{#link-to "poll.evaluation" model tagName='li' activeClass='active' class='evaluation'}}
|
||||
{{#link-to "poll.evaluation" model}}
|
||||
evaluation
|
||||
{{/link-to}}
|
||||
{{/link-to}}
|
||||
</ul>
|
||||
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr class='newUser'>
|
||||
<td>
|
||||
{{#form-wrapper}}
|
||||
{{#input newUserName}}
|
||||
{{input-field newUserName
|
||||
placeholderTranslation="poll.input.newUserName.placeholder"
|
||||
}}
|
||||
{{#if view.showError}}
|
||||
{{error-field newUserName}}
|
||||
{{/if}}
|
||||
{{/input}}
|
||||
{{/form-wrapper}}
|
||||
</td>
|
||||
{{#each newUserSelection in newUserSelections}}
|
||||
<td class="newUserSelection">
|
||||
{{#form-wrapper}}
|
||||
{{#if model.isFreeText}}
|
||||
{{#input newUserSelection.value}}
|
||||
{{input-field newUserSelection.value}}
|
||||
{{/input}}
|
||||
{{else}}
|
||||
{{#each answer in model.answers}}
|
||||
<div class="radio">
|
||||
{{#radio-button value=answer groupValue=newUserSelection.value}}
|
||||
<span {{bind-attr class="answer.type"}}>
|
||||
<span {{bind-attr class="answer.icon"}}></span>
|
||||
{{#if answer.labelTranslation}}
|
||||
{{t answer.labelTranslation}}
|
||||
{{else}}
|
||||
{{answer.label}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/radio-button}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/form-wrapper}}
|
||||
</td>
|
||||
{{/each}}
|
||||
<td>
|
||||
<button {{action "submitNewUser"}} class="btn btn-default btn-primary">
|
||||
{{t "poll.save"}}
|
||||
</button>
|
||||
<span style="white-space: normal;">
|
||||
{{#input everyOptionIsAnswered}}
|
||||
{{#if view.showError}}
|
||||
{{error-field everyOptionIsAnswered}}
|
||||
{{/if}}
|
||||
{{/input}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{#each user in sortedUsers}}
|
||||
<tr class="user">
|
||||
<td>{{user.name}}</td>
|
||||
{{#each selection in user.selections}}
|
||||
<td>
|
||||
{{#if selection.label}}
|
||||
{{#if model.isFreeText}}
|
||||
{{selection.label}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if selection.labelTranslation}}
|
||||
{{#unless model.isFreeText}}
|
||||
<span {{bind-attr class="selection.type"}}>
|
||||
<span {{bind-attr class="selection.icon"}}></span>
|
||||
{{t selection.labelTranslation}}
|
||||
</span>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/each}}
|
||||
<td> </td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active">
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if isEvaluable}}
|
||||
<div class="box evaluation">
|
||||
<h2>
|
||||
{{t "poll.evaluation.label"}}
|
||||
</h2>
|
||||
|
||||
<p class="participants">
|
||||
{{t "poll.evaluation.participants" count=evaluationParticipants}}
|
||||
</p>
|
||||
|
||||
<p class="best-options">
|
||||
{{#if model.isFindADate}}
|
||||
{{t "poll.evaluation.bestOption.label.findADate" count=evaluationBestOptions.length}}
|
||||
{{else}}
|
||||
{{t "poll.evaluation.bestOption.label.makeAPoll" count=evaluationBestOptions.length}}
|
||||
{{/if}}
|
||||
|
||||
{{#if evaluationBestOptionsMultiple}}
|
||||
<ul>
|
||||
{{#each evaluationBestOption in evaluationBestOptions}}
|
||||
<li>
|
||||
{{#if model.isFindADate}}
|
||||
<strong>{{formattedDate evaluationBestOption.title times=model.isDateTime}}</strong>.
|
||||
{{else}}
|
||||
<strong>{{evaluationBestOption.title}}</strong>.
|
||||
{{/if}}
|
||||
|
||||
<br/>
|
||||
|
||||
{{#if model.isFindADate}}
|
||||
{{#if evaluationBestOption.answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.yes" count=evaluationBestOption.answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.maybe" count=evaluationBestOption.answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.no" count=evaluationBestOption.answers.no}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if evaluationBestOption.answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.yes" count=evaluationBestOption.answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.maybe" count=evaluationBestOption.answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.no" count=evaluationBestOption.answers.no}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
{{#if model.isFindADate}}
|
||||
<strong>{{formattedDate evaluationBestOptions.[0].title times=model.isDateTime}}</strong>.
|
||||
{{else}}
|
||||
<strong>{{evaluationBestOptions.[0].title}}</strong>.
|
||||
{{/if}}
|
||||
|
||||
{{#if model.isFindADate}}
|
||||
{{#if evaluationBestOptions.[0].answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.yes" count=evaluationBestOptions.[0].answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.maybe" count=evaluationBestOptions.[0].answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.no" count=evaluationBestOptions.[0].answers.no}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if evaluationBestOptions.[0].answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.yes" count=evaluationBestOptions.[0].answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.maybe" count=evaluationBestOptions.[0].answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.no" count=evaluationBestOptions.[0].answers.no}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</p>
|
||||
|
||||
<p class="last-participation">
|
||||
{{t "poll.evaluation.lastParticipation" ago=(moment-from-now evaluationLastParticipation)}}
|
||||
</p>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="timezoneDiffers">
|
||||
|
|
155
app/templates/poll/evaluation.hbs
Normal file
155
app/templates/poll/evaluation.hbs
Normal file
|
@ -0,0 +1,155 @@
|
|||
<div class="table-scroll">
|
||||
<table class="user-selections-table table table-striped table-condensed">
|
||||
<thead>
|
||||
{{#if model.isDateTime}}
|
||||
<tr class="dateGroups">
|
||||
<th> </th>
|
||||
{{#each dateGroup in dateGroups}}
|
||||
<th {{bind-attr colspan="dateGroup.colspan"}}>
|
||||
{{formattedDate dateGroup.value}}
|
||||
</th>
|
||||
{{/each}}
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr>
|
||||
<th> </th>
|
||||
{{#if model.isFindADate}}
|
||||
{{#each date in dates}}
|
||||
<th>
|
||||
{{#if model.isDateTime}}
|
||||
{{formattedDate date.title format="LT" times=true}}
|
||||
{{else}}
|
||||
{{formattedDate date.title}}
|
||||
{{/if}}
|
||||
</th>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
{{#each option in model.options}}
|
||||
<th>
|
||||
{{option.title}}
|
||||
</th>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each user in sortedUsers}}
|
||||
<tr class="user">
|
||||
<td>{{user.name}}</td>
|
||||
{{#each selection in user.selections}}
|
||||
<td>
|
||||
{{#if selection.label}}
|
||||
{{#if model.isFreeText}}
|
||||
{{selection.label}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if selection.labelTranslation}}
|
||||
{{#unless model.isFreeText}}
|
||||
<span {{bind-attr class="selection.type"}}>
|
||||
<span {{bind-attr class="selection.icon"}}></span>
|
||||
{{t selection.labelTranslation}}
|
||||
</span>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/each}}
|
||||
<td> </td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{#if isEvaluable}}
|
||||
<div class="box evaluation">
|
||||
<h2>
|
||||
{{t "poll.evaluation.label"}}
|
||||
</h2>
|
||||
|
||||
<p class="participants">
|
||||
{{t "poll.evaluation.participants" count=evaluationParticipants}}
|
||||
</p>
|
||||
|
||||
<p class="best-options">
|
||||
{{#if model.isFindADate}}
|
||||
{{t "poll.evaluation.bestOption.label.findADate" count=evaluationBestOptions.length}}
|
||||
{{else}}
|
||||
{{t "poll.evaluation.bestOption.label.makeAPoll" count=evaluationBestOptions.length}}
|
||||
{{/if}}
|
||||
|
||||
{{#if evaluationBestOptionsMultiple}}
|
||||
<ul>
|
||||
{{#each evaluationBestOption in evaluationBestOptions}}
|
||||
<li>
|
||||
{{#if model.isFindADate}}
|
||||
<strong>{{formattedDate evaluationBestOption.title times=model.isDateTime}}</strong>.
|
||||
{{else}}
|
||||
<strong>{{evaluationBestOption.title}}</strong>.
|
||||
{{/if}}
|
||||
|
||||
<br/>
|
||||
|
||||
{{#if model.isFindADate}}
|
||||
{{#if evaluationBestOption.answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.yes" count=evaluationBestOption.answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.maybe" count=evaluationBestOption.answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.no" count=evaluationBestOption.answers.no}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if evaluationBestOption.answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.yes" count=evaluationBestOption.answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.maybe" count=evaluationBestOption.answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOption.answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.no" count=evaluationBestOption.answers.no}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
{{#if model.isFindADate}}
|
||||
<strong>{{formattedDate evaluationBestOptions.[0].title times=model.isDateTime}}</strong>.
|
||||
{{else}}
|
||||
<strong>{{evaluationBestOptions.[0].title}}</strong>.
|
||||
{{/if}}
|
||||
|
||||
{{#if model.isFindADate}}
|
||||
{{#if evaluationBestOptions.[0].answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.yes" count=evaluationBestOptions.[0].answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.maybe" count=evaluationBestOptions.[0].answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.findADate.no" count=evaluationBestOptions.[0].answers.no}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if evaluationBestOptions.[0].answers.yes}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.yes" count=evaluationBestOptions.[0].answers.yes}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.maybe}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.maybe" count=evaluationBestOptions.[0].answers.maybe}}
|
||||
{{/if}}
|
||||
{{#if evaluationBestOptions.[0].answers.no}}
|
||||
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.no" count=evaluationBestOptions.[0].answers.no}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</p>
|
||||
|
||||
<p class="last-participation">
|
||||
{{t "poll.evaluation.lastParticipation" ago=(moment-from-now evaluationLastParticipation)}}
|
||||
</p>
|
||||
</div>
|
||||
{{/if}}
|
94
app/templates/poll/participation.hbs
Normal file
94
app/templates/poll/participation.hbs
Normal file
|
@ -0,0 +1,94 @@
|
|||
<div class="table-scroll">
|
||||
<table class="user-selections-table table table-striped table-condensed">
|
||||
<thead>
|
||||
{{#if model.isDateTime}}
|
||||
<tr class="dateGroups">
|
||||
<th> </th>
|
||||
{{#each dateGroup in dateGroups}}
|
||||
<th {{bind-attr colspan="dateGroup.colspan"}}>
|
||||
{{formattedDate dateGroup.value}}
|
||||
</th>
|
||||
{{/each}}
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr>
|
||||
<th> </th>
|
||||
{{#if model.isFindADate}}
|
||||
{{#each date in dates}}
|
||||
<th>
|
||||
{{#if model.isDateTime}}
|
||||
{{formattedDate date.title format="LT" times=true}}
|
||||
{{else}}
|
||||
{{formattedDate date.title}}
|
||||
{{/if}}
|
||||
</th>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
{{#each option in model.options}}
|
||||
<th>
|
||||
{{option.title}}
|
||||
</th>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr class='newUser'>
|
||||
<td>
|
||||
{{#form-wrapper}}
|
||||
{{#input newUserName}}
|
||||
{{input-field newUserName
|
||||
placeholderTranslation="poll.input.newUserName.placeholder"
|
||||
}}
|
||||
{{#if view.showError}}
|
||||
{{error-field newUserName}}
|
||||
{{/if}}
|
||||
{{/input}}
|
||||
{{/form-wrapper}}
|
||||
</td>
|
||||
{{#each newUserSelection in newUserSelections}}
|
||||
<td class="newUserSelection">
|
||||
{{#form-wrapper}}
|
||||
{{#if model.isFreeText}}
|
||||
{{#input newUserSelection.value}}
|
||||
{{input-field newUserSelection.value}}
|
||||
{{/input}}
|
||||
{{else}}
|
||||
{{#each answer in model.answers}}
|
||||
<div class="radio">
|
||||
{{#radio-button value=answer groupValue=newUserSelection.value}}
|
||||
<span {{bind-attr class="answer.type"}}>
|
||||
<span {{bind-attr class="answer.icon"}}></span>
|
||||
{{#if answer.labelTranslation}}
|
||||
{{t answer.labelTranslation}}
|
||||
{{else}}
|
||||
{{answer.label}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/radio-button}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/form-wrapper}}
|
||||
</td>
|
||||
{{/each}}
|
||||
<td>
|
||||
<button {{action "submitNewUser"}} class="btn btn-default btn-primary">
|
||||
{{t "poll.save"}}
|
||||
</button>
|
||||
<span style="white-space: normal;">
|
||||
{{#input everyOptionIsAnswered}}
|
||||
{{#if view.showError}}
|
||||
{{error-field everyOptionIsAnswered}}
|
||||
{{/if}}
|
||||
{{/input}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
|
@ -30,7 +30,8 @@
|
|||
"pollHasOptionsDates",
|
||||
"pollHasOptionsTimes",
|
||||
"pollHasAnswers",
|
||||
"pollParticipate"
|
||||
"pollParticipate",
|
||||
"switchTab"
|
||||
],
|
||||
"node": false,
|
||||
"browser": false,
|
||||
|
|
|
@ -69,7 +69,7 @@ test("create a default poll", function(assert) {
|
|||
click('.button-next');
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll');
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
|
||||
pollTitleEqual(assert, 'default poll');
|
||||
pollDescriptionEqual(assert, '');
|
||||
|
@ -133,7 +133,7 @@ test("create a poll for answering a question", function(assert) {
|
|||
click('.button-next');
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll');
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
|
||||
pollTitleEqual(assert, 'default poll');
|
||||
pollDescriptionEqual(assert, '');
|
||||
|
@ -174,7 +174,7 @@ test("create a poll with description", function(assert) {
|
|||
click('.button-next');
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll');
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
|
||||
pollTitleEqual(assert, 'default poll');
|
||||
pollDescriptionEqual(assert, 'a sample description');
|
||||
|
|
|
@ -40,11 +40,12 @@ test("participate in a default poll", function(assert) {
|
|||
);
|
||||
|
||||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey).then(function() {
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
pollParticipate('Max Meiner', ['yes', 'no']);
|
||||
|
||||
assert.equal(Ember.$('.has-error').length, 0, "there is no validation error");
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUsersCount(assert, 1, "user is added to user selections table");
|
||||
pollHasUser(assert, 'Max Meiner', [Ember.I18n.t('answerTypes.yes.label'), Ember.I18n.t('answerTypes.no.label')]);
|
||||
});
|
||||
|
@ -73,11 +74,12 @@ test("participate in a poll using freetext", function(assert) {
|
|||
);
|
||||
|
||||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey).then(function() {
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
pollParticipate('Max Manus', ['answer 1', 'answer 2']);
|
||||
|
||||
assert.equal(find('.has-error').length, 0, "there is no validation error");
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUsersCount(assert, 1, "user is added to user selections table");
|
||||
pollHasUser(assert, 'Max Manus', ['answer 1', 'answer 2']);
|
||||
});
|
||||
|
@ -105,11 +107,12 @@ test("participate in a poll which doesn't force an answer to all options", funct
|
|||
);
|
||||
|
||||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey).then(function() {
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
pollParticipate('Karl Käfer', ['yes', null]);
|
||||
|
||||
assert.equal(Ember.$('.has-error').length, 0, "there is no validation error");
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUsersCount(assert, 1, "user is added to user selections table");
|
||||
pollHasUser(assert, "Karl Käfer", [Ember.I18n.t("answerTypes.yes.label"), ""]);
|
||||
});
|
||||
|
@ -137,11 +140,12 @@ test("participate in a poll which allows anonymous participation", function(asse
|
|||
);
|
||||
|
||||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey).then(function() {
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
pollParticipate(null, ['yes', 'no']);
|
||||
|
||||
assert.equal(Ember.$('.has-error').length, 0, "there is no validation error");
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUsersCount(assert, 1, "user is added to user selections table");
|
||||
pollHasUser(assert, "", [Ember.I18n.t("answerTypes.yes.label"), Ember.I18n.t("answerTypes.no.label")]);
|
||||
});
|
||||
|
|
|
@ -39,7 +39,12 @@ test('evaluation is not present for poll without participants', function(assert)
|
|||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey);
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(find('.evaluation').length, 0);
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
switchTab('evaluation');
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(find('.tab-content .evaluation').length, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -116,19 +121,25 @@ test('evaluation is correct', function(assert) {
|
|||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey);
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(find('.evaluation').length, 1, 'evaluation is present');
|
||||
assert.notEqual(
|
||||
find('.participants').text().indexOf(' 2 '),
|
||||
-1,
|
||||
'participants are counted correctly'
|
||||
);
|
||||
assert.equal(find('.best-options strong').text().trim(), formattedDateHelper('2015-12-12'), 'options are evaluated correctly');
|
||||
assert.notEqual(
|
||||
find('.last-participation').text().indexOf(
|
||||
moment('2015-08-01T00:00:00.000Z').from()
|
||||
),
|
||||
-1,
|
||||
'last participation is evaluated correctly'
|
||||
);
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
switchTab('evaluation');
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
assert.equal(find('.tab-content .evaluation').length, 1, 'evaluation is present');
|
||||
assert.notEqual(
|
||||
find('.participants').text().indexOf(' 2 '),
|
||||
-1,
|
||||
'participants are counted correctly'
|
||||
);
|
||||
assert.equal(find('.best-options strong').text().trim(), formattedDateHelper('2015-12-12'), 'options are evaluated correctly');
|
||||
assert.notEqual(
|
||||
find('.last-participation').text().indexOf(
|
||||
moment('2015-08-01T00:00:00.000Z').from()
|
||||
),
|
||||
-1,
|
||||
'last participation is evaluated correctly'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,6 +22,24 @@ module('Acceptance | view poll', {
|
|||
}
|
||||
});
|
||||
|
||||
test('view poll url', function(assert) {
|
||||
var id = 'test',
|
||||
encryptionKey = 'abcdefghijklmnopqrstuvwxyz012345789';
|
||||
|
||||
server.get('/polls/' + id, function() {
|
||||
return serverGetPolls({ id: id }, encryptionKey);
|
||||
});
|
||||
|
||||
visit('/poll/' + id + '?encryptionKey=' + encryptionKey);
|
||||
andThen(function() {
|
||||
assert.equal(
|
||||
find('.share-link .link a').text(),
|
||||
window.location.href,
|
||||
'share link is shown'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('view a poll with dates', function(assert) {
|
||||
var id = 'test',
|
||||
encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
|
|
@ -8,6 +8,7 @@ import './poll-has-users';
|
|||
import './poll-has-options';
|
||||
import './poll-has-answers';
|
||||
import './poll-participate';
|
||||
import './switch-tab';
|
||||
|
||||
export default function startApp(attrs) {
|
||||
var application;
|
||||
|
|
5
tests/helpers/switch-tab.js
Normal file
5
tests/helpers/switch-tab.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Test.registerAsyncHelper('switchTab', function(app, tab) {
|
||||
click('.nav-tabs .' + tab + ' a');
|
||||
});
|
|
@ -42,7 +42,7 @@ test("create a default poll and participate", function(assert) {
|
|||
click('.button-next');
|
||||
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll');
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
|
||||
pollTitleEqual(assert, 'default poll');
|
||||
pollDescriptionEqual(assert, '');
|
||||
|
@ -62,6 +62,7 @@ test("create a default poll and participate", function(assert) {
|
|||
pollHasUsersCount(assert, 0);
|
||||
pollParticipate('Max Hoelz', ['no', 'no']);
|
||||
andThen(function(){
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUsersCount(assert, 1);
|
||||
pollHasUser(assert, 'Max Hoelz', [Ember.I18n.t('answerTypes.no.label'), Ember.I18n.t('answerTypes.no.label')]);
|
||||
});
|
||||
|
|
|
@ -53,33 +53,47 @@ test('show a default poll created with v0.3.0', function(assert) {
|
|||
Ember.I18n.t('answerTypes.no.label')
|
||||
]);
|
||||
|
||||
pollHasUser(assert,
|
||||
'Fritz Bauer',
|
||||
[
|
||||
Ember.I18n.t('answerTypes.yes.label'),
|
||||
Ember.I18n.t('answerTypes.no.label'),
|
||||
Ember.I18n.t('answerTypes.no.label')
|
||||
]
|
||||
);
|
||||
pollHasUser(assert,
|
||||
'Lothar Hermann',
|
||||
[
|
||||
Ember.I18n.t('answerTypes.maybe.label'),
|
||||
Ember.I18n.t('answerTypes.yes.label'),
|
||||
Ember.I18n.t('answerTypes.no.label')
|
||||
]
|
||||
);
|
||||
switchTab('evaluation');
|
||||
|
||||
pollParticipate('Hermann Langbein', ['yes', 'maybe', 'yes']);
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
|
||||
pollHasUser(assert,
|
||||
'Hermann Langbein',
|
||||
'Fritz Bauer',
|
||||
[
|
||||
Ember.I18n.t('answerTypes.yes.label'),
|
||||
Ember.I18n.t('answerTypes.maybe.label'),
|
||||
Ember.I18n.t('answerTypes.yes.label')
|
||||
Ember.I18n.t('answerTypes.no.label'),
|
||||
Ember.I18n.t('answerTypes.no.label')
|
||||
]
|
||||
);
|
||||
pollHasUser(assert,
|
||||
'Lothar Hermann',
|
||||
[
|
||||
Ember.I18n.t('answerTypes.maybe.label'),
|
||||
Ember.I18n.t('answerTypes.yes.label'),
|
||||
Ember.I18n.t('answerTypes.no.label')
|
||||
]
|
||||
);
|
||||
|
||||
switchTab('participation');
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
|
||||
pollParticipate('Hermann Langbein', ['yes', 'maybe', 'yes']);
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUser(assert,
|
||||
'Hermann Langbein',
|
||||
[
|
||||
Ember.I18n.t('answerTypes.yes.label'),
|
||||
Ember.I18n.t('answerTypes.maybe.label'),
|
||||
Ember.I18n.t('answerTypes.yes.label')
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -100,25 +114,37 @@ test('find a poll using free text created with v0.3.0', function(assert) {
|
|||
'plum pie'
|
||||
]);
|
||||
|
||||
pollHasUser(assert,
|
||||
'Paul Levi',
|
||||
[
|
||||
'would be great!',
|
||||
'no way',
|
||||
'if I had to'
|
||||
]
|
||||
);
|
||||
switchTab('evaluation');
|
||||
|
||||
pollParticipate('Hermann Langbein', ["I don't care", 'would be awesome', "can't imagine anything better"]);
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUser(assert,
|
||||
'Hermann Langbein',
|
||||
'Paul Levi',
|
||||
[
|
||||
"I don't care",
|
||||
'would be awesome',
|
||||
"can't imagine anything better"
|
||||
'would be great!',
|
||||
'no way',
|
||||
'if I had to'
|
||||
]
|
||||
);
|
||||
|
||||
switchTab('participation');
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.participation');
|
||||
pollParticipate('Hermann Langbein', ["I don't care", 'would be awesome', "can't imagine anything better"]);
|
||||
|
||||
andThen(function() {
|
||||
assert.equal(currentPath(), 'poll.evaluation');
|
||||
pollHasUser(assert,
|
||||
'Hermann Langbein',
|
||||
[
|
||||
"I don't care",
|
||||
'would be awesome',
|
||||
"can't imagine anything better"
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
12
tests/unit/controllers/poll/participation-test.js
Normal file
12
tests/unit/controllers/poll/participation-test.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { moduleFor, test } from 'ember-qunit';
|
||||
|
||||
moduleFor('controller:poll/participation', {
|
||||
// Specify the other units that are required for this test.
|
||||
// needs: ['controller:foo']
|
||||
});
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it exists', function(assert) {
|
||||
var controller = this.subject();
|
||||
assert.ok(controller);
|
||||
});
|
Loading…
Reference in a new issue