From 4f717b661016841a917f0b1e53c8560d5a389762 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Fri, 18 Nov 2016 13:50:40 +0100 Subject: [PATCH] New assignment and mediafile tables and table generics --- .../assignments/static/js/assignments/site.js | 115 ++--- .../assignments/assignment-list.html | 413 +++++++++++------- openslides/core/static/css/app.css | 43 +- openslides/core/static/js/core/base.js | 14 - openslides/core/static/js/core/site.js | 161 ++++--- .../mediafiles/static/js/mediafiles/site.js | 72 +-- .../templates/mediafiles/mediafile-list.html | 276 +++++++----- openslides/motions/static/js/motions/site.js | 68 +-- .../static/templates/motions/motion-list.html | 240 +++++----- openslides/users/static/js/users/site.js | 75 ++-- .../static/templates/users/user-list.html | 178 +++----- 11 files changed, 924 insertions(+), 731 deletions(-) diff --git a/openslides/assignments/static/js/assignments/site.js b/openslides/assignments/static/js/assignments/site.js index cef4bf1f5..cf6111425 100644 --- a/openslides/assignments/static/js/assignments/site.js +++ b/openslides/assignments/static/js/assignments/site.js @@ -244,8 +244,11 @@ angular.module('OpenSlidesApp.assignments.site', [ 'AssignmentCatalogContentProvider', 'PdfMakeDocumentProvider', 'User', + 'osTableFilter', + 'osTableSort', function($scope, ngDialog, AssignmentForm, Assignment, Tag, Agenda, phases, Projector, ProjectionDefault, - gettextCatalog, AssignmentContentProvider, AssignmentCatalogContentProvider, PdfMakeDocumentProvider, User) { + gettextCatalog, AssignmentContentProvider, AssignmentCatalogContentProvider, PdfMakeDocumentProvider, + User, osTableFilter, osTableSort) { Assignment.bindAll({}, $scope, 'assignments'); Tag.bindAll({}, $scope, 'tags'); $scope.$watch(function () { @@ -259,72 +262,76 @@ angular.module('OpenSlidesApp.assignments.site', [ $scope.phases = phases; $scope.alert = {}; - // setup table sorting - $scope.sortColumn = 'title'; - $scope.filterPresent = ''; - $scope.reverse = false; - // function to sort by clicked column - $scope.toggleSort = function (column) { - if ( $scope.sortColumn === column ) { - $scope.reverse = !$scope.reverse; + // Filtering + $scope.filter = osTableFilter.createInstance(); + $scope.filter.multiselectFilters = { + tag: [], + phase: [], + }; + $scope.filter.propertyList = ['title', 'description']; + $scope.filter.propertyFunctionList = [ + function (assignment) { + return gettextCatalog.getString($scope.phases[assignment.phase].display_name); + }, + ]; + $scope.filter.propertyDict = { + 'assignment_related_users': function (candidate) { + return candidate.user.get_short_name(); + }, + 'tags': function (tag) { + return tag.name; + }, + }; + $scope.getItemId = { + tag: function (assignment) {return assignment.tags_id;}, + phase: function (assignment) {return assignment.phase;}, + }; + // Sorting + $scope.sort = osTableSort.createInstance(); + $scope.sort.column = 'title'; + $scope.sortOptions = [ + {name: 'agenda_item.getItemNumberWithAncestors()', + display_name: 'Item'}, + {name: 'title', + display_name: 'Title'}, + {name: 'open_posts', + display_name: 'Open posts'}, + {name: 'phase', + display_name: 'Phase'}, + ]; + $scope.hasTag = function (assignment, tag) { + return _.indexOf(assignment.tags_id, tag.id) > -1; + }; + $scope.toggleTag = function (assignment, tag) { + if ($scope.hasTag(assignment, tag)) { + assignment.tags_id = _.filter(assignment.tags_id, function (tag_id){ + return tag_id != tag.id; + }); + } else { + assignment.tags_id.push(tag.id); } - $scope.sortColumn = column; + Assignment.save(assignment); }; - // define custom search filter string - $scope.getFilterString = function (assignment) { - return [ - assignment.title, - assignment.description, - $scope.phases[assignment.phase].display_name, - _.map(assignment.assignment_related_users, - function (candidate) { - return candidate.user.get_short_name(); - } - ).join(" "), - _.map(assignment.tags, - function (tag) { - return tag.name; - } - ).join(" "), - ].join(" "); + // update phase + $scope.updatePhase = function (assignment, phase_id) { + assignment.phase = phase_id; + Assignment.save(assignment); }; - // open new/edit dialog $scope.openDialog = function (assignment) { ngDialog.open(AssignmentForm.getDialog(assignment)); }; - // cancel QuickEdit mode - $scope.cancelQuickEdit = function (assignment) { - // revert all changes by restore (refresh) original assignment object from server - Assignment.refresh(assignment); - assignment.quickEdit = false; - }; - // save changed assignment - $scope.save = function (assignment) { - Assignment.save(assignment).then( - function(success) { - assignment.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; + // *** select mode functions *** + $scope.isSelectMode = false; // check all checkboxes $scope.checkAll = function () { angular.forEach($scope.assignments, function (assignment) { assignment.selected = $scope.selectedAll; }); }; - // uncheck all checkboxes if isDeleteMode is closed + // uncheck all checkboxes if isSelectMode is closed $scope.uncheckAll = function () { - if (!$scope.isDeleteMode) { + if (!$scope.isSelectMode) { $scope.selectedAll = false; angular.forEach($scope.assignments, function (assignment) { assignment.selected = false; @@ -337,7 +344,7 @@ angular.module('OpenSlidesApp.assignments.site', [ if (assignment.selected) Assignment.destroy(assignment.id); }); - $scope.isDeleteMode = false; + $scope.isSelectMode = false; $scope.uncheckAll(); }; // delete single assignment diff --git a/openslides/assignments/static/templates/assignments/assignment-list.html b/openslides/assignments/static/templates/assignments/assignment-list.html index 9bf8e97e7..60f40a6d6 100644 --- a/openslides/assignments/static/templates/assignments/assignment-list.html +++ b/openslides/assignments/static/templates/assignments/assignment-list.html @@ -9,10 +9,6 @@ Tags - - - PDF -

Elections

@@ -20,31 +16,35 @@
-
-
- - -
-
-
-
-
-
-
- -
-
- + +
@@ -58,10 +58,10 @@
-
+
- - - - - - - - -
- - - - - - - Item - - - - - - Title - - - - - - Candidates · Posts - - - - - - Phase - - -
- - - - - - - - - - {{ assignment.agenda_item.item_number }} - - - - {{ assignment.title }} - - {{ tag.name }} +
+
+
+ +
+
+ + + + + Filter -
- Edit | - QuickEdit | - + + + Tag + + + + + + + + Phase + + + + + + + + Sort + + + + + + + + + + + + + + + + + + {{ tag.name }} + + + + + No tag set + + + + + {{ phase.display_name | translate }} + + + + + +
+
+ + +
+ + +
+ +
+ +
+ + +
+ +
+
+ +
+ + {{ assignment.title }} + + + + {{ phases[assignment.phase].display_name | translate }} + + + + + + +
+ +
+ + Edit · + Delete +
+
+
- -
- {{ assignment.assignment_related_users.length }} - / - {{ assignment.open_posts }} + +
+
+ + +
+ + + + + + + + + + {{ tag.name }}, + + + + + + +
+ +
+ + + {{ tag.name }}, + +
+
+
- -
- - {{ phases[assignment.phase].display_name | translate }} +
+ + {{ assignment.assignment_related_users.length }} +
+
+
{{ assignment.agenda_item.getItemNumberWithAncestors() }}
+
+ + + - -
-

{{ assignment.title }} – Quick Edit

-
- {{ alert.msg }} -
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-   - - Edit election ... -
-
diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css index a8e30f1b4..4edf8fd7f 100644 --- a/openslides/core/static/css/app.css +++ b/openslides/core/static/css/app.css @@ -864,23 +864,6 @@ img { } /** Motion **/ -#motion-os-table .identifier-col { - width: 50px; - min-height: 1px; -} - -#motion-os-table .identifier-col > div { - text-align: center; -} - -#motion-os-table .title-col { - width: calc(100% - 50px); -} - -#motion-os-table .title-col, .os-table small { - color: #555; -} - .motion-toolbar, .speakers-toolbar { background-color: #f5f5f5; border-bottom: 1px solid #ddd; @@ -900,6 +883,9 @@ img { } /** OS-Table **/ +.os-table small { + color: #555; +} .os-table .row { border: 1px solid #ddd; border-top: 0px; @@ -913,6 +899,11 @@ img { padding: 10px 0px 10px 0px; } +.os-table .id-col { + width: 50px; + min-height: 1px; +} + .os-table .header-row { border-top: 1px solid #ddd; background-color: #f5f5f5; @@ -960,17 +951,13 @@ img { padding-right: 10px; } -.os-table .dropdown { - display: inline-block; -} - .os-table .header-row .dropdown > span, .os-table .sort-spacer { padding: 5px 10px 5px 10px; } .os-table .title { font-size: 115%; - margin-right: 10px; + margin-right: 5px; padding: 0; background-color: transparent; } @@ -1079,16 +1066,6 @@ img { margin-left: 0px !important; } -.dropdown-entries { - white-space: nowrap; -} - -.dropdown-entries > li { - padding: 5px 10px 5px 10px; - width: 100%; - cursor: pointer; -} - .slimDropDown { padding-left: 4px !important; padding-right: 4px !important; @@ -1511,6 +1488,8 @@ tr.selected td { #chatbox { width: 100%; top: 40px; } + .badge { font-size: 10px; } + /* show replacement elements, if any */ .optional-show { display: block !important; } diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index 5141d87c4..e37fbd9d8 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -796,19 +796,6 @@ angular.module('OpenSlidesApp.core', [ } ]) -.filter('osFilter', [ - function () { - return function (array, string, getFilterString) { - if (!string) { - return array; - } - return Array.prototype.filter.call(array, function (item) { - return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1; - }); - }; - } -]) - // mark HTML as "trusted" .filter('trusted', [ '$sce', @@ -838,7 +825,6 @@ angular.module('OpenSlidesApp.core', [ }; }) - // Make sure that the DS factories are loaded by making them a dependency .run([ 'ChatMessage', diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index 4f9805ad1..cadb0dbd0 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -342,61 +342,107 @@ angular.module('OpenSlidesApp.core.site', [ } ]) -.factory('Multiselect', [ +/* This factory handles the filtering of the OS-data-tables. It contains + * all logic needed for the table header filtering. Things to configure: + * - multiselectFilters: A dict associating the filter name to a list (empty per default). E.g. + * { tag: [], + * category: [], } + * - booleanFilters: A dict containing a dict for every filter. The value property is a must. + * For displaying properties like displayName, choiceYes and choiceNo could be usefull. E.g. + * { isPresent: { + * value: undefined, + * displayName: gettext('Is present'), } } + * - propertyList, propertyFunctionList, propertyDict: See function getObjectQueryString + */ +.factory('osTableFilter', [ function () { - var instance = function () { - var areFiltersSet = function () { - var areFiltersSet = false; - _.forEach(self.filters, function (filterList, filter) { - if (filterList.length > 0) { - areFiltersSet = true; + var createInstance = function () { + var self = { + multiselectFilters: {}, + booleanFilters: {}, + filterString: '', + }; + self.areFiltersSet = function () { + var areFiltersSet = _.find(self.multiselectFilters, function (filterList) { + return filterList.length > 0; + }); + areFiltersSet = areFiltersSet || _.find(self.booleanFilters, function (filterDict) { + return filterDict.value !== undefined; + }); + areFiltersSet = areFiltersSet || (self.filterString !== ''); + return areFiltersSet !== false; + }; + self.reset = function () { + _.forEach(self.multiselectFilters, function (filterList, filter) { + self.multiselectFilters[filter] = []; + }); + _.forEach(self.booleanFilters, function (filterDict, filter) { + self.booleanFilters[filter].value = undefined; + }); + self.filterString = ''; + }; + self.operateMultiselectFilter = function (filter, id, danger) { + if (!danger) { + if (_.indexOf(self.multiselectFilters[filter], id) > -1) { + // remove id + self.multiselectFilters[filter].splice(_.indexOf(self.multiselectFilters[filter], id), 1); + } else { + // add id + self.multiselectFilters[filter].push(id); } - }); - return areFiltersSet; - }; - var resetFilters = function () { - _.forEach(self.filters, function (filterList, filter) { - self.filters[filter] = []; - }); - }; - var getFilterString = function (obj) { - var newList = []; - _.forEach(self.propertyList, function (property) { - newList.push(obj[property]); - }); - _.forEach(self.propertyFunctionList, function (fn) { - newList.push(fn(obj)); - }); - _.forEach(self.propertyDict, function (idFunction, property) { - newList.push(_.map(obj[property], idFunction).join(' ')); - }); - return newList.join(' '); - }; - var operate = function (filter, id) { - if (_.indexOf(self.filters[filter], id) > -1) { - // remove id - self.filters[filter] = _.filter(self.filters[filter], function (_id) { - return _id != id; - }); - } else { - // add id - self.filters[filter].push(id); } }; - - var self = { - filters: {}, - areFiltersSet: areFiltersSet, - resetFilters: resetFilters, - operate: operate, - getFilterString: getFilterString, + /* Three things are could be given to create the query string: + * - propertyList: Just a list of object's properties like ['title', 'name'] + * - propertyFunktionList: A list of functions returning a property (e.g. [function(motion) {return motion.getTitle();}] for retrieving the motions title) + * - propertyDict: A dict association properties that are lists to functions on how to handle them. + * E.g.: {'tags': function (tag) {return tag.name;}, } + * The list of tags will be mapped with this function to a list of strings (tag names). + */ + self.getObjectQueryString = function (obj) { + var stringList = []; + _.forEach(self.propertyList, function (property) { + stringList.push(obj[property]); + }); + _.forEach(self.propertyFunctionList, function (fn) { + stringList.push(fn(obj)); + }); + _.forEach(self.propertyDict, function (idFunction, property) { + stringList.push(_.map(obj[property], idFunction).join(' ')); + }); + return stringList.join(' '); }; - resetFilters(); //Initiate filters return self; }; return { - instance: instance + createInstance: createInstance + }; + } +]) + +/* This factory takes care of the sorting of OS-data-tables. Things to configure: + * - column: the default column which is the list sorted by (e.g. + * instance.column='title') + */ +.factory('osTableSort', [ + function () { + var createInstance = function () { + var self = { + column: '', + reverse: false, + }; + self.toggle = function (column) { + if (self.column === column) { + self.reverse = !self.reverse; + } + self.column = column; + }; + return self; + }; + + return { + createInstance: createInstance }; } ]) @@ -407,6 +453,9 @@ angular.module('OpenSlidesApp.core.site', [ * Then, all items in the array are passed, if the item_id (get with id_function) matches * one of the ids in filterArray. id_function could also return a list of ids. Example: * Item 1 has two tags with ids [1, 4]. filterArray == [3, 4] --> match + * + * If -1 is in the array items without an id will not be filtered. This is for implementing + * a filter option like: "All items without a category" */ .filter('MultiselectFilter', [ function () { @@ -414,12 +463,13 @@ angular.module('OpenSlidesApp.core.site', [ if (filterArray.length === 0) { return array; } + var itemsWithoutProperty = _.indexOf(filterArray, -1) > -1; return Array.prototype.filter.call(array, function (item) { var id = idFunction(item); - if (!id) { - return false; - } else if (typeof id === 'number') { + if (typeof id === 'number') { id = [id]; + } else if (id === null || !id.length) { + return itemsWithoutProperty; } return _.intersection(id, filterArray).length > 0; }); @@ -427,6 +477,19 @@ angular.module('OpenSlidesApp.core.site', [ } ]) +.filter('osFilter', [ + function () { + return function (array, string, getFilterString) { + if (!string) { + return array; + } + return Array.prototype.filter.call(array, function (item) { + return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1; + }); + }; + } +]) + // Load the django url patterns .run([ 'runtimeStates', diff --git a/openslides/mediafiles/static/js/mediafiles/site.js b/openslides/mediafiles/static/js/mediafiles/site.js index ea33a45e8..525a4dc55 100644 --- a/openslides/mediafiles/static/js/mediafiles/site.js +++ b/openslides/mediafiles/static/js/mediafiles/site.js @@ -57,7 +57,10 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp. 'User', 'Projector', 'ProjectionDefault', - function($scope, $http, ngDialog, Mediafile, MediafileForm, User, Projector, ProjectionDefault) { + 'osTableFilter', + 'osTableSort', + 'gettext', + function($scope, $http, ngDialog, Mediafile, MediafileForm, User, Projector, ProjectionDefault, osTableFilter, osTableSort, gettext) { Mediafile.bindAll({}, $scope, 'mediafiles'); User.bindAll({}, $scope, 'users'); $scope.$watch(function() { @@ -95,44 +98,61 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp. updatePresentedMediafiles(); - // setup table sorting - $scope.sortColumn = 'title'; - $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; - }; - // define custom search filter string - $scope.getFilterString = function (mediafile) { - return [ - mediafile.title, - mediafile.mediafile.type, - mediafile.mediafile.name, - mediafile.uploader.get_short_name() - ].join(" "); + // Filtering + $scope.filter = osTableFilter.createInstance(); + $scope.filter.booleanFilters = { + isPrivate: { + value: undefined, + displayName: gettext('Private'), + choiceYes: gettext('Is private'), + choiceNo: gettext('Is not private'), + needExtraPermission: true, + }, + isPdf: { + value: undefined, + displayName: gettext('Is PDF'), + choiceYes: gettext('Is PDF file'), + choiceNo: gettext('Is no PDF file'), + }, }; + $scope.filter.propertyList = ['title_or_filename']; + $scope.filter.propertyFunctionList = [ + function (mediafile) {return mediafile.uploader.get_short_name();}, + function (mediafile) {return mediafile.mediafile.type;}, + function (mediafile) {return mediafile.mediafile.name;}, + ]; + // Sorting + $scope.sort = osTableSort.createInstance(); + $scope.sort.column = 'title_or_filename'; + $scope.sortOptions = [ + {name: 'title_or_filename', + display_name: 'Title'}, + {name: 'timestamp', + display_name: 'UploadTime'}, + {name: 'uploader.get_short_name()', + display_name: 'Uploader'}, + {name: 'mediafile.type', + display_name: 'Type'}, + {name: 'filesize', + display_name: 'Filesize'}, + ]; // open new/edit dialog $scope.openDialog = function (mediafile) { ngDialog.open(MediafileForm.getDialog(mediafile)); }; - // *** delete mode functions *** - $scope.isDeleteMode = false; + // *** select mode functions *** + $scope.isSelectMode = false; // check all checkboxes $scope.checkAll = function () { angular.forEach($scope.mediafiles, function (mediafile) { mediafile.selected = $scope.selectedAll; }); }; - // uncheck all checkboxes if isDeleteMode is closed + // uncheck all checkboxes if SelectMode is closed $scope.uncheckAll = function () { - if (!$scope.isDeleteMode) { + if (!$scope.isSelectMode) { $scope.selectedAll = false; angular.forEach($scope.mediafiles, function (mediafile) { mediafile.selected = false; @@ -145,7 +165,7 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp. if (mediafile.selected) Mediafile.destroy(mediafile.id); }); - $scope.isDeleteMode = false; + $scope.isSelectMode = false; $scope.uncheckAll(); }; // delete single mediafile diff --git a/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html b/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html index cf9f5515f..eb76e3c05 100644 --- a/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html +++ b/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html @@ -115,44 +115,21 @@
- +
-
-
-
-
-
- -
-
- -
-
+
-
-
-
- - - Show PDF files only -
-
-
+ + +
+
+ +
+ {{ mediafile.filetype }} + (Encrypted) +
+
{{ mediafile.filesize }}
+
{{ mediafile.timestamp | date:'yyyy-MM-dd HH:mm:ss' }}
+
+
+
+
+ +
+ diff --git a/openslides/motions/static/js/motions/site.js b/openslides/motions/static/js/motions/site.js index 6dcf4d15f..00df75b1e 100644 --- a/openslides/motions/static/js/motions/site.js +++ b/openslides/motions/static/js/motions/site.js @@ -751,10 +751,11 @@ angular.module('OpenSlidesApp.motions.site', [ 'Projector', 'ProjectionDefault', 'MotionCsvExport', - 'Multiselect', + 'osTableFilter', + 'osTableSort', function($scope, $state, $http, ngDialog, MotionForm, Motion, Category, Tag, Workflow, User, Agenda, MotionBlock, MotionDocxExport, MotionContentProvider, MotionCatalogContentProvider, PdfMakeConverter, PdfMakeDocumentProvider, - gettextCatalog, HTMLValidizer, Projector, ProjectionDefault, MotionCsvExport, Multiselect) { + gettextCatalog, HTMLValidizer, Projector, ProjectionDefault, MotionCsvExport, osTableFilter, osTableSort) { Motion.bindAll({}, $scope, 'motions'); Category.bindAll({}, $scope, 'categories'); MotionBlock.bindAll({}, $scope, 'motionBlocks'); @@ -772,22 +773,23 @@ angular.module('OpenSlidesApp.motions.site', [ }); $scope.alert = {}; - $scope.multiselect = Multiselect.instance(); - $scope.multiselect.filters = { + // Filtering + $scope.filter = osTableFilter.createInstance(); + $scope.filter.multiselectFilters = { state: [], category: [], motionBlock: [], tag: [] }; - $scope.multiselect.propertyList = ['identifier', 'origin']; - $scope.multiselect.propertyFunctionList = [ + $scope.filter.propertyList = ['identifier', 'origin']; + $scope.filter.propertyFunctionList = [ function (motion) {return motion.getTitle();}, function (motion) {return motion.getText();}, function (motion) {return motion.getReason();}, function (motion) {return motion.category ? motion.category.name : '';}, function (motion) {return motion.motionBlock ? motion.motionBlock.name : '';}, ]; - $scope.multiselect.PropertyDict = { + $scope.filter.propertyDict = { 'submitters' : function (submitter) { return submitter.get_short_name(); }, @@ -804,7 +806,9 @@ angular.module('OpenSlidesApp.motions.site', [ motionBlock: function (motion) {return motion.motion_block_id;}, tag: function (motion) {return motion.tags_id;} }; - // setup table sorting + // Sorting + $scope.sort = osTableSort.createInstance(); + $scope.sort.column = 'identifier'; $scope.sortOptions = [ {name: 'identifier', display_name: 'Identifier'}, @@ -823,34 +827,6 @@ angular.module('OpenSlidesApp.motions.site', [ {name: 'log_messages[0].time', display_name: 'Last modified'}, ]; - $scope.sortColumn = 'identifier'; - $scope.filterPresent = ''; - $scope.reverse = false; - - // function to operate the multiselectFilter - $scope.operateMultiselectFilter = function (filter, id) { - if (!$scope.isDeleteMode) { - $scope.multiselect.operate(filter, id); - } - }; - // function to sort by clicked column - $scope.toggleSort = function (column) { - if ( $scope.sortColumn === column ) { - $scope.reverse = !$scope.reverse; - } - $scope.sortColumn = column; - }; - // for reset-button - $scope.resetFilters = function () { - $scope.multiselect.resetFilters(); - if ($scope.filter) { - $scope.filter.search = ''; - } - }; - $scope.areFiltersSet = function () { - return $scope.multiselect.areFiltersSet() || - ($scope.filter ? $scope.filter.search : false); - }; // collect all states of all workflows // TODO: regard workflows only which are used by motions @@ -877,7 +853,7 @@ angular.module('OpenSlidesApp.motions.site', [ $http.put('/rest/motions/motion/' + motion.id + '/set_state/', {}); }; - $scope.has_tag = function (motion, tag) { + $scope.hasTag = function (motion, tag) { return _.indexOf(motion.tags_id, tag.id) > -1; }; @@ -889,8 +865,8 @@ angular.module('OpenSlidesApp.motions.site', [ motion.reason = motion.getReason(-1); Motion.save(motion); }; - $scope.toggle_tag = function (motion, tag) { - if ($scope.has_tag(motion, tag)) { + $scope.toggleTag = function (motion, tag) { + if ($scope.hasTag(motion, tag)) { // remove motion.tags_id = _.filter(motion.tags_id, function (tag_id){ return tag_id != tag.id; @@ -900,7 +876,7 @@ angular.module('OpenSlidesApp.motions.site', [ } save(motion); }; - $scope.toggle_category = function (motion, category) { + $scope.toggleCategory = function (motion, category) { if (motion.category_id == category.id) { motion.category_id = null; } else { @@ -908,7 +884,7 @@ angular.module('OpenSlidesApp.motions.site', [ } save(motion); }; - $scope.toggle_motionBlock = function (motion, block) { + $scope.toggleMotionBlock = function (motion, block) { if (motion.motion_block_id == block.id) { motion.motion_block_id = null; } else { @@ -962,8 +938,8 @@ angular.module('OpenSlidesApp.motions.site', [ MotionDocxExport.export($scope.motionsFiltered, $scope.categories); }; - // *** delete mode functions *** - $scope.isDeleteMode = false; + // *** select mode functions *** + $scope.isSelectMode = false; // check all checkboxes from filtered motions $scope.checkAll = function () { $scope.selectedAll = !$scope.selectedAll; @@ -971,9 +947,9 @@ angular.module('OpenSlidesApp.motions.site', [ motion.selected = $scope.selectedAll; }); }; - // uncheck all checkboxes if isDeleteMode is closed + // uncheck all checkboxes if isSelectMode is closed $scope.uncheckAll = function () { - if (!$scope.isDeleteMode) { + if (!$scope.isSelectMode) { $scope.selectedAll = false; angular.forEach($scope.motions, function (motion) { motion.selected = false; @@ -986,7 +962,7 @@ angular.module('OpenSlidesApp.motions.site', [ if (motion.selected) Motion.destroy(motion.id); }); - $scope.isDeleteMode = false; + $scope.isSelectMode = false; $scope.uncheckAll(); }; // delete single motion diff --git a/openslides/motions/static/templates/motions/motion-list.html b/openslides/motions/static/templates/motions/motion-list.html index dc94212b0..55d4d0d01 100644 --- a/openslides/motions/static/templates/motions/motion-list.html +++ b/openslides/motions/static/templates/motions/motion-list.html @@ -29,16 +29,16 @@
- +
-
+
-
+
-
+
- + + Filter - + + ng-class="{'bold': filter.multiselectFilters.state.length > 0, 'disabled': isSelectMode}" + ng-disabled="isSelectMode"> State -
@@ -273,16 +314,16 @@ ng-mouseleave="motion.hover=false" ng-class="{'projected': motion.isProjected().length}" ng-repeat="motion in motionsFiltered = (motions - | osFilter: filter.search : multiselect.getFilterString - | MultiselectFilter: multiselect.filters.state : getItemId.state - | MultiselectFilter: multiselect.filters.category : getItemId.category - | MultiselectFilter: multiselect.filters.motionBlock : getItemId.motionBlock - | MultiselectFilter: multiselect.filters.tag : getItemId.tag + | osFilter: filter.filterString : filter.getObjectQueryString + | MultiselectFilter: filter.multiselectFilters.state : getItemId.state + | MultiselectFilter: filter.multiselectFilters.category : getItemId.category + | MultiselectFilter: filter.multiselectFilters.motionBlock : getItemId.motionBlock + | MultiselectFilter: filter.multiselectFilters.tag : getItemId.tag | toArray - | orderBy: sortColumn : reverse)"> + | orderBy: sort.column : sort.reverse)"> -
+
@@ -293,12 +334,12 @@
-
+
{{ motion.identifier }}
-
+
@@ -310,8 +351,8 @@ {{ motion.getStateName() }} - -
- -
+
@@ -366,7 +402,7 @@ ng-mouseover="motion.categoryHover=true" ng-mouseleave="motion.categoryHover=false"> - @@ -379,12 +415,12 @@ -
-
diff --git a/openslides/users/static/js/users/site.js b/openslides/users/static/js/users/site.js index c7284915d..e36529eba 100644 --- a/openslides/users/static/js/users/site.js +++ b/openslides/users/static/js/users/site.js @@ -462,10 +462,12 @@ angular.module('OpenSlidesApp.users.site', [ 'PdfMakeDocumentProvider', 'gettextCatalog', 'UserCsvExport', - 'Multiselect', + 'osTableFilter', + 'osTableSort', + 'gettext', function($scope, $state, $http, ngDialog, UserForm, User, Group, PasswordGenerator, Projector, ProjectionDefault, UserListContentProvider, Config, UserAccessDataListContentProvider, PdfMakeDocumentProvider, gettextCatalog, - UserCsvExport, Multiselect) { + UserCsvExport, osTableFilter, osTableSort, gettext) { User.bindAll({}, $scope, 'users'); Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups'); $scope.$watch(function () { @@ -478,20 +480,46 @@ angular.module('OpenSlidesApp.users.site', [ }); $scope.alert = {}; - $scope.multiselect = Multiselect.instance(); - $scope.multiselect.filters = { + // Filtering + $scope.filter = osTableFilter.createInstance(); + $scope.filter.multiselectFilters = { group: [], }; - $scope.multiselect.propertyList = ['first_name', 'last_name', 'title', 'number', 'comment', 'structure_level']; - $scope.multiselect.PropertyDict = { + $scope.filter.propertyList = ['first_name', 'last_name', 'title', 'number', 'comment', 'structure_level']; + $scope.filter.propertyDict = { 'groups_id' : function (group_id) { return Group.get(group_id).name; }, }; + $scope.filter.booleanFilters = { + isPresent: { + value: undefined, + displayName: gettext('Present'), + choiceYes: gettext('Is present'), + choiceNo: gettext('Is not present'), + needExtraPermission: true, + }, + isActive: { + value: undefined, + displayName: gettext('Active'), + choiceYes: gettext('Is active'), + choiceNo: gettext('Is not active'), + needExtraPermission: true, + }, + isCommittee: { + value: undefined, + displayName: gettext('Committee'), + choiceYes: gettext('Is committee'), + choiceNo: gettext('Is not committee'), + }, + + }; $scope.getItemId = { group: function (user) {return user.groups_id;}, }; - // setup table sorting + // Sorting + $scope.sort = osTableSort.createInstance(); + $scope.sort.column = $scope.config('users_sort_by'); $scope.sortOptions = [ {name: 'first_name', display_name: 'First name'}, @@ -510,39 +538,6 @@ angular.module('OpenSlidesApp.users.site', [ {name: 'comment', display_name: 'Comment'}, ]; - $scope.sortColumn = $scope.config('users_sort_by'); - $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; - }; - // function to operate the multiselectFilter - $scope.operateMultiselectFilter = function (filter, id) { - if (!$scope.isSelectMode) { - $scope.multiselect.operate(filter, id); - } - }; - // for reset-button - $scope.resetFilters = function () { - $scope.multiselect.resetFilters(); - if ($scope.filter) { - $scope.filter.search = ''; - } - $scope.isPresentFilter = undefined; - $scope.isActiveFilter = undefined; - $scope.isCommitteeFilter = undefined; - }; - $scope.areFiltersSet = function () { - return $scope.multiselect.areFiltersSet() || - $scope.isPresentFilter || - $scope.isActiveFilter || - $scope.isCommitteeFilter || - ($scope.filter ? $scope.filter.search : false); - }; // pagination $scope.currentPage = 1; diff --git a/openslides/users/static/templates/users/user-list.html b/openslides/users/static/templates/users/user-list.html index e2fe495cd..7bf455610 100644 --- a/openslides/users/static/templates/users/user-list.html +++ b/openslides/users/static/templates/users/user-list.html @@ -116,20 +116,20 @@
+ | osFilter: filter.filterString : filter.getObjectQueryString + | filter: {is_present: filter.booleanFilters.isPresent.value} + | filter: {is_active: filter.booleanFilters.isActive.value} + | filter: {is_committee: filter.booleanFilters.isCommittee.value} + | MultiselectFilter: filter.multiselectFilters.group : getItemId.group + | orderBy: sort.column: sort.reverse)">
+ | osFilter: filter.filterString : filter.getObjectQueryString + | filter: {is_committee: filter.booleanFilters.isCommittee.value} + | MultiselectFilter: filter.multiselectFilters.group : getItemId.group + | orderBy: sort.column: sort.reverse)">
@@ -140,100 +140,62 @@
- Filter - + Groups -
+ - -
+
@@ -378,12 +326,12 @@ -
- + Present