From 5b37a21c87e773801bdcfc70ebf9597dccc356f8 Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Thu, 15 Oct 2015 17:25:40 +0200 Subject: [PATCH] Motion detail updated for polls. bower.json: updated ui-select New QuickEdit feature in motion list. --- bower.json | 4 +- .../static/templates/agenda/item-list.html | 2 +- openslides/core/static/css/app.css | 24 ++- openslides/motions/models.py | 1 + .../motions/static/js/motions/motions.js | 198 +++++++++++++++--- .../templates/motions/motion-detail.html | 161 ++++++++++++-- .../static/templates/motions/motion-form.html | 9 +- .../static/templates/motions/motion-list.html | 173 +++++++++++---- .../static/templates/users/user-list.html | 2 +- 9 files changed, 477 insertions(+), 97 deletions(-) diff --git a/bower.json b/bower.json index 9c4fd3c94..6026df924 100644 --- a/bower.json +++ b/bower.json @@ -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", diff --git a/openslides/agenda/static/templates/agenda/item-list.html b/openslides/agenda/static/templates/agenda/item-list.html index 8c7b2aee8..084409fd8 100644 --- a/openslides/agenda/static/templates/agenda/item-list.html +++ b/openslides/agenda/static/templates/agenda/item-list.html @@ -71,7 +71,7 @@ - + diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css index 758a4e8d7..e1e677347 100644 --- a/openslides/core/static/css/app.css +++ b/openslides/core/static/css/app.css @@ -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; diff --git a/openslides/motions/models.py b/openslides/motions/models.py index fdb36aebd..a410c28cd 100644 --- a/openslides/motions/models.py +++ b/openslides/motions/models.py @@ -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.""" diff --git a/openslides/motions/static/js/motions/motions.js b/openslides/motions/static/js/motions/motions.js index 0fa5f22a4..e4ba67e26 100644 --- a/openslides/motions/static/js/motions/motions.js +++ b/openslides/motions/static/js/motions/motions.js @@ -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; + } } ]) diff --git a/openslides/motions/static/templates/motions/motion-detail.html b/openslides/motions/static/templates/motions/motion-detail.html index d9915a9f1..3efb17c2a 100644 --- a/openslides/motions/static/templates/motions/motion-detail.html +++ b/openslides/motions/static/templates/motions/motion-detail.html @@ -6,13 +6,6 @@ - - - {{ tag.name }} - -   - - {{ motion.agenda_item }} -Create Poll -
- {{ poll.id }} - delete -
-

Text

-
{{ motion.getText() }}
+

Reason

-
{{ motion.getReason() }}
+
@@ -61,11 +48,151 @@ {{ submitter.get_full_name() }}
+
+

Supporters

+
    +
  1. + {{ supporters.get_full_name() }} +
+
+ +

State

+ {{ motion.state.name | translate }} + +
+
+ +
+
+ +
+
+ +

Voting result

+
    +
  1. + Vote + + +
    +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    + + +
    +
    +
    + +
    + + Yes: +
    +
    {{ poll.yes }} {{poll.getYesPercent()}}
    + +
    + + No: +
    +
    {{ poll.no }} {{poll.getNoPercent()}}
    + +
    + + Abstain: +
    +
    {{ poll.abstain }} {{poll.getAbstainPercent()}}
    +
    + +
    +
    + + Valid votes: +
    +
    {{ poll.votesvalid }} {{poll.getVotesValidPercent()}}
    +
    + +
    +
    + + Invalid votes: +
    +
    {{ poll.votesinvalid }} {{poll.getVotesInvalidPercent()}}
    +
    +
    + +
    +
    + + Votes cast: +
    +
    {{ poll.votescast }} {{poll.getVotesCastPercent()}}
    +
    +
    +
+ +

Category

{{ motion.category.name }} -

Voting result

- - +

Tags

+ + + {{ tag.name }} + +   +
diff --git a/openslides/motions/static/templates/motions/motion-form.html b/openslides/motions/static/templates/motions/motion-form.html index c89766836..07b64f0d2 100644 --- a/openslides/motions/static/templates/motions/motion-form.html +++ b/openslides/motions/static/templates/motions/motion-form.html @@ -20,7 +20,7 @@
- + {{ $item.get_full_name() }} @@ -31,7 +31,7 @@
- +
@@ -69,13 +69,10 @@ {{ file.title }} -
- + {{ $item.get_full_name() }} diff --git a/openslides/motions/static/templates/motions/motion-list.html b/openslides/motions/static/templates/motions/motion-list.html index d6d9db6ec..2fad69694 100644 --- a/openslides/motions/static/templates/motions/motion-list.html +++ b/openslides/motions/static/templates/motions/motion-list.html @@ -21,7 +21,24 @@
- +
+ +
+ + + +
+ + + + Delete selected motions + + +
- - - Agenda item - - + + + + + Identifier - + Title - - + Submitters - + Category - - Actions + + State + + - - {{ motion.identifier }} - - {{ motion.getTitle() }} - - -
- {{ submitter.get_full_name() }}
-
- - {{ motion.category.name }} - - - + + + - - - - - - - - + + + + + {{ motion.identifier }} + + {{ motion.getTitle() }} +
+ Edit | + QuickEdit | + Delete +
+ +
+ {{ submitter.get_full_name() }}
+
+ + {{ motion.category.name }} + + {{ motion.state.name | translate }} + + +

{{ motion.getTitle() }} – Quick Edit

+ + {{alert.msg}} + +
+
+ + +
+
+ + +
+
+
+
+ + + + {{ $item.get_full_name() }} + + +
+
+
+
+
+ + + + {{ $item.name }} + + + {{ tag.name }} + + +
+
+
+
+
+ + + + {{ $item.get_full_name() }} + + +
+
+
+
+
+
+ + +
+
+
+   + + Edit motion... +
diff --git a/openslides/users/static/templates/users/user-list.html b/openslides/users/static/templates/users/user-list.html index 63b8a4097..466e5543d 100644 --- a/openslides/users/static/templates/users/user-list.html +++ b/openslides/users/static/templates/users/user-list.html @@ -40,7 +40,7 @@
-
+