Several template fixes and clean up
- Use ng-cloak for hide template parts while loading. - Set html lang attribute dynamically (Fixes #1546) - Clean up: Rename 'dashboard' to 'home'. - Show duration of speech in minutes. (Fixes #1882) - Save agenda specific stuff for customslides. (Fixes #1887) - Remove title from QuickEdit from. - Checkbox for item.closed is now visible for manager only. - Agenda list view: Show list of speakers link also for normal users. - Improve slide templates: Show agenda item number and subtitle. - Fixed agenda title for motions and assignments. (Don't load motions and assignmetn in agenda app.) - Added missing seach template.
This commit is contained in:
parent
741cae028c
commit
23503eb4ba
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# General
|
# General
|
||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
*.swp
|
||||||
|
*.swo
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# Virtual Environment
|
# Virtual Environment
|
||||||
|
@ -299,6 +299,17 @@ class Item(RESTModelMixin, models.Model):
|
|||||||
raise NotImplementedError('You have to provide a get_agenda_title '
|
raise NotImplementedError('You have to provide a get_agenda_title '
|
||||||
'method on your related model.')
|
'method on your related model.')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def list_view_title(self):
|
||||||
|
"""
|
||||||
|
Return get_agenda_list_view_title() from the content_object.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.content_object.get_agenda_list_view_title()
|
||||||
|
except AttributeError:
|
||||||
|
raise NotImplementedError('You have to provide a get_agenda_list_view_title '
|
||||||
|
'method on your related model.')
|
||||||
|
|
||||||
def is_hidden(self):
|
def is_hidden(self):
|
||||||
"""
|
"""
|
||||||
Returns True if the type of this object itself is a hidden item or any
|
Returns True if the type of this object itself is a hidden item or any
|
||||||
|
@ -53,6 +53,7 @@ class ItemSerializer(ModelSerializer):
|
|||||||
'id',
|
'id',
|
||||||
'item_number',
|
'item_number',
|
||||||
'title',
|
'title',
|
||||||
|
'list_view_title',
|
||||||
'comment',
|
'comment',
|
||||||
'closed',
|
'closed',
|
||||||
'type',
|
'type',
|
||||||
|
@ -48,12 +48,24 @@ angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users'])
|
|||||||
try {
|
try {
|
||||||
title = this.getContentObject().getAgendaTitle();
|
title = this.getContentObject().getAgendaTitle();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Only use this.title when the content object is not
|
// when the content object is not in the DS store.
|
||||||
// in the DS store.
|
|
||||||
title = this.title;
|
title = this.title;
|
||||||
}
|
}
|
||||||
if (this.getContentResource().agendaSupplement) {
|
if (this.item_number) {
|
||||||
title = gettextCatalog.getString(this.getContentResource().agendaSupplement) + ' ' + title;
|
title = this.item_number + ' · ' + title;
|
||||||
|
}
|
||||||
|
return title;
|
||||||
|
},
|
||||||
|
getAgendaTitle: function () {
|
||||||
|
return this.title;
|
||||||
|
},
|
||||||
|
getListViewTitle: function () {
|
||||||
|
var title;
|
||||||
|
try {
|
||||||
|
title = this.getContentObject().getAgendaListViewTitle();
|
||||||
|
} catch (e) {
|
||||||
|
// when the content object is not in the DS store
|
||||||
|
title = this.list_view_title;
|
||||||
}
|
}
|
||||||
if (this.item_number) {
|
if (this.item_number) {
|
||||||
title = this.item_number + ' · ' + title;
|
title = this.item_number + ' · ' + title;
|
||||||
|
@ -280,6 +280,14 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
|||||||
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
$scope.alert = { type: 'danger', msg: data.detail, show: true };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// gets speech duration of selected speaker in seconds
|
||||||
|
$scope.getDuration = function (speaker) {
|
||||||
|
var beginTimestamp = new Date(speaker.begin_time).getTime()
|
||||||
|
var endTimestamp = new Date(speaker.end_time).getTime()
|
||||||
|
// calculate duration in seconds
|
||||||
|
return Math.floor((endTimestamp - beginTimestamp) / 1000);
|
||||||
|
|
||||||
|
}
|
||||||
// save reordered list of speakers
|
// save reordered list of speakers
|
||||||
$scope.treeOptions = {
|
$scope.treeOptions = {
|
||||||
dropped: function (event) {
|
dropped: function (event) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<a href="" ng-click="open(item)" class="btn btn-sm btn-default">
|
<a href="" ng-click="open(item)" class="btn btn-sm btn-default">
|
||||||
<i class="fa fa-angle-double-left fa-lg"></i>
|
<i class="fa fa-angle-double-left fa-lg"></i>
|
||||||
{{ item.getContentResource().verboseName }}
|
{{ item.getContentResource().verboseName | translate }}
|
||||||
</a>
|
</a>
|
||||||
<!-- project list of speakers -->
|
<!-- project list of speakers -->
|
||||||
<a os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
|
<a os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
|
||||||
@ -22,7 +22,7 @@
|
|||||||
ng-click="item.project()"
|
ng-click="item.project()"
|
||||||
title="{{ 'Project item' | translate }}">
|
title="{{ 'Project item' | translate }}">
|
||||||
<i class="fa fa-video-camera"></i>
|
<i class="fa fa-video-camera"></i>
|
||||||
{{ item.getContentResource().verboseName }}
|
{{ item.getContentResource().verboseName | translate }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<h1>{{ item.getTitle() }}</h1>
|
<h1>{{ item.getTitle() }}</h1>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<div class="spacer">
|
<div class="spacer">
|
||||||
<h3 translate>Last speakers</h3>
|
<h3 translate>Last speakers</h3>
|
||||||
<button ng-click="showOldSpeakers = !showOldSpeakers"
|
<button ng-click="showOldSpeakers = !showOldSpeakers"
|
||||||
class="btn btn-xs btn-default">
|
class="btn btn-sm btn-default">
|
||||||
<translate ng-if="!showOldSpeakers">Show</translate>
|
<translate ng-if="!showOldSpeakers">Show</translate>
|
||||||
<translate ng-if="showOldSpeakers">Hide</translate>
|
<translate ng-if="showOldSpeakers">Hide</translate>
|
||||||
</button>
|
</button>
|
||||||
@ -77,8 +77,9 @@
|
|||||||
<li ng-repeat="speaker in item.speakers | filter: {end_time: '!!'}">
|
<li ng-repeat="speaker in item.speakers | filter: {end_time: '!!'}">
|
||||||
{{ speaker.user.get_full_name() }}
|
{{ speaker.user.get_full_name() }}
|
||||||
<small class="grey">
|
<small class="grey">
|
||||||
[{{ speaker.begin_time | date:'yyyy-MM-dd HH:mm:ss' }} –
|
{{ getDuration(speaker) | osSecondsToTime }} <translate>minutes</translate>
|
||||||
{{ speaker.end_time | date:'yyyy-MM-dd HH:mm:ss' }}]
|
(<translate>Start time</translate>:
|
||||||
|
{{ speaker.begin_time | date:'yyyy-MM-dd HH:mm:ss' }})
|
||||||
</small>
|
</small>
|
||||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||||
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
||||||
@ -94,11 +95,11 @@
|
|||||||
filter: {end_time: null, begin_time: '!!'}">
|
filter: {end_time: null, begin_time: '!!'}">
|
||||||
{{ speaker.user.get_full_name() }}
|
{{ speaker.user.get_full_name() }}
|
||||||
<button os-perms="agenda.can_manage" ng-click="endSpeech()"
|
<button os-perms="agenda.can_manage" ng-click="endSpeech()"
|
||||||
class="btn btn-default btn-xs" title="{{ 'End speech' | translate }}">
|
class="btn btn-default btn-sm" title="{{ 'End speech' | translate }}">
|
||||||
<i class="fa fa-microphone-slash"></i>
|
<i class="fa fa-microphone-slash"></i> <translate>Stop</translate>
|
||||||
</button>
|
</button>
|
||||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||||
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
class="btn btn-default btn-sm" title="{{ 'Remove' | translate }}">
|
||||||
<i class="fa fa-times"></i>
|
<i class="fa fa-times"></i>
|
||||||
</button>
|
</button>
|
||||||
</strong>
|
</strong>
|
||||||
@ -113,11 +114,11 @@
|
|||||||
{{ $index + 1 }}.
|
{{ $index + 1 }}.
|
||||||
{{ speaker.user.get_full_name() }}
|
{{ speaker.user.get_full_name() }}
|
||||||
<button os-perms="agenda.can_manage" ng-click="beginSpeech(speaker.id)"
|
<button os-perms="agenda.can_manage" ng-click="beginSpeech(speaker.id)"
|
||||||
class="btn btn-default btn-xs" title="{{ 'Begin speech' | translate }}">
|
class="btn btn-default btn-sm" title="{{ 'Begin speech' | translate }}">
|
||||||
<i class="fa fa-microphone"></i>
|
<i class="fa fa-microphone"></i> <translate>Start</translate>
|
||||||
</button>
|
</button>
|
||||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||||
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
class="btn btn-default btn-sm" title="{{ 'Remove' | translate }}">
|
||||||
<i class="fa fa-times"></i>
|
<i class="fa fa-times"></i>
|
||||||
</button>
|
</button>
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -28,19 +28,18 @@
|
|||||||
|
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-7">
|
||||||
<form class="form-inline">
|
<div class="form-inline">
|
||||||
<!-- delete mode -->
|
<!-- delete mode -->
|
||||||
<button os-perms="agenda.can_manage" class="btn"
|
<button os-perms="agenda.can_manage" class="btn"
|
||||||
ng-class="$parent.isDeleteMode ? 'btn-primary' : 'btn-default'"
|
ng-class="$parent.isDeleteMode ? 'btn-primary' : 'btn-default'"
|
||||||
ng-click="$parent.isDeleteMode = !$parent.isDeleteMode; uncheckAll()">
|
ng-click="$parent.isDeleteMode = !$parent.isDeleteMode; uncheckAll()">
|
||||||
<i class="fa fa-check-square-o"></i>
|
<i class="fa fa-check-square-o"></i>
|
||||||
<translate>Select ...</translate>
|
<translate>Select ...</translate>
|
||||||
</button>
|
</button>
|
||||||
<div class="form-group">
|
|
||||||
<!-- project agenda button -->
|
<!-- project agenda button -->
|
||||||
<a os-perms="core.can_manage_projector"
|
<a os-perms="core.can_manage_projector"
|
||||||
class="btn btn-default form-control"
|
class="btn btn-default"
|
||||||
title="{{ 'Project agenda' | translate }}"
|
title="{{ 'Project agenda' | translate }}"
|
||||||
ng-click="projectAgenda()"
|
ng-click="projectAgenda()"
|
||||||
ng-class="{ 'btn-primary': isAgendaProjected() }">
|
ng-class="{ 'btn-primary': isAgendaProjected() }">
|
||||||
@ -49,15 +48,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<!-- auto numbering button -->
|
<!-- auto numbering button -->
|
||||||
<a os-perms="core.can_manage_projector"
|
<a os-perms="core.can_manage_projector"
|
||||||
class="btn btn-default form-control"
|
class="btn btn-default"
|
||||||
ng-click="autoNumbering()">
|
ng-click="autoNumbering()">
|
||||||
<i class="fa fa-sort-numeric-asc"></i>
|
<i class="fa fa-sort-numeric-asc"></i>
|
||||||
<translate>Number agenda</translate>
|
<translate>Numbering</translate>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-5">
|
||||||
<div class="form-inline text-right">
|
<div class="form-inline text-right">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -138,29 +136,34 @@
|
|||||||
style="padding-left: calc(8px + {{ item.parentCount }}*15px)">
|
style="padding-left: calc(8px + {{ item.parentCount }}*15px)">
|
||||||
<strong>
|
<strong>
|
||||||
<a href="" ng-click="open(item)">
|
<a href="" ng-click="open(item)">
|
||||||
{{ item.getTitle() }}
|
{{ item.getListViewTitle() }}
|
||||||
</a>
|
</a>
|
||||||
</strong>
|
</strong>
|
||||||
<span ng-if="item.is_hidden" title="{{ 'Internal item' | translate }}"><i class="fa fa-ban"></i></span>
|
<span ng-if="item.is_hidden" title="{{ 'Internal item' | translate }}"><i class="fa fa-ban"></i></span>
|
||||||
<div ng-if="item.comment">
|
<div ng-if="item.comment">
|
||||||
<small><i class="fa fa-info-circle"></i> {{ item.comment }}</small>
|
<small><i class="fa fa-info-circle"></i> {{ item.comment }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div os-perms="agenda.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !item.hover}">
|
<div os-perms="agenda.can_see" class="hoverActions" ng-class="{'hiddenDiv': !item.hover}">
|
||||||
<a ui-sref="agenda.item.detail({id: item.id})" translate>List of speakers</a> |
|
<a ui-sref="agenda.item.detail({id: item.id})" translate>List of speakers</a>
|
||||||
<a href="" ng-click="editDialog(item)" translate>Edit</a> |
|
<span os-perms="agenda.can_manage"> |
|
||||||
<a href="" ng-click="item.quickEdit=true" translate>QuickEdit</a>
|
<a href="" ng-click="editDialog(item)" translate>Edit</a> |
|
||||||
<span ng-if="item.content_object.collection == 'core/customslide'"> |
|
<a href="" ng-click="item.quickEdit=true" translate>QuickEdit</a>
|
||||||
<a href="" class="text-danger"
|
<span ng-if="item.content_object.collection == 'core/customslide'"> |
|
||||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
<a href="" class="text-danger"
|
||||||
<b>{{ item.getTitle() }}</b>"
|
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
||||||
ng-bootbox-confirm-action="deleteRelatedItem(item)" translate>Delete</a>
|
<b>{{ item.getTitle() }}</b>"
|
||||||
|
ng-bootbox-confirm-action="deleteRelatedItem(item)" translate>Delete</a>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<td ng-show="!item.quickEdit" os-perms="agenda.can_see_hidden_items" class="optional">
|
<td ng-show="!item.quickEdit" os-perms="agenda.can_see_hidden_items" class="optional">
|
||||||
{{ item.duration }}
|
{{ item.duration }}
|
||||||
<span ng-if="item.duration" translate-comment="'h' means time in hours" translate>h</span>
|
<span ng-if="item.duration" translate-comment="'h' means time in hours" translate>h</span>
|
||||||
<td ng-if="!item.quickEdit">
|
<td ng-if="!item.quickEdit">
|
||||||
<input type="checkbox" ng-model="item.closed" ng-change="save(item.id);">
|
<span os-perms="!agenda.can_manage">
|
||||||
|
<i ng-if="item.closed" class="fa fa-check-square-o"></i>
|
||||||
|
</span>
|
||||||
|
<input os-perms="agenda.can_manage" type="checkbox" ng-model="item.closed" ng-change="save(item.id);">
|
||||||
<!-- quickEdit columns -->
|
<!-- quickEdit columns -->
|
||||||
<td ng-show="item.quickEdit" os-perms="agenda.can_manage" colspan="3">
|
<td ng-show="item.quickEdit" os-perms="agenda.can_manage" colspan="3">
|
||||||
<form ng-submit="save(item)">
|
<form ng-submit="save(item)">
|
||||||
@ -170,8 +173,8 @@
|
|||||||
</uib-alert>
|
</uib-alert>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<label for="inputTitle" translate>Title</label>
|
<label for="inputItemNumber" translate>Item number</label>
|
||||||
<input type="text" ng-model="item.title" class="form-control input-sm" id="inputTitle">
|
<input type="text" ng-model="item.item_number" class="form-control input-sm" id="inputItemNumber">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<label for="inputComment" translate>Comment</label>
|
<label for="inputComment" translate>Comment</label>
|
||||||
@ -180,25 +183,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<label for="inputItemNumber" translate>Item number</label>
|
<!-- item type: AGENDA_ITEM = 1, HIDDEN_ITEM = 2 -->
|
||||||
<input type="text" ng-model="item.item_number" class="form-control input-sm" id="inputItemNumber">
|
<input type="checkbox" ng-model="item.type" ng-true-value="1" ng-false-value="2">
|
||||||
|
<translate>Show as agenda item</translate>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<label for="inputDuration" translate>Duration</label>
|
<label for="inputDuration" translate>Duration</label>
|
||||||
<input type="text" ng-model="item.duration" class="form-control input-sm" id="inputDuration">
|
<input type="text" ng-model="item.duration" class="form-control input-sm" id="inputDuration">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-6">
|
|
||||||
<label>
|
|
||||||
<!-- item type: AGENDA_ITEM = 1, HIDDEN_ITEM = 2 -->
|
|
||||||
<input type="checkbox" ng-model="item.type" ng-true-value="2" ng-false-value="1">
|
|
||||||
<translate> Hidden item</translate>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-6">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="spacer">
|
<div class="spacer">
|
||||||
<button ng-click="item.quickEdit=false" class="btn btn-default pull-left" translate>
|
<button ng-click="item.quickEdit=false" class="btn btn-default pull-left" translate>
|
||||||
Cancel
|
Cancel
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<!-- item type: AGENDA_ITEM = 1, HIDDEN_ITEM = 2 -->
|
<!-- item type: AGENDA_ITEM = 1, HIDDEN_ITEM = 2 -->
|
||||||
<p ng-repeat="item in items | filter: {type: 1}" ng-class="{ 'spacer-top': !item.parent_id }">
|
<p ng-repeat="item in items | filter: {type: 1}" ng-class="{ 'spacer-top': !item.parent_id }">
|
||||||
<span ng-repeat="n in [].constructor(item.parentCount) track by $index"> </span>
|
<span ng-repeat="n in [].constructor(item.parentCount) track by $index"> </span>
|
||||||
{{ item.getTitle() }}
|
{{ item.getListViewTitle() }}
|
||||||
<i ng-if="item.closed" class="fa fa-check"></i>
|
<i ng-if="item.closed" class="fa fa-check"></i>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@ from collections import OrderedDict
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.agenda.models import Item, Speaker
|
from openslides.agenda.models import Item, Speaker
|
||||||
@ -268,6 +269,15 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
def get_agenda_title(self):
|
def get_agenda_title(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
def get_agenda_list_view_title(self):
|
||||||
|
"""
|
||||||
|
Return a title string for the agenda list view.
|
||||||
|
|
||||||
|
Contains agenda item number, title and assignment verbose name.
|
||||||
|
Note: It has to be the same return value like in JavaScript.
|
||||||
|
"""
|
||||||
|
return '%s (%s)' % (self.title, _(self._meta.verbose_name))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def agenda_item(self):
|
def agenda_item(self):
|
||||||
"""
|
"""
|
||||||
|
@ -73,18 +73,21 @@ angular.module('OpenSlidesApp.assignments', [])
|
|||||||
'AssignmentPoll',
|
'AssignmentPoll',
|
||||||
'jsDataModel',
|
'jsDataModel',
|
||||||
'gettext',
|
'gettext',
|
||||||
function ($http, DS, AssignmentRelatedUser, AssignmentPoll, jsDataModel, gettext) {
|
'gettextCatalog',
|
||||||
|
function ($http, DS, AssignmentRelatedUser, AssignmentPoll, jsDataModel, gettext, gettextCatalog) {
|
||||||
var name = 'assignments/assignment';
|
var name = 'assignments/assignment';
|
||||||
var phases;
|
var phases;
|
||||||
return DS.defineResource({
|
return DS.defineResource({
|
||||||
name: name,
|
name: name,
|
||||||
useClass: jsDataModel,
|
useClass: jsDataModel,
|
||||||
verboseName: gettext('Election'),
|
verboseName: gettext('Election'),
|
||||||
agendaSupplement: gettext('Election'),
|
|
||||||
phases: phases,
|
phases: phases,
|
||||||
getPhases: function () {
|
getPhases: function () {
|
||||||
if (!this.phases) {
|
if (!this.phases) {
|
||||||
this.phases = $http({ 'method': 'OPTIONS', 'url': '/rest/assignments/assignment/' });
|
this.phases = $http({ 'method': 'OPTIONS', 'url': '/rest/assignments/assignment/' })
|
||||||
|
.then(function(phases) {
|
||||||
|
return phases.data.actions.POST.phase.choices;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return this.phases;
|
return this.phases;
|
||||||
},
|
},
|
||||||
|
@ -22,8 +22,16 @@ angular.module('OpenSlidesApp.assignments.projector', ['OpenSlidesApp.assignment
|
|||||||
// Add it to the coresponding get_requirements method of the ProjectorElement
|
// Add it to the coresponding get_requirements method of the ProjectorElement
|
||||||
// class.
|
// class.
|
||||||
var id = $scope.element.id;
|
var id = $scope.element.id;
|
||||||
Assignment.find(id);
|
|
||||||
|
// load assignemt object and related agenda item
|
||||||
|
Assignment.find(id).then(function(assignment) {
|
||||||
|
Assignment.loadRelations(assignment, 'agenda_item');
|
||||||
|
});
|
||||||
Assignment.bindOne(id, $scope, 'assignment');
|
Assignment.bindOne(id, $scope, 'assignment');
|
||||||
|
Assignment.getPhases().then(function(phases) {
|
||||||
|
$scope.phases = phases;
|
||||||
|
});
|
||||||
|
// load all users
|
||||||
User.findAll();
|
User.findAll();
|
||||||
User.bindAll({}, $scope, 'users');
|
User.bindAll({}, $scope, 'users');
|
||||||
}
|
}
|
||||||
|
@ -36,19 +36,21 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
|
|||||||
assignments: function(Assignment) {
|
assignments: function(Assignment) {
|
||||||
return Assignment.findAll();
|
return Assignment.findAll();
|
||||||
},
|
},
|
||||||
|
items: function(Agenda) {
|
||||||
|
return Agenda.findAll();
|
||||||
|
},
|
||||||
phases: function(Assignment) {
|
phases: function(Assignment) {
|
||||||
return Assignment.getPhases();
|
return Assignment.getPhases();
|
||||||
},
|
}
|
||||||
users: function(User) {
|
|
||||||
return User.findAll();
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.state('assignments.assignment.detail', {
|
.state('assignments.assignment.detail', {
|
||||||
controller: 'AssignmentDetailCtrl',
|
controller: 'AssignmentDetailCtrl',
|
||||||
resolve: {
|
resolve: {
|
||||||
assignment: function(Assignment, $stateParams) {
|
assignment: function(Assignment, $stateParams) {
|
||||||
return Assignment.find($stateParams.id);
|
return Assignment.find($stateParams.id).then(function(assignment) {
|
||||||
|
return Assignment.loadRelations(assignment, 'agenda_item');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
users: function(User) {
|
users: function(User) {
|
||||||
return User.findAll();
|
return User.findAll();
|
||||||
@ -172,8 +174,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
|
|||||||
'phases',
|
'phases',
|
||||||
function($scope, ngDialog, AssignmentForm, Assignment, phases) {
|
function($scope, ngDialog, AssignmentForm, Assignment, phases) {
|
||||||
Assignment.bindAll({}, $scope, 'assignments');
|
Assignment.bindAll({}, $scope, 'assignments');
|
||||||
// get all item types via OPTIONS request
|
$scope.phases = phases;
|
||||||
$scope.phases = phases.data.actions.POST.phase.choices;
|
|
||||||
$scope.alert = {};
|
$scope.alert = {};
|
||||||
|
|
||||||
// setup table sorting
|
// setup table sorting
|
||||||
@ -266,8 +267,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
|
|||||||
Assignment.bindOne(assignment.id, $scope, 'assignment');
|
Assignment.bindOne(assignment.id, $scope, 'assignment');
|
||||||
Assignment.loadRelations(assignment, 'agenda_item');
|
Assignment.loadRelations(assignment, 'agenda_item');
|
||||||
$scope.candidateSelectBox = {};
|
$scope.candidateSelectBox = {};
|
||||||
// get all item types via OPTIONS request
|
$scope.phases = phases;
|
||||||
$scope.phases = phases.data.actions.POST.phase.choices;
|
|
||||||
$scope.alert = {};
|
$scope.alert = {};
|
||||||
|
|
||||||
// open edit dialog
|
// open edit dialog
|
||||||
|
@ -28,13 +28,9 @@
|
|||||||
<i class="fa fa-pencil"></i>
|
<i class="fa fa-pencil"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<h1>{{ assignment.title }}</h1>
|
<h1>{{ assignment.agenda_item.getTitle() }}</h1>
|
||||||
<h2>
|
<h2>
|
||||||
<translate>Election</translate>
|
<translate>Election</translate>
|
||||||
<span ng-if="assignment.agenda_item.item_number">
|
|
||||||
–
|
|
||||||
<translate>Agenda</translate>: {{ assignment.agenda_item.item_number }}
|
|
||||||
</span>
|
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,19 +80,33 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<!-- projector column -->
|
<!-- projector column -->
|
||||||
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="minimum">
|
<th ng-show="!isDeleteMode" os-perms="core.can_manage_projector" class="minimum">
|
||||||
|
|
||||||
<!-- delete selection column -->
|
<!-- delete selection column -->
|
||||||
<th ng-show="isDeleteMode" os-perms="assignments.can_manage" class="minimum deleteColumn">
|
<th ng-show="isDeleteMode" os-perms="assignments.can_manage" class="minimum deleteColumn">
|
||||||
<input type="checkbox" ng-model="$parent.selectedAll" ng-change="checkAll()">
|
<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">
|
<th ng-click="toggleSort('title')" class="sortable">
|
||||||
<translate>Title</translate>
|
<translate>Title</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'title' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'title' && header.sortable != false"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
<!-- candicates / posts column -->
|
||||||
<th ng-click="toggleSort('open_posts')" class="sortable optional">
|
<th ng-click="toggleSort('open_posts')" class="sortable optional">
|
||||||
<translate>Candidates</translate> · <translate>Posts</translate>
|
<translate>Candidates</translate> · <translate>Posts</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'open_posts' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'open_posts' && header.sortable != false"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
<!-- phase column -->
|
||||||
<th ng-click="toggleSort('phase')" class="sortable optional">
|
<th ng-click="toggleSort('phase')" class="sortable optional">
|
||||||
<translate>Phase</translate>
|
<translate>Phase</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'phase' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'phase' && header.sortable != false"
|
||||||
@ -103,7 +117,8 @@
|
|||||||
filter: {phase: phaseFilter} | orderBy: sortColumn:reverse)"
|
filter: {phase: phaseFilter} | orderBy: sortColumn:reverse)"
|
||||||
class="animate-item"
|
class="animate-item"
|
||||||
ng-class="{ 'activeline': assignment.isProjected(), 'selected': assignment.selected }">
|
ng-class="{ 'activeline': assignment.isProjected(), 'selected': assignment.selected }">
|
||||||
<!-- projector column -->
|
|
||||||
|
<!-- projector -->
|
||||||
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
|
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
|
||||||
<a class="btn btn-default btn-sm"
|
<a class="btn btn-default btn-sm"
|
||||||
ng-class="{ 'btn-primary': assignment.isProjected() }"
|
ng-class="{ 'btn-primary': assignment.isProjected() }"
|
||||||
@ -111,10 +126,16 @@
|
|||||||
title="{{ 'Project election' | translate }}">
|
title="{{ 'Project election' | translate }}">
|
||||||
<i class="fa fa-video-camera"></i>
|
<i class="fa fa-video-camera"></i>
|
||||||
</a>
|
</a>
|
||||||
<!-- delete selection column -->
|
|
||||||
|
<!-- delete selection -->
|
||||||
<td ng-show="isDeleteMode" os-perms="assignments.can_manage" class="deleteColumn">
|
<td ng-show="isDeleteMode" os-perms="assignments.can_manage" class="deleteColumn">
|
||||||
<input type="checkbox" ng-model="assignment.selected">
|
<input type="checkbox" ng-model="assignment.selected">
|
||||||
<!-- assignment data colums -->
|
|
||||||
|
<!-- 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">
|
<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>
|
<strong><a ui-sref="assignments.assignment.detail({id: assignment.id})">{{ assignment.title }}</a></strong>
|
||||||
<div os-perms="assignments.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !assignment.hover}">
|
<div os-perms="assignments.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !assignment.hover}">
|
||||||
@ -125,16 +146,21 @@
|
|||||||
<b>{{ assignment.title }}</b>"
|
<b>{{ assignment.title }}</b>"
|
||||||
ng-bootbox-confirm-action="delete(assignment)" translate>Delete</a>
|
ng-bootbox-confirm-action="delete(assignment)" translate>Delete</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- candidates / posts -->
|
||||||
<td ng-if="!assignment.quickEdit" class="optional">
|
<td ng-if="!assignment.quickEdit" class="optional">
|
||||||
<span class="badge">{{ assignment.assignment_related_users.length }}</span>
|
<span class="badge">{{ assignment.assignment_related_users.length }}</span>
|
||||||
/
|
/
|
||||||
<span class="badge">{{ assignment.open_posts }}</span>
|
<span class="badge">{{ assignment.open_posts }}</span>
|
||||||
|
|
||||||
|
<!-- phase -->
|
||||||
<td ng-if="!assignment.quickEdit" class="optional">
|
<td ng-if="!assignment.quickEdit" class="optional">
|
||||||
<span class="label" ng-class="{'label-primary': assignment.phase == 0,
|
<span class="label" ng-class="{'label-primary': assignment.phase == 0,
|
||||||
'label-warning': assignment.phase == 1,
|
'label-warning': assignment.phase == 1,
|
||||||
'label-success': assignment.phase == 2 }">
|
'label-success': assignment.phase == 2 }">
|
||||||
{{ phases[assignment.phase].display_name }}
|
{{ phases[assignment.phase].display_name }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- quickEdit columns -->
|
<!-- quickEdit columns -->
|
||||||
<td ng-if="assignment.quickEdit" colspan="3">
|
<td ng-if="assignment.quickEdit" colspan="3">
|
||||||
<h4>{{ assignment.title }} <span class="text-muted">– Quick Edit</span></h4>
|
<h4>{{ assignment.title }} <span class="text-muted">– Quick Edit</span></h4>
|
||||||
|
@ -1,9 +1,28 @@
|
|||||||
<div ng-controller="SlideAssignmentCtrl" class="content scrollcontent">
|
<div ng-controller="SlideAssignmentCtrl" class="content scrollcontent">
|
||||||
<h1>{{ assignment.title }}</h1>
|
|
||||||
|
<div id="sidebox">
|
||||||
|
<!-- Phase -->
|
||||||
|
<h3 translate>State</h3>
|
||||||
|
{{ phases[assignment.phase].display_name }}
|
||||||
|
|
||||||
|
<!-- Posts -->
|
||||||
|
<h3 translate>Posts</h3>
|
||||||
|
{{ assignment.open_posts }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<div id="title">
|
||||||
|
<h1>{{ assignment.agenda_item.getTitle() }}</h1>
|
||||||
|
<h2>
|
||||||
|
<translate>Election</translate>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
<div class="white-space-pre-line">{{ assignment.description }}</div>
|
<div class="white-space-pre-line">{{ assignment.description }}</div>
|
||||||
|
|
||||||
<!-- candidates -->
|
<!-- Candidates -->
|
||||||
<h2 translate>Candidates</h2>
|
<h3 translate>Candidates</h3>
|
||||||
<ol>
|
<ol>
|
||||||
<li ng-repeat="related_user in assignment.assignment_related_users">
|
<li ng-repeat="related_user in assignment.assignment_related_users">
|
||||||
{{ related_user.user.get_full_name() }}
|
{{ related_user.user.get_full_name() }}
|
||||||
|
21
openslides/core/migrations/0003_auto_20160125_2138.py
Normal file
21
openslides/core/migrations/0003_auto_20160125_2138.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0002_customslide_attachments'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='projector',
|
||||||
|
options={'default_permissions': (), 'permissions': (
|
||||||
|
('can_see_projector', 'Can see the projector'),
|
||||||
|
('can_manage_projector', 'Can manage the projector'),
|
||||||
|
('can_see_frontpage', 'Can see the front page'))},
|
||||||
|
),
|
||||||
|
]
|
@ -66,7 +66,7 @@ class Projector(RESTModelMixin, models.Model):
|
|||||||
permissions = (
|
permissions = (
|
||||||
('can_see_projector', ugettext_noop('Can see the projector')),
|
('can_see_projector', ugettext_noop('Can see the projector')),
|
||||||
('can_manage_projector', ugettext_noop('Can manage the projector')),
|
('can_manage_projector', ugettext_noop('Can manage the projector')),
|
||||||
('can_see_dashboard', ugettext_noop('Can see the dashboard')))
|
('can_see_frontpage', ugettext_noop('Can see the front page')))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def elements(self):
|
def elements(self):
|
||||||
@ -159,6 +159,9 @@ class CustomSlide(RESTModelMixin, models.Model):
|
|||||||
def get_agenda_title(self):
|
def get_agenda_title(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
def get_agenda_list_view_title(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
def get_search_index_string(self):
|
def get_search_index_string(self):
|
||||||
"""
|
"""
|
||||||
Returns a string that can be indexed for the search.
|
Returns a string that can be indexed for the search.
|
||||||
|
@ -102,7 +102,7 @@ h2 {
|
|||||||
}
|
}
|
||||||
h3 {
|
h3 {
|
||||||
color: #222;
|
color: #222;
|
||||||
margin-bottom: 2px
|
margin-bottom: 10px
|
||||||
}
|
}
|
||||||
#title {
|
#title {
|
||||||
width: calc(100% - 230px);
|
width: calc(100% - 230px);
|
||||||
|
@ -89,7 +89,9 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
|
|||||||
// Add it to the coresponding get_requirements method of the ProjectorElement
|
// Add it to the coresponding get_requirements method of the ProjectorElement
|
||||||
// class.
|
// class.
|
||||||
var id = $scope.element.id;
|
var id = $scope.element.id;
|
||||||
Customslide.find(id);
|
Customslide.find(id).then(function(customslide) {
|
||||||
|
Customslide.loadRelations(customslide, 'agenda_item');
|
||||||
|
});
|
||||||
Customslide.bindOne(id, $scope, 'customslide');
|
Customslide.bindOne(id, $scope, 'customslide');
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
@ -68,7 +68,7 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
'gettext',
|
'gettext',
|
||||||
function (mainMenuProvider, gettext) {
|
function (mainMenuProvider, gettext) {
|
||||||
mainMenuProvider.register({
|
mainMenuProvider.register({
|
||||||
'ui_sref': 'dashboard',
|
'ui_sref': 'home',
|
||||||
'img_class': 'home',
|
'img_class': 'home',
|
||||||
'title': gettext('Home'),
|
'title': gettext('Home'),
|
||||||
'weight': 100,
|
'weight': 100,
|
||||||
@ -193,9 +193,9 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
function($stateProvider, $locationProvider) {
|
function($stateProvider, $locationProvider) {
|
||||||
// Core urls
|
// Core urls
|
||||||
$stateProvider
|
$stateProvider
|
||||||
.state('dashboard', {
|
.state('home', {
|
||||||
url: '/',
|
url: '/',
|
||||||
templateUrl: 'static/templates/dashboard.html'
|
templateUrl: 'static/templates/home.html'
|
||||||
})
|
})
|
||||||
.state('projector', {
|
.state('projector', {
|
||||||
url: '/projector',
|
url: '/projector',
|
||||||
@ -556,11 +556,11 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'showOnAgenda',
|
key: 'showAsAgendaItem',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
templateOptions: {
|
templateOptions: {
|
||||||
label: gettextCatalog.getString('Show on agenda'),
|
label: gettextCatalog.getString('Show as agenda item'),
|
||||||
description: gettextCatalog.getString('If deactivated it appears as internal item.')
|
description: gettextCatalog.getString('If deactivated it appears as internal item on agenda.')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -791,6 +791,8 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
'Agenda',
|
'Agenda',
|
||||||
function($scope, $state, Customslide, CustomslideForm, Agenda) {
|
function($scope, $state, Customslide, CustomslideForm, Agenda) {
|
||||||
$scope.customslide = {};
|
$scope.customslide = {};
|
||||||
|
$scope.model = {};
|
||||||
|
$scope.model.showAsAgendaItem = true;
|
||||||
// get all form fields
|
// get all form fields
|
||||||
$scope.formFields = CustomslideForm.getFormFields();
|
$scope.formFields = CustomslideForm.getFormFields();
|
||||||
|
|
||||||
@ -798,14 +800,16 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
$scope.save = function (customslide) {
|
$scope.save = function (customslide) {
|
||||||
Customslide.create(customslide).then(
|
Customslide.create(customslide).then(
|
||||||
function(success) {
|
function(success) {
|
||||||
// show as agenda item
|
// find related agenda item
|
||||||
if (customslide.showOnAgenda) {
|
Agenda.find(success.agenda_item_id).then(function(item) {
|
||||||
Agenda.find(success.agenda_item_id).then(function(item) {
|
// check form element and set item type (AGENDA_ITEM = 1, HIDDEN_ITEM = 2)
|
||||||
// set item type to AGENDA_ITEM = 1 (default is HIDDEN_ITEM = 2)
|
var type = customslide.showAsAgendaItem ? 1 : 2;
|
||||||
item.type = 1;
|
// save only if agenda item type is modified
|
||||||
|
if (item.type != type) {
|
||||||
|
item.type = type;
|
||||||
Agenda.save(item);
|
Agenda.save(item);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
$scope.closeThisDialog();
|
$scope.closeThisDialog();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -818,14 +822,21 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
'$state',
|
'$state',
|
||||||
'Customslide',
|
'Customslide',
|
||||||
'CustomslideForm',
|
'CustomslideForm',
|
||||||
|
'Agenda',
|
||||||
'customslide',
|
'customslide',
|
||||||
function($scope, $state, Customslide, CustomslideForm, customslide) {
|
function($scope, $state, Customslide, CustomslideForm, Agenda, customslide) {
|
||||||
$scope.alert = {};
|
$scope.alert = {};
|
||||||
// set initial values for form model by create deep copy of customslide object
|
// set initial values for form model by create deep copy of customslide object
|
||||||
// so list/detail view is not updated while editing
|
// so list/detail view is not updated while editing
|
||||||
$scope.model = angular.copy(customslide);
|
$scope.model = angular.copy(customslide);
|
||||||
// get all form fields
|
// get all form fields
|
||||||
$scope.formFields = CustomslideForm.getFormFields();
|
$scope.formFields = CustomslideForm.getFormFields();
|
||||||
|
for (var i = 0; i < $scope.formFields.length; i++) {
|
||||||
|
if ($scope.formFields[i].key == "showAsAgendaItem") {
|
||||||
|
// get state from agenda item (hidden/internal or agenda item)
|
||||||
|
$scope.formFields[i].defaultValue = !customslide.agenda_item.is_hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// save form
|
// save form
|
||||||
$scope.save = function (customslide) {
|
$scope.save = function (customslide) {
|
||||||
@ -834,6 +845,12 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
// save change customslide object on server
|
// save change customslide object on server
|
||||||
Customslide.save(customslide).then(
|
Customslide.save(customslide).then(
|
||||||
function(success) {
|
function(success) {
|
||||||
|
// save agenda specific stuff
|
||||||
|
var type = customslide.showAsAgendaItem ? 1 : 2;
|
||||||
|
if (customslide.agenda_item.type != type) {
|
||||||
|
customslide.agenda_item.type = type;
|
||||||
|
Agenda.save(customslide.agenda_item);
|
||||||
|
}
|
||||||
$scope.closeThisDialog();
|
$scope.closeThisDialog();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<i class="fa toggle-icon" ng-class="isLiveViewClosed ? 'fa-angle-up' : 'fa-angle-down'"></i>
|
<i class="fa toggle-icon" ng-class="isLiveViewClosed ? 'fa-angle-up' : 'fa-angle-down'"></i>
|
||||||
<h4 translate>Live view</h4>
|
<h4 translate>Live view</h4>
|
||||||
</a>
|
</a>
|
||||||
<div uib-collapse="isLiveViewClosed">
|
<div uib-collapse="isLiveViewClosed" ng-cloak>
|
||||||
<a ui-sref="projector" target="_blank">
|
<a ui-sref="projector" target="_blank">
|
||||||
<div id="iframewrapper">
|
<div id="iframewrapper">
|
||||||
<iframe id="iframe" src="/projector" frameborder="0"></iframe>
|
<iframe id="iframe" src="/projector" frameborder="0"></iframe>
|
||||||
@ -61,7 +61,7 @@
|
|||||||
<i class="fa toggle-icon" ng-class="isCountdowns ? 'fa-angle-up' : 'fa-angle-down'"></i>
|
<i class="fa toggle-icon" ng-class="isCountdowns ? 'fa-angle-up' : 'fa-angle-down'"></i>
|
||||||
<h4 translate>Countdowns</h4>
|
<h4 translate>Countdowns</h4>
|
||||||
</a>
|
</a>
|
||||||
<div uib-collapse="!isCountdowns">
|
<div uib-collapse="!isCountdowns" ng-cloak>
|
||||||
<div ng-repeat="countdown in countdowns | orderBy: 'index'" id="{{countdown.uuid}}"
|
<div ng-repeat="countdown in countdowns | orderBy: 'index'" id="{{countdown.uuid}}"
|
||||||
class="countdown panel panel-default">
|
class="countdown panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@ -153,7 +153,7 @@
|
|||||||
<i class="fa toggle-icon" ng-class="isMessages ? 'fa-angle-up' : 'fa-angle-down'"></i>
|
<i class="fa toggle-icon" ng-class="isMessages ? 'fa-angle-up' : 'fa-angle-down'"></i>
|
||||||
<h4 translate>Messages</h4>
|
<h4 translate>Messages</h4>
|
||||||
</a>
|
</a>
|
||||||
<div uib-collapse="!isMessages">
|
<div uib-collapse="!isMessages" ng-cloak>
|
||||||
<div ng-repeat="message in messages | orderBy: 'index'" id="{{message.uuid}}" class="message panel panel-default">
|
<div ng-repeat="message in messages | orderBy: 'index'" id="{{message.uuid}}" class="message panel panel-default">
|
||||||
<div class="panel-body"
|
<div class="panel-body"
|
||||||
ng-class="{ 'projected': message.visible }">
|
ng-class="{ 'projected': message.visible }">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div ng-controller="SlideCustomSlideCtrl" class="content scrollcontent">
|
<div ng-controller="SlideCustomSlideCtrl" class="content scrollcontent">
|
||||||
<h1>{{ customslide.title }}</h1>
|
<h1>{{ customslide.agenda_item.getTitle() }}</h1>
|
||||||
<div ng-bind-html="customslide.text"></div>
|
<div ng-bind-html="customslide.text"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="no-js"> <!-- TODO: make lang dynamic -->
|
<html ng-controller="LanguageCtrl" lang="{{ selectedLanguage[0].code }}" class="no-js">
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<base href="/">
|
<base href="/">
|
||||||
@ -11,17 +11,17 @@
|
|||||||
<link rel="icon" href="/static/img/favicon.png">
|
<link rel="icon" href="/static/img/favicon.png">
|
||||||
<script src="static/js/openslides-libs.js"></script>
|
<script src="static/js/openslides-libs.js"></script>
|
||||||
<script src="static/ckeditor/ckeditor.js"></script>
|
<script src="static/ckeditor/ckeditor.js"></script>
|
||||||
<div id="wrapper">
|
|
||||||
|
<div id="wrapper" ng-cloak>
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div class="containerOS">
|
<div class="containerOS">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<a ui-sref="dashboard">
|
<a ui-sref="home">
|
||||||
<img src="/static/img/openslides-logo-dark.png" alt="Logo" height="35">
|
<img src="/static/img/openslides-logo-dark.png" alt="Logo" height="35">
|
||||||
</a>
|
</a>
|
||||||
<!-- TODO: <span class="navbar-text optional">{{ config('general_event_name') }}</span>-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- user specific header (chat, user settings / login, language)-->
|
<!-- user specific header (chat, user settings / login, language)-->
|
||||||
@ -104,7 +104,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- language switcher -->
|
<!-- language switcher -->
|
||||||
<span ng-controller="LanguageCtrl" uib-dropdown>
|
<span uib-dropdown>
|
||||||
| <a href class="headerlink" uib-dropdown-toggle>
|
| <a href class="headerlink" uib-dropdown-toggle>
|
||||||
<i class="fa fa-flag"></i>
|
<i class="fa fa-flag"></i>
|
||||||
{{ selectedLanguage[0].name | translate }}
|
{{ selectedLanguage[0].name | translate }}
|
||||||
@ -157,7 +157,7 @@
|
|||||||
<div class="containerOS">
|
<div class="containerOS">
|
||||||
<div class="col1" ng-class="isProjectorSidebar ? 'min' : 'max'">
|
<div class="col1" ng-class="isProjectorSidebar ? 'min' : 'max'">
|
||||||
<!-- dynamic views -->
|
<!-- dynamic views -->
|
||||||
<div ui-view></div>
|
<div ui-view ng-cloak></div>
|
||||||
<!-- footer -->
|
<!-- footer -->
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
© Copyright by <a href="http://www.openslides.org" target="_blank">OpenSlides</a> |
|
© Copyright by <a href="http://www.openslides.org" target="_blank">OpenSlides</a> |
|
||||||
|
23
openslides/core/static/templates/search.html
Normal file
23
openslides/core/static/templates/search.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
<h1 translate>Search results</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="details">
|
||||||
|
<form class="input-group" ng-submit="search(query)">
|
||||||
|
<input type="text" ng-model="query" class="form-control">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button type="submit" class="btn btn-default" translate>Search</button>
|
||||||
|
</span>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="searchresults spacer-top-lg">
|
||||||
|
<ol ng-show="results">
|
||||||
|
<li ng-repeat="result in results">
|
||||||
|
<a ui-sref="{{ result.urlState }}({{ result.urlParam }})">{{ result.getSearchResultName() }}</a><br>
|
||||||
|
<span class="grey">{{ result.getSearchResultSubtitle() | translate }}</span>
|
||||||
|
</ol>
|
||||||
|
<p ng-show="!results" translate>No results.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -125,13 +125,9 @@ class Motion(RESTModelMixin, models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
Return a human readable name of this motion.
|
Return the title of this motion.
|
||||||
"""
|
"""
|
||||||
if self.identifier:
|
return self.title
|
||||||
string = '%s: %s' % (self.identifier, self.title)
|
|
||||||
else:
|
|
||||||
string = self.title
|
|
||||||
return string
|
|
||||||
|
|
||||||
# TODO: Use transaction
|
# TODO: Use transaction
|
||||||
def save(self, use_version=None, *args, **kwargs):
|
def save(self, use_version=None, *args, **kwargs):
|
||||||
@ -464,11 +460,25 @@ class Motion(RESTModelMixin, models.Model):
|
|||||||
|
|
||||||
def get_agenda_title(self):
|
def get_agenda_title(self):
|
||||||
"""
|
"""
|
||||||
Return a title for the agenda.
|
Return a simple title string for the agenda.
|
||||||
|
|
||||||
|
Contains only agenda item number and title.
|
||||||
"""
|
"""
|
||||||
# There has to be a function with the same return value in javascript.
|
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
def get_agenda_list_view_title(self):
|
||||||
|
"""
|
||||||
|
Return a title string for the agenda list view.
|
||||||
|
|
||||||
|
Contains agenda item number, title and motion identifier.
|
||||||
|
Note: It has to be the same return value like in JavaScript.
|
||||||
|
"""
|
||||||
|
if self.identifier:
|
||||||
|
string = '%s (%s %s)' % (self.title, _(self._meta.verbose_name), self.identifier)
|
||||||
|
else:
|
||||||
|
string = '%s (%s)' % (self.title, _(self._meta.verbose_name))
|
||||||
|
return string
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def agenda_item(self):
|
def agenda_item(self):
|
||||||
"""
|
"""
|
||||||
|
@ -161,15 +161,15 @@ angular.module('OpenSlidesApp.motions', ['OpenSlidesApp.users'])
|
|||||||
'MotionPoll',
|
'MotionPoll',
|
||||||
'jsDataModel',
|
'jsDataModel',
|
||||||
'gettext',
|
'gettext',
|
||||||
|
'gettextCatalog',
|
||||||
'operator',
|
'operator',
|
||||||
'Config',
|
'Config',
|
||||||
function(DS, MotionPoll, jsDataModel, gettext, operator, Config) {
|
function(DS, MotionPoll, jsDataModel, gettext, gettextCatalog, operator, Config) {
|
||||||
var name = 'motions/motion';
|
var name = 'motions/motion';
|
||||||
return DS.defineResource({
|
return DS.defineResource({
|
||||||
name: name,
|
name: name,
|
||||||
useClass: jsDataModel,
|
useClass: jsDataModel,
|
||||||
verboseName: gettext('Motion'),
|
verboseName: gettext('Motion'),
|
||||||
agendaSupplement: gettext('Motion'),
|
|
||||||
methods: {
|
methods: {
|
||||||
getResourceName: function () {
|
getResourceName: function () {
|
||||||
return name;
|
return name;
|
||||||
@ -195,16 +195,9 @@ angular.module('OpenSlidesApp.motions', ['OpenSlidesApp.users'])
|
|||||||
getReason: function (versionId) {
|
getReason: function (versionId) {
|
||||||
return this.getVersion(versionId).reason;
|
return this.getVersion(versionId).reason;
|
||||||
},
|
},
|
||||||
getAgendaTitle: function () {
|
|
||||||
var value = '';
|
|
||||||
if (this.identifier) {
|
|
||||||
value = ' ' + this.identifier;
|
|
||||||
}
|
|
||||||
return "Motion " + value + ': ' + this.getTitle();
|
|
||||||
},
|
|
||||||
// link name which is shown in search result
|
// link name which is shown in search result
|
||||||
getSearchResultName: function () {
|
getSearchResultName: function () {
|
||||||
return this.getAgendaTitle();
|
return this.getTitle();
|
||||||
},
|
},
|
||||||
// subtitle of search result
|
// subtitle of search result
|
||||||
getSearchResultSubtitle: function () {
|
getSearchResultSubtitle: function () {
|
||||||
|
@ -22,9 +22,16 @@ angular.module('OpenSlidesApp.motions.projector', ['OpenSlidesApp.motions'])
|
|||||||
// Add it to the coresponding get_requirements method of the ProjectorElement
|
// Add it to the coresponding get_requirements method of the ProjectorElement
|
||||||
// class.
|
// class.
|
||||||
var id = $scope.element.id;
|
var id = $scope.element.id;
|
||||||
Motion.find(id);
|
|
||||||
User.findAll();
|
// load motion object and related agenda item
|
||||||
|
Motion.find(id).then(function(motion) {
|
||||||
|
Motion.loadRelations(motion, 'agenda_item');
|
||||||
|
});
|
||||||
Motion.bindOne(id, $scope, 'motion');
|
Motion.bindOne(id, $scope, 'motion');
|
||||||
|
|
||||||
|
// load all users
|
||||||
|
User.findAll();
|
||||||
|
User.bindAll({}, $scope, 'users');
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -34,7 +34,12 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
|
|||||||
.state('motions.motion.list', {
|
.state('motions.motion.list', {
|
||||||
resolve: {
|
resolve: {
|
||||||
motions: function(Motion) {
|
motions: function(Motion) {
|
||||||
return Motion.findAll();
|
return Motion.findAll().then(function(motions) {
|
||||||
|
angular.forEach(motions, function(motion) {
|
||||||
|
Motion.loadRelations(motion, 'agenda_item');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
categories: function(Category) {
|
categories: function(Category) {
|
||||||
return Category.findAll();
|
return Category.findAll();
|
||||||
@ -53,7 +58,9 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
|
|||||||
.state('motions.motion.detail', {
|
.state('motions.motion.detail', {
|
||||||
resolve: {
|
resolve: {
|
||||||
motion: function(Motion, $stateParams) {
|
motion: function(Motion, $stateParams) {
|
||||||
return Motion.find($stateParams.id);
|
return Motion.find($stateParams.id).then(function(motion) {
|
||||||
|
return Motion.loadRelations(motion, 'agenda_item');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
categories: function(Category) {
|
categories: function(Category) {
|
||||||
return Category.findAll();
|
return Category.findAll();
|
||||||
@ -85,7 +92,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
|
|||||||
resolve: {
|
resolve: {
|
||||||
motion: function() {
|
motion: function() {
|
||||||
return Motion.find($stateParams.id).then(function(motion) {
|
return Motion.find($stateParams.id).then(function(motion) {
|
||||||
return Motion.loadRelations(motion, 'agenda_item');
|
Motion.loadRelations(motion, 'agenda_item');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
<i class="fa fa-pencil"></i>
|
<i class="fa fa-pencil"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<h1>{{ motion.getTitle(version) }}</h1>
|
<h1>{{ motion.agenda_item.getTitle() }}</h1>
|
||||||
<h2>
|
<h2>
|
||||||
<translate>Motion</translate> {{ motion.identifier }}
|
<translate>Motion</translate> {{ motion.identifier }}
|
||||||
<span ng-if="motion.versions.length > 1" >| Version {{ motion.getVersion(version).version_number }}</span>
|
<span ng-if="motion.versions.length > 1" >| Version {{ motion.getVersion(version).version_number }}</span>
|
||||||
@ -36,10 +36,6 @@
|
|||||||
<i class="fa fa-exclamation-triangle"></i>
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
<translate>This version is not permitted.</translate>
|
<translate>This version is not permitted.</translate>
|
||||||
</span>
|
</span>
|
||||||
<span ng-if="motion.agenda_item.item_number">
|
|
||||||
–
|
|
||||||
<translate>Agenda</translate>: {{ motion.agenda_item.item_number }}
|
|
||||||
</span>
|
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -89,26 +89,42 @@
|
|||||||
<!-- delete selection column -->
|
<!-- delete selection column -->
|
||||||
<th ng-show="$parent.isDeleteMode" os-perms="motions.can_manage" class="minimum deleteColumn">
|
<th ng-show="$parent.isDeleteMode" os-perms="motions.can_manage" class="minimum deleteColumn">
|
||||||
<input type="checkbox" ng-model="$parent.selectedAll" ng-change="checkAll()">
|
<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>
|
||||||
|
<!-- identifier column -->
|
||||||
<th ng-click="toggleSort('identifier')" class="sortable minimum">
|
<th ng-click="toggleSort('identifier')" class="sortable minimum">
|
||||||
<translate>Identifier</translate>
|
<translate>Identifier</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
<!-- title column -->
|
||||||
<th ng-click="toggleSort('getTitle()')" class="sortable">
|
<th ng-click="toggleSort('getTitle()')" class="sortable">
|
||||||
<translate>Title</translate>
|
<translate>Title</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'getTitle()' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'getTitle()' && header.sortable != false"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
<!-- submitters column -->
|
||||||
<th ng-click="toggleSort('submitters')" class="sortable optional">
|
<th ng-click="toggleSort('submitters')" class="sortable optional">
|
||||||
<translate>Submitters</translate>
|
<translate>Submitters</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'submitters' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'submitters' && header.sortable != false"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
<!-- category column -->
|
||||||
<th ng-click="toggleSort('category')" class="sortable optional">
|
<th ng-click="toggleSort('category')" class="sortable optional">
|
||||||
<translate>Category</translate>
|
<translate>Category</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
|
<!-- state column -->
|
||||||
<th ng-click="toggleSort('state.name')" class="sortable optional">
|
<th ng-click="toggleSort('state.name')" class="sortable optional">
|
||||||
<translate>State</translate>
|
<translate>State</translate>
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'state.name' && header.sortable != false"
|
<i class="pull-right fa" ng-show="sortColumn === 'state.name' && header.sortable != false"
|
||||||
@ -119,7 +135,8 @@
|
|||||||
filter: {state_id: stateFilter} | orderBy: sortColumn:reverse)"
|
filter: {state_id: stateFilter} | orderBy: sortColumn:reverse)"
|
||||||
class="animate-item"
|
class="animate-item"
|
||||||
ng-class="{ 'activeline': motion.isProjected(), 'selected': motion.selected }">
|
ng-class="{ 'activeline': motion.isProjected(), 'selected': motion.selected }">
|
||||||
<!-- projector column -->
|
|
||||||
|
<!-- projector -->
|
||||||
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
|
<td ng-show="!isDeleteMode" os-perms="core.can_manage_projector">
|
||||||
<a class="btn btn-default btn-sm"
|
<a class="btn btn-default btn-sm"
|
||||||
ng-class="{ 'btn-primary': motion.isProjected() }"
|
ng-class="{ 'btn-primary': motion.isProjected() }"
|
||||||
@ -127,11 +144,18 @@
|
|||||||
title="{{ 'Project motion' | translate }}">
|
title="{{ 'Project motion' | translate }}">
|
||||||
<i class="fa fa-video-camera"></i>
|
<i class="fa fa-video-camera"></i>
|
||||||
</a>
|
</a>
|
||||||
<!-- delete selection column -->
|
|
||||||
|
<!-- delete selection -->
|
||||||
<td ng-show="isDeleteMode" os-perms="motions.can_manage" class="deleteColumn">
|
<td ng-show="isDeleteMode" os-perms="motions.can_manage" class="deleteColumn">
|
||||||
<input type="checkbox" ng-model="motion.selected">
|
<input type="checkbox" ng-model="motion.selected">
|
||||||
<!-- motion data colums -->
|
|
||||||
|
<!-- agenda item number -->
|
||||||
|
<td ng-if="!motion.quickEdit">{{ motion.agenda_item.item_number }}
|
||||||
|
|
||||||
|
<!-- identifier -->
|
||||||
<td ng-if="!motion.quickEdit">{{ motion.identifier }}
|
<td ng-if="!motion.quickEdit">{{ motion.identifier }}
|
||||||
|
|
||||||
|
<!-- title -->
|
||||||
<td ng-if="!motion.quickEdit" ng-mouseover="motion.hover=true" ng-mouseleave="motion.hover=false">
|
<td ng-if="!motion.quickEdit" ng-mouseover="motion.hover=true" ng-mouseleave="motion.hover=false">
|
||||||
<strong><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.getTitle() }}</a></strong>
|
<strong><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.getTitle() }}</a></strong>
|
||||||
<span ng-repeat="tag in motion.tags" class="label label-default">
|
<span ng-repeat="tag in motion.tags" class="label label-default">
|
||||||
@ -151,16 +175,23 @@
|
|||||||
ng-bootbox-confirm-action="delete(motion)" translate>Delete</a>
|
ng-bootbox-confirm-action="delete(motion)" translate>Delete</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- submitters -->
|
||||||
<td ng-if="!motion.quickEdit" class="optional">
|
<td ng-if="!motion.quickEdit" class="optional">
|
||||||
<div ng-repeat="submitter in motion.submitters">
|
<div ng-repeat="submitter in motion.submitters">
|
||||||
{{ submitter.get_full_name() }}<br>
|
{{ submitter.get_full_name() }}<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- category -->
|
||||||
<td ng-if="!motion.quickEdit" class="optional">
|
<td ng-if="!motion.quickEdit" class="optional">
|
||||||
{{ motion.category.name }}
|
{{ motion.category.name }}
|
||||||
|
|
||||||
|
<!-- state -->
|
||||||
<td ng-if="!motion.quickEdit" class="optional">
|
<td ng-if="!motion.quickEdit" class="optional">
|
||||||
<span class="label" ng-class="'label-'+motion.state.css_class">
|
<span class="label" ng-class="'label-'+motion.state.css_class">
|
||||||
{{ motion.state.name | translate }}
|
{{ motion.state.name | translate }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- quickEdit columns -->
|
<!-- quickEdit columns -->
|
||||||
<td ng-if="motion.quickEdit && motion.isAllowed('quickedit')" colspan="5">
|
<td ng-if="motion.quickEdit && motion.isAllowed('quickedit')" colspan="5">
|
||||||
<h4>{{ motion.getTitle() }} <span class="text-muted">– <translate>QuickEdit</translate></span></h4>
|
<h4>{{ motion.getTitle() }} <span class="text-muted">– <translate>QuickEdit</translate></span></h4>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<div id="title">
|
<div id="title">
|
||||||
<h1>{{ motion.getTitle() }}</h1>
|
<h1>{{ motion.agenda_item.getTitle() }}</h1>
|
||||||
<h2>
|
<h2>
|
||||||
<translate>Motion</translate> {{ motion.identifier }}
|
<translate>Motion</translate> {{ motion.identifier }}
|
||||||
<span ng-if="motion.versions.length > 1" >| Version {{ motion.getVersion().version_number }}</span>
|
<span ng-if="motion.versions.length > 1" >| Version {{ motion.getVersion().version_number }}</span>
|
||||||
@ -25,6 +25,6 @@
|
|||||||
<div ng-bind-html="motion.getText()"></div>
|
<div ng-bind-html="motion.getText()"></div>
|
||||||
|
|
||||||
<!-- Reason -->
|
<!-- Reason -->
|
||||||
<h2 ng-if="motion.getReason()" translate>Reason</h2>
|
<h3 ng-if="motion.getReason()" translate>Reason</h3>
|
||||||
<div ng-bind-html="motion.getReason()"></div>
|
<div ng-bind-html="motion.getReason()"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,7 +113,7 @@ def create_builtin_groups_and_admin(**kwargs):
|
|||||||
'core.can_manage_config',
|
'core.can_manage_config',
|
||||||
'core.can_manage_projector',
|
'core.can_manage_projector',
|
||||||
'core.can_manage_tags',
|
'core.can_manage_tags',
|
||||||
'core.can_see_dashboard',
|
'core.can_see_frontpage',
|
||||||
'core.can_see_projector',
|
'core.can_see_projector',
|
||||||
'core.can_use_chat',
|
'core.can_use_chat',
|
||||||
'mediafiles.can_manage',
|
'mediafiles.can_manage',
|
||||||
@ -143,7 +143,7 @@ def create_builtin_groups_and_admin(**kwargs):
|
|||||||
permission_dict['agenda.can_see'],
|
permission_dict['agenda.can_see'],
|
||||||
permission_dict['agenda.can_see_hidden_items'],
|
permission_dict['agenda.can_see_hidden_items'],
|
||||||
permission_dict['assignments.can_see'],
|
permission_dict['assignments.can_see'],
|
||||||
permission_dict['core.can_see_dashboard'],
|
permission_dict['core.can_see_frontpage'],
|
||||||
permission_dict['core.can_see_projector'],
|
permission_dict['core.can_see_projector'],
|
||||||
permission_dict['mediafiles.can_see'],
|
permission_dict['mediafiles.can_see'],
|
||||||
permission_dict['motions.can_see'],
|
permission_dict['motions.can_see'],
|
||||||
|
@ -130,7 +130,7 @@ angular.module('OpenSlidesApp.users.site', ['OpenSlidesApp.users'])
|
|||||||
closeByEscape: $stateParams.guest_enabled,
|
closeByEscape: $stateParams.guest_enabled,
|
||||||
closeByDocument: $stateParams.guest_enabled,
|
closeByDocument: $stateParams.guest_enabled,
|
||||||
preCloseCallback: function() {
|
preCloseCallback: function() {
|
||||||
$state.go('dashboard');
|
$state.go('home');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -128,7 +128,7 @@ class ModelTest(TestCase):
|
|||||||
motion.active_version = None
|
motion.active_version = None
|
||||||
motion.save(update_fields=['active_version'])
|
motion.save(update_fields=['active_version'])
|
||||||
# motion.__unicode__() raised an AttributeError
|
# motion.__unicode__() raised an AttributeError
|
||||||
self.assertEqual(str(motion), 'test_identifier_VohT1hu9uhiSh6ooVBFS: test_title_Koowoh1ISheemeey1air')
|
self.assertEqual(str(motion), 'test_title_Koowoh1ISheemeey1air')
|
||||||
|
|
||||||
def test_is_amendment(self):
|
def test_is_amendment(self):
|
||||||
config['motions_amendments_enabled'] = True
|
config['motions_amendments_enabled'] = True
|
||||||
|
Loading…
Reference in New Issue
Block a user