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', {
resolve: {
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', {
resolve: {
items: function(Agenda) {
@ -115,7 +93,7 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
);
};
// open new customslide dialog
// open new dialog
$scope.newDialog = function () {
ngDialog.open({
template: 'static/templates/core/customslide-form.html',
@ -123,32 +101,18 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
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)
$scope.open = function (item) {
$state.go(item.content_object.collection.replace('/','.')+'.detail',
{id: item.content_object.id});
};
// edit view of related item (content object)
$scope.edit = 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) {
// save changed item
$scope.save = function (item) {
Agenda.save(item).then(
function(success) {
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', [
'$scope',
'$http',

View File

@ -131,7 +131,7 @@
<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 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 -->
<span ng-if="item.content_object.collection == 'core/customslide'"> |
<a href="" class="text-danger"
@ -143,10 +143,10 @@
{{ item.duration }}
<span ng-if="item.duration" translate>h</span>
<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 -->
<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>
<alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
{{alert.msg}}

View File

@ -102,10 +102,13 @@ class AssignmentAllPollSerializer(ModelSerializer):
Customized update method for polls. To update votes use the write
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},
{"Yes": -1, "No": 0, "Abstain": -2}]
Example data for a 'yesnoabstain'=false poll with two candidates:
"votes": [{"Votes": 10}, {"Votes": 0}]
"""
# Update 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', {
controller: 'AssignmentDetailCtrl',
resolve: {
@ -51,9 +50,15 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
}
})
.state('assignments.assignment.detail.update', {
views: {
'@assignments.assignment': {}
}
onEnter: ['$stateParams', 'ngDialog', 'Assignment', function($stateParams, ngDialog, 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;
};
// open new customslide dialog
// open new dialog
$scope.newDialog = function () {
ngDialog.open({
template: 'static/templates/assignments/assignment-form.html',
@ -165,7 +170,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
className: 'ngdialog-theme-default wide-form'
});
};
// edit view of related item (content object)
// open edit dialog
$scope.editDialog = function (assignment) {
ngDialog.open({
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) {
Assignment.save(assignment).then(
function(success) {
@ -193,6 +198,23 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
$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
$scope.deleteMultiple = function () {
angular.forEach($scope.assignments, function (assignment) {
@ -329,7 +351,6 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
'Assignment',
'AssignmentFormFieldFactory',
function($scope, $state, Assignment, AssignmentFormFieldFactory) {
$scope.assignment = {};
// get all form fields
$scope.formFields = AssignmentFormFieldFactory.getFormFields();
@ -379,7 +400,8 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
$scope.formFields = [];
// add dynamic form fields
assignmentpoll.options.forEach(function(option) {
$scope.formFields.push(
if (assignmentpoll.yesnoabstain) {
$scope.formFields.push(
{
noFormControl: true,
template: '<strong>' + option.candidate.get_full_name() + '</strong>'
@ -410,8 +432,19 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
type: 'number',
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
$scope.formFields.push(
@ -455,13 +488,21 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
// save assignment
$scope.save = function (poll) {
var votes = [];
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]
if (assignmentpoll.yesnoabstain) {
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 {
assignmentpoll.options.forEach(function(option) {
votes.push({
"Votes": poll['vote_' + option.candidate_id],
});
});
}
poll.DSUpdate({
assignment_id: poll.assignment_id,
votes: votes,

View File

@ -9,6 +9,11 @@
<i class="fa fa-file-pdf-o fa-lg"></i>
<translate>PDF</translate>
</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 -->
<a os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
ng-class="{ 'btn-primary': assignment.isProjected() }"
@ -105,7 +110,7 @@
</div>
<div class="results">
<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-repeat="vote in option.votes">
{{ vote.value}}: {{ vote.weight}}

View File

@ -1,5 +1,5 @@
<h1 ng-if="assignment.id" translate>Edit election</h1>
<h1 ng-if="!assignment.id" translate>New election</h1>
<h1 ng-if="model.id" translate>Edit election</h1>
<h1 ng-if="!model.id" translate>New election</h1>
<form name="assignmentForm" ng-submit="save(model)">
<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
.state('core.tag', {
url: '/tag',

View File

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

View File

@ -59,13 +59,13 @@
</div>
<!-- user settings / logout button -->
<div class="btn-group" dropdown is-open="status.isopen">
<button type="button" class="btn btn-default dropdown-toggle" dropdown-toggle>
<div class="btn-group" uib-dropdown>
<button type="button" class="btn btn-default" uib-dropdown-toggle>
<i class="fa fa-user"></i>
<span class="optional-small">{{ operator.user.get_short_name() }}</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu pull-right" role="menu">
<ul class="uib-dropdown-menu pull-right" role="menu" aria-labelledby="single-button">
<li>
<a ui-sref="users.user.detail.profile({ id: operator.user.id })">
<i class="fa fa-cog"></i>
@ -95,12 +95,12 @@
</div>
<!-- language switcher -->
<div class="btn-group" ng-controller="LanguageCtrl">
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<div class="btn-group" ng-controller="LanguageCtrl" uib-dropdown>
<button class="btn btn-default" uib-dropdown-toggle>
<i class="fa fa-flag"></i>
<span class="caret"></span>
</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>
<a href="" ng-click="switchLanguage('en')">
<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) {
return DS.defineResource({
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', {
resolve: {
motion: function(Motion, $stateParams) {
@ -84,26 +65,15 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}
})
.state('motions.motion.detail.update', {
views: {
'@motions.motion': {}
},
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();
}
}
onEnter: ['$stateParams', 'ngDialog', 'Motion', function($stateParams, ngDialog, Motion) {
ngDialog.open({
template: 'static/templates/motions/motion-form.html',
controller: 'MotionUpdateCtrl',
className: 'ngdialog-theme-default wide-form',
resolve: { motion: function() {
return Motion.find($stateParams.id) }}
});
}]
})
.state('motions.motion.csv-import', {
url: '/csv-import',
@ -134,18 +104,163 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
views: {
'@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', [
'$scope',
'$state',
'ngDialog',
'Motion',
'Category',
'Tag',
'Workflow',
'User',
function($scope, $state, Motion, Category, Tag, Workflow, User) {
function($scope, $state, ngDialog, Motion, Category, Tag, Workflow, User) {
Motion.bindAll({}, $scope, 'motions');
Category.bindAll({}, $scope, 'categories');
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
$scope.update = function (motion) {
$scope.save = function (motion) {
// get (unchanged) values from latest version for update method
motion.title = motion.getTitle(-1);
motion.text = motion.getText(-1);
@ -218,7 +354,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}
};
// delete selected motions
$scope.delete = function () {
$scope.deleteMultiple = function () {
angular.forEach($scope.motions, function (motion) {
if (motion.selected)
Motion.destroy(motion.id);
@ -227,7 +363,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.uncheckAll();
};
// delete single motion
$scope.deleteSingleMotion = function (motion) {
$scope.delete = function (motion) {
Motion.destroy(motion.id);
};
}
@ -236,6 +372,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
.controller('MotionDetailCtrl', [
'$scope',
'$http',
'ngDialog',
'Motion',
'Category',
'Mediafile',
@ -243,7 +380,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
'User',
'Workflow',
'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');
Category.bindAll({}, $scope, 'categories');
Mediafile.bindAll({}, $scope, 'mediafiles');
@ -257,6 +394,20 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.alert = {};
$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 () {
$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;
}
}
// save motion
$scope.save = function (motion) {
Motion.create(motion).then(
function(success) {
$state.go('motions.motion.list');
$scope.closeThisDialog();
}
);
};
@ -398,16 +550,13 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}
}
// save form
$scope.save = function (model) {
Motion.save(model)
.then(function(success) {
$state.go('motions.motion.detail', {id: motion.id});
})
.catch(function(fallback) {
//TODO: show error in GUI
console.log(fallback);
});
// save motion
$scope.save = function (motion) {
Motion.save(motion).then(
function(success) {
$scope.closeThisDialog();
}
);
};
}
])

View File

@ -30,7 +30,7 @@
<i class="fa fa-video-camera"></i>
</a>
<!-- 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"
title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i>

View File

@ -1,19 +1,12 @@
<h1 ng-if="motion.id" translate>Edit motion</h1>
<h1 ng-if="!motion.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>
<h1 ng-if="model.id" translate>Edit motion</h1>
<h1 ng-if="!model.id" translate>New motion</h1>
<form name="motionForm" ng-submit="save(model)">
<formly-form model="model" fields="formFields">
<button type="submit" ng-disabled="motionForm.$invalid" class="btn btn-primary" translate>
Submit
</button>
<button ui-sref="motions.motion.list" class="btn btn-default" translate>
<button ng-click="closeThisDialog()" class="btn btn-default" translate>
Cancel
</button>
</formly-form>

View File

@ -1,7 +1,7 @@
<h1 translate>Motions</h1>
<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>
<translate>New</translate>
</a>
@ -32,7 +32,7 @@
</div>
<!-- delete button -->
<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">
<i class="fa fa-trash fa-lg"></i>
<translate>Delete selected motions</translate>
@ -109,7 +109,7 @@
<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}">
<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 ng-if="motion.isAllowed('quickedit')">
| <a href="" ng-click="motion.quickEdit=true" translate>QuickEdit</a> |
@ -118,7 +118,7 @@
<!-- TODO: translate confirm message -->
<a href="" class="text-danger"
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>
</div>
<td ng-if="!motion.quickEdit" class="optional">
@ -193,7 +193,7 @@
<button ng-click="motion.quickEdit=false" class="btn btn-default pull-left" translate>
Cancel
</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
</button>
<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', [
'$scope',
'$state',
'ngDialog',
'User',
'Group',
function($scope, $state, User, Group) {
function($scope, $state, ngDialog, User, Group) {
User.bindAll({}, $scope, 'users');
Group.bindAll({}, $scope, 'groups');
@ -267,17 +364,42 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
$scope.sortColumn = column;
};
// open detail view link
$scope.openDetail = function (id) {
$state.go('users.user.detail', {id: id});
// open new dialog
$scope.newDialog = function () {
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
$scope.togglePresent = function (user) {
//the value was changed by the template (checkbox)
User.save(user);
$scope.save = function (user) {
Assignment.save(user).then(
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 ***
$scope.isDeleteMode = false;
// check all checkboxes
@ -295,8 +417,8 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
});
}
};
// delete selected user
$scope.delete = function () {
// delete all selected users
$scope.deleteMultiple = function () {
angular.forEach($scope.users, function (user) {
if (user.selected)
User.destroy(user.id);
@ -304,6 +426,10 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
$scope.isDeleteMode = false;
$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',
'$state',
'User',
'UserFormFieldFactory',
'Group',
function($scope, $state, User, Group) {
function($scope, $state, User, UserFormFieldFactory, Group) {
Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups');
$scope.user = {};
// get all form fields
$scope.formFields = UserFormFieldFactory.getFormFields();
// save user
$scope.save = function (user) {
if (!user.groups) {
user.groups = [];
}
User.create(user).then(
function(success) {
$state.go('users.user.list');
$scope.closeThisDialog();
}
);
};
@ -344,32 +474,27 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
'$state',
'$http',
'User',
'user',
'UserFormFieldFactory',
'Group',
function($scope, $state, $http, User, user, Group) {
'user',
function($scope, $state, $http, User, UserFormFieldFactory, Group, user) {
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) {
if (!user.groups) {
user.groups = [];
}
User.save(user).then(
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(",");
groups.forEach(function(group) {
user.groups.push(group);
console.log(group);
});
}
user.comment = obj[i].comment;

View File

@ -1,85 +1,13 @@
<h1 ng-if="user.id" translate>Edit participant</h1>
<h1 ng-if="!user.id" translate>New participant</h1>
<h1 ng-if="model.id" translate>Edit participant</h1>
<h1 ng-if="!model.id" translate>New participant</h1>
<div id="submenu">
<a ui-sref="users.user.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="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>
</span>
</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
</button>
<form name="userForm" ng-submit="save(model)">
<formly-form model="model" fields="formFields">
<button type="submit" ng-disabled="userForm.$invalid" class="btn btn-primary" translate>
Submit
</button>
<button ng-click="closeThisDialog()" class="btn btn-default" translate>
Cancel
</button>
</formly-form>
</form>

View File

@ -1,7 +1,7 @@
<h1 translate>Participants</h1>
<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>
<translate>New</translate>
</a>
@ -13,16 +13,13 @@
<i class="fa fa-download fa-lg"></i>
<translate>Import</translate>
</a>
<div class="btn-group">
<a ui-sref="user_print" class="btn btn-default btn-sm" target="_blank">
<div class="btn-group" uib-dropdown>
<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>
<translate>PDF</translate>
</a>
<button os-perms="users.can_manage" class="btn btn-default btn-sm dropdown-toggle"
data-toggle="dropdown">
<i class="fa fa-caret-down"></i>
<span class="caret"></span>
</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">
<i class="fa fa-list fa-fw"></i>
<translate>List of participants</translate>
@ -49,7 +46,7 @@
</div>
<!-- delete button -->
<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">
<i class="fa fa-trash fa-lg"></i>
<translate>Delete selected users</translate>
@ -74,8 +71,7 @@
<!-- projector column -->
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="firstColumn">
<!-- delete selection column -->
<th ng-show="isDeleteMode" os-perms-lite="users.can_manage" class="firstColumn deleteColumn"
ng-click="$event.stopPropagation();">
<th ng-show="isDeleteMode" os-perms-lite="users.can_manage" class="firstColumn deleteColumn">
<input type="checkbox" ng-model="selectedAll" ng-change="checkAll()">
<th ng-click="toggleSort('first_name')" class="sortable">
<translate>Name</translate>
@ -101,30 +97,35 @@
<tbody>
<tr ng-repeat="user in users | filter: filter.search | filter: {is_present: filterPresent} |
orderBy: sortColumn:reverse"
ng-click="openDetail(user.id)"
ng-class="{ 'activeline': user.isProjected() }"
class="pointer">
ng-class="{ 'activeline': user.isProjected(), 'selected': assignment.selected }">
<!-- projector column -->
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
<a class="btn btn-default btn-sm"
ng-class="{ 'btn-primary': user.isProjected() }"
ng-click="user.project(); $event.stopPropagation();"
ng-click="user.project()"
title="{{ 'Project user' | translate }}">
<i class="fa fa-video-camera"></i>
</a>
<!-- delete selection column -->
<td ng-show="isDeleteMode" os-perms="users.can_manage" class="deleteColumn"
ng-click="$event.stopPropagation();">
<td ng-show="isDeleteMode" os-perms="users.can_manage" class="deleteColumn">
<input type="checkbox" ng-model="user.selected">
<!-- user data colums -->
<td>{{ user.get_short_name() }}
<div ng-if="user.comment">
<small><i class="fa fa-info-circle"></i> {{ user.comment }}</small>
</div>
<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">
<small><i class="fa fa-info-circle"></i> {{ user.comment }}</small>
</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">
<div ng-repeat="group in user.groups">
{{ (groups | filter: {id: group})[0].name }}
</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>