Merge pull request #1715 from emanuelschuetze/template-improvements

Template improvements
This commit is contained in:
Oskar Hahn 2015-11-29 22:32:08 +01:00
commit ca201758e8
17 changed files with 502 additions and 466 deletions

View File

@ -37,17 +37,6 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
} }
} }
}) })
.state('agenda.item.create', {
resolve: {
types: function($http) {
// get all item types
return $http({ 'method': 'OPTIONS', 'url': '/rest/agenda/item/' });
},
tags: function(Tag) {
return Tag.findAll();
}
}
})
.state('agenda.item.detail', { .state('agenda.item.detail', {
resolve: { resolve: {
item: function(Agenda, $stateParams) { item: function(Agenda, $stateParams) {
@ -61,17 +50,6 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
} }
} }
}) })
.state('agenda.item.detail.update', {
views: {
'@agenda.item': {}
},
resolve: {
types: function($http) {
// get all item types
return $http({ 'method': 'OPTIONS', 'url': '/rest/agenda/item/' });
}
}
})
.state('agenda.item.sort', { .state('agenda.item.sort', {
resolve: { resolve: {
items: function(Agenda) { items: function(Agenda) {
@ -115,7 +93,7 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
); );
}; };
// open new customslide dialog // open new dialog
$scope.newDialog = function () { $scope.newDialog = function () {
ngDialog.open({ ngDialog.open({
template: 'static/templates/core/customslide-form.html', template: 'static/templates/core/customslide-form.html',
@ -123,32 +101,18 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
className: 'ngdialog-theme-default wide-form' className: 'ngdialog-theme-default wide-form'
}); });
}; };
// open edit dialog
$scope.editDialog = function (item) {
$state.go(item.content_object.collection.replace('/','.')+'.detail.update',
{id: item.content_object.id});
};
// detail view of related item (content object) // detail view of related item (content object)
$scope.open = function (item) { $scope.open = function (item) {
$state.go(item.content_object.collection.replace('/','.')+'.detail', $state.go(item.content_object.collection.replace('/','.')+'.detail',
{id: item.content_object.id}); {id: item.content_object.id});
}; };
// edit view of related item (content object) // save changed item
$scope.edit = function (item) { $scope.save = function (item) {
if (item.content_object.collection == "core/customslide") {
ngDialog.open({
template: 'static/templates/core/customslide-form.html',
controller: 'CustomslideUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: {
customslide: function(Customslide) {
return Customslide.find(item.content_object.id);
}
}
});
}
else {
$state.go(item.content_object.collection.replace('/','.')+'.detail.update',
{id: item.content_object.id});
}
};
// update changed item
$scope.update = function (item) {
Agenda.save(item).then( Agenda.save(item).then(
function(success) { function(success) {
item.quickEdit = false; item.quickEdit = false;
@ -286,48 +250,6 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
} }
]) ])
.controller('ItemCreateCtrl', [
'$scope',
'$state',
'Agenda',
'Tag',
'types',
function($scope, $state, Agenda, Tag, types) {
$scope.types = types.data.actions.POST.type.choices; // get all item types
Tag.bindAll({}, $scope, 'tags');
$scope.save = function (item) {
if (!item)
return null;
Agenda.create(item).then(
function(success) {
$state.go('agenda.item.list');
}
);
};
}
])
.controller('ItemUpdateCtrl', [
'$scope',
'$state',
'Agenda',
'Tag',
'types',
'item',
function($scope, $state, Agenda, Tag, types, item) {
$scope.types = types.data.actions.POST.type.choices; // get all item types
Tag.bindAll({}, $scope, 'tags');
$scope.item = item;
$scope.save = function (item) {
Agenda.save(item).then(
function(success) {
$state.go('agenda.item.list');
}
);
};
}
])
.controller('AgendaSortCtrl', [ .controller('AgendaSortCtrl', [
'$scope', '$scope',
'$http', '$http',

View File

@ -131,7 +131,7 @@
<div os-perms="agenda.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !item.hover}"> <div os-perms="agenda.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !item.hover}">
<a ui-sref="agenda.item.detail({id: item.id})" translate>List of speakers</a> | <a ui-sref="agenda.item.detail({id: item.id})" translate>List of speakers</a> |
<a href="" ng-click="item.quickEdit=true" translate>QuickEdit</a> | <a href="" ng-click="item.quickEdit=true" translate>QuickEdit</a> |
<a href="" ng-click="edit(item)" translate>Edit</a> <a href="" ng-click="editDialog(item)" translate>Edit</a>
<!-- TODO: translate confirm message --> <!-- TODO: translate confirm message -->
<span ng-if="item.content_object.collection == 'core/customslide'"> | <span ng-if="item.content_object.collection == 'core/customslide'"> |
<a href="" class="text-danger" <a href="" class="text-danger"
@ -143,10 +143,10 @@
{{ item.duration }} {{ item.duration }}
<span ng-if="item.duration" translate>h</span> <span ng-if="item.duration" translate>h</span>
<td ng-if="!item.quickEdit"> <td ng-if="!item.quickEdit">
<input type="checkbox" ng-model="item.closed" ng-change="update(item.id);"> <input type="checkbox" ng-model="item.closed" ng-change="save(item.id);">
<!-- quickEdit columns --> <!-- quickEdit columns -->
<td ng-if="item.quickEdit" os-perms-lite="agenda.can_manage" colspan="3"> <td ng-if="item.quickEdit" os-perms-lite="agenda.can_manage" colspan="3">
<form ng-submit="update(item)"> <form ng-submit="save(item)">
<h4>{{ item.getTitle() }} <span class="text-muted">&ndash; QuickEdit</span></h4> <h4>{{ item.getTitle() }} <span class="text-muted">&ndash; QuickEdit</span></h4>
<alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}"> <alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
{{alert.msg}} {{alert.msg}}

View File

@ -102,10 +102,13 @@ class AssignmentAllPollSerializer(ModelSerializer):
Customized update method for polls. To update votes use the write Customized update method for polls. To update votes use the write
only field 'votes'. only field 'votes'.
Example data for a 'yesnoabstain' poll with two candidates: Example data for a 'yesnoabstain'=true poll with two candidates:
"votes": [{"Yes": 10, "No": 4, "Abstain": -2}, "votes": [{"Yes": 10, "No": 4, "Abstain": -2},
{"Yes": -1, "No": 0, "Abstain": -2}] {"Yes": -1, "No": 0, "Abstain": -2}]
Example data for a 'yesnoabstain'=false poll with two candidates:
"votes": [{"Votes": 10}, {"Votes": 0}]
""" """
# Update votes. # Update votes.
votes = validated_data.get('votes') votes = validated_data.get('votes')

View File

@ -38,7 +38,6 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
} }
} }
}) })
.state('assignments.assignment.create', {})
.state('assignments.assignment.detail', { .state('assignments.assignment.detail', {
controller: 'AssignmentDetailCtrl', controller: 'AssignmentDetailCtrl',
resolve: { resolve: {
@ -51,9 +50,15 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
} }
}) })
.state('assignments.assignment.detail.update', { .state('assignments.assignment.detail.update', {
views: { onEnter: ['$stateParams', 'ngDialog', 'Assignment', function($stateParams, ngDialog, Assignment) {
'@assignments.assignment': {} ngDialog.open({
} template: 'static/templates/assignments/assignment-form.html',
controller: 'AssignmentUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: { assignment: function() {
return Assignment.find($stateParams.id) }}
});
}]
}); });
}) })
@ -157,7 +162,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
$scope.sortColumn = column; $scope.sortColumn = column;
}; };
// open new customslide dialog // open new dialog
$scope.newDialog = function () { $scope.newDialog = function () {
ngDialog.open({ ngDialog.open({
template: 'static/templates/assignments/assignment-form.html', template: 'static/templates/assignments/assignment-form.html',
@ -165,7 +170,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
className: 'ngdialog-theme-default wide-form' className: 'ngdialog-theme-default wide-form'
}); });
}; };
// edit view of related item (content object) // open edit dialog
$scope.editDialog = function (assignment) { $scope.editDialog = function (assignment) {
ngDialog.open({ ngDialog.open({
template: 'static/templates/assignments/assignment-form.html', template: 'static/templates/assignments/assignment-form.html',
@ -178,7 +183,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
} }
}); });
}; };
// save changed item // save changed assignment
$scope.save = function (assignment) { $scope.save = function (assignment) {
Assignment.save(assignment).then( Assignment.save(assignment).then(
function(success) { function(success) {
@ -193,6 +198,23 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
$scope.alert = { type: 'danger', msg: message, show: true }; $scope.alert = { type: 'danger', msg: message, show: true };
}); });
}; };
// *** delete mode functions ***
$scope.isDeleteMode = false;
// check all checkboxes
$scope.checkAll = function () {
angular.forEach($scope.assignments, function (assignment) {
assignment.selected = $scope.selectedAll;
});
};
// uncheck all checkboxes if isDeleteMode is closed
$scope.uncheckAll = function () {
if (!$scope.isDeleteMode) {
$scope.selectedAll = false;
angular.forEach($scope.assignments, function (assignment) {
assignment.selected = false;
});
}
};
// delete all selected assignments // delete all selected assignments
$scope.deleteMultiple = function () { $scope.deleteMultiple = function () {
angular.forEach($scope.assignments, function (assignment) { angular.forEach($scope.assignments, function (assignment) {
@ -329,7 +351,6 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
'Assignment', 'Assignment',
'AssignmentFormFieldFactory', 'AssignmentFormFieldFactory',
function($scope, $state, Assignment, AssignmentFormFieldFactory) { function($scope, $state, Assignment, AssignmentFormFieldFactory) {
$scope.assignment = {};
// get all form fields // get all form fields
$scope.formFields = AssignmentFormFieldFactory.getFormFields(); $scope.formFields = AssignmentFormFieldFactory.getFormFields();
@ -379,6 +400,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
$scope.formFields = []; $scope.formFields = [];
// add dynamic form fields // add dynamic form fields
assignmentpoll.options.forEach(function(option) { assignmentpoll.options.forEach(function(option) {
if (assignmentpoll.yesnoabstain) {
$scope.formFields.push( $scope.formFields.push(
{ {
noFormControl: true, noFormControl: true,
@ -410,8 +432,19 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
type: 'number', type: 'number',
required: true required: true
} }
});
} else {
$scope.formFields.push(
{
key: 'vote_' + option.candidate_id,
type: 'input',
templateOptions: {
label: option.candidate.get_full_name(),
type: 'number',
required: true
}
});
} }
);
}); });
// add general form fields // add general form fields
$scope.formFields.push( $scope.formFields.push(
@ -455,6 +488,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
// save assignment // save assignment
$scope.save = function (poll) { $scope.save = function (poll) {
var votes = []; var votes = [];
if (assignmentpoll.yesnoabstain) {
assignmentpoll.options.forEach(function(option) { assignmentpoll.options.forEach(function(option) {
votes.push({ votes.push({
"Yes": poll['yes_' + option.candidate_id], "Yes": poll['yes_' + option.candidate_id],
@ -462,6 +496,13 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
"Abstain": poll['abstain_' + option.candidate_id] "Abstain": poll['abstain_' + option.candidate_id]
}); });
}); });
} else {
assignmentpoll.options.forEach(function(option) {
votes.push({
"Votes": poll['vote_' + option.candidate_id],
});
});
}
poll.DSUpdate({ poll.DSUpdate({
assignment_id: poll.assignment_id, assignment_id: poll.assignment_id,
votes: votes, votes: votes,

View File

@ -9,6 +9,11 @@
<i class="fa fa-file-pdf-o fa-lg"></i> <i class="fa fa-file-pdf-o fa-lg"></i>
<translate>PDF</translate> <translate>PDF</translate>
</a> </a>
<!-- List of speakers -->
<a ui-sref="agenda.item.detail({id: assignment.agenda_item_id})" class="btn btn-sm btn-default">
<i class="fa fa-microphone fa-lg"></i>
<translate>List of speakers</translate>
</a>
<!-- project --> <!-- project -->
<a os-perms="core.can_manage_projector" class="btn btn-default btn-sm" <a os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
ng-class="{ 'btn-primary': assignment.isProjected() }" ng-class="{ 'btn-primary': assignment.isProjected() }"
@ -105,7 +110,7 @@
</div> </div>
<div class="results"> <div class="results">
<div ng-repeat="option in poll.options"> <div ng-repeat="option in poll.options">
<strong>User#{{ option.candidate_id }}</strong> <strong>{{ option.candidate.get_full_name() }}</strong>
<div ng-if="option.votes.length > 0"> <div ng-if="option.votes.length > 0">
<div ng-repeat="vote in option.votes"> <div ng-repeat="vote in option.votes">
{{ vote.value}}: {{ vote.weight}} {{ vote.value}}: {{ vote.weight}}

View File

@ -1,5 +1,5 @@
<h1 ng-if="assignment.id" translate>Edit election</h1> <h1 ng-if="model.id" translate>Edit election</h1>
<h1 ng-if="!assignment.id" translate>New election</h1> <h1 ng-if="!model.id" translate>New election</h1>
<form name="assignmentForm" ng-submit="save(model)"> <form name="assignmentForm" ng-submit="save(model)">
<formly-form model="model" fields="formFields"> <formly-form model="model" fields="formFields">

View File

@ -227,6 +227,17 @@ angular.module('OpenSlidesApp.core.site', [
} }
} }
}) })
.state('core.customslide.detail.update', {
onEnter: ['$stateParams', 'ngDialog', 'Customslide', function($stateParams, ngDialog, Customslide) {
ngDialog.open({
template: 'static/templates/core/customslide-form.html',
controller: 'CustomslideUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: { customslide: function() {
return Customslide.find($stateParams.id) }}
});
}]
})
// tag // tag
.state('core.tag', { .state('core.tag', {
url: '/tag', url: '/tag',

View File

@ -1,5 +1,5 @@
<h1 ng-if="customslide.id" translate>Edit agenda item</h1> <h1 ng-if="model.id" translate>Edit agenda item</h1>
<h2 ng-if="!customslide.id" translate>New agenda item</h2> <h2 ng-if="!model.id" translate>New agenda item</h2>
<form name="customslideForm" ng-submit="save(model)"> <form name="customslideForm" ng-submit="save(model)">
<formly-form model="model" fields="formFields"> <formly-form model="model" fields="formFields">

View File

@ -59,13 +59,13 @@
</div> </div>
<!-- user settings / logout button --> <!-- user settings / logout button -->
<div class="btn-group" dropdown is-open="status.isopen"> <div class="btn-group" uib-dropdown>
<button type="button" class="btn btn-default dropdown-toggle" dropdown-toggle> <button type="button" class="btn btn-default" uib-dropdown-toggle>
<i class="fa fa-user"></i> <i class="fa fa-user"></i>
<span class="optional-small">{{ operator.user.get_short_name() }}</span> <span class="optional-small">{{ operator.user.get_short_name() }}</span>
<span class="caret"></span> <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu pull-right" role="menu"> <ul class="uib-dropdown-menu pull-right" role="menu" aria-labelledby="single-button">
<li> <li>
<a ui-sref="users.user.detail.profile({ id: operator.user.id })"> <a ui-sref="users.user.detail.profile({ id: operator.user.id })">
<i class="fa fa-cog"></i> <i class="fa fa-cog"></i>
@ -95,12 +95,12 @@
</div> </div>
<!-- language switcher --> <!-- language switcher -->
<div class="btn-group" ng-controller="LanguageCtrl"> <div class="btn-group" ng-controller="LanguageCtrl" uib-dropdown>
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> <button class="btn btn-default" uib-dropdown-toggle>
<i class="fa fa-flag"></i> <i class="fa fa-flag"></i>
<span class="caret"></span> <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-right" role="menu"> <ul class="uib-dropdown-menu uib-dropdown-menu-right" role="menu" aria-labelledby="single-button">
<li> <li>
<a href="" ng-click="switchLanguage('en')"> <a href="" ng-click="switchLanguage('en')">
<i class="fa fa-flag"></i> <i class="fa fa-flag"></i>

View File

@ -298,147 +298,6 @@ angular.module('OpenSlidesApp.motions', ['OpenSlidesApp.users'])
} }
]) ])
// Provide generic motion form fields for create and update view
.factory('MotionFormFieldFactory', [
'gettext',
'operator',
'Category',
'Config',
'Mediafile',
'Tag',
'User',
'Workflow',
function (gettext, operator, Category, Config, Mediafile, Tag, User, Workflow) {
return {
getFormFields: function () {
return [
{
key: 'identifier',
type: 'input',
templateOptions: {
label: gettext('Identifier')
},
hide: true
},
{
key: 'submitters_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Submitters'),
optionsAttr: 'bs-options',
options: User.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'full_name',
placeholder: gettext('Select or search a submitter...')
},
hide: !operator.hasPerms('motions.can_manage')
},
{
key: 'title',
type: 'input',
templateOptions: {
label: gettext('Title'),
required: true
}
},
{
key: 'text',
type: 'textarea',
templateOptions: {
label: gettext('Text'),
required: true
}
},
{
key: 'reason',
type: 'textarea',
templateOptions: {
label: gettext('Reason')
}
},
{
key: 'more',
type: 'checkbox',
templateOptions: {
label: gettext('Show extended fields')
},
hide: !operator.hasPerms('motions.can_manage')
},
{
key: 'attachments_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Attachment'),
optionsAttr: 'bs-options',
options: Mediafile.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'title_or_filename',
placeholder: gettext('Select or search an attachment...')
},
hideExpression: '!model.more'
},
{
key: 'category_id',
type: 'ui-select-single',
templateOptions: {
label: gettext('Category'),
optionsAttr: 'bs-options',
options: Category.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a category...')
},
hideExpression: '!model.more'
},
{
key: 'tags_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Tags'),
optionsAttr: 'bs-options',
options: Tag.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a tag...')
},
hideExpression: '!model.more'
},
{
key: 'supporters_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Supporters'),
optionsAttr: 'bs-options',
options: User.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'full_name',
placeholder: gettext('Select or search a supporter...')
},
hideExpression: '!model.more'
},
{
key: 'workflow_id',
type: 'ui-select-single',
templateOptions: {
label: gettext('Workflow'),
optionsAttr: 'bs-options',
options: Workflow.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a workflow...')
},
hideExpression: '!model.more',
}];
}
}
}
])
.factory('Category', ['DS', function(DS) { .factory('Category', ['DS', function(DS) {
return DS.defineResource({ return DS.defineResource({
name: 'motions/category', name: 'motions/category',

View File

@ -45,25 +45,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
} }
} }
}) })
.state('motions.motion.create', {
resolve: {
categories: function(Category) {
return Category.findAll();
},
tags: function(Tag) {
return Tag.findAll();
},
users: function(User) {
return User.findAll();
},
mediafiles: function(Mediafile) {
return Mediafile.findAll();
},
workflows: function(Workflow) {
return Workflow.findAll();
}
}
})
.state('motions.motion.detail', { .state('motions.motion.detail', {
resolve: { resolve: {
motion: function(Motion, $stateParams) { motion: function(Motion, $stateParams) {
@ -84,26 +65,15 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
} }
}) })
.state('motions.motion.detail.update', { .state('motions.motion.detail.update', {
views: { onEnter: ['$stateParams', 'ngDialog', 'Motion', function($stateParams, ngDialog, Motion) {
'@motions.motion': {} ngDialog.open({
}, template: 'static/templates/motions/motion-form.html',
resolve: { controller: 'MotionUpdateCtrl',
categories: function(Category) { className: 'ngdialog-theme-default wide-form',
return Category.findAll(); resolve: { motion: function() {
}, return Motion.find($stateParams.id) }}
tags: function(Tag) { });
return Tag.findAll(); }]
},
users: function(User) {
return User.findAll();
},
mediafiles: function(Mediafile) {
return Mediafile.findAll();
},
workflows: function(Workflow) {
return Workflow.findAll();
}
}
}) })
.state('motions.motion.csv-import', { .state('motions.motion.csv-import', {
url: '/csv-import', url: '/csv-import',
@ -134,18 +104,163 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
views: { views: {
'@motions.category': {} '@motions.category': {}
} }
}) });
}) })
// Provide generic motion form fields for create and update view
.factory('MotionFormFieldFactory', [
'gettext',
'operator',
'Category',
'Config',
'Mediafile',
'Tag',
'User',
'Workflow',
function (gettext, operator, Category, Config, Mediafile, Tag, User, Workflow) {
return {
getFormFields: function () {
return [
{
key: 'identifier',
type: 'input',
templateOptions: {
label: gettext('Identifier')
},
hide: true
},
{
key: 'submitters_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Submitters'),
optionsAttr: 'bs-options',
options: User.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'full_name',
placeholder: gettext('Select or search a submitter...')
},
hide: !operator.hasPerms('motions.can_manage')
},
{
key: 'title',
type: 'input',
templateOptions: {
label: gettext('Title'),
required: true
}
},
{
key: 'text',
type: 'textarea',
templateOptions: {
label: gettext('Text'),
required: true
},
ngModelElAttrs: {'ckeditor': 'CKEditorOptions'}
},
{
key: 'reason',
type: 'textarea',
templateOptions: {
label: gettext('Reason')
},
ngModelElAttrs: {'ckeditor': 'CKEditorOptions'}
},
{
key: 'more',
type: 'checkbox',
templateOptions: {
label: gettext('Show extended fields')
},
hide: !operator.hasPerms('motions.can_manage')
},
{
key: 'attachments_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Attachment'),
optionsAttr: 'bs-options',
options: Mediafile.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'title_or_filename',
placeholder: gettext('Select or search an attachment...')
},
hideExpression: '!model.more'
},
{
key: 'category_id',
type: 'ui-select-single',
templateOptions: {
label: gettext('Category'),
optionsAttr: 'bs-options',
options: Category.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a category...')
},
hideExpression: '!model.more'
},
{
key: 'tags_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Tags'),
optionsAttr: 'bs-options',
options: Tag.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a tag...')
},
hideExpression: '!model.more'
},
{
key: 'supporters_id',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Supporters'),
optionsAttr: 'bs-options',
options: User.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'full_name',
placeholder: gettext('Select or search a supporter...')
},
hideExpression: '!model.more'
},
{
key: 'workflow_id',
type: 'ui-select-single',
templateOptions: {
label: gettext('Workflow'),
optionsAttr: 'bs-options',
options: Workflow.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a workflow...')
},
hideExpression: '!model.more',
}];
}
}
}
])
.controller('MotionListCtrl', [ .controller('MotionListCtrl', [
'$scope', '$scope',
'$state', '$state',
'ngDialog',
'Motion', 'Motion',
'Category', 'Category',
'Tag', 'Tag',
'Workflow', 'Workflow',
'User', 'User',
function($scope, $state, Motion, Category, Tag, Workflow, User) { function($scope, $state, ngDialog, Motion, Category, Tag, Workflow, User) {
Motion.bindAll({}, $scope, 'motions'); Motion.bindAll({}, $scope, 'motions');
Category.bindAll({}, $scope, 'categories'); Category.bindAll({}, $scope, 'categories');
Tag.bindAll({}, $scope, 'tags'); Tag.bindAll({}, $scope, 'tags');
@ -180,8 +295,29 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}); });
}); });
// open new dialog
$scope.newDialog = function () {
ngDialog.open({
template: 'static/templates/motions/motion-form.html',
controller: 'MotionCreateCtrl',
className: 'ngdialog-theme-default wide-form'
});
};
// open edit dialog
$scope.editDialog = function (motion) {
ngDialog.open({
template: 'static/templates/motions/motion-form.html',
controller: 'MotionUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: {
motion: function(Motion) {
return Motion.find(motion.id);
}
}
});
};
// save changed motion // save changed motion
$scope.update = function (motion) { $scope.save = function (motion) {
// get (unchanged) values from latest version for update method // get (unchanged) values from latest version for update method
motion.title = motion.getTitle(-1); motion.title = motion.getTitle(-1);
motion.text = motion.getText(-1); motion.text = motion.getText(-1);
@ -218,7 +354,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
} }
}; };
// delete selected motions // delete selected motions
$scope.delete = function () { $scope.deleteMultiple = function () {
angular.forEach($scope.motions, function (motion) { angular.forEach($scope.motions, function (motion) {
if (motion.selected) if (motion.selected)
Motion.destroy(motion.id); Motion.destroy(motion.id);
@ -227,7 +363,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.uncheckAll(); $scope.uncheckAll();
}; };
// delete single motion // delete single motion
$scope.deleteSingleMotion = function (motion) { $scope.delete = function (motion) {
Motion.destroy(motion.id); Motion.destroy(motion.id);
}; };
} }
@ -236,6 +372,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
.controller('MotionDetailCtrl', [ .controller('MotionDetailCtrl', [
'$scope', '$scope',
'$http', '$http',
'ngDialog',
'Motion', 'Motion',
'Category', 'Category',
'Mediafile', 'Mediafile',
@ -243,7 +380,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
'User', 'User',
'Workflow', 'Workflow',
'motion', 'motion',
function($scope, $http, Motion, Category, Mediafile, Tag, User, Workflow, motion) { function($scope, $http, ngDialog, Motion, Category, Mediafile, Tag, User, Workflow, motion) {
Motion.bindOne(motion.id, $scope, 'motion'); Motion.bindOne(motion.id, $scope, 'motion');
Category.bindAll({}, $scope, 'categories'); Category.bindAll({}, $scope, 'categories');
Mediafile.bindAll({}, $scope, 'mediafiles'); Mediafile.bindAll({}, $scope, 'mediafiles');
@ -257,6 +394,20 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.alert = {}; $scope.alert = {};
$scope.isCollapsed = true; $scope.isCollapsed = true;
// open edit dialog
$scope.editDialog = function (motion) {
ngDialog.open({
template: 'static/templates/motions/motion-form.html',
controller: 'MotionUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: {
motion: function(Motion) {
return Motion.find(motion.id);
}
}
});
};
$scope.support = function () { $scope.support = function () {
$http.post('/rest/motions/motion/' + motion.id + '/support/'); $http.post('/rest/motions/motion/' + motion.id + '/support/');
} }
@ -339,10 +490,11 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.formFields[i].defaultValue = Config.get('motions_workflow').value; $scope.formFields[i].defaultValue = Config.get('motions_workflow').value;
} }
} }
// save motion
$scope.save = function (motion) { $scope.save = function (motion) {
Motion.create(motion).then( Motion.create(motion).then(
function(success) { function(success) {
$state.go('motions.motion.list'); $scope.closeThisDialog();
} }
); );
}; };
@ -398,16 +550,13 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
} }
} }
// save form // save motion
$scope.save = function (model) { $scope.save = function (motion) {
Motion.save(model) Motion.save(motion).then(
.then(function(success) { function(success) {
$state.go('motions.motion.detail', {id: motion.id}); $scope.closeThisDialog();
}) }
.catch(function(fallback) { );
//TODO: show error in GUI
console.log(fallback);
});
}; };
} }
]) ])

View File

@ -30,7 +30,7 @@
<i class="fa fa-video-camera"></i> <i class="fa fa-video-camera"></i>
</a> </a>
<!-- edit --> <!-- edit -->
<a ng-if="motion.isAllowed('update')" ui-sref="motions.motion.detail.update({id: motion.id })" <a ng-if="motion.isAllowed('update')" ng-click="editDialog(motion)"
class="btn btn-default btn-sm" class="btn btn-default btn-sm"
title="{{ 'Edit' | translate}}"> title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i> <i class="fa fa-pencil"></i>

View File

@ -1,19 +1,12 @@
<h1 ng-if="motion.id" translate>Edit motion</h1> <h1 ng-if="model.id" translate>Edit motion</h1>
<h1 ng-if="!motion.id" translate>New motion</h1> <h1 ng-if="!model.id" translate>New motion</h1>
<div id="submenu">
<a ui-sref="motions.motion.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<form name="motionForm" ng-submit="save(model)"> <form name="motionForm" ng-submit="save(model)">
<formly-form model="model" fields="formFields"> <formly-form model="model" fields="formFields">
<button type="submit" ng-disabled="motionForm.$invalid" class="btn btn-primary" translate> <button type="submit" ng-disabled="motionForm.$invalid" class="btn btn-primary" translate>
Submit Submit
</button> </button>
<button ui-sref="motions.motion.list" class="btn btn-default" translate> <button ng-click="closeThisDialog()" class="btn btn-default" translate>
Cancel Cancel
</button> </button>
</formly-form> </formly-form>

View File

@ -1,7 +1,7 @@
<h1 translate>Motions</h1> <h1 translate>Motions</h1>
<div id="submenu"> <div id="submenu">
<a ui-sref="motions.motion.create" os-perms="motions.can_create" class="btn btn-primary btn-sm"> <a ng-click="newDialog()" os-perms="motions.can_create" class="btn btn-primary btn-sm">
<i class="fa fa-plus fa-lg"></i> <i class="fa fa-plus fa-lg"></i>
<translate>New</translate> <translate>New</translate>
</a> </a>
@ -32,7 +32,7 @@
</div> </div>
<!-- delete button --> <!-- delete button -->
<a ng-show="isDeleteMode && (motions|filter:{selected:true}).length > 0" <a ng-show="isDeleteMode && (motions|filter:{selected:true}).length > 0"
os-perms="motions.can_manage" ng-click="delete()" os-perms="motions.can_manage" ng-click="deleteMultiple()"
class="btn btn-primary btn-sm form-control"> class="btn btn-primary btn-sm form-control">
<i class="fa fa-trash fa-lg"></i> <i class="fa fa-trash fa-lg"></i>
<translate>Delete selected motions</translate> <translate>Delete selected motions</translate>
@ -109,7 +109,7 @@
<strong><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.getTitle() }}</a></strong> <strong><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.getTitle() }}</a></strong>
<div ng-if="motion.isAllowed('update')" class="hoverActions" ng-class="{'hiddenDiv': !motion.hover}"> <div ng-if="motion.isAllowed('update')" class="hoverActions" ng-class="{'hiddenDiv': !motion.hover}">
<span ng-if="motion.isAllowed('update')"> <span ng-if="motion.isAllowed('update')">
<a ui-sref="motions.motion.detail.update({ id: motion.id })" translate>Edit</a> <a href="" ng-click="editDialog(motion)" translate>Edit</a>
</span> </span>
<span ng-if="motion.isAllowed('quickedit')"> <span ng-if="motion.isAllowed('quickedit')">
| <a href="" ng-click="motion.quickEdit=true" translate>QuickEdit</a> | | <a href="" ng-click="motion.quickEdit=true" translate>QuickEdit</a> |
@ -118,7 +118,7 @@
<!-- TODO: translate confirm message --> <!-- TODO: translate confirm message -->
<a href="" class="text-danger" <a href="" class="text-danger"
ng-bootbox-confirm="Are you sure you want to delete <b>{{ motion.getTitle() }}</b>?" ng-bootbox-confirm="Are you sure you want to delete <b>{{ motion.getTitle() }}</b>?"
ng-bootbox-confirm-action="deleteSingleMotion(motion)" translate>Delete</a> ng-bootbox-confirm-action="delete(motion)" translate>Delete</a>
</span> </span>
</div> </div>
<td ng-if="!motion.quickEdit" class="optional"> <td ng-if="!motion.quickEdit" class="optional">
@ -193,7 +193,7 @@
<button ng-click="motion.quickEdit=false" class="btn btn-default pull-left" translate> <button ng-click="motion.quickEdit=false" class="btn btn-default pull-left" translate>
Cancel Cancel
</button> &nbsp; </button> &nbsp;
<button ng-if="motion.isAllowed('update')" ng-click="update(motion)" class="btn btn-primary" translate> <button ng-if="motion.isAllowed('update')" ng-click="save(motion)" class="btn btn-primary" translate>
Update Update
</button> </button>
<a ng-if="motion.isAllowed('update')" ui-sref="motions.motion.detail.update({id: motion.id })" <a ng-if="motion.isAllowed('update')" ui-sref="motions.motion.detail.update({id: motion.id })"

View File

@ -246,12 +246,109 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
} }
]) ])
// Provide generic user form fields for create and update view
.factory('UserFormFieldFactory', [
'$http',
'gettext',
'Group',
function ($http, gettext, Group) {
return {
getFormFields: function () {
return [
{
key: 'title',
type: 'input',
templateOptions: {
label: gettext('Title'),
}
},
{
key: 'first_name',
type: 'input',
templateOptions: {
label: gettext('First name')
}
},
{
key: 'last_name',
type: 'input',
templateOptions: {
label: gettext('Last name')
}
},
{
key: 'structure_level',
type: 'input',
templateOptions: {
label: gettext('Structure level')
}
},
{
key: 'groups',
type: 'ui-select-multiple',
templateOptions: {
label: gettext('Groups'),
optionsAttr: 'bs-options',
options: Group.getAll(),
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
valueProp: 'id',
labelProp: 'name',
placeholder: gettext('Select or search a group...')
}
},
{
key: 'default_password',
type: 'input',
templateOptions: {
label: gettext('Default password'),
addonRight: { text: 'Reset', class: 'fa fa-undo', onClick: function () {
// TODO: find a way to get user.id
//$http.post('/rest/users/user/' + model.id + '/reset_password/', {})
}
}
}
},
{
key: 'comment',
type: 'input',
templateOptions: {
label: gettext('Comment')
}
},
{
key: 'about_me',
type: 'textarea',
templateOptions: {
label: gettext('About me')
},
ngModelElAttrs: {'ckeditor': 'CKEditorOptions'}
},
{
key: 'is_present',
type: 'checkbox',
templateOptions: {
label: gettext('Is present')
}
},
{
key: 'is_active',
type: 'checkbox',
templateOptions: {
label: gettext('Is active')
}
}];
}
}
}
])
.controller('UserListCtrl', [ .controller('UserListCtrl', [
'$scope', '$scope',
'$state', '$state',
'ngDialog',
'User', 'User',
'Group', 'Group',
function($scope, $state, User, Group) { function($scope, $state, ngDialog, User, Group) {
User.bindAll({}, $scope, 'users'); User.bindAll({}, $scope, 'users');
Group.bindAll({}, $scope, 'groups'); Group.bindAll({}, $scope, 'groups');
@ -267,17 +364,42 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
$scope.sortColumn = column; $scope.sortColumn = column;
}; };
// open detail view link // open new dialog
$scope.openDetail = function (id) { $scope.newDialog = function () {
$state.go('users.user.detail', {id: id}); ngDialog.open({
template: 'static/templates/users/user-form.html',
controller: 'UserCreateCtrl',
className: 'ngdialog-theme-default wide-form'
});
};
// open edit dialog
$scope.editDialog = function (user) {
ngDialog.open({
template: 'static/templates/users/user-form.html',
controller: 'UserUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: {
user: function(User) {
return User.find(user.id);
}
}
});
}; };
// save changed user // save changed user
$scope.togglePresent = function (user) { $scope.save = function (user) {
//the value was changed by the template (checkbox) Assignment.save(user).then(
User.save(user); function(success) {
//user.quickEdit = false;
$scope.alert.show = false;
},
function(error){
var message = '';
for (var e in error.data) {
message += e + ': ' + error.data[e] + ' ';
}
$scope.alert = { type: 'danger', msg: message, show: true };
});
}; };
// *** delete mode functions *** // *** delete mode functions ***
$scope.isDeleteMode = false; $scope.isDeleteMode = false;
// check all checkboxes // check all checkboxes
@ -295,8 +417,8 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
}); });
} }
}; };
// delete selected user // delete all selected users
$scope.delete = function () { $scope.deleteMultiple = function () {
angular.forEach($scope.users, function (user) { angular.forEach($scope.users, function (user) {
if (user.selected) if (user.selected)
User.destroy(user.id); User.destroy(user.id);
@ -304,6 +426,10 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
$scope.isDeleteMode = false; $scope.isDeleteMode = false;
$scope.uncheckAll(); $scope.uncheckAll();
}; };
// delete single user
$scope.delete = function (user) {
User.destroy(user.id);
};
} }
]) ])
@ -322,17 +448,21 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
'$scope', '$scope',
'$state', '$state',
'User', 'User',
'UserFormFieldFactory',
'Group', 'Group',
function($scope, $state, User, Group) { function($scope, $state, User, UserFormFieldFactory, Group) {
Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups'); Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups');
$scope.user = {}; // get all form fields
$scope.formFields = UserFormFieldFactory.getFormFields();
// save user
$scope.save = function (user) { $scope.save = function (user) {
if (!user.groups) { if (!user.groups) {
user.groups = []; user.groups = [];
} }
User.create(user).then( User.create(user).then(
function(success) { function(success) {
$state.go('users.user.list'); $scope.closeThisDialog();
} }
); );
}; };
@ -344,32 +474,27 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
'$state', '$state',
'$http', '$http',
'User', 'User',
'user', 'UserFormFieldFactory',
'Group', 'Group',
function($scope, $state, $http, User, user, Group) { 'user',
function($scope, $state, $http, User, UserFormFieldFactory, Group, user) {
Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups'); Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups');
$scope.user = user; // autoupdate is not activated // set initial values for form model
$scope.model = user;
// get all form fields
$scope.formFields = UserFormFieldFactory.getFormFields();
// save user
$scope.save = function (user) { $scope.save = function (user) {
if (!user.groups) { if (!user.groups) {
user.groups = []; user.groups = [];
} }
User.save(user).then( User.save(user).then(
function(success) { function(success) {
$state.go('users.user.list'); $scope.closeThisDialog();
} }
); );
}; };
$scope.reset_password = function (user) {
$http.post('/rest/users/user/2/reset_password/', {})
.then(
function(data) {
// TODO: Success message
},
function(data) {
// TODO: error message
}
);
}
} }
]) ])
@ -477,7 +602,6 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
var groups = obj[i].groups.replace('"','').split(","); var groups = obj[i].groups.replace('"','').split(",");
groups.forEach(function(group) { groups.forEach(function(group) {
user.groups.push(group); user.groups.push(group);
console.log(group);
}); });
} }
user.comment = obj[i].comment; user.comment = obj[i].comment;

View File

@ -1,85 +1,13 @@
<h1 ng-if="user.id" translate>Edit participant</h1> <h1 ng-if="model.id" translate>Edit participant</h1>
<h1 ng-if="!user.id" translate>New participant</h1> <h1 ng-if="!model.id" translate>New participant</h1>
<div id="submenu"> <form name="userForm" ng-submit="save(model)">
<a ui-sref="users.user.list" class="btn btn-sm btn-default"> <formly-form model="model" fields="formFields">
<i class="fa fa-angle-double-left fa-lg"></i> <button type="submit" ng-disabled="userForm.$invalid" class="btn btn-primary" translate>
<translate>Back to overview</translate> Submit
</a>
</div>
<form name="userForm" >
<div ng-if="user.id" class="form-group">
<label for="inputUsername" translate>Username</label>
<input type="text"
ng-model="user.username"
class="form-control"
name="inputUsername"
required>
</div>
<div class="form-group row">
<div class="col-xs-2">
<label for="inputTitle" translate-comment="academic degree" translate>Title</label>
<input type="text" ng-model="user.title" class="form-control" name="inputTitle">
</div>
<div class="col-xs-5">
<label for="inputFirstName" translate>First name</label>
<input type="text" ng-model="user.first_name" class="form-control" name="inputFirstName">
</div>
<div class="col-xs-5">
<label for="inputLastName" translate>Last name</label>
<input type="text" ng-model="user.last_name" class="form-control" name="inputLastName">
</div>
</div>
<div class="form-group">
<label for="inputStructureLevel" translate>Structure level</label>
<input type="text" ng-model="user.structure_level" class="form-control" name="inputStructureLevel">
</div>
<div class="form-group">
<label for="selectGroups" translate>Groups</label>
<select multiple ng-options="group.id as group.name for group in groups"
ng-model="user.groups" class="form-control" name="selectGroups">
</select>
</div>
<div class="form-group row">
<div class="col-xs-6">
<label for="inputDefaultPassword" translate>Default password</label>
<div class="input-group">
<input type="text" ng-model="user.default_password" class="form-control" name="inputDefaultPassword">
<span class="input-group-btn">
<button ng-click="reset_password(user)" class="btn btn-default">
<i class="fa fa-undo"></i>
<translate>Reset</translate>
</button> </button>
</span> <button ng-click="closeThisDialog()" class="btn btn-default" translate>
</div>
</div>
</div>
<div class="form-group">
<label for="textComment" translate>Comment</label>
<textarea ng-model="user.comment" class="form-control" name="textComment" />
</div>
<div class="form-group">
<label for="textAbout" translate>About me</label>
<textarea ng-model="user.about_me" class="form-control" name="textAbout" />
</div>
<div class="form-group">
<label class="checkbox-inline">
<input type="checkbox" ng-model="user.is_present" ng-checked="user.is_present" name="checkboxActive">
<translate>Is present</translate>
</label>
</div>
<div class="form-group">
<label class="checkbox-inline">
<input type="checkbox" ng-model="user.is_active" ng-checked="user.is_active" name="checkboxActive">
<translate>Is active</translate>
</label>
</div>
<button type="submit" ng-click="save(user)" class="btn btn-primary" translate>
Save
</button>
<button ui-sref="users.user.list" class="btn btn-default" translate>
Cancel Cancel
</button> </button>
</formly-form>
</form> </form>

View File

@ -1,7 +1,7 @@
<h1 translate>Participants</h1> <h1 translate>Participants</h1>
<div id="submenu"> <div id="submenu">
<a ui-sref="users.user.create" os-perms="users.can_manage" class="btn btn-primary btn-sm"> <a ng-click="newDialog()" os-perms="users.can_manage" class="btn btn-primary btn-sm">
<i class="fa fa-user-plus fa-lg"></i> <i class="fa fa-user-plus fa-lg"></i>
<translate>New</translate> <translate>New</translate>
</a> </a>
@ -13,16 +13,13 @@
<i class="fa fa-download fa-lg"></i> <i class="fa fa-download fa-lg"></i>
<translate>Import</translate> <translate>Import</translate>
</a> </a>
<div class="btn-group"> <div class="btn-group" uib-dropdown>
<a ui-sref="user_print" class="btn btn-default btn-sm" target="_blank"> <button os-perms="users.can_manage" class="btn btn-default btn-sm" uib-dropdown-toggle>
<i class="fa fa-file-pdf-o fa-lg"></i> <i class="fa fa-file-pdf-o fa-lg"></i>
<translate>PDF</translate> <translate>PDF</translate>
</a> <span class="caret"></span>
<button os-perms="users.can_manage" class="btn btn-default btn-sm dropdown-toggle"
data-toggle="dropdown">
<i class="fa fa-caret-down"></i>
</button> </button>
<ul class="dropdown-menu dropdown-menu-right"> <ul class="uib-dropdown-menu uib-dropdown-menu-right">
<li><a ui-sref="user_listpdf" target="_blank"> <li><a ui-sref="user_listpdf" target="_blank">
<i class="fa fa-list fa-fw"></i> <i class="fa fa-list fa-fw"></i>
<translate>List of participants</translate> <translate>List of participants</translate>
@ -49,7 +46,7 @@
</div> </div>
<!-- delete button --> <!-- delete button -->
<a ng-show="isDeleteMode && (users|filter:{selected:true}).length > 0" <a ng-show="isDeleteMode && (users|filter:{selected:true}).length > 0"
os-perms="users.can_manage" ng-click="delete()" os-perms="users.can_manage" ng-click="deleteMultiple()"
class="btn btn-primary btn-sm form-control"> class="btn btn-primary btn-sm form-control">
<i class="fa fa-trash fa-lg"></i> <i class="fa fa-trash fa-lg"></i>
<translate>Delete selected users</translate> <translate>Delete selected users</translate>
@ -74,8 +71,7 @@
<!-- projector column --> <!-- projector column -->
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="firstColumn"> <th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="firstColumn">
<!-- delete selection column --> <!-- delete selection column -->
<th ng-show="isDeleteMode" os-perms-lite="users.can_manage" class="firstColumn deleteColumn" <th ng-show="isDeleteMode" os-perms-lite="users.can_manage" class="firstColumn deleteColumn">
ng-click="$event.stopPropagation();">
<input type="checkbox" ng-model="selectedAll" ng-change="checkAll()"> <input type="checkbox" ng-model="selectedAll" ng-change="checkAll()">
<th ng-click="toggleSort('first_name')" class="sortable"> <th ng-click="toggleSort('first_name')" class="sortable">
<translate>Name</translate> <translate>Name</translate>
@ -101,30 +97,35 @@
<tbody> <tbody>
<tr ng-repeat="user in users | filter: filter.search | filter: {is_present: filterPresent} | <tr ng-repeat="user in users | filter: filter.search | filter: {is_present: filterPresent} |
orderBy: sortColumn:reverse" orderBy: sortColumn:reverse"
ng-click="openDetail(user.id)" ng-class="{ 'activeline': user.isProjected(), 'selected': assignment.selected }">
ng-class="{ 'activeline': user.isProjected() }"
class="pointer">
<!-- projector column --> <!-- projector column -->
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector"> <td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
<a class="btn btn-default btn-sm" <a class="btn btn-default btn-sm"
ng-class="{ 'btn-primary': user.isProjected() }" ng-class="{ 'btn-primary': user.isProjected() }"
ng-click="user.project(); $event.stopPropagation();" ng-click="user.project()"
title="{{ 'Project user' | translate }}"> title="{{ 'Project user' | translate }}">
<i class="fa fa-video-camera"></i> <i class="fa fa-video-camera"></i>
</a> </a>
<!-- delete selection column --> <!-- delete selection column -->
<td ng-show="isDeleteMode" os-perms="users.can_manage" class="deleteColumn" <td ng-show="isDeleteMode" os-perms="users.can_manage" class="deleteColumn">
ng-click="$event.stopPropagation();">
<input type="checkbox" ng-model="user.selected"> <input type="checkbox" ng-model="user.selected">
<!-- user data colums --> <!-- user data colums -->
<td>{{ user.get_short_name() }} <td ng-mouseover="user.hover=true" ng-mouseleave="user.hover=false">
<strong><a ui-sref="users.user.detail({id: user.id})">{{ user.get_short_name() }}</a></strong>
<div ng-if="user.comment"> <div ng-if="user.comment">
<small><i class="fa fa-info-circle"></i> {{ user.comment }}</small> <small><i class="fa fa-info-circle"></i> {{ user.comment }}</small>
</div> </div>
<div os-perms="users.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !user.hover}">
<a href="" ng-click="editDialog(user)" translate>Edit</a> |
<!-- TODO: translate confirm message -->
<a href="" class="text-danger"
ng-bootbox-confirm="Are you sure you want to delete <b>{{ user.get_short_name() }}</b>?"
ng-bootbox-confirm-action="delete(user)" translate>Delete</a>
</div>
<td class="optional">{{ user.structure_level }} <td class="optional">{{ user.structure_level }}
<td class="optional"> <td class="optional">
<div ng-repeat="group in user.groups"> <div ng-repeat="group in user.groups">
{{ (groups | filter: {id: group})[0].name }} {{ (groups | filter: {id: group})[0].name }}
</div> </div>
<td><input type="checkbox" ng-model="user.is_present" ng-click="togglePresent(user)"> <td><input type="checkbox" ng-model="user.is_present" ng-click="save(user)">
</table> </table>