1a17862d6b
The old hidden type was used as internal, so everything is changed to not be shown if the item is internal. hidden is "new", and actually behaves as hidden now.
924 lines
34 KiB
JavaScript
924 lines
34 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',
|
|
function ($scope, MajorityMethodChoices, Config, AssignmentPollDetailCtrlCache, AssignmentPoll) {
|
|
// Define choices.
|
|
$scope.methodChoices = MajorityMethodChoices;
|
|
// TODO: Get $scope.baseChoices from config_variables.py without copying them.
|
|
|
|
// 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',
|
|
'ballot',
|
|
'ErrorMessage',
|
|
function($scope, $filter, gettextCatalog, AssignmentPoll, assignmentpollId, 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 = {};
|
|
|
|
// 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,
|
|
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,
|
|
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,
|
|
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,
|
|
required: true,
|
|
},
|
|
defaultValue: defaultValue
|
|
});
|
|
}
|
|
});
|
|
if (assignmentpoll.pollmethod == 'votes'){
|
|
$scope.formFields.push(
|
|
{
|
|
key: 'votesabstain',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Abstain'),
|
|
type: 'number',
|
|
min: -2,
|
|
}
|
|
},
|
|
{
|
|
key: 'votesno',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('No'),
|
|
type: 'number',
|
|
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',
|
|
min: -2,
|
|
}
|
|
},
|
|
{
|
|
key: 'votesinvalid',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Invalid ballots'),
|
|
type: 'number',
|
|
min: -2,
|
|
}
|
|
},
|
|
{
|
|
key: 'votescast',
|
|
type: 'input',
|
|
templateOptions: {
|
|
label: gettextCatalog.getString('Casted ballots'),
|
|
type: 'number',
|
|
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');
|
|
}
|
|
]);
|
|
|
|
}());
|