diff --git a/CHANGELOG b/CHANGELOG
index 8fe5f6e73..17146e2e6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,7 +20,7 @@ Core:
- Added support for big assemblies with lots of users.
- Added HTML support for messages on the projector.
- Moved custom slides to own app "topics". Renamed it to "Topic".
-- Added support for multiple projectors
+- Added support for multiple projectors.
Motions:
- Added origin field.
diff --git a/openslides/agenda/static/js/agenda/site.js b/openslides/agenda/static/js/agenda/site.js
index 1b34573a3..7ca0ee866 100644
--- a/openslides/agenda/static/js/agenda/site.js
+++ b/openslides/agenda/static/js/agenda/site.js
@@ -251,7 +251,7 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
var isAgendaProjectedId = $scope.isAgendaProjected($scope.mainListTree);
if (isAgendaProjectedId > 0) {
// Deactivate
- $http.post('/rest/core/projector/' + isAgendaProjectedId + '/prune_elements/', []);
+ $http.post('/rest/core/projector/' + isAgendaProjectedId + '/clear_elements/');
}
if (isAgendaProjectedId != projectorId) {
$http.post('/rest/core/projector/' + projectorId + '/prune_elements/',
@@ -332,7 +332,7 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
if (projectiondefaultItem) {
$scope.defaultProjectorItemId = projectiondefaultItem.projector_id;
}
- var projectiondefaultListOfSpeakers = ProjectionDefault.filter({name: 'list_of_speakers'})[0];
+ var projectiondefaultListOfSpeakers = ProjectionDefault.filter({name: 'agenda_list_of_speakers'})[0];
if (projectiondefaultListOfSpeakers) {
$scope.defaultProjectorListOfSpeakersId = projectiondefaultListOfSpeakers.projector_id;
}
@@ -515,16 +515,11 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
}, function() {
$scope.projectors = Projector.getAll();
$scope.updateCurrentListOfSpeakers();
- });
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'current_list_of_speakers'})[0];
+ var projectiondefault = ProjectionDefault.filter({name: 'agenda_current_list_of_speakers'})[0];
if (projectiondefault) {
$scope.defaultProjectorId = projectiondefault.projector_id;
}
});
-
$scope.updateCurrentListOfSpeakers = function () {
var itemPromise = CurrentListOfSpeakersItem.getItem($scope.currentListOfSpeakersReference);
if (itemPromise) {
@@ -539,7 +534,7 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
var isCurrentLoSProjectedId = $scope.isCurrentLoSProjected($scope.mainListTree);
if (isCurrentLoSProjectedId > 0) {
// Deactivate
- $http.post('/rest/core/projector/' + isCurrentLoSProjectedId + '/prune_elements/', []);
+ $http.post('/rest/core/projector/' + isCurrentLoSProjectedId + '/clear_elements/');
}
if (isCurrentLoSProjectedId != projectorId) {
$http.post('/rest/core/projector/' + projectorId + '/prune_elements/',
diff --git a/openslides/core/migrations/0006_multiprojector.py b/openslides/core/migrations/0006_multiprojector.py
index 592695384..638ceb839 100644
--- a/openslides/core/migrations/0006_multiprojector.py
+++ b/openslides/core/migrations/0006_multiprojector.py
@@ -13,7 +13,7 @@ def name_default_projector(apps, schema_editor):
Set the name of the default projector to 'Defaultprojector'
"""
Projector = apps.get_model('core', 'Projector')
- Projector.objects.filter(pk=1).update(name='Defaultprojector')
+ Projector.objects.filter(pk=1).update(name='Default projector')
class Migration(migrations.Migration):
diff --git a/openslides/core/models.py b/openslides/core/models.py
index 77bba0286..953496b42 100644
--- a/openslides/core/models.py
+++ b/openslides/core/models.py
@@ -179,18 +179,19 @@ class Projector(RESTModelMixin, models.Model):
class ProjectionDefault(RESTModelMixin, models.Model):
"""
- Model for the ProjectionDefaults like Motion, Agenda, List of speakers,...
- The name is the technical name like 'topics', 'motions'. For apps the name should
- be the app name to get keep the ProjectionDefault for apps generic. But it is
- possible to give some special name like 'list_of_speakers'.
- The display_name is the shown name on the front end for the user.
+ Model for the projection defaults like motions, agenda, list of
+ speakers and thelike. The name is the technical name like 'topics' or
+ 'motions'. For apps the name should be the app name to get keep the
+ ProjectionDefault for apps generic. But it is possible to give some
+ special name like 'list_of_speakers'. The display_name is the shown
+ name on the front end for the user.
"""
name = models.CharField(max_length=256)
display_name = models.CharField(max_length=256)
projector = models.ForeignKey(
- 'Projector',
+ Projector,
on_delete=models.CASCADE,
related_name='projectiondefaults')
diff --git a/openslides/core/serializers.py b/openslides/core/serializers.py
index aeb0482b7..a3c45dd89 100644
--- a/openslides/core/serializers.py
+++ b/openslides/core/serializers.py
@@ -40,8 +40,8 @@ class ProjectorSerializer(ModelSerializer):
class Meta:
model = Projector
- fields = ('id', 'config', 'elements', 'scale', 'scroll', 'name', 'blank', 'width', 'height', 'projectiondefaults')
- read_only_fields = ('scale', 'scroll', 'blank', 'width', 'height', 'projectiondefaults')
+ fields = ('id', 'config', 'elements', 'scale', 'scroll', 'name', 'blank', 'width', 'height', 'projectiondefaults', )
+ read_only_fields = ('scale', 'scroll', 'blank', 'width', 'height', )
class TagSerializer(ModelSerializer):
diff --git a/openslides/core/signals.py b/openslides/core/signals.py
index 7ec363245..92609c323 100644
--- a/openslides/core/signals.py
+++ b/openslides/core/signals.py
@@ -27,18 +27,20 @@ def delete_django_app_permissions(sender, **kwargs):
def create_builtin_projection_defaults(**kwargs):
"""
Creates the builtin defaults:
- - agenda_all_items, agenda_item
+ - agenda_all_items, agenda_list_of_speakers, agenda_current_list_of_speakers
+ - topics
- assignments
- mediafiles
- motion
- users
- - list_of_speakers
- - current_list_of_speakers
- """
- # Check whether ProjectionDefaults exists
+ These strings have to be used in the controllers where you want to
+ define a projector button. Use the string to get the id of the
+ responsible projector and pass this id to the projector button directive.
+ """
+ # Check whether ProjectionDefault objects exist.
if ProjectionDefault.objects.all().exists():
- # Do completely nothing if the defaults are already in the database.
+ # Do completely nothing if some defaults are already in the database.
return
default_projector = Projector.objects.get(pk=1)
@@ -52,11 +54,11 @@ def create_builtin_projection_defaults(**kwargs):
display_name='Topics',
projector=default_projector)
ProjectionDefault.objects.create(
- name='list_of_speakers',
+ name='agenda_list_of_speakers',
display_name='List of speakers',
projector=default_projector)
ProjectionDefault.objects.create(
- name='current_list_of_speakers',
+ name='agenda_current_list_of_speakers',
display_name='Current list of speakers',
projector=default_projector)
ProjectionDefault.objects.create(
diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js
index a9c09c88c..0a66870a1 100644
--- a/openslides/core/static/js/core/base.js
+++ b/openslides/core/static/js/core/base.js
@@ -192,10 +192,12 @@ angular.module('OpenSlidesApp.core', [
autoupdate.onMessage(function(json) {
// TODO: when MODEL.find() is called after this
// a new request is fired. This could be a bug in DS
- // TODO: If you don't have the permission to see a projector, the
- // variable json is a string with an error message. Therefor
- // the next line fails.
- var dataList = JSON.parse(json);
+ var dataList = [];
+ try {
+ dataList = JSON.parse(json);
+ } catch(err) {
+ console.error(json);
+ }
_.forEach(dataList, function(data) {
console.log("Received object: " + data.collection + ", " + data.id);
var instance = DS.get(data.collection, data.id);
@@ -313,15 +315,17 @@ angular.module('OpenSlidesApp.core', [
}
])
-// This places a Projectorbutton in the document. Example:
-//
-//
-// This button references to model (in this case 'motion'). Also a defaultProjectionId has to
-// be given. In the Exable its a scope variable. The next two parameters are additional:
-// - additional-id: Then the model.project and model.isProjected will be called whith this
-// argument (ex.: model.project(2))
-// - content: A not trusted text placed behind the projector symbol.
+/*
+ * This places a projector button in the document.
+ *
+ * Example:
+ * This button references to model (in this example 'motion'). Also a defaultProjectionId
+ * has to be given. In the example it's a scope variable. The next two parameters are additional:
+ * - additional-id: Then the model.project and model.isProjected will be called with
+ * this argument (e. g.: model.project(2))
+ * - content: A text placed behind the projector symbol.
+ */
.directive('projectorButton', [
'Projector',
function (Projector) {
@@ -370,7 +374,7 @@ angular.module('OpenSlidesApp.core', [
// if this object is already projected on projectorId, delete this element from this projector
var isProjectedId = this.isProjected();
if (isProjectedId > 0) {
- $http.post('/rest/core/projector/' + isProjectedId + '/prune_elements/');
+ $http.post('/rest/core/projector/' + isProjectedId + '/clear_elements/');
}
// if it was the same projector before, just delete it but not show again
if (isProjectedId != projectorId) {
@@ -483,7 +487,7 @@ angular.module('OpenSlidesApp.core', [
},
getStateForCurrentSlide: function () {
var return_dict;
- $.each(this.elements, function(key, value) {
+ angular.forEach(this.elements, function(key, value) {
if (value.name == 'agenda/list-of-speakers') {
return_dict = {
'state': 'agenda.item.detail',
@@ -592,11 +596,13 @@ angular.module('OpenSlidesApp.core', [
}
])
-// This filter filters all items in array. If the filterArray is empty, the array is passed.
-// The filterArray contains numbers of the multiselect: [1, 3, 4].
-// Then, all items in 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
+/*
+ * This filter filters all items in an array. If the filterArray is empty, the
+ * array is passed. The filterArray contains numbers of the multiselect, e. g. [1, 3, 4].
+ * 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
+ */
.filter('SelectMultipleFilter', [
function () {
return function (array, filterArray, idFunction) {
diff --git a/openslides/core/static/js/core/projector.js b/openslides/core/static/js/core/projector.js
index c0acd41d2..dbaaed9a3 100644
--- a/openslides/core/static/js/core/projector.js
+++ b/openslides/core/static/js/core/projector.js
@@ -60,10 +60,11 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
.controller('ProjectorContainerCtrl', [
'$scope',
'$location',
+ 'gettext',
'loadGlobalData',
'Projector',
'ProjectorID',
- function($scope, $location, loadGlobalData, Projector, ProjectorID) {
+ function($scope, $location, gettext, loadGlobalData, Projector, ProjectorID) {
loadGlobalData();
$scope.projector_id = ProjectorID();
@@ -73,17 +74,15 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
$scope.$watch(function () {
return Projector.lastModified($scope.projector_id);
}, function () {
- Projector.find($scope.projector_id).then(function (projector) {
+ var projector = Projector.get($scope.projector_id)
+ if (projector) {
+ $scope.error = '';
$scope.projectorWidth = projector.width;
$scope.projectorHeight = projector.height;
$scope.recalculateIframe();
- }, function (error) {
- if (error.status == 404) {
- $scope.error = 'Projector not found.';
- } else if (error.status == 403) {
- $scope.error = 'You have to login to see the projector.';
- }
- });
+ } else {
+ $scope.error = gettext('Can not open the projector.');
+ }
});
// recalculate the actual Iframesize and scale
@@ -164,34 +163,31 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
$scope.$watch(function () {
return Config.lastModified('projector_broadcast');
}, function () {
- Config.findAll().then(function () {
- var bc = Config.get('projector_broadcast').value;
- if ($scope.broadcast != bc) {
- $scope.broadcast = bc;
- if ($scope.broadcastDeregister) {
- // revert to original $scope.projector
- $scope.broadcastDeregister();
- $scope.broadcastDeregister = null;
- setElements($scope.projector);
- $scope.blank = $scope.projector.blank;
+ var bc = Config.get('projector_broadcast').value;
+ if ($scope.broadcast != bc) {
+ $scope.broadcast = bc;
+ if ($scope.broadcastDeregister) {
+ // revert to original $scope.projector
+ $scope.broadcastDeregister();
+ $scope.broadcastDeregister = null;
+ setElements($scope.projector);
+ $scope.blank = $scope.projector.blank;
+ }
+ }
+ if ($scope.broadcast > 0) {
+ // get elements and blank from broadcast projector
+ $scope.broadcastDeregister = $scope.$watch(function () {
+ return Projector.lastModified($scope.broadcast);
+ }, function () {
+ if ($scope.broadcast > 0) {
+ // var broadcast_projector = Projector.get($scope.broadcast);
+ Projector.find($scope.broadcast).then(function (broadcast_projector) {
+ setElements(broadcast_projector);
+ $scope.blank = broadcast_projector.blank;
+ });
}
- }
-
- if ($scope.broadcast > 0) {
- // get elements and blank from broadcast projector
- $scope.broadcastDeregister = $scope.$watch(function () {
- return Projector.lastModified($scope.broadcast);
- }, function () {
- if ($scope.broadcast > 0) {
- // var broadcast_projector = Projector.get($scope.broadcast);
- Projector.find($scope.broadcast).then(function (broadcast_projector) {
- setElements(broadcast_projector);
- $scope.blank = broadcast_projector.blank;
- });
- }
- });
- }
- });
+ });
+ }
});
$scope.$on('$destroy', function() {
diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js
index 825cfdaba..beb1694cf 100644
--- a/openslides/core/static/js/core/site.js
+++ b/openslides/core/static/js/core/site.js
@@ -1205,7 +1205,7 @@ angular.module('OpenSlidesApp.core.site', [
});
};
- // Get all message and countdown data from the defaultprojector (id=1)
+ // Get all message and countdown data from the defaultprojector (id=1)
var rebuildAllElements = function () {
$scope.countdowns = [];
$scope.messages = [];
@@ -1246,7 +1246,7 @@ angular.module('OpenSlidesApp.core.site', [
// stop ALL interval timer
cancelIntervalTimers();
-
+
rebuildAllElements();
});
$scope.$on('$destroy', function() {
@@ -1424,7 +1424,7 @@ angular.module('OpenSlidesApp.core.site', [
$http.post('/rest/core/projector/' + projector.id + '/update_elements/', data);
}
});
- });
+ });
};
$scope.isProjected = function (element) {
var projectorIds = [];
@@ -1616,7 +1616,7 @@ angular.module('OpenSlidesApp.core.site', [
};
$scope.removeIdentifierMessages = function () {
Projector.getAll().forEach(function (projector) {
- $.each(projector.elements, function (uuid, value) {
+ angular.forEach(projector.elements, function (uuid, value) {
if (value.name == 'core/message' && value.type == 'identify') {
$http.post('/rest/core/projector/' + projector.id + '/deactivate_elements/', [uuid]);
}
diff --git a/openslides/core/static/templates/core/manage-projectors.html b/openslides/core/static/templates/core/manage-projectors.html
index 508611299..fe115510e 100644
--- a/openslides/core/static/templates/core/manage-projectors.html
+++ b/openslides/core/static/templates/core/manage-projectors.html
@@ -56,7 +56,7 @@