Motion detail updated for polls.
bower.json: updated ui-select New QuickEdit feature in motion list.
This commit is contained in:
parent
2495ba609b
commit
5b37a21c87
@ -7,13 +7,13 @@
|
||||
"jquery.cookie": "~1.4.1",
|
||||
"bootstrap-css-only": "~3.3.4",
|
||||
"angular": "~1.3.15",
|
||||
"angular-bootstrap": "~0.13.0",
|
||||
"angular-bootstrap": "~0.14.2",
|
||||
"angular-messages": "~1.3.15",
|
||||
"angular-animate": "~1.3.15",
|
||||
"angular-csv-import": "~0.0.15",
|
||||
"angular-loading-bar": "~0.7.1",
|
||||
"angular-ui-router": "~0.2.13",
|
||||
"angular-ui-select": "~0.12",
|
||||
"angular-ui-select": "~0.13",
|
||||
"angular-ui-switch": "~0.1.0",
|
||||
"angular-ui-tree": "~2.2.0",
|
||||
"angular-gettext": "~2.0.2",
|
||||
|
@ -71,7 +71,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- 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 -->
|
||||
<th ng-show="isDeleteMode" os-perms-lite="agenda.can_manage" class="firstColumn deleteColumn"
|
||||
ng-click="$event.stopPropagation();">
|
||||
|
@ -49,6 +49,15 @@ body {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
.spacer {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.hoverActions {
|
||||
font-size: 85%;
|
||||
}
|
||||
.hiddenDiv {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* TODO: used by ng-fab-forms */
|
||||
.validation-success {
|
||||
@ -274,14 +283,25 @@ tr.offline td, li.offline {
|
||||
tr.activeline td, li.activeline, .projected {
|
||||
background-color: #bed4de;
|
||||
}
|
||||
tr.selected td {
|
||||
background-color: #ff9999;
|
||||
}
|
||||
.nopadding {
|
||||
padding: 0;
|
||||
}
|
||||
.alert form {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
tr.total td {
|
||||
border-top: 1px solid #333333;
|
||||
.slimlist {
|
||||
padding-left: 20px;
|
||||
}
|
||||
.smallhr {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
border-color: #333333;
|
||||
}
|
||||
.resultcolumn {
|
||||
font-weight: bold;
|
||||
}
|
||||
.nobr {
|
||||
white-space: nowrap;
|
||||
|
@ -763,6 +763,7 @@ class State(RESTModelMixin, models.Model):
|
||||
This behavior can be changed by the form and view, e. g. via the
|
||||
MotionDisableVersioningMixin.
|
||||
"""
|
||||
# TODO: preferred_for = ChoiceField
|
||||
|
||||
leave_old_version_active = models.BooleanField(default=False)
|
||||
"""If true, new versions are not automaticly set active."""
|
||||
|
@ -4,9 +4,78 @@ angular.module('OpenSlidesApp.motions', [])
|
||||
|
||||
.factory('MotionPoll', [
|
||||
'DS',
|
||||
function(DS) {
|
||||
'Config',
|
||||
'jsDataModel',
|
||||
function(DS, Config, jsDataModel) {
|
||||
return DS.defineResource({
|
||||
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) {
|
||||
Motion.bindAll({}, $scope, 'motions');
|
||||
Category.bindAll({}, $scope, 'categories');
|
||||
User.bindAll({}, $scope, 'users');
|
||||
.controller('MotionListCtrl', [
|
||||
'$scope',
|
||||
'$state',
|
||||
'Motion',
|
||||
'Category',
|
||||
'User',
|
||||
function($scope, $state, Motion, Category, User) {
|
||||
Motion.bindAll({}, $scope, 'motions');
|
||||
Category.bindAll({}, $scope, 'categories');
|
||||
User.bindAll({}, $scope, 'users');
|
||||
|
||||
// setup table sorting
|
||||
$scope.sortColumn = 'identifier';
|
||||
$scope.filterPresent = '';
|
||||
$scope.reverse = false;
|
||||
// function to sort by clicked column
|
||||
$scope.toggleSort = function ( column ) {
|
||||
if ( $scope.sortColumn === column ) {
|
||||
$scope.reverse = !$scope.reverse;
|
||||
}
|
||||
$scope.sortColumn = column;
|
||||
};
|
||||
// setup table sorting
|
||||
$scope.sortColumn = 'identifier';
|
||||
$scope.filterPresent = '';
|
||||
$scope.reverse = false;
|
||||
// function to sort by clicked column
|
||||
$scope.toggleSort = function ( column ) {
|
||||
if ( $scope.sortColumn === column ) {
|
||||
$scope.reverse = !$scope.reverse;
|
||||
}
|
||||
$scope.sortColumn = column;
|
||||
};
|
||||
|
||||
// save changed motion
|
||||
$scope.save = function (motion) {
|
||||
Motion.save(motion);
|
||||
};
|
||||
// delete selected motion
|
||||
$scope.delete = function (motion) {
|
||||
Motion.destroy(motion.id);
|
||||
};
|
||||
})
|
||||
// hover edit actions
|
||||
$scope.hoverIn = function () {
|
||||
$scope.showEditActions = true;
|
||||
};
|
||||
$scope.hoverOut = function () {
|
||||
$scope.showEditActions = false;
|
||||
};
|
||||
|
||||
// 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', [
|
||||
'$scope',
|
||||
'Motion',
|
||||
'Category',
|
||||
'Workflow',
|
||||
'User',
|
||||
'motion',
|
||||
'$http',
|
||||
function($scope, Motion, Category, User, motion, $http) {
|
||||
function($scope, Motion, Category, Workflow, User, motion, $http) {
|
||||
Motion.bindOne(motion.id, $scope, 'motion');
|
||||
Category.bindAll({}, $scope, 'categories');
|
||||
Workflow.bindAll({}, $scope, 'workflows');
|
||||
User.bindAll({}, $scope, 'users');
|
||||
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 () {
|
||||
$http.post('/rest/motions/motion/' + motion.id + '/create_poll/', {})
|
||||
.success(function(data){
|
||||
@ -288,10 +423,19 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
|
||||
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
||||
});
|
||||
}
|
||||
|
||||
$scope.delete_poll = function (poll) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -6,13 +6,6 @@
|
||||
</small>
|
||||
</h1>
|
||||
|
||||
<span ng-repeat="tag in motion.tags">
|
||||
<span class="label label-default">
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
|
||||
</span>
|
||||
|
||||
{{ motion.agenda_item }}
|
||||
|
||||
<div id="submenu">
|
||||
@ -39,19 +32,13 @@
|
||||
</a>
|
||||
</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="col-sm-8">
|
||||
<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>
|
||||
<div class="white-space-pre-line">{{ motion.getReason() }}</div>
|
||||
<div class="white-space-pre-line" ng-bind-html="motion.getReason()"></div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
@ -61,11 +48,151 @@
|
||||
{{ submitter.get_full_name() }}<br>
|
||||
</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>∅</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>∑</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>∅</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>∑</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>
|
||||
{{ 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>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,7 +20,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<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-match placeholder="{{ 'Select or search a submitter...' | translate }}">
|
||||
{{ $item.get_full_name() }}
|
||||
@ -31,7 +31,7 @@
|
||||
</ui-select>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -69,13 +69,10 @@
|
||||
{{ file.title }}
|
||||
</ui-select-choices>
|
||||
</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>
|
||||
<!-- show supporters if enabled -->
|
||||
<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-match placeholder="{{ 'Select or search a supporter...' | translate }}">
|
||||
{{ $item.get_full_name() }}
|
||||
|
@ -21,7 +21,24 @@
|
||||
|
||||
<div class="row form-group">
|
||||
<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 class="col-sm-4">
|
||||
<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">
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- TODO: Add motion.agenda_item to rest api -->
|
||||
<th ng-click="toggleSort('agenda_item')" class="sortable minimum">
|
||||
<translate>Agenda item</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'agenda_item' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<!-- projector column -->
|
||||
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="firstColumn">
|
||||
<!-- delete selection column -->
|
||||
<th ng-show="isDeleteMode" os-perms-lite="motions.can_manage" class="firstColumn deleteColumn">
|
||||
<input type="checkbox" ng-model="selectedAll" ng-change="checkAll()">
|
||||
<th ng-click="toggleSort('identifier')" class="sortable minimum">
|
||||
<translate>Identifier</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<th ng-click="toggleSort('title')" class="sortable">
|
||||
<th ng-click="toggleSort('getTitle()')" class="sortable">
|
||||
<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'">
|
||||
</i>
|
||||
<th ng-click="toggleSort('submitters')" class="sortable">
|
||||
<th ng-click="toggleSort('submitters')" class="sortable optional">
|
||||
<translate>Submitters</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'submitters' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<th ng-click="toggleSort('category')" class="sortable">
|
||||
<th ng-click="toggleSort('category')" class="sortable optional">
|
||||
<translate>Category</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<th os-perms="motions.can_manage core.can_manage_projector" class="minimum">
|
||||
<translate>Actions</translate>
|
||||
<th ng-click="toggleSort('state.name')" class="sortable optional">
|
||||
<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>
|
||||
<tr ng-repeat="motion in motions | filter: filter.search |
|
||||
orderBy: sortColumn:reverse" ng-class="{ 'activeline': motion.isProjected() }">
|
||||
<td> <!--TOOD: add agenda item reference -->
|
||||
<td><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.identifier }}</a>
|
||||
<td><a ui-sref="motions.motion.detail({id: motion.id})">
|
||||
{{ motion.getTitle() }}
|
||||
</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"
|
||||
orderBy: sortColumn:reverse"
|
||||
ng-class="{ 'activeline': motion.isProjected(), 'selected': motion.selected }">
|
||||
<!-- projector column -->
|
||||
<td ng-show="!isDeleteMode" os-perms-lite="core.can_manage_projector">
|
||||
<a class="btn btn-default btn-sm"
|
||||
ng-class="{ 'btn-primary': motion.isProjected() }"
|
||||
ng-click="motion.project()"
|
||||
title="{{ 'Project motion' | translate }}">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
</a>
|
||||
<!-- edit -->
|
||||
<a ui-sref="motions.motion.detail.update({id: motion.id })" os-perms="motions.can_manage"
|
||||
class="btn btn-default btn-sm"
|
||||
title="{{ 'Edit' | translate}}">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
<!-- delete -->
|
||||
<a os-perms="motions.can_manage" class="btn btn-danger btn-sm"
|
||||
ng-bootbox-confirm="Are you sure you want to delete <b>{{ motion.getTitle() }}</b>?"
|
||||
ng-bootbox-confirm-action="delete(motion)"
|
||||
title="{{ 'Delete' | translate }}">
|
||||
<i class="fa fa-trash-o"></i>
|
||||
</a>
|
||||
<!-- delete selection column -->
|
||||
<td ng-show="isDeleteMode" os-perms="motions.can_manage" class="deleteColumn">
|
||||
<input type="checkbox" ng-model="motion.selected">
|
||||
<!-- motion data colums -->
|
||||
<td ng-if="!motion.quickEdit">{{ motion.identifier }}
|
||||
<td ng-if="!motion.quickEdit" ng-mouseover="motion.hover=true" ng-mouseleave="motion.hover=false">
|
||||
<strong><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.getTitle() }}</a></strong>
|
||||
<div os-perms-lite="motions.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !motion.hover}">
|
||||
<a ui-sref="motions.motion.detail.update({id: motion.id })" translate>Edit</a> |
|
||||
<a href="" ng-click="motion.quickEdit=true" translate>QuickEdit</a> |
|
||||
<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>
|
||||
</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">– 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>
|
||||
<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>
|
||||
|
@ -40,7 +40,7 @@
|
||||
<div class="col-sm-8">
|
||||
<form class="form-inline">
|
||||
<!-- 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>
|
||||
<switch id="deleteSwitcher" ng-model="isDeleteMode" ng-change="uncheckAll()"
|
||||
on="{{'On'|translate}}" off="{{'Off'|translate}}"
|
||||
|
Loading…
Reference in New Issue
Block a user