Motion detail updated for polls.

bower.json: updated ui-select
New QuickEdit feature in motion list.
This commit is contained in:
Emanuel Schuetze 2015-10-15 17:25:40 +02:00
parent 2495ba609b
commit 5b37a21c87
9 changed files with 477 additions and 97 deletions

View File

@ -7,13 +7,13 @@
"jquery.cookie": "~1.4.1", "jquery.cookie": "~1.4.1",
"bootstrap-css-only": "~3.3.4", "bootstrap-css-only": "~3.3.4",
"angular": "~1.3.15", "angular": "~1.3.15",
"angular-bootstrap": "~0.13.0", "angular-bootstrap": "~0.14.2",
"angular-messages": "~1.3.15", "angular-messages": "~1.3.15",
"angular-animate": "~1.3.15", "angular-animate": "~1.3.15",
"angular-csv-import": "~0.0.15", "angular-csv-import": "~0.0.15",
"angular-loading-bar": "~0.7.1", "angular-loading-bar": "~0.7.1",
"angular-ui-router": "~0.2.13", "angular-ui-router": "~0.2.13",
"angular-ui-select": "~0.12", "angular-ui-select": "~0.13",
"angular-ui-switch": "~0.1.0", "angular-ui-switch": "~0.1.0",
"angular-ui-tree": "~2.2.0", "angular-ui-tree": "~2.2.0",
"angular-gettext": "~2.0.2", "angular-gettext": "~2.0.2",

View File

@ -71,7 +71,7 @@
<thead> <thead>
<tr> <tr>
<!-- 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"></th>
<!-- delete selection column --> <!-- delete selection column -->
<th ng-show="isDeleteMode" os-perms-lite="agenda.can_manage" class="firstColumn deleteColumn" <th ng-show="isDeleteMode" os-perms-lite="agenda.can_manage" class="firstColumn deleteColumn"
ng-click="$event.stopPropagation();"> ng-click="$event.stopPropagation();">

View File

@ -49,6 +49,15 @@ body {
color: red; color: red;
font-weight: bold; font-weight: bold;
} }
.spacer {
margin-top: 7px;
}
.hoverActions {
font-size: 85%;
}
.hiddenDiv {
visibility: hidden;
}
/* TODO: used by ng-fab-forms */ /* TODO: used by ng-fab-forms */
.validation-success { .validation-success {
@ -274,14 +283,25 @@ tr.offline td, li.offline {
tr.activeline td, li.activeline, .projected { tr.activeline td, li.activeline, .projected {
background-color: #bed4de; background-color: #bed4de;
} }
tr.selected td {
background-color: #ff9999;
}
.nopadding { .nopadding {
padding: 0; padding: 0;
} }
.alert form { .alert form {
margin-bottom: 0; margin-bottom: 0;
} }
tr.total td { .slimlist {
border-top: 1px solid #333333; padding-left: 20px;
}
.smallhr {
margin-top: 2px;
margin-bottom: 2px;
border-color: #333333;
}
.resultcolumn {
font-weight: bold;
} }
.nobr { .nobr {
white-space: nowrap; white-space: nowrap;

View File

@ -763,6 +763,7 @@ class State(RESTModelMixin, models.Model):
This behavior can be changed by the form and view, e. g. via the This behavior can be changed by the form and view, e. g. via the
MotionDisableVersioningMixin. MotionDisableVersioningMixin.
""" """
# TODO: preferred_for = ChoiceField
leave_old_version_active = models.BooleanField(default=False) leave_old_version_active = models.BooleanField(default=False)
"""If true, new versions are not automaticly set active.""" """If true, new versions are not automaticly set active."""

View File

@ -4,9 +4,78 @@ angular.module('OpenSlidesApp.motions', [])
.factory('MotionPoll', [ .factory('MotionPoll', [
'DS', 'DS',
function(DS) { 'Config',
'jsDataModel',
function(DS, Config, jsDataModel) {
return DS.defineResource({ return DS.defineResource({
name: 'motions/motionpoll', name: 'motions/motionpoll',
useClass: jsDataModel,
relations: {
belongsTo: {
'motions/motion': {
localField: 'motion',
localKey: 'motion_id',
}
}
},
methods: {
getYesPercent: function () {
var config = Config.get('motions_poll_100_percent_base').value;
if (config == "WITHOUT_INVALID" && this.votesvalid > 0) {
return "(" + Math.round(this.yes * 100 / this.votesvalid * 10) / 10 + " %)";
} else if (config == "WITH_INVALID" && this.votescast > 0) {
return "(" + Math.round(this.yes * 100 / (this.votescast) * 10) / 10 + " %)";
} else {
return null;
}
},
getNoPercent: function () {
var config = Config.get('motions_poll_100_percent_base').value;
if (config == "WITHOUT_INVALID" && this.votesvalid > 0) {
return "(" + Math.round(this.no * 100 / this.votesvalid * 10) / 10 + " %)";
} else if (config == "WITH_INVALID" && this.votescast > 0) {
return "(" + Math.round(this.no * 100 / (this.votescast) * 10) / 10 + " %)";
} else {
return null;
}
},
getAbstainPercent: function () {
var config = Config.get('motions_poll_100_percent_base').value;
if (config == "WITHOUT_INVALID" && this.votesvalid > 0) {
return "(" + Math.round(this.abstain * 100 / this.votesvalid * 10) / 10 + " %)";
} else if (config == "WITH_INVALID" && this.votescast > 0) {
return "(" + Math.round(this.abstain * 100 / (this.votescast) * 10) / 10 + " %)";
} else {
return null;
}
},
getVotesValidPercent: function () {
var config = Config.get('motions_poll_100_percent_base').value;
if (config == "WITHOUT_INVALID") {
return "(100 %)";
} else if (config == "WITH_INVALID") {
return "(" + Math.round(this.votesvalid * 100 / (this.votescast) * 10) / 10 + " %)";
} else {
return null;
}
},
getVotesInvalidPercent: function () {
var config = Config.get('motions_poll_100_percent_base').value;
if (config == "WITH_INVALID") {
return "(" + Math.round(this.votesinvalid * 100 / (this.votescast) * 10) / 10 + " %)";
} else {
return null;
}
},
getVotesCastPercent: function () {
var config = Config.get('motions_poll_100_percent_base').value;
if (config == "WITH_INVALID") {
return "(100 %)";
} else {
return null;
}
}
}
}); });
} }
]) ])
@ -239,46 +308,112 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}) })
}) })
.controller('MotionListCtrl', function($scope, Motion, Category, User) { .controller('MotionListCtrl', [
Motion.bindAll({}, $scope, 'motions'); '$scope',
Category.bindAll({}, $scope, 'categories'); '$state',
User.bindAll({}, $scope, 'users'); 'Motion',
'Category',
'User',
function($scope, $state, Motion, Category, User) {
Motion.bindAll({}, $scope, 'motions');
Category.bindAll({}, $scope, 'categories');
User.bindAll({}, $scope, 'users');
// setup table sorting // setup table sorting
$scope.sortColumn = 'identifier'; $scope.sortColumn = 'identifier';
$scope.filterPresent = ''; $scope.filterPresent = '';
$scope.reverse = false; $scope.reverse = false;
// function to sort by clicked column // function to sort by clicked column
$scope.toggleSort = function ( column ) { $scope.toggleSort = function ( column ) {
if ( $scope.sortColumn === column ) { if ( $scope.sortColumn === column ) {
$scope.reverse = !$scope.reverse; $scope.reverse = !$scope.reverse;
} }
$scope.sortColumn = column; $scope.sortColumn = column;
}; };
// save changed motion // hover edit actions
$scope.save = function (motion) { $scope.hoverIn = function () {
Motion.save(motion); $scope.showEditActions = true;
}; };
// delete selected motion $scope.hoverOut = function () {
$scope.delete = function (motion) { $scope.showEditActions = false;
Motion.destroy(motion.id); };
};
}) // save changed motion
$scope.update = function (motion) {
// get (unchanged) values from latest version for update method
motion.title = motion.getTitle(-1);
motion.text = motion.getText(-1);
motion.reason = motion.getReason(-1);
Motion.save(motion).then(
function(success) {
motion.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
$scope.checkAll = function () {
angular.forEach($scope.motions, function (motion) {
motion.selected = $scope.selectedAll;
});
};
// uncheck all checkboxes if isDeleteMode is closed
$scope.uncheckAll = function () {
if (!$scope.isDeleteMode) {
$scope.selectedAll = false;
angular.forEach($scope.motions, function (motion) {
motion.selected = false;
});
}
};
// delete selected motions
$scope.delete = function () {
angular.forEach($scope.motions, function (motion) {
if (motion.selected)
Motion.destroy(motion.id);
});
$scope.isDeleteMode = false;
$scope.uncheckAll();
};
// delete single motion
$scope.deleteSingleMotion = function (motion) {
Motion.destroy(motion.id);
};
}
])
.controller('MotionDetailCtrl', [ .controller('MotionDetailCtrl', [
'$scope', '$scope',
'Motion', 'Motion',
'Category', 'Category',
'Workflow',
'User', 'User',
'motion', 'motion',
'$http', '$http',
function($scope, Motion, Category, User, motion, $http) { function($scope, Motion, Category, Workflow, User, motion, $http) {
Motion.bindOne(motion.id, $scope, 'motion'); Motion.bindOne(motion.id, $scope, 'motion');
Category.bindAll({}, $scope, 'categories'); Category.bindAll({}, $scope, 'categories');
Workflow.bindAll({}, $scope, 'workflows');
User.bindAll({}, $scope, 'users'); User.bindAll({}, $scope, 'users');
Motion.loadRelations(motion); Motion.loadRelations(motion);
$scope.alert = {}; // TODO: show alert in template
$scope.update_state = function (state_id) {
$http.put('/rest/motions/motion/' + motion.id + '/set_state/', {'state': state_id});
}
$scope.reset_state = function (state_id) {
$http.put('/rest/motions/motion/' + motion.id + '/set_state/', {});
}
$scope.create_poll = function () { $scope.create_poll = function () {
$http.post('/rest/motions/motion/' + motion.id + '/create_poll/', {}) $http.post('/rest/motions/motion/' + motion.id + '/create_poll/', {})
.success(function(data){ .success(function(data){
@ -288,10 +423,19 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.alert = { type: 'danger', msg: data.detail, show: true }; $scope.alert = { type: 'danger', msg: data.detail, show: true };
}); });
} }
$scope.delete_poll = function (poll) { $scope.delete_poll = function (poll) {
poll.DSDestroy(); poll.DSDestroy();
} }
$scope.update_poll = function (poll) {
poll.DSUpdate({
motion_id: motion.id,
votes: {"Yes": poll.yes, "No": poll.no, "Abstain": poll.abstain},
votesvalid: poll.votesvalid,
votesinvalid: poll.votesinvalid,
votescast: poll.votescast
});
poll.isEditMode = false;
}
} }
]) ])

View File

@ -6,13 +6,6 @@
</small> </small>
</h1> </h1>
<span ng-repeat="tag in motion.tags">
<span class="label label-default">
{{ tag.name }}
</span>
&nbsp;
</span>
{{ motion.agenda_item }} {{ motion.agenda_item }}
<div id="submenu"> <div id="submenu">
@ -39,19 +32,13 @@
</a> </a>
</div> </div>
<a href="#" ng-click="create_poll()">Create Poll</a>
<div ng-repeat="poll in motion.polls">
{{ poll.id }}
<a href="#" ng-click="delete_poll(poll)">delete</a>
</div>
<div class="row"> <div class="row">
<div class="col-sm-8"> <div class="col-sm-8">
<h3 translate>Text</h3> <h3 translate>Text</h3>
<div class="white-space-pre-line">{{ motion.getText() }}</div> <div class="white-space-pre-line" ng-bind-html="motion.getText()"></div>
<h3 translate>Reason</h3> <h3 translate>Reason</h3>
<div class="white-space-pre-line">{{ motion.getReason() }}</div> <div class="white-space-pre-line" ng-bind-html="motion.getReason()"></div>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
@ -61,11 +48,151 @@
{{ submitter.get_full_name() }}<br> {{ submitter.get_full_name() }}<br>
</div> </div>
<div ng-if="config('motions_min_supporters') > 0">
<h3 translate>Supporters</h3>
<ol>
<li ng-repeat="supporters in motion.supporters">
{{ supporters.get_full_name() }}
</ol>
</div>
<h3 translate>State</h3>
<span class="label label-primary">{{ motion.state.name | translate }}</span>
<button os-perms-lite="motions.can_manage" ng-click="motion.isStatusEditMode=true"
class="btn btn-default btn-xs">
<i class="fa fa-pencil"></i>
</button>
<div ng-if="motion.isStatusEditMode" os-perms-lite="motions.can_manage">
<div class="btn-group-vertical spacer" role="group">
<button ng-repeat="state_id in motion.state.next_states_id" class="btn btn-default btn-sm"
ng-click="update_state(state_id)">
State #{{state_id}}
</button>
</div>
<div>
<button ng-click="reset_state()"
class="btn btn-danger btn-xs spacer">
<i class="fa fa-exclamation-triangle"></i> Reset
</button>
</div>
</div>
<h3 translate>Voting result</h3>
<ol class="slimlist">
<li ng-repeat="poll in motion.polls" class="spacer">
<translate>Vote</translate>
<button os-perms-lite="motions.can_manage" ng-click="poll.isEditMode=true;"
class="btn btn-default btn-xs">
<i class="fa fa-pencil"></i>
</button>
<button os-perms="motions.can_manage" ng-click="delete_poll(poll)"
class="btn btn-default btn-xs">
<i class="fa fa-times"></i>
</button>
<br>
<form ng-show="poll.isEditMode">
<!-- yes -->
<div class="input-group col-sm-8 spacer">
<div class="input-group-addon" title="{{ 'Yes' | translate }}"><i class="fa fa-thumbs-up"></i></div>
<input type="number" ng-model="poll.yes" class="form-control input-sm" placeholder="{{ 'Yes' | translate }}">
</div>
<!-- no -->
<div class="input-group col-sm-8">
<div class="input-group-addon" title="{{ 'No' | translate }}"><i class="fa fa-thumbs-down"></i></div>
<input type="number" ng-model="poll.no" class="form-control input-sm" placeholder="{{ 'No' | translate }}">
</div>
<!-- abstain -->
<div class="input-group col-sm-8">
<div class="input-group-addon" title="{{ 'Abstain' | translate }}"><b>&empty;</b></div>
<input type="number" ng-model="poll.abstain" class="form-control input-sm" placeholder="{{ 'Abstain' | translate }}">
</div>
<!-- valid votes -->
<div class="input-group col-sm-8 spacer">
<div class="input-group-addon" title="{{ 'Valid votes' | translate }}"><i class="fa fa-check"></i></div>
<input type="number" ng-model="poll.votesvalid" class="form-control input-sm" placeholder="{{ 'Valid votes' | translate }}">
</div>
<!-- invalid votes -->
<div class="input-group col-sm-8">
<div class="input-group-addon" title="{{ 'Invalid votes' | translate }}"><i class="fa fa-ban"></i></div>
<input type="number" ng-model="poll.votesinvalid" class="form-control input-sm" placeholder="{{ 'Invalid votes' | translate }}">
</div>
<!-- votes cast -->
<div class="input-group col-sm-8 spacer">
<div class="input-group-addon" title="{{ 'Votes cast' | translate }}"><b>&sum;</b></div>
<input type="number" ng-model="poll.votescast" class="form-control input-sm" placeholder="{{ 'Votes cast' | translate }}">
</div>
<!-- buttons -->
<div class="spacer">
<button type="submit" ng-click="update_poll(poll)" class="btn btn-primary" translate>
Save
</button>
<button ng-click="poll.isEditMode=false;" class="btn btn-default" translate>
Cancel
</button>
</div>
</form>
<div ng-show="!poll.isEditMode && poll.yes">
<!-- yes -->
<div class="result_label">
<i class="fa fa-thumbs-up"></i>
<translate>Yes</translate>:
</div>
<div class="result_value">{{ poll.yes }} {{poll.getYesPercent()}}</div>
<!-- no -->
<div class="result_label">
<i class="fa fa-thumbs-down"></i>
<translate>No</translate>:
</div>
<div class="result_value">{{ poll.no }} {{poll.getNoPercent()}}</div>
<!-- abstain -->
<div class="resutl_label">
<b>&empty;</b>
<translate>Abstain</translate>:
</div>
<div class="result_value">{{ poll.abstain }} {{poll.getAbstainPercent()}}</div>
<hr class="smallhr" ng-if="poll.votesvalid || poll.votesinvalid">
<!-- valid votes -->
<div ng-if="poll.votesvalid">
<div class="result_label">
<i class="fa fa-check"></i>
<translate>Valid votes</translate>:
</div>
<div class="result_value">{{ poll.votesvalid }} {{poll.getVotesValidPercent()}}</div>
</div>
<!-- invalid votes -->
<div ng-if="poll.votesinvalid">
<div class="result_label">
<i class="fa fa-ban"></i>
<translate>Invalid votes</translate>:
</div>
<div class="result_value">{{ poll.votesinvalid }} {{poll.getVotesInvalidPercent()}}</div>
</div>
<hr class="smallhr" ng-if="poll.votescast">
<!-- votes cast -->
<div ng-if="poll.votescast">
<div class="resutl_label">
<b>&sum;</b>
<translate>Votes cast</translate>:
</div>
<div class="result_value">{{ poll.votescast }} {{poll.getVotesCastPercent()}}</div>
</div>
</div>
</ol>
<button ng-click="create_poll()" class="btn btn-default btn-sm">
<i class="fa fa-bar-chart fa-lg"></i>
<translate>New poll</translate>
</button>
<h3 translate>Category</h3> <h3 translate>Category</h3>
{{ motion.category.name }}</a> {{ motion.category.name }}</a>
<h3 translate>Voting result</h3> <h3 translate>Tags</h3>
- <span ng-repeat="tag in motion.tags">
<span class="label label-default">
{{ tag.name }}
</span>
&nbsp;
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="selectSubmitter" translate>Submitter</label> <label for="selectSubmitter" translate>Submitters</label>
<ui-select multiple ng-model="motion.submitters_id" name="selectSubmitter"> <ui-select multiple ng-model="motion.submitters_id" name="selectSubmitter">
<ui-select-match placeholder="{{ 'Select or search a submitter...' | translate }}"> <ui-select-match placeholder="{{ 'Select or search a submitter...' | translate }}">
{{ $item.get_full_name() }} {{ $item.get_full_name() }}
@ -31,7 +31,7 @@
</ui-select> </ui-select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputName" translate>Title</label> <label for="inputTitle" translate>Title</label>
<input type="text" ng-model="motion.title" class="form-control" name="inputTitle" required> <input type="text" ng-model="motion.title" class="form-control" name="inputTitle" required>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -69,13 +69,10 @@
{{ file.title }} {{ file.title }}
</ui-select-choices> </ui-select-choices>
</ui-select> </ui-select>
<select ng-options="file.id as file.title for file in mediafiles"
ng-model="motion.attachments_id" class="form-control" name="selectAttachments">
</select>
</div> </div>
<!-- show supporters if enabled --> <!-- show supporters if enabled -->
<div class="form-group" ng-if="config('motions_min_supporters') > 0"> <div class="form-group" ng-if="config('motions_min_supporters') > 0">
<label for="selectSupporter" translate>Supporters</label> <label for="selectSupporter" translate>Supporters</label>
<ui-select multiple ng-model="motion.supporters_id"> <ui-select multiple ng-model="motion.supporters_id">
<ui-select-match placeholder="{{ 'Select or search a supporter...' | translate }}"> <ui-select-match placeholder="{{ 'Select or search a supporter...' | translate }}">
{{ $item.get_full_name() }} {{ $item.get_full_name() }}

View File

@ -21,7 +21,24 @@
<div class="row form-group"> <div class="row form-group">
<div class="col-sm-8"> <div class="col-sm-8">
<!-- TODO: add filters --> <form class="form-inline">
<!-- delete mode -->
<div os-perms-lite="motions.can_manage" class="form-group">
<label for="deleteSwitcher" translate>Delete mode</label>
<switch id="deleteSwitcher" ng-model="isDeleteMode" ng-change="uncheckAll()"
on="{{'On'|translate}}" off="{{'Off'|translate}}"
class="green wide form-control">
</switch>
</div>
<!-- delete button -->
<a ng-show="isDeleteMode && (motions|filter:{selected:true}).length > 0"
os-perms="motions.can_manage" ng-click="delete()"
class="btn btn-primary btn-sm form-control">
<i class="fa fa-trash fa-lg"></i>
<translate>Delete selected motions</translate>
</a>
<!-- TODO: add filters -->
</form>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="text" os-focus-me ng-model="filter.search" class="form-control" <input type="text" os-focus-me ng-model="filter.search" class="form-control"
@ -32,67 +49,141 @@
<table class="table table-striped table-bordered table-hover"> <table class="table table-striped table-bordered table-hover">
<thead> <thead>
<tr> <tr>
<!-- TODO: Add motion.agenda_item to rest api --> <!-- projector column -->
<th ng-click="toggleSort('agenda_item')" class="sortable minimum"> <th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="firstColumn">
<translate>Agenda item</translate> <!-- delete selection column -->
<i class="pull-right fa" ng-show="sortColumn === 'agenda_item' && header.sortable != false" <th ng-show="isDeleteMode" os-perms-lite="motions.can_manage" class="firstColumn deleteColumn">
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"> <input type="checkbox" ng-model="selectedAll" ng-change="checkAll()">
</i>
<th ng-click="toggleSort('identifier')" class="sortable minimum"> <th ng-click="toggleSort('identifier')" class="sortable minimum">
<translate>Identifier</translate> <translate>Identifier</translate>
<i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false" <i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"> ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i> </i>
<th ng-click="toggleSort('title')" class="sortable"> <th ng-click="toggleSort('getTitle()')" class="sortable">
<translate>Title</translate> <translate>Title</translate>
<i class="pull-right fa" ng-show="sortColumn === 'title' && header.sortable != false" <i class="pull-right fa" ng-show="sortColumn === 'getTitle()' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"> ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i> </i>
<th ng-click="toggleSort('submitters')" class="sortable"> <th ng-click="toggleSort('submitters')" class="sortable optional">
<translate>Submitters</translate> <translate>Submitters</translate>
<i class="pull-right fa" ng-show="sortColumn === 'submitters' && header.sortable != false" <i class="pull-right fa" ng-show="sortColumn === 'submitters' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"> ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i> </i>
<th ng-click="toggleSort('category')" class="sortable"> <th ng-click="toggleSort('category')" class="sortable optional">
<translate>Category</translate> <translate>Category</translate>
<i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false" <i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"> ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i> </i>
<th os-perms="motions.can_manage core.can_manage_projector" class="minimum"> <th ng-click="toggleSort('state.name')" class="sortable optional">
<translate>Actions</translate> <translate>State</translate>
<i class="pull-right fa" ng-show="sortColumn === 'state.name' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i>
<tbody> <tbody>
<tr ng-repeat="motion in motions | filter: filter.search | <tr ng-repeat="motion in motions | filter: filter.search |
orderBy: sortColumn:reverse" ng-class="{ 'activeline': motion.isProjected() }"> orderBy: sortColumn:reverse"
<td> <!--TOOD: add agenda item reference --> ng-class="{ 'activeline': motion.isProjected(), 'selected': motion.selected }">
<td><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.identifier }}</a> <!-- projector column -->
<td><a ui-sref="motions.motion.detail({id: motion.id})"> <td ng-show="!isDeleteMode" os-perms-lite="core.can_manage_projector">
{{ motion.getTitle() }} <a class="btn btn-default btn-sm"
</a>
<td class="optional">
<div ng-repeat="submitter in motion.submitters">
{{ submitter.get_full_name() }}<br>
</div>
<td class="optional">
{{ motion.category.name }}
<td os-perms="motions.can_manage core.can_manage_projector" class="nobr">
<!-- project -->
<a os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
ng-class="{ 'btn-primary': motion.isProjected() }" ng-class="{ 'btn-primary': motion.isProjected() }"
ng-click="motion.project()" ng-click="motion.project()"
title="{{ 'Project motion' | translate }}"> title="{{ 'Project motion' | translate }}">
<i class="fa fa-video-camera"></i> <i class="fa fa-video-camera"></i>
</a> </a>
<!-- edit --> <!-- delete selection column -->
<a ui-sref="motions.motion.detail.update({id: motion.id })" os-perms="motions.can_manage" <td ng-show="isDeleteMode" os-perms="motions.can_manage" class="deleteColumn">
class="btn btn-default btn-sm" <input type="checkbox" ng-model="motion.selected">
title="{{ 'Edit' | translate}}"> <!-- motion data colums -->
<i class="fa fa-pencil"></i> <td ng-if="!motion.quickEdit">{{ motion.identifier }}
</a> <td ng-if="!motion.quickEdit" ng-mouseover="motion.hover=true" ng-mouseleave="motion.hover=false">
<!-- delete --> <strong><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.getTitle() }}</a></strong>
<a os-perms="motions.can_manage" class="btn btn-danger btn-sm" <div os-perms-lite="motions.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !motion.hover}">
ng-bootbox-confirm="Are you sure you want to delete <b>{{ motion.getTitle() }}</b>?" <a ui-sref="motions.motion.detail.update({id: motion.id })" translate>Edit</a> |
ng-bootbox-confirm-action="delete(motion)" <a href="" ng-click="motion.quickEdit=true" translate>QuickEdit</a> |
title="{{ 'Delete' | translate }}"> <a href="" class="text-danger"
<i class="fa fa-trash-o"></i> ng-bootbox-confirm="Are you sure you want to delete <b>{{ motion.getTitle() }}</b>?"
</a> ng-bootbox-confirm-action="deleteSingleMotion(motion)" translate>Delete</a>
</div>
<td ng-if="!motion.quickEdit" class="optional">
<div ng-repeat="submitter in motion.submitters">
{{ submitter.get_full_name() }}<br>
</div>
<td ng-if="!motion.quickEdit" class="optional">
{{ motion.category.name }}
<td ng-if="!motion.quickEdit" class="optional">
<span class="label label-primary">{{ motion.state.name | translate }}</span>
<!-- quickEdit columns -->
<td ng-if="motion.quickEdit" colspan="5">
<h4>{{ motion.getTitle() }} <span class="text-muted">&ndash; Quick Edit</span></h4>
<alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
{{alert.msg}}
</alert>
<div class="row">
<div class="col-xs-6">
<label for="inputIdentifier" translate>Identifier</label>
<input type="text" ng-model="motion.identifier" class="form-control input-sm"
name="inputIdentifier">
</div>
<div class="col-xs-6">
<label for="selectCategory" translate>Category</label>
<select ng-options="category.id as category.name for category in categories"
ng-model="motion.category_id" class="form-control" name="selectCategory">
</select>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<label for="selectSubmitter" translate>Submitters</label>
<ui-select multiple ng-model="motion.submitters_id" name="selectSubmitter">
<ui-select-match placeholder="{{ 'Select or search a submitter...' | translate }}">
{{ $item.get_full_name() }}
</ui-select-match>
<ui-select-choices repeat="user.id as user in users | filter: $select.search">
<div ng-bind-html="user.get_full_name() | highlight: $select.search"></div>
</ui-select-choices>
</ui-select>
</div>
<div class="col-xs-6">
<label for="selectTags" translate>Tags</label>
<ui-select multiple ng-model="motion.tags_id">
<ui-select-match placeholder="{{ 'Select or search a tag...' | translate }}">
{{ $item.name }}
</ui-select-match>
<ui-select-choices repeat="tag.id as tag in tags | filter: $select.search">
{{ tag.name }}
</ui-select-choices>
</ui-select>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div ng-if="config('motions_min_supporters') > 0">
<label for="selectSubmitter" translate>Supporters</label>
<ui-select multiple ng-model="motion.supporters_id">
<ui-select-match placeholder="{{ 'Select or search a supporter...' | translate }}">
{{ $item.get_full_name() }}
</ui-select-match>
<ui-select-choices repeat="user.id as user in users | filter: $select.search">
<div ng-bind-html="user.get_full_name() | highlight: $select.search"></div>
</ui-select-choices>
</ui-select>
</div>
</div>
<div class="col-xs-6">
<label for="selectState" translate>State</label>
<select ng-model="motion.state" class="form-control" name="selectState">
</select>
</div>
</div>
<div class="spacer">
<button ng-click="motion.quickEdit=false" class="btn btn-default pull-left" translate>
Cancel
</button> &nbsp;
<button ng-click="update(motion)" class="btn btn-primary" translate>
Update
</button>
<a ui-sref="motions.motion.detail.update({id: motion.id })" class="pull-right"
translate>Edit motion...</a>
</div>
</table> </table>

View File

@ -40,7 +40,7 @@
<div class="col-sm-8"> <div class="col-sm-8">
<form class="form-inline"> <form class="form-inline">
<!-- delete mode --> <!-- delete mode -->
<div os-perms-lite="agenda.can_manage" class="form-group"> <div os-perms-lite="users.can_manage" class="form-group">
<label for="deleteSwitcher" translate>Delete mode</label> <label for="deleteSwitcher" translate>Delete mode</label>
<switch id="deleteSwitcher" ng-model="isDeleteMode" ng-change="uncheckAll()" <switch id="deleteSwitcher" ng-model="isDeleteMode" ng-change="uncheckAll()"
on="{{'On'|translate}}" off="{{'Off'|translate}}" on="{{'On'|translate}}" off="{{'Off'|translate}}"