942 lines
35 KiB
JavaScript
942 lines
35 KiB
JavaScript
(function () {
|
|
|
|
'use strict';
|
|
|
|
angular.module('OpenSlidesApp.assignments.site', [
|
|
'OpenSlidesApp.assignments',
|
|
'OpenSlidesApp.core.pdf',
|
|
'OpenSlidesApp.assignments.pdf',
|
|
'OpenSlidesApp.poll.majority'
|
|
])
|
|
|
|
.config([
|
|
'mainMenuProvider',
|
|
'gettext',
|
|
function (mainMenuProvider, gettext) {
|
|
mainMenuProvider.register({
|
|
'ui_sref': 'assignments.assignment.list',
|
|
'img_class': 'pie-chart',
|
|
'title': gettext('Elections'),
|
|
'weight': 400,
|
|
'perm': 'assignments.can_see'
|
|
});
|
|
}
|
|
])
|
|
|
|
.config([
|
|
'SearchProvider',
|
|
'gettext',
|
|
function (SearchProvider, gettext) {
|
|
SearchProvider.register({
|
|
'verboseName': gettext('Elections'),
|
|
'collectionName': 'assignments/assignment',
|
|
'urlDetailState': 'assignments.assignment.detail',
|
|
'weight': 400,
|
|
});
|
|
}
|
|
])
|
|
|
|
.config([
|
|
'$stateProvider',
|
|
'gettext',
|
|
function($stateProvider, gettext) {
|
|
$stateProvider
|
|
.state('assignments', {
|
|
url: '/assignments',
|
|
abstract: true,
|
|
template: "<ui-view/>",
|
|
data: {
|
|
title: gettext('Elections'),
|
|
basePerm: 'assignments.can_see',
|
|
},
|
|
})
|
|
.state('assignments.assignment', {
|
|
abstract: true,
|
|
template: "<ui-view/>",
|
|
})
|
|
.state('assignments.assignment.list', {})
|
|
.state('assignments.assignment.detail', {
|
|
controller: 'AssignmentDetailCtrl',
|
|
resolve: {
|
|
assignmentId: ['$stateParams', function($stateParams) {
|
|
return $stateParams.id;
|
|
}],
|
|
}
|
|
})
|
|
// redirects to assignment detail and opens assignment edit form dialog, uses edit url,
|
|
// used by ui-sref links from agenda only
|
|
// (from assignment controller use AssignmentForm factory instead to open dialog in front
|
|
// of current view without redirect)
|
|
.state('assignments.assignment.detail.update', {
|
|
onEnter: ['$stateParams', '$state', 'ngDialog',
|
|
function($stateParams, $state, ngDialog) {
|
|
ngDialog.open({
|
|
template: 'static/templates/assignments/assignment-form.html',
|
|
controller: 'AssignmentUpdateCtrl',
|
|
className: 'ngdialog-theme-default wide-form',
|
|
closeByEscape: false,
|
|
closeByDocument: false,
|
|
resolve: {
|
|
assignmentId: function() {
|
|
return $stateParams.id;
|
|
},
|
|
},
|
|
preCloseCallback: function() {
|
|
$state.go('assignments.assignment.detail', {assignment: $stateParams.id});
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
]
|
|
});
|
|
}
|
|
])
|
|
|
|
// Service for generic assignment form (create and update)
|
|
.factory('AssignmentForm', [
|
|
'gettextCatalog',
|
|
'operator',
|
|
'Editor',
|
|
'Mediafile',
|
|
'Tag',
|
|
'Assignment',
|
|
'Agenda',
|
|
'AgendaTree',
|
|
'ShowAsAgendaItemField',
|
|
function (gettextCatalog, operator, Editor, Mediafile, Tag, Assignment, Agenda, AgendaTree, ShowAsAgendaItemField) {
|
|
return {
|
|
// ngDialog for assignment form
|
|
getDialog: function (assignment) {
|
|
return {
|
|
template: 'static/templates/assignments/assignment-form.html',
|
|
controller: (assignment) ? 'AssignmentUpdateCtrl' : 'AssignmentCreateCtrl',
|
|
className: 'ngdialog-theme-default wide-form',
|
|
closeByEscape: false,
|
|
closeByDocument: false,
|
|
resolve: {
|
|
assignmentId: function () {return assignment ? assignment.id : void 0;}
|
|
},
|
|
};
|
|
},
|
|
// angular-formly fields for assignment form
|
|
getFormFields: function (isCreateForm) {
|
|
var images = Mediafile.getAllImages();
|
|
var formFields = [
|
|
{
|
|
key: 'title',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Title'),
|
|
required: true
|
|
}
|
|
},
|
|
{
|
|
key: 'description',
|
|
type: 'editor',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Description')
|
|
},
|
|
data: {
|
|
ckeditorOptions: Editor.getOptions(images)
|
|
}
|
|
},
|
|
{
|
|
key: 'open_posts',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Number of persons to be elected'),
|
|
type: 'number',
|
|
min: 1,
|
|
required: true
|
|
}
|
|
},
|
|
{
|
|
key: 'poll_description_default',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Default comment on the ballot paper')
|
|
}
|
|
}];
|
|
|
|
// show as agenda item + parent item
|
|
if (isCreateForm) {
|
|
formFields.push(ShowAsAgendaItemField('assignments.can_manage'));
|
|
formFields.push({
|
|
key: 'agenda_parent_id',
|
|
type: 'select-single',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Parent item'),
|
|
options: AgendaTree.getFlatTree(Agenda.getAll()),
|
|
ngOptions: 'item.id as item.getListViewTitle() for item in to.options | notself : model.agenda_item_id',
|
|
placeholder: gettextCatalog.getString('Select a parent item ...')
|
|
},
|
|
hide: !operator.hasPerms('agenda.can_manage')
|
|
});
|
|
}
|
|
// more (with tags field)
|
|
if (Tag.getAll().length > 0) {
|
|
formFields.push(
|
|
{
|
|
key: 'more',
|
|
type: 'checkbox',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Show extended fields')
|
|
},
|
|
hide: !operator.hasPerms('assignments.can_manage')
|
|
},
|
|
{
|
|
template: '<hr class="smallhr">',
|
|
hideExpression: '!model.more'
|
|
},
|
|
{
|
|
key: 'tags_id',
|
|
type: 'select-multiple',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Tags'),
|
|
options: Tag.getAll(),
|
|
ngOptions: 'option.id as option.name for option in to.options',
|
|
placeholder: gettextCatalog.getString('Select or search a tag ...')
|
|
},
|
|
hideExpression: '!model.more'
|
|
}
|
|
);
|
|
}
|
|
|
|
return formFields;
|
|
}
|
|
};
|
|
}
|
|
])
|
|
|
|
// Cache for AssignmentPollDetailCtrl so that users choices are keeped during user actions (e. g. save poll form).
|
|
.value('AssignmentPollDetailCtrlCache', {})
|
|
|
|
// Child controller of AssignmentDetailCtrl for each single poll.
|
|
.controller('AssignmentPollDetailCtrl', [
|
|
'$scope',
|
|
'MajorityMethodChoices',
|
|
'Config',
|
|
'AssignmentPollDetailCtrlCache',
|
|
'AssignmentPoll',
|
|
'AssignmentPollDecimalPlaces',
|
|
function ($scope, MajorityMethodChoices, Config, AssignmentPollDetailCtrlCache,
|
|
AssignmentPoll, AssignmentPollDecimalPlaces) {
|
|
// Define choices.
|
|
$scope.methodChoices = MajorityMethodChoices;
|
|
// TODO: Get $scope.baseChoices from config_variables.py without copying them.
|
|
|
|
$scope.votesPrecision = AssignmentPollDecimalPlaces.getPlaces($scope.poll);
|
|
|
|
// Setup empty cache with default values.
|
|
if (typeof AssignmentPollDetailCtrlCache[$scope.poll.id] === 'undefined') {
|
|
AssignmentPollDetailCtrlCache[$scope.poll.id] = {
|
|
method: $scope.config('assignments_poll_default_majority_method'),
|
|
};
|
|
}
|
|
|
|
// Fetch users choices from cache.
|
|
$scope.method = AssignmentPollDetailCtrlCache[$scope.poll.id].method;
|
|
|
|
$scope.recalculateMajorities = function (method) {
|
|
$scope.method = method;
|
|
_.forEach($scope.poll.options, function (option) {
|
|
option.majorityReached = option.isReached(method);
|
|
});
|
|
};
|
|
$scope.recalculateMajorities($scope.method);
|
|
|
|
$scope.saveDescriptionChange = function (poll) {
|
|
AssignmentPoll.save(poll);
|
|
};
|
|
|
|
// Save current values to cache on destroy of this controller.
|
|
$scope.$on('$destroy', function() {
|
|
AssignmentPollDetailCtrlCache[$scope.poll.id] = {
|
|
method: $scope.method,
|
|
};
|
|
});
|
|
}
|
|
])
|
|
|
|
.controller('AssignmentListCtrl', [
|
|
'$scope',
|
|
'ngDialog',
|
|
'AssignmentForm',
|
|
'Assignment',
|
|
'Tag',
|
|
'Agenda',
|
|
'Projector',
|
|
'ProjectionDefault',
|
|
'gettextCatalog',
|
|
'User',
|
|
'osTableFilter',
|
|
'osTableSort',
|
|
'osTablePagination',
|
|
'gettext',
|
|
'AssignmentPhases',
|
|
'AssignmentPdfExport',
|
|
function($scope, ngDialog, AssignmentForm, Assignment, Tag, Agenda, Projector,
|
|
ProjectionDefault, gettextCatalog, User, osTableFilter, osTableSort, osTablePagination,
|
|
gettext, AssignmentPhases, AssignmentPdfExport) {
|
|
$scope.$watch(function () {
|
|
return Assignment.lastModified();
|
|
}, function () {
|
|
$scope.assignments = _.orderBy(Assignment.getAll(), ['title']);
|
|
});
|
|
Tag.bindAll({}, $scope, 'tags');
|
|
$scope.$watch(function () {
|
|
return Projector.lastModified();
|
|
}, function () {
|
|
var projectiondefault = ProjectionDefault.filter({name: 'assignments'})[0];
|
|
if (projectiondefault) {
|
|
$scope.defaultProjectorId = projectiondefault.projector_id;
|
|
}
|
|
});
|
|
$scope.phases = AssignmentPhases;
|
|
$scope.alert = {};
|
|
|
|
// Filtering
|
|
$scope.filter = osTableFilter.createInstance('AssignmentTableFilter');
|
|
|
|
if (!$scope.filter.existsStorageEntry()) {
|
|
$scope.filter.multiselectFilters = {
|
|
tag: [],
|
|
phase: [],
|
|
};
|
|
}
|
|
$scope.filter.propertyList = ['title', 'description'];
|
|
$scope.filter.propertyFunctionList = [
|
|
function (assignment) {
|
|
return gettextCatalog.getString($scope.phases[assignment.phase].display_name);
|
|
},
|
|
];
|
|
$scope.filter.propertyDict = {
|
|
'assignment_related_users': function (candidate) {
|
|
return candidate.user.get_short_name();
|
|
},
|
|
'tags': function (tag) {
|
|
return tag.name;
|
|
},
|
|
};
|
|
$scope.getItemId = {
|
|
tag: function (assignment) {return assignment.tags_id;},
|
|
phase: function (assignment) {return assignment.phase;},
|
|
};
|
|
|
|
// Sorting
|
|
$scope.sort = osTableSort.createInstance('AssignmentTableSort');
|
|
if (!$scope.sort.column) {
|
|
$scope.sort.column = 'title';
|
|
}
|
|
$scope.sortOptions = [
|
|
{name: 'agenda_item.getItemNumberWithAncestors()',
|
|
display_name: gettext('Item')},
|
|
{name: 'title',
|
|
display_name: gettext('Title')},
|
|
{name: 'phase',
|
|
display_name: gettext('Phase')},
|
|
{name: 'assignment_related_users.length',
|
|
display_name: gettext('Number of candidates')},
|
|
];
|
|
$scope.hasTag = function (assignment, tag) {
|
|
return _.indexOf(assignment.tags_id, tag.id) > -1;
|
|
};
|
|
$scope.toggleTag = function (assignment, tag) {
|
|
if ($scope.hasTag(assignment, tag)) {
|
|
assignment.tags_id = _.filter(assignment.tags_id, function (tag_id){
|
|
return tag_id != tag.id;
|
|
});
|
|
} else {
|
|
assignment.tags_id.push(tag.id);
|
|
}
|
|
Assignment.save(assignment);
|
|
};
|
|
|
|
// Pagination
|
|
$scope.pagination = osTablePagination.createInstance('AssignmentTablePagination');
|
|
|
|
// update phase
|
|
$scope.updatePhase = function (assignment, phase_id) {
|
|
assignment.phase = phase_id;
|
|
Assignment.save(assignment);
|
|
};
|
|
// open new/edit dialog
|
|
$scope.openDialog = function (assignment) {
|
|
ngDialog.open(AssignmentForm.getDialog(assignment));
|
|
};
|
|
// *** select mode functions ***
|
|
$scope.isSelectMode = false;
|
|
// check all checkboxes
|
|
$scope.checkAll = function () {
|
|
$scope.selectedAll = !$scope.selectedAll;
|
|
angular.forEach($scope.assignments, function (assignment) {
|
|
assignment.selected = $scope.selectedAll;
|
|
});
|
|
};
|
|
// uncheck all checkboxes if isSelectMode is closed
|
|
$scope.uncheckAll = function () {
|
|
if (!$scope.isSelectMode) {
|
|
$scope.selectedAll = false;
|
|
angular.forEach($scope.assignments, function (assignment) {
|
|
assignment.selected = false;
|
|
});
|
|
}
|
|
};
|
|
// delete all selected assignments
|
|
$scope.deleteMultiple = function () {
|
|
angular.forEach($scope.assignments, function (assignment) {
|
|
if (assignment.selected)
|
|
Assignment.destroy(assignment.id);
|
|
});
|
|
$scope.isSelectMode = false;
|
|
$scope.uncheckAll();
|
|
};
|
|
// delete single assignment
|
|
$scope.delete = function (assignment) {
|
|
Assignment.destroy(assignment.id);
|
|
};
|
|
// create the PDF List
|
|
$scope.pdfExport = function () {
|
|
AssignmentPdfExport.export($scope.assignmentsFiltered);
|
|
};
|
|
}
|
|
])
|
|
|
|
.controller('AssignmentDetailCtrl', [
|
|
'$scope',
|
|
'$http',
|
|
'$filter',
|
|
'$timeout',
|
|
'filterFilter',
|
|
'gettext',
|
|
'ngDialog',
|
|
'AssignmentForm',
|
|
'operator',
|
|
'Assignment',
|
|
'User',
|
|
'assignmentId',
|
|
'Projector',
|
|
'ProjectionDefault',
|
|
'gettextCatalog',
|
|
'AssignmentPhases',
|
|
'AssignmentPdfExport',
|
|
'WebpageTitle',
|
|
'ErrorMessage',
|
|
function($scope, $http, $filter, $timeout, filterFilter, gettext, ngDialog, AssignmentForm, operator,
|
|
Assignment, User, assignmentId, Projector, ProjectionDefault, gettextCatalog, AssignmentPhases,
|
|
AssignmentPdfExport, WebpageTitle, ErrorMessage) {
|
|
User.bindAll({}, $scope, 'users');
|
|
var assignment = Assignment.get(assignmentId);
|
|
Assignment.loadRelations(assignment, 'agenda_item');
|
|
// This flag is for setting 'activeTab' to recently added (last) ballot tab.
|
|
// Set this flag, if ballots are added/removed. When the next autoupdate comes
|
|
// in, the tabset will be updated.
|
|
var updateBallotTabsFlag = true;
|
|
$scope.$watch(function () {
|
|
return Projector.lastModified();
|
|
}, function () {
|
|
var projectiondefault = ProjectionDefault.filter({name: 'assignments'})[0];
|
|
if (projectiondefault) {
|
|
$scope.defaultProjectorId = projectiondefault.projector_id;
|
|
}
|
|
});
|
|
$scope.$watch(function () {
|
|
return Assignment.lastModified(assignmentId);
|
|
}, function () {
|
|
// setup sorting of candidates
|
|
$scope.relatedUsersSorted = $filter('orderBy')(assignment.assignment_related_users, 'weight');
|
|
$scope.assignment = Assignment.get(assignment.id);
|
|
if (updateBallotTabsFlag) {
|
|
$scope.activeTab = $scope.assignment.polls.length - 1;
|
|
updateBallotTabsFlag = false;
|
|
}
|
|
WebpageTitle.updateTitle(gettextCatalog.getString('Election') + ' ' + $scope.assignment.title);
|
|
});
|
|
$scope.candidateSelectBox = {};
|
|
$scope.phases = AssignmentPhases;
|
|
$scope.alert = {};
|
|
|
|
// open edit dialog
|
|
$scope.openDialog = function () {
|
|
ngDialog.open(AssignmentForm.getDialog($scope.assignment));
|
|
};
|
|
// add (nominate) candidate
|
|
$scope.addCandidate = function (userId) {
|
|
$http.post('/rest/assignments/assignment/' + assignmentId + '/candidature_other/', {'user': userId})
|
|
.then(function (success){
|
|
$scope.alert.show = false;
|
|
$scope.candidateSelectBox = {};
|
|
}, function (error){
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
$scope.candidateSelectBox = {};
|
|
});
|
|
};
|
|
// remove candidate
|
|
$scope.removeCandidate = function (userId) {
|
|
$http.delete('/rest/assignments/assignment/' + assignmentId + '/candidature_other/',
|
|
{headers: {'Content-Type': 'application/json'},
|
|
data: JSON.stringify({user: userId})})
|
|
.then(function (success) {},
|
|
function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
}
|
|
);
|
|
};
|
|
// add me (nominate self as candidate)
|
|
$scope.addMe = function () {
|
|
$http.post('/rest/assignments/assignment/' + assignmentId + '/candidature_self/', {}).then(
|
|
function (success) {
|
|
$scope.alert.show = false;
|
|
}, function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
}
|
|
);
|
|
};
|
|
// remove me (withdraw own candidature)
|
|
$scope.removeMe = function () {
|
|
$http.delete('/rest/assignments/assignment/' + assignmentId + '/candidature_self/').then(
|
|
function (success) {
|
|
$scope.alert.show = false;
|
|
}, function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
}
|
|
);
|
|
};
|
|
// check if current user is already a candidate (elected==false)
|
|
$scope.isCandidate = function () {
|
|
var check = $scope.assignment.assignment_related_users.map(function(candidate) {
|
|
if (!candidate.elected) {
|
|
return candidate.user_id;
|
|
}
|
|
}).indexOf(operator.user.id);
|
|
if (check > -1) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
// Sort all candidates
|
|
$scope.treeOptions = {
|
|
dropped: function () {
|
|
var sortedCandidates = [];
|
|
_.forEach($scope.relatedUsersSorted, function (user) {
|
|
sortedCandidates.push(user.id);
|
|
});
|
|
$http.post('/rest/assignments/assignment/' + assignmentId + '/sort_related_users/',
|
|
{related_users: sortedCandidates}
|
|
);
|
|
}
|
|
};
|
|
// update phase
|
|
$scope.updatePhase = function (phase_id) {
|
|
$scope.assignment.phase = phase_id;
|
|
Assignment.save($scope.assignment);
|
|
};
|
|
// create new ballot
|
|
$scope.createBallot = function () {
|
|
$http.post('/rest/assignments/assignment/' + assignmentId + '/create_poll/').then(
|
|
function (success) {
|
|
$scope.alert.show = false;
|
|
if (assignment.phase === 0) {
|
|
$scope.updatePhase(1);
|
|
}
|
|
updateBallotTabsFlag = true;
|
|
}, function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
}
|
|
);
|
|
};
|
|
// delete ballot
|
|
$scope.deleteBallot = function (poll) {
|
|
poll.DSDestroy().then(
|
|
function (success) {
|
|
$scope.activeTab = $scope.activeTab - 1;
|
|
updateBallotTabsFlag = true;
|
|
}
|
|
);
|
|
};
|
|
// edit poll dialog
|
|
$scope.editPollDialog = function (poll, ballot) {
|
|
ngDialog.open({
|
|
template: 'static/templates/assignments/assignmentpoll-form.html',
|
|
controller: 'AssignmentPollUpdateCtrl',
|
|
className: 'ngdialog-theme-default',
|
|
closeByEscape: false,
|
|
closeByDocument: false,
|
|
resolve: {
|
|
assignmentpollId: function () {return poll.id;},
|
|
ballot: function () {return ballot;},
|
|
}
|
|
});
|
|
};
|
|
// publish ballot
|
|
$scope.togglePublishBallot = function (poll) {
|
|
poll.DSUpdate({
|
|
assignment_id: assignmentId,
|
|
published: !poll.published,
|
|
})
|
|
.then(function (success) {
|
|
$scope.alert.show = false;
|
|
}, function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
});
|
|
};
|
|
|
|
// mark candidate as (not) elected
|
|
$scope.markElected = function (user, reverse) {
|
|
if (reverse) {
|
|
$http.delete(
|
|
'/rest/assignments/assignment/' + assignmentId + '/mark_elected/', {
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
data: JSON.stringify({user: user})
|
|
});
|
|
} else {
|
|
$http.post('/rest/assignments/assignment/' + assignmentId + '/mark_elected/', {'user': user});
|
|
}
|
|
|
|
};
|
|
|
|
// Creates the document as pdf
|
|
$scope.pdfExport = function() {
|
|
AssignmentPdfExport.export($scope.assignment, true);
|
|
};
|
|
// Creates the ballotpaper as pdf
|
|
$scope.ballotpaperExport = function(pollId) {
|
|
AssignmentPdfExport.createBallotPdf($scope.assignment, pollId);
|
|
};
|
|
|
|
// Just mark some vote value strings for translation.
|
|
gettext('Yes');
|
|
gettext('No');
|
|
gettext('Abstain');
|
|
}
|
|
])
|
|
|
|
.controller('AssignmentCreateCtrl', [
|
|
'$scope',
|
|
'$state',
|
|
'Assignment',
|
|
'AssignmentForm',
|
|
'Agenda',
|
|
'Config',
|
|
'ErrorMessage',
|
|
function($scope, $state, Assignment, AssignmentForm, Agenda, Config, ErrorMessage) {
|
|
$scope.model = {
|
|
agenda_type: parseInt(Config.get('agenda_new_items_default_visibility').value),
|
|
};
|
|
// set default value for open posts form field
|
|
$scope.model.open_posts = 1;
|
|
// get all form fields
|
|
$scope.formFields = AssignmentForm.getFormFields(true);
|
|
// save assignment
|
|
$scope.save = function(assignment, gotoDetailView) {
|
|
Assignment.create(assignment).then(
|
|
function (success) {
|
|
if (gotoDetailView) {
|
|
$state.go('assignments.assignment.detail', {id: success.id});
|
|
}
|
|
$scope.closeThisDialog();
|
|
},
|
|
function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
}
|
|
);
|
|
};
|
|
}
|
|
])
|
|
|
|
.controller('AssignmentUpdateCtrl', [
|
|
'$scope',
|
|
'$state',
|
|
'Assignment',
|
|
'AssignmentForm',
|
|
'Agenda',
|
|
'assignmentId',
|
|
'ErrorMessage',
|
|
function($scope, $state, Assignment, AssignmentForm, Agenda, assignmentId, ErrorMessage) {
|
|
var assignment = Assignment.get(assignmentId);
|
|
$scope.alert = {};
|
|
// set initial values for form model by create deep copy of assignment object
|
|
// so list/detail view is not updated while editing
|
|
$scope.model = angular.copy(assignment);
|
|
// get all form fields
|
|
$scope.formFields = AssignmentForm.getFormFields();
|
|
|
|
// save assignment
|
|
$scope.save = function (assignment, gotoDetailView) {
|
|
// inject the changed assignment (copy) object back into DS store
|
|
Assignment.inject(assignment);
|
|
// save changed assignment object on server
|
|
Assignment.save(assignment).then(
|
|
function(success) {
|
|
if (gotoDetailView) {
|
|
$state.go('assignments.assignment.detail', {id: success.id});
|
|
}
|
|
$scope.closeThisDialog();
|
|
},
|
|
function (error) {
|
|
// save error: revert all changes by restore
|
|
// (refresh) original assignment object from server
|
|
Assignment.refresh(assignment);
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
}
|
|
);
|
|
};
|
|
}
|
|
])
|
|
|
|
.controller('AssignmentPollUpdateCtrl', [
|
|
'$scope',
|
|
'$filter',
|
|
'gettextCatalog',
|
|
'AssignmentPoll',
|
|
'assignmentpollId',
|
|
'AssignmentPollDecimalPlaces',
|
|
'ballot',
|
|
'ErrorMessage',
|
|
function($scope, $filter, gettextCatalog, AssignmentPoll, assignmentpollId,
|
|
AssignmentPollDecimalPlaces, ballot, ErrorMessage) {
|
|
// set initial values for form model by create deep copy of assignmentpoll object
|
|
// so detail view is not updated while editing poll
|
|
var assignmentpoll = angular.copy(AssignmentPoll.get(assignmentpollId));
|
|
$scope.model = assignmentpoll;
|
|
$scope.ballot = ballot;
|
|
$scope.formFields = [];
|
|
$scope.alert = {};
|
|
|
|
// For number inputs
|
|
var step = Math.pow(10, -AssignmentPollDecimalPlaces.getPlaces(assignmentpoll));
|
|
|
|
// add dynamic form fields
|
|
var options = $filter('orderBy')(assignmentpoll.options, 'weight');
|
|
_.forEach(options, function(option) {
|
|
var defaultValue;
|
|
if (assignmentpoll.pollmethod == 'yna' || assignmentpoll.pollmethod == 'yn') {
|
|
defaultValue = {};
|
|
_.forEach(option.votes, function (vote) {
|
|
defaultValue[vote.value.toLowerCase()] = vote.weight;
|
|
});
|
|
|
|
var columnClass = (assignmentpoll.pollmethod === 'yna') ? 'col-xs-4' : 'col-xs-6';
|
|
var columns = [
|
|
{
|
|
key: 'yes_' + option.candidate_id,
|
|
type: 'input',
|
|
className: columnClass + ' no-padding-left',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Yes'),
|
|
type: 'number',
|
|
min: -2,
|
|
step: step,
|
|
required: true
|
|
},
|
|
defaultValue: defaultValue.yes
|
|
},
|
|
{
|
|
key: 'no_' + option.candidate_id,
|
|
type: 'input',
|
|
className: columnClass + ' no-padding-left' +
|
|
(assignmentpoll.pollmethod === 'yn' ? ' no-padding-right' : ''),
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('No'),
|
|
type: 'number',
|
|
min: -2,
|
|
step: step,
|
|
required: true
|
|
},
|
|
defaultValue: defaultValue.no
|
|
}
|
|
];
|
|
if (assignmentpoll.pollmethod == 'yna'){
|
|
columns.push({
|
|
key:'abstain_' + option.candidate_id,
|
|
type: 'input',
|
|
className: columnClass + ' no-padding-left no-padding-right',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Abstain'),
|
|
type: 'number',
|
|
min: -2,
|
|
step: step,
|
|
required: true
|
|
},
|
|
defaultValue: defaultValue.abstain
|
|
});
|
|
}
|
|
$scope.formFields.push({
|
|
noFormControl: true,
|
|
template: '<strong>' + option.candidate.get_full_name() + '</strong>'
|
|
},
|
|
{
|
|
className: 'row',
|
|
fieldGroup: columns,
|
|
});
|
|
} else { // votes method
|
|
if (option.votes.length) {
|
|
defaultValue = option.votes[0].weight;
|
|
}
|
|
$scope.formFields.push({
|
|
key: 'vote_' + option.candidate_id,
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: option.candidate.get_full_name(),
|
|
type: 'number',
|
|
min: -2,
|
|
step: step,
|
|
required: true,
|
|
},
|
|
defaultValue: defaultValue
|
|
});
|
|
}
|
|
});
|
|
if (assignmentpoll.pollmethod == 'votes'){
|
|
$scope.formFields.push(
|
|
{
|
|
key: 'votesabstain',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Abstain'),
|
|
type: 'number',
|
|
step: step,
|
|
min: -2,
|
|
}
|
|
},
|
|
{
|
|
key: 'votesno',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('No'),
|
|
type: 'number',
|
|
step: step,
|
|
min: -2,
|
|
}
|
|
}
|
|
);
|
|
}
|
|
// add general form fields
|
|
$scope.formFields.push(
|
|
{
|
|
template: '<hr class="smallhr">',
|
|
},
|
|
{
|
|
key: 'votesvalid',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Valid ballots'),
|
|
type: 'number',
|
|
step: step,
|
|
min: -2,
|
|
}
|
|
},
|
|
{
|
|
key: 'votesinvalid',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Invalid ballots'),
|
|
type: 'number',
|
|
step: step,
|
|
min: -2,
|
|
}
|
|
},
|
|
{
|
|
key: 'votescast',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Casted ballots'),
|
|
type: 'number',
|
|
step: step,
|
|
min: -2,
|
|
}
|
|
}
|
|
);
|
|
|
|
// save assignmentpoll
|
|
$scope.save = function (poll) {
|
|
var votes = [];
|
|
if (assignmentpoll.pollmethod == 'yna') {
|
|
assignmentpoll.options.forEach(function(option) {
|
|
votes.push({
|
|
'Yes': poll['yes_' + option.candidate_id],
|
|
'No': poll['no_' + option.candidate_id],
|
|
'Abstain': poll['abstain_' + option.candidate_id]
|
|
});
|
|
});
|
|
} else if (assignmentpoll.pollmethod == 'yn') {
|
|
assignmentpoll.options.forEach(function(option) {
|
|
votes.push({
|
|
'Yes': poll['yes_' + option.candidate_id],
|
|
'No': poll['no_' + option.candidate_id]
|
|
});
|
|
});
|
|
} else {
|
|
assignmentpoll.options.forEach(function(option) {
|
|
votes.push({
|
|
'Votes': poll['vote_' + option.candidate_id],
|
|
});
|
|
});
|
|
}
|
|
// save change poll object on server
|
|
poll.DSUpdate({
|
|
assignment_id: poll.assignment_id,
|
|
votes: votes,
|
|
votesabstain: poll.votesabstain,
|
|
votesno: poll.votesno,
|
|
votesvalid: poll.votesvalid,
|
|
votesinvalid: poll.votesinvalid,
|
|
votescast: poll.votescast,
|
|
})
|
|
.then(function(success) {
|
|
$scope.alert.show = false;
|
|
$scope.closeThisDialog();
|
|
}, function (error) {
|
|
$scope.alert = ErrorMessage.forAlert(error);
|
|
});
|
|
};
|
|
}
|
|
])
|
|
|
|
//mark all assignment config strings for translation with Javascript
|
|
.config([
|
|
'gettext',
|
|
function (gettext) {
|
|
gettext('Election method');
|
|
gettext('Automatic assign of method');
|
|
gettext('Always one option per candidate');
|
|
gettext('Always Yes-No-Abstain per candidate');
|
|
gettext('Always Yes/No per candidate');
|
|
gettext('Elections');
|
|
gettext('Ballot and ballot papers');
|
|
gettext('The 100-%-base of an election result consists of');
|
|
gettext('For Yes/No/Abstain per candidate and Yes/No per candidate the 100-%-base ' +
|
|
'depends on the election method: If there is only one option per candidate, ' +
|
|
'the sum of all votes of all candidates is 100 %. Otherwise for each ' +
|
|
'candidate the sum of all votes is 100 %.');
|
|
gettext('Yes/No/Abstain per candidate');
|
|
gettext('Yes/No per candidate');
|
|
gettext('All valid ballots');
|
|
gettext('All casted ballots');
|
|
gettext('Disabled (no percents)');
|
|
gettext('Number of ballot papers (selection)');
|
|
gettext('Number of all delegates');
|
|
gettext('Number of all participants');
|
|
gettext('Use the following custom number');
|
|
gettext('Custom number of ballot papers');
|
|
gettext('Required majority');
|
|
gettext('Default method to check whether a candidate has reached the required majority.');
|
|
gettext('Simple majority');
|
|
gettext('Two-thirds majority');
|
|
gettext('Three-quarters majority');
|
|
gettext('Disabled');
|
|
gettext('Put all candidates on the list of speakers');
|
|
gettext('Title for PDF document (all elections)');
|
|
gettext('Preamble text for PDF document (all elections)');
|
|
//other translations
|
|
gettext('Searching for candidates');
|
|
gettext('Voting');
|
|
gettext('Finished');
|
|
}
|
|
]);
|
|
|
|
}());
|