New assignment and mediafile tables and table generics
This commit is contained in:
parent
d068765db9
commit
4f717b6610
@ -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
|
||||
|
@ -9,10 +9,6 @@
|
||||
<i class="fa fa-tags fa-lg"></i>
|
||||
<translate>Tags</translate>
|
||||
</a>
|
||||
<a href="" ng-click="makePDF_assignmentList()" class="btn btn-default btn-sm">
|
||||
<i class="fa fa-file-pdf-o fa-lg"></i>
|
||||
<translate>PDF</translate>
|
||||
</a>
|
||||
</div>
|
||||
<h1 translate>Elections</h1>
|
||||
</div>
|
||||
@ -20,31 +16,35 @@
|
||||
|
||||
<div class="details">
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-6">
|
||||
<form class="form-inline">
|
||||
<!-- delete mode -->
|
||||
<button os-perms="assignments.can_manage" class="btn"
|
||||
ng-class="$parent.isDeleteMode ? 'btn-primary' : 'btn-default'"
|
||||
ng-click="$parent.isDeleteMode = !$parent.isDeleteMode; uncheckAll()">
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
<translate>Select ...</translate>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-inline text-right">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="fa fa-search"></i></div>
|
||||
<input type="text" ng-model="filter.search" class="form-control"
|
||||
placeholder="{{ 'Search' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-default" ng-click="isFilterOpen = !isFilterOpen"
|
||||
ng-class="isFilterOpen ? 'btn-primary' : 'btn-default'">
|
||||
<i class="fa fa-filter"></i>
|
||||
<translate>Filter ...</translate>
|
||||
<div class="col-sm-12">
|
||||
<!-- delete mode -->
|
||||
<button os-perms="assignments.can_manage" class="btn"
|
||||
ng-class="$parent.isSelectMode ? 'btn-primary' : 'btn-default'"
|
||||
ng-click="$parent.isSelectMode = !$parent.isSelectMode; uncheckAll()">
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
<translate>Select ...</translate>
|
||||
</button>
|
||||
<!-- export dropdown -->
|
||||
<div class="dropdown pull-right" uib-dropdown>
|
||||
<button type="button" class="btn btn-default" id="dropdownExport" uib-dropdown-toggle>
|
||||
<i class="fa fa-upload"></i>
|
||||
<span ng-if="assignmentsFiltered.length == assignments.length" translate>
|
||||
Export all
|
||||
</span>
|
||||
<span ng-if="assignmentsFiltered.length != assignments.length" translate>
|
||||
Export filtered
|
||||
</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownExport">
|
||||
<!-- PDF export -->
|
||||
<li>
|
||||
<a href="" ng-click="makePDF_assignmentList()">
|
||||
<i class="fa fa-file-pdf-o fa-lg"></i>
|
||||
<translate>PDF</translate>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -58,10 +58,10 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div uib-collapse="!isDeleteMode" class="row spacer">
|
||||
<div uib-collapse="!isSelectMode" class="row spacer">
|
||||
<div class="col-sm-12 text-left">
|
||||
<!-- delete button -->
|
||||
<a ng-show="isDeleteMode" os-perms="assignments.can_manage"
|
||||
<a ng-show="isSelectMode" os-perms="assignments.can_manage"
|
||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete all selected elections?' | translate }}"
|
||||
ng-bootbox-confirm-action="deleteMultiple()"
|
||||
class="btn btn-primary">
|
||||
@ -76,134 +76,247 @@
|
||||
{{ assignments.length }} {{ "elections" | translate }}<span ng-if="(assignments|filter:{selected:true}).length > 0">,
|
||||
{{(assignments|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- projector column -->
|
||||
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="minimum">
|
||||
|
||||
<!-- delete selection column -->
|
||||
<th ng-show="isDeleteMode" os-perms="assignments.can_manage" class="minimum deleteColumn">
|
||||
<input type="checkbox" ng-model="$parent.selectedAll" ng-change="checkAll()">
|
||||
|
||||
<!-- agenda item column -->
|
||||
<th ng-click="toggleSort('agenda_item.item_number')" class="sortable">
|
||||
<translate translate-comment="short form of agenda item">Item</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'agenda_item.item_number' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
|
||||
<!-- title column -->
|
||||
<th ng-click="toggleSort('title')" class="sortable">
|
||||
<translate>Title</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'title' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
|
||||
<!-- candicates / posts column -->
|
||||
<th ng-click="toggleSort('open_posts')" class="sortable optional">
|
||||
<translate>Candidates</translate> · <translate>Posts</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'open_posts' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
|
||||
<!-- phase column -->
|
||||
<th ng-click="toggleSort('phase')" class="sortable optional">
|
||||
<translate>Phase</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'phase' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<tbody>
|
||||
<tr ng-repeat="assignment in assignmentsFiltered = (assignments | osFilter: filter.search : getFilterString |
|
||||
filter: {phase: phaseFilter} | orderBy: sortColumn:reverse)"
|
||||
class="animate-item"
|
||||
ng-class="{ 'activeline': assignment.isProjected().length, 'selected': assignment.selected }">
|
||||
|
||||
<!-- projector -->
|
||||
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
|
||||
<projector-button model="assignment" default-projector-id="defaultProjectorId">
|
||||
</projector-button>
|
||||
|
||||
<!-- delete selection -->
|
||||
<td ng-show="isDeleteMode" os-perms="assignments.can_manage" class="deleteColumn">
|
||||
<input type="checkbox" ng-model="assignment.selected">
|
||||
|
||||
<!-- agenda item number -->
|
||||
<td ng-if="!assignment.quickEdit">
|
||||
{{ assignment.agenda_item.item_number }}
|
||||
|
||||
<!-- title -->
|
||||
<td ng-if="!assignment.quickEdit" ng-mouseover="assignment.hover=true" ng-mouseleave="assignment.hover=false">
|
||||
<strong><a ui-sref="assignments.assignment.detail({id: assignment.id})">{{ assignment.title }}</a></strong>
|
||||
<span ng-repeat="tag in assignment.tags" class="label label-default">
|
||||
{{ tag.name }}
|
||||
<div class="os-table container-fluid">
|
||||
<div class="row header-row">
|
||||
<div class="col-xs-1 centered" ng-show="isSelectMode">
|
||||
<i class="fa text-danger pointer" ng-class=" selectedAll ? 'fa-check-square-o' : 'fa-square-o'"
|
||||
ng-click="checkAll()"></i>
|
||||
</div>
|
||||
<div class="col-xs-11 main-header">
|
||||
<span class="form-inline text-right pull-right">
|
||||
<!-- clear all filters -->
|
||||
<span class="sort-spacer pointer" ng-click="filter.reset()"
|
||||
ng-if="filter.areFiltersSet()" ng-disabled="isSelectMode"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>Filter</translate>
|
||||
</span>
|
||||
<div os-perms="assignments.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !assignment.hover}">
|
||||
<a href="" ng-click="openDialog(assignment)" translate>Edit</a> |
|
||||
<a href="" ng-click="assignment.quickEdit=true" translate>QuickEdit</a> |
|
||||
<a href="" class="text-danger"
|
||||
<!-- Tag filter -->
|
||||
<span uib-dropdown ng-if="tags.length > 0">
|
||||
<span class="pointer" id="dropdownTag" uib-dropdown-toggle
|
||||
ng-class="{'bold': filter.multiselectFilters.tag.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Tag</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right"
|
||||
aria-labelledby="dropdownTag">
|
||||
<li ng-repeat="tag in tags">
|
||||
<a href ng-click="filter.operateMultiselectFilter('tag', tag.id, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.MultiselectFilters.tag.indexOf(tag.id) > -1"></i>
|
||||
{{ tag.name }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href ng-click="filter.operateMultiselectFilter('tag', -1, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.tag.indexOf(-1) > -1"></i>
|
||||
<translate>No tag set</translate>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Phase filter -->
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownPhase" uib-dropdown-toggle
|
||||
ng-class="{'bold': filter.multiselectFilters.phase.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Phase</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right"
|
||||
aria-labelledby="dropdownPhase">
|
||||
<li ng-repeat="phase in phases">
|
||||
<a href ng-click="filter.operateMultiselectFilter('phase', phase.value, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.phase.indexOf(phase.value) > -1"></i>
|
||||
{{ phase.display_name | translate }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- dropdown sort -->
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownSort" uib-dropdown-toggle
|
||||
ng-class="{'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Sort</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSort">
|
||||
<!-- all sortOptions -->
|
||||
<li ng-repeat="option in sortOptions">
|
||||
<a ng-click="sort.toggle(option.name)">
|
||||
{{ option.display_name | translate }}
|
||||
<span class="spacer-right pull-right"></span>
|
||||
<i class="pull-right fa"
|
||||
ng-style="{'visibility': sort.column === option.name ? 'visible' : 'hidden'}"
|
||||
ng-class="sort.reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- search field -->
|
||||
<span class="form-group">
|
||||
<span class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||
<input type="text" ng-model="filter.filterString" class="form-control"
|
||||
placeholder="{{ 'Search' | translate}}">
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</span>
|
||||
<!-- show all selected multiselectoptions -->
|
||||
<span ng-repeat="tag in tags" class="pointer spacer-left-lg"
|
||||
ng-if="filter.multiselectFilters.tag.indexOf(tag.id) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('tag', tag.id, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
</span>
|
||||
<span ng-if="filter.multiselectFilters.tag.indexOf(-1) > -1" class="pointer spacer-left-lg"
|
||||
ng-click="filter.operateMultiselectFilter('tag', -1, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>No tag set</translate>
|
||||
</span>
|
||||
<span ng-repeat="phase in phases" class="pointer spacer-left-lg"
|
||||
ng-if="filter.multiselectFilters.phase.indexOf(phase.value) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('phase', phase.value, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ phase.display_name | translate }}
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- main table -->
|
||||
<div class="row data-row" ng-mouseover="assignment.hover=true"
|
||||
ng-mouseleave="assignment.hover=false"
|
||||
ng-class="{'projected': assignment.isProjected().length}"
|
||||
ng-repeat="assignment in assignmentsFiltered = (assignments
|
||||
| osFilter: filter.filterString : filter.getObjectQueryString
|
||||
| MultiselectFilter: filter.multiselectFilters.tag : getItemId.tag
|
||||
| MultiselectFilter: filter.multiselectFilters.phase : getItemId.phase
|
||||
| orderBy: sort.column : sort.reverse)">
|
||||
|
||||
<!-- select column -->
|
||||
<div ng-show="isSelectMode" os-perms="assignments.can_manage" class="col-xs-1 centered">
|
||||
<i class="fa text-danger pointer" ng-click="assignment.selected=!assignment.selected"
|
||||
ng-class="assignment.selected ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||
</div>
|
||||
<!-- projector column -->
|
||||
<div class="col-xs-1 centered projector" os-perms="core.can_manage_projector">
|
||||
<projector-button model="assignment", default-projector-id="defaultProjectorId">
|
||||
</projector-button>
|
||||
</div>
|
||||
<!-- main contant column -->
|
||||
<div class="col-xs-6 content">
|
||||
<div class="title-col">
|
||||
<!-- title and phase -->
|
||||
<div>
|
||||
<strong>
|
||||
<a ui-sref="assignments.assignment.detail({id: assignment.id})">{{ assignment.title }}</a>
|
||||
</strong>
|
||||
<span style="padding: 5px;" ng-mouseover="assignment.phaseHover=true" ng-mouseleave="assignment.phaseHover=false">
|
||||
<span class="label" ng-class="{'label-primary': assignment.phase == 0,
|
||||
'label-warning': assignment.phase == 1,
|
||||
'label-success': assignment.phase == 2 }">
|
||||
{{ phases[assignment.phase].display_name | translate }}
|
||||
</span>
|
||||
<span os-perms="assignments.can_manage" ng-class="{'hiddenDiv': !assignment.phaseHover}" uib-dropdown>
|
||||
<i class="fa fa-cog pointer" uib-dropdown-toggle id="phaseDropdown{{ assignment.id }}"></i>
|
||||
<ul uib-dropdown-menu aria-labelledby="phaseDropdown{{ assignment.id }}"
|
||||
class="dropdown-menu">
|
||||
<li ng-repeat="phase in phases">
|
||||
<a href>
|
||||
<i class="fa fa-check" ng-if="assignment.phase == phase.value"></i>
|
||||
<span class="pointer" ng-click="updatePhase(assignment, phase.value)">{{ phase.display_name | translate }}</a>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- hover menu -->
|
||||
<div os-perms="assignments.can_manage" ng-class="{'hiddenDiv': !assignment.hover}">
|
||||
<small>
|
||||
<a href="" ng-click="openDialog(assignment)" translate>Edit</a> ·
|
||||
<a href="" class="text-danger"
|
||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
||||
<b>{{ assignment.title }}</b>"
|
||||
ng-bootbox-confirm-action="delete(assignment)" translate>Delete</a>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- candidates / posts -->
|
||||
<td ng-if="!assignment.quickEdit" class="optional">
|
||||
<span class="badge">{{ assignment.assignment_related_users.length }}</span>
|
||||
/
|
||||
<span class="badge">{{ assignment.open_posts }}</span>
|
||||
<!-- additional content column -->
|
||||
<div class="col-xs-4 content" ng-style="{'width': isSelectMode ? 'calc(50% - 120px)' : 'calc(50% - 70px)'}">
|
||||
<div style="width: 60%;" class="optional">
|
||||
<small>
|
||||
<!-- Tag dropdown for manage user -->
|
||||
<div os-perms="assignments.can_manage" ng-show="tags.length > 0"
|
||||
ng-mouseover="assignment.tagHover=true"
|
||||
ng-mouseleave="assignment.tagHover=false">
|
||||
<span uib-dropdown>
|
||||
<span id="dropdownTags{{ assignment.id }}" class="pointer"
|
||||
uib-dropdown-toggle uib-tooltip="{{ 'Add a tag' | translate }}"
|
||||
tooltip-class="nobr">
|
||||
<span ng-if="assignment.tags.length == 0" ng-show="assignment.hover">
|
||||
<i class="fa fa-tags"></i>
|
||||
<i class="fa fa-plus"></i>
|
||||
</span>
|
||||
<span ng-if="assignment.tags.length > 0">
|
||||
<i class="fa fa-tags"></i>
|
||||
<span ng-repeat="tag in assignment.tags">
|
||||
{{ tag.name }}<span ng-if="!$last">,</span>
|
||||
</span>
|
||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="assignment.tagHover"></i>
|
||||
</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownTags{{ assignment.id }}">
|
||||
<li ng-repeat="tag in tags">
|
||||
<a href ng-click="toggleTag(assignment, tag)">
|
||||
<i class="fa fa-check" ng-if="hasTag(assignment, tag)"></i>
|
||||
{{ tag.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<!-- Tag string for normal user -->
|
||||
<div os-perms="!assignments.can_manage" ng-show="assignment.tags.length > 0">
|
||||
<i class="fa fa-tags spacer-right"></i>
|
||||
<span ng-repeat="tag in assignment.tags">
|
||||
{{ tag.name }}<span ng-if="!$last">,</span>
|
||||
</span>
|
||||
</div>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- phase -->
|
||||
<td ng-if="!assignment.quickEdit" class="optional">
|
||||
<span class="label" ng-class="{'label-primary': assignment.phase == 0,
|
||||
'label-warning': assignment.phase == 1,
|
||||
'label-success': assignment.phase == 2 }">
|
||||
{{ phases[assignment.phase].display_name | translate }}
|
||||
<div style="width: 20%;" class="pull-right nobr optional centered">
|
||||
<span class="badge"
|
||||
uib-tooltip="{{ assignment.assignment_related_users.length }} {{ 'Candidates' | translate }}
|
||||
{{ (assignment.open_posts - assignment.assignment_related_users.length) > 0 ? '(' + (assignment.open_posts - assignment.assignment_related_users.length) + ' ' + ('needed' | translate) + ')' : '' }}"
|
||||
tooltip-class="nobr"
|
||||
ng-class="{'badge-info': assignment.assignment_related_users.length < assignment.open_posts}">
|
||||
{{ assignment.assignment_related_users.length }}
|
||||
</span>
|
||||
</div>
|
||||
<div style="width: 20%;" class="pull-right nobr">
|
||||
<div class="centered">{{ assignment.agenda_item.getItemNumberWithAncestors() }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- main table -->
|
||||
</div> <!-- end container -->
|
||||
|
||||
<!-- quickEdit columns -->
|
||||
<td ng-if="assignment.quickEdit" colspan="4">
|
||||
<h4>{{ assignment.title }} <span class="text-muted">– Quick Edit</span></h4>
|
||||
<div uib-alert ng-show="alert.show" ng-class="'alert-' + (alert.type || 'warning')" ng-click="alert={}" close="alert={}">
|
||||
{{ alert.msg }}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="inputTitle" translate>Title</label>
|
||||
<input type="text" ng-model="assignment.title" class="form-control input-sm" id="inputTitle">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="inputPosts" translate>Number of members to be elected</label>
|
||||
<input type="number" ng-model="assignment.open_posts" class="form-control input-sm" id="inputPosts">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label for="selectPhase" translate>Phase</label>
|
||||
<select ng-options="phase.value as phase.display_name | translate for phase in phases"
|
||||
ng-model="assignment.phase" class="form-control" id="selectPhase">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label for="selectTags" translate>Tags</label>
|
||||
<select multiple chosen
|
||||
ng-model="assignment.tags_id"
|
||||
ng-options="tag.id as tag.name for tag in tags"
|
||||
search-contains="true"
|
||||
id="selectTag"
|
||||
class="form-control">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spacer">
|
||||
<button ng-click="cancelQuickEdit(assignment)" class="btn btn-default pull-left" translate>
|
||||
Cancel
|
||||
</button>
|
||||
<button ng-click="save(assignment)" class="btn btn-primary" translate>
|
||||
Update
|
||||
</button>
|
||||
<a href="" ng-click="openDialog(assignment)"
|
||||
class="pull-right" translate>Edit election ...</a>
|
||||
</div>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -115,44 +115,21 @@
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-6">
|
||||
<form class="form-inline">
|
||||
<!-- delete mode -->
|
||||
<!-- select mode -->
|
||||
<button os-perms="mediafiles.can_manage" class="btn"
|
||||
ng-class="$parent.isDeleteMode ? 'btn-primary' : 'btn-default'"
|
||||
ng-click="$parent.isDeleteMode = !$parent.isDeleteMode; uncheckAll()">
|
||||
ng-class="$parent.isSelectMode ? 'btn-primary' : 'btn-default'"
|
||||
ng-click="$parent.isSelectMode = !$parent.isSelectMode; uncheckAll()">
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
<translate>Select ...</translate>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-inline text-right">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="fa fa-search"></i></div>
|
||||
<input type="text" ng-model="filter.search" class="form-control"
|
||||
placeholder="{{ 'Search' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-default" ng-click="isFilterOpen = !isFilterOpen"
|
||||
ng-class="isFilterOpen ? 'btn-primary' : 'btn-default'">
|
||||
<i class="fa fa-filter"></i>
|
||||
<translate>Filter ...</translate>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6"></div>
|
||||
</div>
|
||||
<div uib-collapse="!isFilterOpen" class="row">
|
||||
<div class="col-sm-6 text-right"></div>
|
||||
<div class="col-sm-6 text-right">
|
||||
<!-- pdf filter -->
|
||||
<input type="checkbox" ng-model="filter.showPDFs" ng-true-value="'application/pdf'" ng-false-value=''>
|
||||
<translate> Show PDF files only</translate>
|
||||
</div>
|
||||
</div>
|
||||
<div uib-collapse="!isDeleteMode" class="row spacer">
|
||||
<div uib-collapse="!isSelectMode" class="row spacer">
|
||||
<div class="col-sm-12 text-left">
|
||||
<!-- delete button -->
|
||||
<a ng-show="isDeleteMode"
|
||||
<a ng-show="isSelectMode"
|
||||
os-perms="mediafiles.can_manage" ng-click="deleteMultiple()"
|
||||
class="btn btn-primary">
|
||||
<i class="fa fa-trash fa-lg"></i>
|
||||
@ -166,87 +143,180 @@
|
||||
{{ mediafiles.length }} {{ "files" | translate }}<span ng-if="(mediafiles|filter:{selected:true}).length > 0">,
|
||||
{{(mediafiles|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- projector column -->
|
||||
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="minimum">
|
||||
<!-- delete selection column -->
|
||||
<th ng-show="isDeleteMode" os-perms="mediafiles.can_manage" class="minimum deleteColumn">
|
||||
<input type="checkbox" ng-model="$parent.selectedAll" ng-change="checkAll()">
|
||||
<!-- title -->
|
||||
<th ng-click="toggleSort('title_or_filename')" class="sortable">
|
||||
<translate>Title</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'title_or_filename' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<!-- upload time -->
|
||||
<th ng-click="toggleSort('timestamp')" class="sortable optional">
|
||||
<translate>Upload time</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'timestamp' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
<!-- uploaded by -->
|
||||
<th ng-click="toggleSort('uploader')" class="sortable">
|
||||
<translate>Uploaded by</translate>
|
||||
<i class="pull-right fa" ng-show="sortColumn === 'uploader' && header.sortable != false"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
</tr>
|
||||
<tbody>
|
||||
<tr ng-repeat="mediafile in mediafilesFiltered = (mediafiles | privateFilter | osFilter: filter.search : getFilterString |
|
||||
filter: {filetype: filter.showPDFs} | orderBy: sortColumn:reverse )"
|
||||
class="animate-item"
|
||||
ng-class="{ 'activeline': mediafile.isProjected().length, 'selected': mediafile.selected }">
|
||||
<!-- projector column -->
|
||||
<td ng-show="!isDeleteMode"
|
||||
os-perms="core.can_manage_projector">
|
||||
<div class="btn-group" style="min-width:{{ projectors.length > 1 ? '54' : '34' }}px;" uib-dropdown
|
||||
ng-if="mediafile.is_presentable"
|
||||
uib-tooltip="{{ 'Projector' | translate }} {{ mediafile.isProjected()[0] || '' }}"
|
||||
tooltip-enable="mediafile.isProjected().length">
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-click="showMediafile(defaultProjectorId, mediafile)"
|
||||
ng-class="{ 'btn-primary': inArray(mediafile.isProjected(), defaultProjectorId) }">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm slimDropDown"
|
||||
ng-class="{ 'btn-primary': (mediafile.isProjected().length && !inArray(mediafile.isProjected(), defaultProjectorId) ) }"
|
||||
ng-if="projectors.length > 1"
|
||||
uib-dropdown-toggle>
|
||||
|
||||
<div class="os-table container-fluid">
|
||||
<div class="row header-row">
|
||||
<div class="col-xs-1 centered" ng-show="isSelectMode" os-perms="mediafiles.can_manage">
|
||||
<i class="fa text-danger pointer" ng-class="selectedAll ? 'fa-check-square-o' : 'fa-square-o'"
|
||||
ng-click="checkAll()"></i>
|
||||
</div>
|
||||
<div class="col-xs-11 main-header">
|
||||
<span class="form-inline text-right pull-right">
|
||||
<!-- reset Filters -->
|
||||
<span class="sort-spacer pointer" ng-click="filter.reset()"
|
||||
ng-if="filter.areFiltersSet()" ng-disabled="isSelectMode"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>Filter</translate>
|
||||
</span>
|
||||
<!-- boolean Filters -->
|
||||
<span ng-repeat="(name, booleanFilter) in filter.booleanFilters"
|
||||
ng-if="!booleanFilter.needExtraPermission || operator.hasPerms('mediafiles.can_see_private')" uib-dropdown>
|
||||
<span class="pointer" id="dropdown{{ name }}" uib-dropdown-toggle
|
||||
ng-class="{'bold': booleanFilter.value !== undefined, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
{{ booleanFilter.displayName }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" ng-if="projectors.length > 1">
|
||||
<li role="menuitem" ng-repeat="projector in projectors">
|
||||
<a href="" ng-click="showMediafile(projector.id, mediafile)"
|
||||
ng-class="{ 'projected': inArray(mediafile.isProjected(), projector.id) }">
|
||||
<i class="fa fa-video-camera" ng-show="inArray(mediafile.isProjected(), projector.id) "></i>
|
||||
{{ projector.name }}
|
||||
<span ng-if="defaultProjectorId == projector.id">(<translate>Default</translate>)</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdown{{ name }}">
|
||||
<li>
|
||||
<a href ng-click="booleanFilter.value = (booleanFilter.value ? undefined : true)">
|
||||
<i class="fa" ng-class="{'fa-check': booleanFilter.value === true}"></i>
|
||||
{{ booleanFilter.choiceYes }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href ng-click="booleanFilter.value = (booleanFilter.value === false) ? undefined : false">
|
||||
<i class="fa" ng-class="{'fa-check': booleanFilter.value === false}"></i>
|
||||
{{ booleanFilter.choiceNo }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- dropdown sort -->
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownSort" uib-dropdown-toggle
|
||||
ng-class="{'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Sort</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSort">
|
||||
<li ng-repeat="option in sortOptions">
|
||||
<a href ng-click="sort.toggle(option.name)">
|
||||
{{ option.display_name | translate }}
|
||||
<span class="spacer-right pull-right"></span>
|
||||
<i class="pull-right fa"
|
||||
ng-style="{'visibility': sort.column === option.name ? 'visible' : 'hidden'}"
|
||||
ng-class="sort.reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- search field -->
|
||||
<span class="form-group">
|
||||
<span class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||
<input type="text" ng-model="filter.filterString" class="form-control"
|
||||
placeholder="{{ 'Search' | translate}}" ng-disabled="isSelectMode">
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<!-- show all selected multiselectoptions -->
|
||||
<span>
|
||||
<!-- for all boolean Filters -->
|
||||
<span ng-repeat="(name, booleanFilter) in filter.booleanFilters"
|
||||
ng-hide="booleanFilter.value === undefined"
|
||||
class="pointer spacer-left-lg"
|
||||
ng-click="booleanFilter.value = undefined;"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ booleanFilter.value ? booleanFilter.choiceYes : booleanFilter.choiceNo | translate }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- main table -->
|
||||
<div class="row data-row" ng-mouseover="mediafile.hover=true"
|
||||
ng-mouseleave="mediafile.hover=false"
|
||||
ng-class="{'projected': mediafile.isProjected().length}"
|
||||
ng-repeat="mediafile in mediafilesFiltered = (mediafiles
|
||||
| privateFilter
|
||||
| osFilter: filter.filterString : filter.getObjectQueryString
|
||||
| filter: {filetype: (filter.booleanFilters.isPdf.value ? 'application/pdf' : (filter.booleanFilters.isPdf.value === false ? '!application/pdf' : ''))}
|
||||
| filter: {private: filter.booleanFilters.isPrivate.value}
|
||||
| orderBy: sort.column : sort.reverse )">
|
||||
|
||||
<!-- select column -->
|
||||
<div ng-show="isSelectMode" os-perms="mediafiles.can_manage" class="col-xs-1 centered">
|
||||
<i class="fa text-danger pointer" ng-click="mediafile.selected=!mediafile.selected"
|
||||
ng-class="mediafile.selected ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||
</div>
|
||||
<!-- projector column -->
|
||||
<div class="col-xs-1 centered projector" os-perms="core.can_manage_projector">
|
||||
<div class="btn-group" style="min-width:{{ projectors.length > 1 ? '54' : '34' }}px;" uib-dropdown
|
||||
ng-if="mediafile.is_presentable"
|
||||
uib-tooltip="{{ 'Projector' | translate }} {{ mediafile.isProjected()[0] || '' }}"
|
||||
tooltip-enable="mediafile.isProjected().length">
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-click="showMediafile(defaultProjectorId, mediafile)"
|
||||
ng-class="{ 'btn-primary': inArray(mediafile.isProjected(), defaultProjectorId) }">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm slimDropDown"
|
||||
ng-class="{ 'btn-primary': (mediafile.isProjected().length && !inArray(mediafile.isProjected(), defaultProjectorId) ) }"
|
||||
ng-if="projectors.length > 1"
|
||||
uib-dropdown-toggle>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" ng-if="projectors.length > 1">
|
||||
<li role="menuitem" ng-repeat="projector in projectors">
|
||||
<a href="" ng-click="showMediafile(projector.id, mediafile)"
|
||||
ng-class="{ 'projected': inArray(mediafile.isProjected(), projector.id) }">
|
||||
<i class="fa fa-video-camera" ng-show="inArray(mediafile.isProjected(), projector.id) "></i>
|
||||
{{ projector.name }}
|
||||
<span ng-if="defaultProjectorId == projector.id">(<translate>Default</translate>)</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- main content column -->
|
||||
<div class="col-xs-6 content">
|
||||
<div class="spacer-right"> <!-- horizontal block -->
|
||||
<strong>
|
||||
<i ng-style="{'visibility': mediafile.private ? 'visible' : 'hidden'}" class="fa fa-lock fa-lg"
|
||||
title="{{ 'Is private' | translate }}"></i>
|
||||
</strong>
|
||||
</div>
|
||||
<div>
|
||||
<div> <!-- vertical block -->
|
||||
<strong>
|
||||
<a ng-href="{{ mediafile.mediafileUrl }}" target="_blank">{{ mediafile.title_or_filename }}</a>
|
||||
</strong>
|
||||
</div>
|
||||
<!-- delete selection column -->
|
||||
<td ng-show="isDeleteMode" os-perms="mediafiles.can_manage" class="deleteColumn">
|
||||
<input type="checkbox" ng-model="mediafile.selected">
|
||||
<!-- mediafile data colums -->
|
||||
<td ng-mouseover="mediafile.hover=true" ng-mouseleave="mediafile.hover=false">
|
||||
<strong><a ng-href="{{ mediafile.mediafileUrl }}" target="_blank">{{ mediafile.title_or_filename }}</a></strong>
|
||||
<br><small><i class="fa fa-file"></i> {{ mediafile.filetype }}
|
||||
<span ng-if="mediafile.mediafile.encrypted">(<translate>Encrypted</translate>)</span>
|
||||
</small>
|
||||
<br><small><i class="fa fa-database"></i> {{ mediafile.filesize }}</small>
|
||||
<span ng-if="mediafile.private"><br><small><i class="fa fa-lock"></i> <translate>Private</translate></small></span>
|
||||
<div os-perms="mediafiles.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !mediafile.hover}">
|
||||
<a href="" ng-click="openDialog(mediafile)" translate>Edit</a> |
|
||||
<a href="" class="text-danger"
|
||||
<div><small>{{ mediafile.uploader.get_full_name() }}</small></div>
|
||||
<div os-perms="mediafiles.can_manage" ng-class="{'hiddenDiv': !mediafile.hover}">
|
||||
<small>
|
||||
<a href="" ng-click="openDialog(mediafile)" translate>Edit</a> ·
|
||||
<a href="" class="text-danger"
|
||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this file?' | translate }}<br>
|
||||
<b>{{ mediafile.title }} [{{ mediafile.mediafile.name }}]</b>"
|
||||
ng-bootbox-confirm-action="delete(mediafile)" translate>Delete</a>
|
||||
</small>
|
||||
</div>
|
||||
<td class="optional">{{ mediafile.timestamp | date:'yyyy-MM-dd HH:mm:ss' }}
|
||||
<td>{{ mediafile.uploader.get_full_name() }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- additional content column -->
|
||||
<div class="col-xs-4 content" ng-style="{'width': isSelectMode ? 'calc(50% - 120px)' : 'calc(50% - 70px)'}">
|
||||
<div style="width: 60%;" class="optional">
|
||||
<small>
|
||||
<div>
|
||||
<i class="fa fa-file"></i> {{ mediafile.filetype }}
|
||||
<span ng-if="mediafile.mediafile.encrypted">(<translate>Encrypted</translate>)</span>
|
||||
</div>
|
||||
<div><i class="fa fa-database"></i> {{ mediafile.filesize }}</div>
|
||||
<div><i class="fa fa-upload"></i> {{ mediafile.timestamp | date:'yyyy-MM-dd HH:mm:ss' }}</div>
|
||||
</small>
|
||||
</div>
|
||||
<div style="width: 40%;" class="pull-right optional"></div>
|
||||
</div>
|
||||
|
||||
</div><!-- end data row -->
|
||||
</div><!-- end os-table -->
|
||||
</div>
|
||||
|
@ -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
|
||||
|
@ -29,16 +29,16 @@
|
||||
<div class="details">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<!-- delete mode -->
|
||||
<!-- select mode -->
|
||||
<button os-perms="motions.can_manage" class="btn"
|
||||
ng-class="$parent.isDeleteMode ? 'btn-primary' : 'btn-default'"
|
||||
ng-click="$parent.isDeleteMode = !$parent.isDeleteMode; uncheckAll()">
|
||||
ng-class="$parent.isSelectMode ? 'btn-primary' : 'btn-default'"
|
||||
ng-click="$parent.isSelectMode = !$parent.isSelectMode; uncheckAll()">
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
<translate>Select ...</translate>
|
||||
</button>
|
||||
<!-- Export dropdown -->
|
||||
<div class="dropdown pull-right" uib-dropdown>
|
||||
<button type=button" class="btn btn-default" id="dropdownExport" uib-dropdown-toggle>
|
||||
<button type="button" class="btn btn-default" id="dropdownExport" uib-dropdown-toggle>
|
||||
<i class="fa fa-upload"></i>
|
||||
<span ng-if="motionsFiltered.length == motions.length" translate>
|
||||
Export all
|
||||
@ -76,10 +76,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div uib-collapse="!isDeleteMode" class="row spacer">
|
||||
<div uib-collapse="!isSelectMode" class="row spacer">
|
||||
<div class="col-sm-12 text-left">
|
||||
<!-- delete button -->
|
||||
<a ng-show="isDeleteMode" os-perms="motions.can_manage"
|
||||
<a ng-show="isSelectMode" os-perms="motions.can_manage"
|
||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete all selected motions?' | translate }}"
|
||||
ng-bootbox-confirm-action="deleteMultiple()"
|
||||
class="btn btn-primary">
|
||||
@ -95,125 +95,144 @@
|
||||
{{(motions|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div id="motion-os-table" class="os-table container-fluid">
|
||||
<div class="os-table container-fluid">
|
||||
<div class="row header-row">
|
||||
<div class="col-xs-1 centered" ng-show="isDeleteMode">
|
||||
<div class="col-xs-1 centered" ng-show="isSelectMode">
|
||||
<i class="fa text-danger pointer" ng-class=" selectedAll ? 'fa-check-square-o' : 'fa-square-o'"
|
||||
ng-click="checkAll()"></i>
|
||||
</div>
|
||||
<div class="col-xs-11 main-header">
|
||||
<span class="form-inline text-right pull-right">
|
||||
<span class="sort-spacer pointer" ng-click="resetFilters()"
|
||||
ng-if="areFiltersSet()" ng-disabled="isDeleteMode"
|
||||
ng-class="{'disabled': isDeleteMode}">
|
||||
<!-- clear all filters -->
|
||||
<span class="sort-spacer pointer" ng-click="filter.reset()"
|
||||
ng-if="filter.areFiltersSet()" ng-disabled="isSelectMode"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>Filter</translate>
|
||||
</span>
|
||||
<!-- State filter -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownState" uib-dropdown-toggle
|
||||
ng-class="{'bold': multiselect.filters.state.length > 0, 'disabled': isDeleteMode}"
|
||||
ng-disabled="isDeleteMode">
|
||||
ng-class="{'bold': filter.multiselectFilters.state.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>State</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownState">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownState">
|
||||
<li ng-repeat="state in states" ng-class="state.workflowHeader ? 'dropdown-header' : ''">
|
||||
<div ng-if="state.workflowHeader">
|
||||
<a ng-if="state.workflowHeader">
|
||||
{{ state.name | translate }}
|
||||
</div>
|
||||
<div ng-if="!state.workflowHeader"
|
||||
ng-click="operateMultiselectFilter('state', state.id)">
|
||||
<i class="fa fa-check" ng-if="multiselect.filters.state.indexOf(state.id) > -1"></i>
|
||||
</a>
|
||||
<a href ng-if="!state.workflowHeader"
|
||||
ng-click="filter.operateMultiselectFilter('state', state.id, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.state.indexOf(state.id) > -1"></i>
|
||||
{{ state.name | translate }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Category filter -->
|
||||
<span class="dropdown" uib-dropdown ng-if="categories.length > 0">
|
||||
<span uib-dropdown ng-if="categories.length > 0">
|
||||
<span class="pointer" id="dropdownCategory" uib-dropdown-toggle
|
||||
ng-class="{'bold': multiselect.filters.category.length > 0, 'disabled': isDeleteMode}"
|
||||
ng-disabled="isDeleteMode">
|
||||
ng-class="{'bold': filter.multiselectFilters.category.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Category</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries"
|
||||
aria-labelledby="dropdownCategory">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownCategory">
|
||||
<li ng-repeat="category in categories">
|
||||
<div ng-click="operateMultiselectFilter('category', category.id)">
|
||||
<i class="fa fa-check" ng-if="multiselect.filters.category.indexOf(category.id) > -1"></i>
|
||||
<a href ng-click="filter.operateMultiselectFilter('category', category.id, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.category.indexOf(category.id) > -1"></i>
|
||||
{{ category.name }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href ng-click="filter.operateMultiselectFilter('category', -1, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.category.indexOf(-1) > -1"></i>
|
||||
<translate>No category set</translate>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Motion block filter -->
|
||||
<span class="dropdown" uib-dropdown ng-if="motionBlocks.length > 0">
|
||||
<span uib-dropdown ng-if="motionBlocks.length > 0">
|
||||
<span class="pointer" id="dropdownBlock" uib-dropdown-toggle
|
||||
ng-class="{'bold': multiselect.filters.motionBlock.length > 0, 'disabled': isDeleteMode}"
|
||||
ng-disabled="isDeleteMode">
|
||||
ng-class="{'bold': filter.multiselectFilters.motionBlock.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Motion block</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries"
|
||||
aria-labelledby="dropdownBlock">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownBlock">
|
||||
<li ng-repeat="block in motionBlocks">
|
||||
<div ng-click="operateMultiselectFilter('motionBlock', block.id)">
|
||||
<i class="fa fa-check" ng-if="multiselect.filters.motionBlock.indexOf(block.id) > -1"></i>
|
||||
<a href ng-click="filter.operateMultiselectFilter('motionBlock', block.id, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.motionBlock.indexOf(block.id) > -1"></i>
|
||||
{{ block.title }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href ng-click="filter.operateMultiselectFilter('motionBlock', -1, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.motionBlock.indexOf(-1) > -1"></i>
|
||||
<translate>No motion block set</translate>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Tag filter -->
|
||||
<span class="dropdown" uib-dropdown ng-if="tags.length > 0">
|
||||
<span uib-dropdown ng-if="tags.length > 0">
|
||||
<span class="pointer" id="dropdownTag" uib-dropdown-toggle
|
||||
ng-class="{'bold': multiselect.filters.tag.length > 0, 'disabled': isDeleteMode}"
|
||||
ng-disabled="isDeleteMode">
|
||||
ng-class="{'bold': filter.multiselectFilters.tag.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Tag</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries"
|
||||
aria-labelledby="dropdownTag">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownTag">
|
||||
<li ng-repeat="tag in tags">
|
||||
<div ng-click="operateMultiselectFilter('tag', tag.id)">
|
||||
<i class="fa fa-check" ng-if="multiselect.filters.tag.indexOf(tag.id) > -1"></i>
|
||||
<a href ng-click="filter.operateMultiselectFilter('tag', tag.id, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.tag.indexOf(tag.id) > -1"></i>
|
||||
{{ tag.name }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href ng-click="filter.operateMultiselectFilter('tag', -1, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.tag.indexOf(-1) > -1"></i>
|
||||
<translate>No tag set</translate>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- dropdown sort -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownSort" uib-dropdown-toggle
|
||||
ng-class="{'disabled': isDeleteMode}"
|
||||
ng-disabled="isDeleteMode">
|
||||
ng-class="{'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Sort</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownSort">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSort">
|
||||
<!-- item -->
|
||||
<li>
|
||||
<div ng-click="toggleSort('agenda_item.getItemNumberWithAncestors()')">
|
||||
<a href ng-click="sort.toggle('agenda_item.getItemNumberWithAncestors()')">
|
||||
<translate translate-comment="short form of agenda item">Item</translate>
|
||||
<span class="spacer-right pull-right"></span>
|
||||
<i class="pull-right fa"
|
||||
ng-style="{'visibility': sortColumn === 'agenda_item.getItemNumberWithAncestors()' ? 'visible' : 'hidden'}"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
ng-style="{'visibility': sort.column === 'agenda_item.getItemNumberWithAncestors()' ? 'visible' : 'hidden'}"
|
||||
ng-class="sort.reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<!-- all other sortOptions -->
|
||||
<li ng-repeat="option in sortOptions">
|
||||
<div ng-click="toggleSort(option.name)">
|
||||
<a href ng-click="sort.toggle(option.name)">
|
||||
{{ option.display_name | translate }}
|
||||
<span class="spacer-right pull-right"></span>
|
||||
<i class="pull-right fa"
|
||||
ng-style="{'visibility': sortColumn === option.name ? 'visible' : 'hidden'}"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
ng-style="{'visibility': sort.column === option.name ? 'visible' : 'hidden'}"
|
||||
ng-class="sort.reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
@ -221,49 +240,71 @@
|
||||
<span class="form-group">
|
||||
<span class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||
<input type="text" ng-model="filter.search" class="form-control"
|
||||
placeholder="{{ 'Search' | translate}}" ng-disabled="isDeleteMode">
|
||||
<input type="text" ng-model="filter.filterString" class="form-control"
|
||||
placeholder="{{ 'Search' | translate}}" ng-disabled="isSelectMode">
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<!-- show all selected multiselectoptions -->
|
||||
<span>
|
||||
<!-- state -->
|
||||
<span ng-repeat="state in states" class="pointer spacer-left-lg"
|
||||
ng-if="!state.workflowHeader && multiselect.filters.state.indexOf(state.id) > -1"
|
||||
ng-click="operateMultiselectFilter('state', state.id)"
|
||||
ng-class="{'disabled': isDeleteMode}">
|
||||
ng-if="!state.workflowHeader && filter.multiselectFilters.state.indexOf(state.id) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('state', state.id, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ state.name | translate }}
|
||||
</span>
|
||||
</span>
|
||||
<!-- category -->
|
||||
<span ng-repeat="category in categories" class="pointer spacer-left-lg"
|
||||
ng-if="multiselect.filters.category.indexOf(category.id) > -1"
|
||||
ng-click="operateMultiselectFilter('category', category.id)"
|
||||
ng-class="{'disabled': isDeleteMode}">
|
||||
ng-if="filter.multiselectFilters.category.indexOf(category.id) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('category', category.id, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ category.name }}
|
||||
</span>
|
||||
</span>
|
||||
<span ng-if="filter.multiselectFilters.category.indexOf(-1) > -1" class="pointer spacer-left-lg"
|
||||
ng-click="filter.operateMultiselectFilter('category', -1, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>No category set</translate>
|
||||
</span>
|
||||
<!-- motion block -->
|
||||
<span ng-repeat="motionBlock in motionBlocks" class="pointer spacer-left-lg"
|
||||
ng-if="multiselect.filters.motionBlock.indexOf(motionBlock.id) > -1"
|
||||
ng-click="operateMultiselectFilter('motionBlock', motionBlock.id)"
|
||||
ng-class="{'disabled': isDeleteMode}">
|
||||
ng-if="filter.multiselectFilters.motionBlock.indexOf(motionBlock.id) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('motionBlock', motionBlock.id, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ motionBlock.title }}
|
||||
</span>
|
||||
</span>
|
||||
<span ng-if="filter.multiselectFilters.motionBlock.indexOf(-1) > -1" class="pointer spacer-left-lg"
|
||||
ng-click="filter.operateMultiselectFilter('motionBlock', -1, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>No motion block set</translate>
|
||||
</span>
|
||||
<!-- tags -->
|
||||
<span ng-repeat="tag in tags" class="pointer spacer-left-lg"
|
||||
ng-if="multiselect.flters.tag.indexOf(tag.id) > -1"
|
||||
ng-click="operateMultiselectFilter('tag', tag.id)"
|
||||
ng-class="{'disabled': isDeleteMode}">
|
||||
ng-if="filter.multiselectFilters.tag.indexOf(tag.id) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('tag', tag.id, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
</span>
|
||||
<span ng-if="filter.multiselectFilters.tag.indexOf(-1) > -1" class="pointer spacer-left-lg"
|
||||
ng-click="filter.operateMultiselectFilter('tag', -1, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>No tag set</translate>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -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)">
|
||||
|
||||
<!-- select column -->
|
||||
<div ng-show="isDeleteMode" os-perms="motions.can_manage" class="col-xs-1 centered">
|
||||
<div ng-show="isSelectMode" os-perms="motions.can_manage" class="col-xs-1 centered">
|
||||
<i class="fa text-danger pointer" ng-click="motion.selected=!motion.selected"
|
||||
ng-class="motion.selected ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||
</div>
|
||||
@ -293,12 +334,12 @@
|
||||
</div>
|
||||
<!-- main content column -->
|
||||
<div class="col-xs-6 content">
|
||||
<div class="identifier-col">
|
||||
<div class="id-col">
|
||||
<span ng-show="motion.identifier">
|
||||
{{ motion.identifier }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="title-col">
|
||||
<div>
|
||||
<!-- ID and title -->
|
||||
<div>
|
||||
<strong>
|
||||
@ -310,8 +351,8 @@
|
||||
{{ motion.getStateName() }}
|
||||
</span>
|
||||
<span os-perms="motions.can_manage" ng-class="{'hiddenDiv': !motion.stateHover}" uib-dropdown>
|
||||
<i class="fa fa-cog pointer" uib-dropdown-toggle id="state-dropdown{{ motion.id }}"></i>
|
||||
<ul uib-dropdown-menu aria-labelledby="state-dropdown{{ motion.id }}">
|
||||
<i class="fa fa-cog pointer" uib-dropdown-toggle id="stateDropdown{{ motion.id }}"></i>
|
||||
<ul class="dropdown-menu" aria-labelledby="stateDropdown{{ motion.id }}">
|
||||
<li ng-repeat="state in motion.state.getNextStates()">
|
||||
<a href ng-click="updateState(motion, state.id)">{{ state.action_word | translate }}</a>
|
||||
</li>
|
||||
@ -353,12 +394,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- additional content column -->
|
||||
<style>
|
||||
#motion-table .row .col-xs-4 {
|
||||
width: calc(50% - {{ isDeleteMode ? '120' : '70' }}px);
|
||||
}
|
||||
</style>
|
||||
<div class="col-xs-4 content">
|
||||
<div class="col-xs-4 content" ng-style="{'width': isSelectMode ? 'calc(50% - 120px)' : 'calc(50% - 70px)'}">
|
||||
<div style="width: 60%;" class="optional">
|
||||
<small>
|
||||
<!-- Category dropdown for manage user -->
|
||||
@ -366,7 +402,7 @@
|
||||
ng-mouseover="motion.categoryHover=true"
|
||||
ng-mouseleave="motion.categoryHover=false">
|
||||
<span uib-dropdown>
|
||||
<span id="dropdown-category{{ motion.id }}" class="pointer"
|
||||
<span id="dropdownCategory{{ motion.id }}" class="pointer"
|
||||
uib-dropdown-toggle uib-tooltip="{{ 'Set a category' | translate }}"
|
||||
tooltip-class="nobr">
|
||||
<span ng-if="motion.category == null" ng-show="motion.hover">
|
||||
@ -379,12 +415,12 @@
|
||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.categoryHover"></i>
|
||||
</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-category{{ motion.id }}">
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownCategory{{ motion.id }}">
|
||||
<li ng-repeat="category in categories">
|
||||
<div ng-click="toggle_category(motion, category)">
|
||||
<a href ng-click="toggleCategory(motion, category)">
|
||||
<i class="fa fa-check" ng-if="category.id == motion.category.id"></i>
|
||||
{{ category.name }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
@ -400,7 +436,7 @@
|
||||
ng-mouseover="motion.motionBlockHover=true"
|
||||
ng-mouseleave="motion.motionBlockHover=false">
|
||||
<span uib-dropdown>
|
||||
<span id="dropdown-motionBlock{{ motion.id }}" class="pointer"
|
||||
<span id="dropdownMotionBlock{{ motion.id }}" class="pointer"
|
||||
uib-dropdown-toggle uib-tooltip="{{ 'Set a motion block' | translate }}"
|
||||
tooltip-class="nobr">
|
||||
<span ng-if="motion.motionBlock == null" ng-show="motion.hover">
|
||||
@ -413,12 +449,12 @@
|
||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.motionBlockHover"></i>
|
||||
</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-motionBlock{{ motion.id }}">
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMotionBlock{{ motion.id }}">
|
||||
<li ng-repeat="motionBlock in motionBlocks">
|
||||
<div ng-click="toggle_motionBlock(motion, motionBlock)">
|
||||
<a href ng-click="toggleMotionBlock(motion, motionBlock)">
|
||||
<i class="fa fa-check" ng-if="motionBlock.id == motion.motionBlock.id"></i>
|
||||
{{ motionBlock.title }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
@ -434,7 +470,7 @@
|
||||
ng-mouseover="motion.tagHover=true"
|
||||
ng-mouseleave="motion.tagHover=false">
|
||||
<span uib-dropdown>
|
||||
<span id="dropdown-tags{{ motion.id }}" class="pointer"
|
||||
<span id="dropdownTags{{ motion.id }}" class="pointer"
|
||||
uib-dropdown-toggle uib-tooltip="{{ 'Add a tag' | translate }}"
|
||||
tooltip-class="nobr">
|
||||
<span ng-if="motion.tags.length == 0" ng-show="motion.hover">
|
||||
@ -449,12 +485,12 @@
|
||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.tagHover"></i>
|
||||
</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-tags{{ motion.id }}">
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownTags{{ motion.id }}">
|
||||
<li ng-repeat="tag in tags">
|
||||
<div ng-click="toggle_tag(motion, tag)">
|
||||
<i class="fa fa-check" ng-if="has_tag(motion, tag)"></i>
|
||||
<a href ng-click="toggleTag(motion, tag)">
|
||||
<i class="fa fa-check" ng-if="hasTag(motion, tag)"></i>
|
||||
{{ tag.name }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
@ -475,7 +511,7 @@
|
||||
</small>
|
||||
</div>
|
||||
<div style="width: 10%;" class="pull-right optional">
|
||||
<div class="pull-right" ng-if="config('motions_min_supporters') != 0"
|
||||
<div class="centered" ng-if="config('motions_min_supporters') != 0"
|
||||
uib-tooltip="{{ motion.supporters.length }} {{ 'Supporters' | translate }}
|
||||
{{ (config('motions_min_supporters') - motion.supporters.length) > 0 ? '(' + (config('motions_min_supporters') - motion.supporters.length) + ' ' + ('needed' | translate) + ')': '' }}"
|
||||
tooltip-class="nobr">
|
||||
|
@ -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;
|
||||
|
@ -116,20 +116,20 @@
|
||||
<!-- filter users (for user with 'can_see_extra_data' permission) - consider present filter -->
|
||||
<div os-perms="users.can_see_extra_data">
|
||||
<span ng-repeat="user in $parent.usersFiltered = (users
|
||||
| osFilter: filter.search : multiselect.getFilterString
|
||||
| filter: {is_present: isPresentFilter}
|
||||
| filter: {is_active: isActiveFilter}
|
||||
| filter: {is_committee: isCommitteeFilter}
|
||||
| MultiselectFilter: multiselect.filters.group : getItemId.group
|
||||
| orderBy: sortColumn:reverse)"></span>
|
||||
| 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)"></span>
|
||||
</div>
|
||||
<!-- filter users (for user without 'can_see_extra_data' permission) -->
|
||||
<div os-perms="!users.can_see_extra_data"
|
||||
ng-repeat="user in $parent.usersFiltered = (users
|
||||
| osFilter: filter.search : multiselect.getFilterString
|
||||
| filter: {is_committee: isCommitteeFilter}
|
||||
| MultiselectFilter: multiselect.filters.group : getItemId.group
|
||||
| orderBy: sortColumn:reverse)"></div>
|
||||
| osFilter: filter.filterString : filter.getObjectQueryString
|
||||
| filter: {is_committee: filter.booleanFilters.isCommittee.value}
|
||||
| MultiselectFilter: filter.multiselectFilters.group : getItemId.group
|
||||
| orderBy: sort.column: sort.reverse)"></div>
|
||||
|
||||
<div class="os-table container-fluid">
|
||||
<div class="row header-row">
|
||||
@ -140,100 +140,62 @@
|
||||
<div class="col-xs-11 main-header">
|
||||
<span class="form-inline text-right pull-right">
|
||||
<!-- reset Filters -->
|
||||
<span class="sort-spacer pointer" ng-click="resetFilters()"
|
||||
ng-if="areFiltersSet()" ng-disabled="isSelectMode"
|
||||
<span class="sort-spacer pointer" ng-click="filter.reset()"
|
||||
ng-if="filter.areFiltersSet()" ng-disabled="isSelectMode"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>Filter</translate>
|
||||
</span>
|
||||
<!-- Group filter -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownGroup" uib-dropdown-toggle
|
||||
ng-class="{'bold': multiselect.filters.group.length > 0, 'disabled': isSelectMode}"
|
||||
ng-class="{'bold': filter.multiselectFilters.group.length > 0, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Groups</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownGroup">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownGroup">
|
||||
<li ng-repeat="group in groups">
|
||||
<div ng-click="operateMultiselectFilter('group', group.id)">
|
||||
<i class="fa fa-check" ng-if="multiselect.filters.group.indexOf(group.id) > -1"></i>
|
||||
<a href ng-click="filter.operateMultiselectFilter('group', group.id, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.group.indexOf(group.id) > -1"></i>
|
||||
{{ group.name | translate }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href ng-click="filter.operateMultiselectFilter('group', -1, isSelectMode)">
|
||||
<i class="fa fa-check" ng-if="filter.multiselectFilters.group.indexOf(-1) > -1"></i>
|
||||
<translate>No group set</translate>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Present filter -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span class="pointer" id="dropdownPresent" uib-dropdown-toggle
|
||||
ng-class="{'bold': isPresentFilter !== undefined, 'disabled': isSelectMode}"
|
||||
<!-- boolean Filters -->
|
||||
<span ng-repeat="(name, booleanFilter) in filter.booleanFilters"
|
||||
ng-if="!booleanFilter.needExtraPermission || operator.hasPerms('users.can_see_extra_data')" uib-dropdown>
|
||||
<span class="pointer" id="dropdown{{ name }}" uib-dropdown-toggle
|
||||
ng-class="{'bold': booleanFilter.value !== undefined, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
<translate>Present</translate>
|
||||
{{ booleanFilter.displayName }}
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownPresent">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdown{{ name }}">
|
||||
<li>
|
||||
<div ng-click="isPresentFilter = (isPresentFilter ? undefined : true)">
|
||||
<i class="fa" ng-class="{'fa-check': isPresentFilter === true}"></i>
|
||||
<translate>Is present</translate>
|
||||
</div>
|
||||
<a href ng-click="booleanFilter.value = (booleanFilter.value ? undefined : true)">
|
||||
<i class="fa" ng-class="{'fa-check': booleanFilter.value === true}"></i>
|
||||
{{ booleanFilter.choiceYes }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<div ng-click="isPresentFilter = (isPresentFilter === false) ? undefined : false">
|
||||
<i class="fa" ng-class="{'fa-check': isPresentFilter === false}"></i>
|
||||
<translate>Is not present</translate>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Active filter -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span class="pointer" id="dropdownActive" uib-dropdown-toggle
|
||||
ng-class="{'bold': isActiveFilter !== undefined, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelecteMode">
|
||||
<translate>Active</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownActive">
|
||||
<li>
|
||||
<div ng-click="isActiveFilter = (isActiveFilter ? undefined : true)">
|
||||
<i class="fa" ng-class="{'fa-check': isActiveFilter === true}"></i>
|
||||
<translate>Is active</translate>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div ng-click="isActiveFilter = (isActiveFilter === false ? undefined : false)">
|
||||
<i class="fa" ng-class="{'fa-check': isActiveFilter === false}"></i>
|
||||
<translate>Is not active</translate>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- Committee filter -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span class="pointer" id="dropdownCommittee" uib-dropdown-toggle
|
||||
ng-class="{'bold': isCommitteeFilter !== undefined, 'disabled': isSelectMode}"
|
||||
ng-disabled="isSelecteMode">
|
||||
<translate>Committee</translate>
|
||||
<span class="caret"></span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownCommittee">
|
||||
<li>
|
||||
<div ng-click="isCommitteeFilter = (isCommitteeFilter ? undefined : true)">
|
||||
<i class="fa" ng-class="{'fa-check': isCommitteeFilter === true}"></i>
|
||||
<translate>Yes</translate>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div ng-click="isCommitteeFilter = (isCommitteeFilter === false ? undefined : false)">
|
||||
<i class="fa" ng-class="{'fa-check': isCommitteeFilter === false}"></i>
|
||||
<translate>No</translate>
|
||||
</div>
|
||||
<a href ng-click="booleanFilter.value = (booleanFilter.value === false) ? undefined : false">
|
||||
<i class="fa" ng-class="{'fa-check': booleanFilter.value === false}"></i>
|
||||
{{ booleanFilter.choiceNo }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!-- dropdown sort -->
|
||||
<span class="dropdown" uib-dropdown>
|
||||
<span uib-dropdown>
|
||||
<span class="pointer" id="dropdownSort" uib-dropdown-toggle
|
||||
ng-class="{'disabled': isSelectMode}"
|
||||
ng-disabled="isSelectMode">
|
||||
@ -242,14 +204,14 @@
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownSort">
|
||||
<li ng-repeat="option in sortOptions">
|
||||
<div ng-click="toggleSort(option.name)">
|
||||
<a href ng-click="sort.toggle(option.name)">
|
||||
{{ option.display_name | translate }}
|
||||
<span class="spacer-right pull-right"></span>
|
||||
<i class="pull-right fa"
|
||||
ng-style="{'visibility': sortColumn === option.name ? 'visible' : 'hidden'}"
|
||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
ng-style="{'visibility': sort.column === option.name ? 'visible' : 'hidden'}"
|
||||
ng-class="sort.reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||
</i>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
@ -257,7 +219,7 @@
|
||||
<span class="form-group">
|
||||
<span class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||
<input type="text" ng-model="filter.search" class="form-control" ng-model-options="{debounce: 500}"
|
||||
<input type="text" ng-model="filter.filterString" class="form-control" ng-model-options="{debounce: 500}"
|
||||
placeholder="{{ 'Search' | translate}}" ng-disabled="isSelectMode">
|
||||
</span>
|
||||
</span>
|
||||
@ -265,39 +227,29 @@
|
||||
<!-- show all selected multiselectoptions -->
|
||||
<span>
|
||||
<span ng-repeat="group in groups" class="pointer spacer-left-lg"
|
||||
ng-if="multiselect.filters.group.indexOf(group.id) > -1"
|
||||
ng-click="operateMultiselectFilter('group', group.id)"
|
||||
ng-if="filter.multiselectFilters.group.indexOf(group.id) > -1"
|
||||
ng-click="filter.operateMultiselectFilter('group', group.id, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ group.name | translate }}
|
||||
</span>
|
||||
</span>
|
||||
<span ng-hide="isPresentFilter === undefined"
|
||||
class="pointer spacer-left-lg"
|
||||
ng-click="isPresentFilter = undefined;"
|
||||
<span ng-if="filter.multiselectFilters.group.indexOf(-1) > -1" class="pointer spacer-left-lg"
|
||||
ng-click="filter.operateMultiselectFilter('group', -1, isSelectMode)"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ isPresentFilter ? 'Is present' : 'Is not present' | translate }}
|
||||
</span>
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<translate>No group set</translate>
|
||||
</span>
|
||||
<span ng-hide="isActiveFilter === undefined"
|
||||
<!-- for all boolean Filters -->
|
||||
<span ng-repeat="(name, booleanFilter) in filter.booleanFilters"
|
||||
ng-hide="booleanFilter.value === undefined"
|
||||
class="pointer spacer-left-lg"
|
||||
ng-click="isActiveFilter = undefined;"
|
||||
ng-click="booleanFilter.value = undefined;"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ isActiveFilter ? 'Is active' : 'Is not active' | translate }}
|
||||
</span>
|
||||
</span>
|
||||
<span ng-hide="isCommitteeFilter === undefined"
|
||||
class="pointer spacer-left-lg"
|
||||
ng-click="isCommitteeFilter = undefined;"
|
||||
ng-class="{'disabled': isSelectMode}">
|
||||
<span class="nobr">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
{{ isCommitteeFilter ? 'Is committee' : 'Is not committee' | translate }}
|
||||
{{ booleanFilter.value ? booleanFilter.choiceYes : booleanFilter.choiceNo | translate }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@ -350,13 +302,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- additional content column -->
|
||||
<style>
|
||||
.os-table .row .col-xs-4 {
|
||||
width: calc(50% - {{ isSelectMode ? '120' : '70' }}px);
|
||||
}
|
||||
</style>
|
||||
<div class="col-xs-4 content">
|
||||
<div class="col-xs-4 content" ng-style="{'width': isSelectMode ? 'calc(50% - 120px)' : 'calc(50% - 70px)'}">
|
||||
<div style="width: 60%;" class="optional">
|
||||
<small>
|
||||
<!-- Group dropdown for manage user -->
|
||||
@ -378,12 +326,12 @@
|
||||
<i class="fa fa-cog fa-lg spcaer-left" ng-show="user.groupHover"></i>
|
||||
</span>
|
||||
</span>
|
||||
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-group{{ user.id }}">
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdown-group{{ user.id }}">
|
||||
<li ng-repeat="group in groups">
|
||||
<div ng-click="toggleGroup(user, group)">
|
||||
<a href ng-click="toggleGroup(user, group)">
|
||||
<i class="fa fa-check" ng-if="inArray(user.groups_id, group.id)"></i>
|
||||
{{ group.name | translate }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
@ -409,7 +357,7 @@
|
||||
</div>
|
||||
<div style="width: 40%;" class="pull-right" os-perms="users.can_see_extra_data">
|
||||
<div os-perms="users.can_manage">
|
||||
<span class="pointer" ng-click="user.is_present = !user.is_present; save(user);">
|
||||
<span class="pointer nobr" ng-click="user.is_present = !user.is_present; save(user);">
|
||||
<i class="fa" ng-class="user.is_present ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||
<span class="spacer-left" translate>Present</span>
|
||||
</span>
|
||||
|
Loading…
Reference in New Issue
Block a user