Several template improvements
- Move Languages services from site.js to base.js Now the detected browser language is used as projector language. - Use verboseName instead of agendaSupplement. - Show submitters on projector (load Users on Controller). - Improve list of speakers (slide and item detail).
This commit is contained in:
parent
82f5239b8c
commit
bc60b7e7ca
@ -52,8 +52,8 @@ angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users'])
|
||||
// in the DS store.
|
||||
title = this.title;
|
||||
}
|
||||
if (this.getContentResource().agendaSupplement) {
|
||||
title = gettextCatalog.getString(this.getContentResource().agendaSupplement) + ' ' + title;
|
||||
if (this.getContentResource().verboseName) {
|
||||
title = gettextCatalog.getString(this.getContentResource().verboseName) + ' ' + title;
|
||||
}
|
||||
if (this.item_number) {
|
||||
title = this.item_number + ' ' + title;
|
||||
|
@ -184,10 +184,11 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
||||
'$filter',
|
||||
'$http',
|
||||
'$state',
|
||||
'operator',
|
||||
'Agenda',
|
||||
'User',
|
||||
'item',
|
||||
function ($scope, $filter, $http, $state, Agenda, User, item) {
|
||||
function ($scope, $filter, $http, $state, operator, Agenda, User, item) {
|
||||
Agenda.bindOne(item.id, $scope, 'item');
|
||||
User.bindAll({}, $scope, 'users');
|
||||
$scope.speakerSelectBox = {};
|
||||
@ -199,7 +200,6 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
||||
$scope.speakers = $filter('orderBy')(item.speakers, 'weight');
|
||||
});
|
||||
|
||||
|
||||
// go to detail view of related item (content object)
|
||||
$scope.open = function (item) {
|
||||
$state.go(item.content_object.collection.replace('/','.')+'.detail',
|
||||
@ -242,6 +242,23 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
|
||||
$scope.speakers = item.speakers;
|
||||
};
|
||||
|
||||
// check if user is allowed to see 'add me' / 'remove me' button
|
||||
$scope.isAllowed = function (action) {
|
||||
var nextUsers = [];
|
||||
var nextSpeakers = $filter('filter')($scope.speakers, {'begin_time': null});
|
||||
angular.forEach(nextSpeakers, function (speaker) {
|
||||
nextUsers.push(speaker.user_id);
|
||||
});
|
||||
if (action == 'add') {
|
||||
return (operator.hasPerms('agenda.can_be_speaker') &&
|
||||
!item.speaker_list_closed &&
|
||||
$.inArray(operator.user.id, nextUsers) == -1);
|
||||
}
|
||||
if (action == 'remove') {
|
||||
return ($.inArray(operator.user.id, nextUsers) != -1);
|
||||
}
|
||||
}
|
||||
|
||||
// begin speech of selected/next speaker
|
||||
$scope.beginSpeech = function (speakerId) {
|
||||
$http.put('/rest/agenda/item/' + item.id + '/speak/', {'speaker': speakerId})
|
||||
|
@ -22,20 +22,25 @@
|
||||
ng-click="item.project()"
|
||||
title="{{ 'Project item' | translate }}">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
{{ item.getContentResource().verboseName }}
|
||||
</a>
|
||||
</div>
|
||||
<h1>{{ item.getTitle() }}</h1>
|
||||
<h2><translate>List of speakers</translate></h2>
|
||||
<h2>
|
||||
<translate>List of speakers</translate>
|
||||
<span ng-if="item.speaker_list_closed" class="slimlabel label label-danger"
|
||||
translate>Closed</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<div class="details listOfSpeakers">
|
||||
<div class="pull-right">
|
||||
<span os-perms="agenda.can_manage">
|
||||
<button ng-if="item.speaker_list_closed" ng-click="closeList(false)"
|
||||
class="btn btn-sm btn-default">
|
||||
<i class="fa fa-toggle-off"></i>
|
||||
<translate>Close</translate>
|
||||
<translate>Closed</translate>
|
||||
</button>
|
||||
<button ng-if="!item.speaker_list_closed" ng-click="closeList(true)"
|
||||
class="btn btn-sm btn-default">
|
||||
@ -45,32 +50,30 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- TODO:
|
||||
* show only 'add me' OR 'remove me' button
|
||||
-->
|
||||
<!-- Start/Stop controls -->
|
||||
<div os-perms="agenda.can_manage">
|
||||
<button ng-click="beginSpeech()"
|
||||
class="btn btn-primary">
|
||||
<i class="fa fa-play"></i>
|
||||
<translate>Start next speaker</translate>
|
||||
class="btn btn-sm btn-primary">
|
||||
<i class="fa fa-microphone"></i>
|
||||
<translate>Begin next speech</translate>
|
||||
</button>
|
||||
<button ng-click="endSpeech()"
|
||||
class="btn btn-default">
|
||||
<i class="fa fa-stop"></i>
|
||||
<translate>Stop current speaker</translate>
|
||||
class="btn btn-sm btn-default">
|
||||
<i class="fa fa-microphone-slash"></i>
|
||||
<translate>End current speech</translate>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- Last speakers -->
|
||||
<div class="spacer">
|
||||
<h3 translate>Last speakers</h3>
|
||||
<button ng-click="showOldSpeakers = !showOldSpeakers"
|
||||
class="btn btn-sm btn-default spacer">
|
||||
<i ng-if="!showOldSpeakers" class="fa fa-toggle-off"></i>
|
||||
<i ng-if="showOldSpeakers"class="fa fa-toggle-on"></i>
|
||||
<translate>Show all speakers</translate>
|
||||
class="btn btn-xs btn-default">
|
||||
<translate ng-if="!showOldSpeakers">Show</translate>
|
||||
<translate ng-if="showOldSpeakers">Hide</translate>
|
||||
</button>
|
||||
<div uib-collapse="!showOldSpeakers">
|
||||
<h3 translate>Old speakers:</h3>
|
||||
<ol>
|
||||
<ol class="indentation-lg">
|
||||
<li ng-repeat="speaker in item.speakers | filter: {end_time: '!!'}">
|
||||
{{ speaker.user.get_full_name() }}
|
||||
<small class="grey">
|
||||
@ -78,46 +81,50 @@
|
||||
{{ speaker.end_time | date:'yyyy-MM-dd HH:mm:ss' }}]
|
||||
</small>
|
||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||
class="btn btn-default btn-xs">
|
||||
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 translate class="">Current speaker:</h3>
|
||||
<strong ng-repeat="speaker in item.speakers | filter: {end_time: null, begin_time: '!!'}">
|
||||
<!-- Current speaker -->
|
||||
<h3 translate class="">Current speaker</h3>
|
||||
<strong class="indentation" ng-repeat="speaker in item.speakers |
|
||||
filter: {end_time: null, begin_time: '!!'}">
|
||||
{{ speaker.user.get_full_name() }}
|
||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||
class="btn btn-default btn-xs">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button os-perms="agenda.can_manage" ng-click="endSpeech()"
|
||||
class="btn btn-default btn-xs">
|
||||
<i class="fa fa-stop"></i>
|
||||
class="btn btn-default btn-xs" title="{{ 'End speech' | translate }}">
|
||||
<i class="fa fa-microphone-slash"></i>
|
||||
</button>
|
||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</strong>
|
||||
|
||||
<h3 translate>Next speakers:</h3>
|
||||
<div class="row" ng-show="speakers.length > 0">
|
||||
<div ui-tree="treeOptions" class="col-sm-6">
|
||||
<!-- Next speakers -->
|
||||
<h3 translate>Next speakers</h3>
|
||||
<div ng-show="speakers.length > 0">
|
||||
<div ui-tree="treeOptions" class="halfWidth">
|
||||
<ol ui-tree-nodes="" ng-model="speakers">
|
||||
<li ng-repeat="speaker in speakers | filter: {begin_time: null}" ui-tree-node>
|
||||
<i os-perms="agenda.can_manage" ui-tree-handle="" class="fa fa-arrows-v"></i>
|
||||
{{ $index + 1 }}.
|
||||
{{ speaker.user.get_full_name() }}
|
||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||
class="btn btn-default btn-xs">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
<button os-perms="agenda.can_manage" ng-click="beginSpeech(speaker.id)"
|
||||
class="btn btn-default btn-xs">
|
||||
<i class="fa fa-play"></i>
|
||||
class="btn btn-default btn-xs" title="{{ 'Begin speech' | translate }}">
|
||||
<i class="fa fa-microphone"></i>
|
||||
</button>
|
||||
<button os-perms="agenda.can_manage" ng-click="removeSpeaker(speaker.id)"
|
||||
class="btn btn-default btn-xs" title="{{ 'Remove' | translate }}">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Select speakers form -->
|
||||
<div class="form-group spacer">
|
||||
<alert ng-show="alert.show" type="{{ alert.type }}" ng-click="alert={}" close="alert={}">
|
||||
{{ alert.msg }}
|
||||
@ -137,12 +144,12 @@
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<p os-perm="agenda.can_be_speaker">
|
||||
<button ng-click="addSpeaker()" class="btn btn-default">
|
||||
<p class="spacer">
|
||||
<button ng-if="isAllowed('add')" ng-click="addSpeaker()" class="btn btn-default">
|
||||
<i class="fa fa-plus"></i>
|
||||
<translate>Add me</translate>
|
||||
</button>
|
||||
<button ng-click="removeSpeaker()" class="btn btn-default">
|
||||
<button ng-if="isAllowed('remove')" ng-click="removeSpeaker()" class="btn btn-default">
|
||||
<i class="fa fa-minus"></i>
|
||||
<translate>Remove me</translate>
|
||||
</button>
|
||||
|
@ -1,19 +1,28 @@
|
||||
<div ng-controller="SlideListOfSpeakersCtrl" class="content scrollcontent">
|
||||
<h1>
|
||||
{{ item.title }}
|
||||
|
||||
<!-- Title -->
|
||||
<div id="title">
|
||||
<h1>{{ item.getTitle() }}</h1>
|
||||
<h2>
|
||||
<span translate>List of speakers</span>
|
||||
<span ng-if="item.speaker_list_closed" class="label label-danger" translate>Closed</span>
|
||||
</h1>
|
||||
<!-- List of speakers -->
|
||||
<!-- TODO: show last old speakers -->
|
||||
<span ng-if="(item.speakers | filter: {begin_time: null}).length > 0">
|
||||
– {{ (item.speakers | filter: {begin_time: null}).length }} <translate>speakers</translate>
|
||||
<span ng-if="item.speaker_list_closed" class="slimlabel label label-danger" translate>Closed</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- Last speakers -->
|
||||
<p ng-repeat="speaker in item.speakers | filter: {end_time: '!!', begin_time: '!!'} |
|
||||
limitTo: config('agenda_show_last_speakers')" class="lastSpeakers">
|
||||
{{ speaker.user.get_full_name() }}
|
||||
|
||||
<!-- Current speaker -->
|
||||
<p>
|
||||
<strong ng-repeat="speaker in item.speakers | filter: {end_time: null, begin_time: '!!'}">
|
||||
{{ speaker.user.get_full_name() }}
|
||||
</strong>
|
||||
<p ng-repeat="speaker in item.speakers | filter: {end_time: null, begin_time: '!!'}"
|
||||
class="currentSpeaker">
|
||||
<i class="fa fa-microphone fa-lg"></i> {{ speaker.user.get_full_name() }}
|
||||
|
||||
<!-- Next speakers -->
|
||||
<ol id="list_of_speakers">
|
||||
<ol class="nextSpeakers">
|
||||
<li ng-repeat="speaker in item.speakers | filter: {begin_time: null}">
|
||||
{{ speaker.user.get_full_name() }}
|
||||
</ol>
|
||||
|
@ -80,7 +80,6 @@ angular.module('OpenSlidesApp.assignments', [])
|
||||
name: name,
|
||||
useClass: jsDataModel,
|
||||
verboseName: gettext('Election'),
|
||||
agendaSupplement: this.verboseName,
|
||||
phases: phases,
|
||||
getPhases: function () {
|
||||
if (!this.phases) {
|
||||
|
@ -534,6 +534,26 @@ img {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.slimlabel.label {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.indentation, .indentation20 {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.indentation-lg {
|
||||
margin-left: 35px !important;
|
||||
}
|
||||
|
||||
.halfWidth {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.listOfSpeakers h3 {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.smallhr {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
|
@ -60,7 +60,6 @@ body{
|
||||
bottom: 0;
|
||||
height: 35px;
|
||||
color: #F5F5F5;
|
||||
opacity: 0.8;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
padding-left: 50px;
|
||||
@ -69,6 +68,9 @@ body{
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
}
|
||||
#footer span {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/*** CONTENT with base style elements ***/
|
||||
.content {
|
||||
@ -253,3 +255,27 @@ tr.elected td {
|
||||
}
|
||||
.spacer-top {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
/*** List of speakers ***/
|
||||
.slimlabel.label {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.lastSpeakers {
|
||||
color: #9a9898;
|
||||
margin-left: 27px;
|
||||
}
|
||||
.currentSpeaker {
|
||||
font-weight: bold;
|
||||
margin-left: 0px;
|
||||
}
|
||||
.currentSpeaker i {
|
||||
padding-right: 5px;
|
||||
}
|
||||
.nextSpeakers {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.nextSpeakers li {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
@ -66,6 +66,69 @@ angular.module('OpenSlidesApp.core', [
|
||||
}
|
||||
])
|
||||
|
||||
// gets all in OpenSlides available languages
|
||||
.factory('Languages', [
|
||||
'gettext',
|
||||
'gettextCatalog',
|
||||
function (gettext, gettextCatalog) {
|
||||
return {
|
||||
// get all available languages
|
||||
getLanguages: function () {
|
||||
var current = gettextCatalog.getCurrentLanguage();
|
||||
// Define here new languages...
|
||||
var languages = [
|
||||
{ code: 'en', name: gettext('English') },
|
||||
{ code: 'de', name: gettext('German') },
|
||||
{ code: 'fr', name: gettext('French') }
|
||||
];
|
||||
angular.forEach(languages, function (language) {
|
||||
if (language.code == current)
|
||||
language.selected = true;
|
||||
});
|
||||
return languages
|
||||
},
|
||||
// get detected browser language code
|
||||
getBrowserLanguage: function () {
|
||||
var lang = navigator.language || navigator.userLanguage;
|
||||
if (lang.indexOf('-') !== -1)
|
||||
lang = lang.split('-')[0];
|
||||
if (lang.indexOf('_') !== -1)
|
||||
lang = lang.split('_')[0];
|
||||
return lang;
|
||||
},
|
||||
// set current language and return updated languages object array
|
||||
setCurrentLanguage: function (lang) {
|
||||
var languages = this.getLanguages();
|
||||
angular.forEach(languages, function (language) {
|
||||
language.selected = false;
|
||||
if (language.code == lang) {
|
||||
language.selected = true;
|
||||
gettextCatalog.setCurrentLanguage(lang);
|
||||
if (lang != 'en') {
|
||||
gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
|
||||
}
|
||||
}
|
||||
});
|
||||
return languages;
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
// set browser language as default language for OpenSlides
|
||||
.run([
|
||||
'gettextCatalog',
|
||||
'Languages',
|
||||
function(gettextCatalog, Languages) {
|
||||
// set detected browser language as default language (fallback: 'en')
|
||||
Languages.setCurrentLanguage(Languages.getBrowserLanguage());
|
||||
|
||||
// Set this to true for debug. Helps to find untranslated strings by
|
||||
// adding "[MISSING]:".
|
||||
gettextCatalog.debug = false;
|
||||
}
|
||||
])
|
||||
|
||||
.run(['DS', 'autoupdate', function(DS, autoupdate) {
|
||||
autoupdate.on_message(function(data) {
|
||||
// TODO: when MODEL.find() is called after this
|
||||
|
@ -63,19 +63,6 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
}
|
||||
])
|
||||
|
||||
// set browser language as default language for OpenSlides
|
||||
.run([
|
||||
'gettextCatalog',
|
||||
'Languages',
|
||||
function(gettextCatalog, Languages) {
|
||||
// set detected browser language as default language (fallback: 'en')
|
||||
Languages.setCurrentLanguage(Languages.getBrowserLanguage());
|
||||
|
||||
// Set this to true for debug. Helps to find untranslated strings by
|
||||
// adding "[MISSING]:".
|
||||
gettextCatalog.debug = false;
|
||||
}
|
||||
])
|
||||
.config([
|
||||
'mainMenuProvider',
|
||||
'gettext',
|
||||
@ -367,55 +354,6 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
}
|
||||
])
|
||||
|
||||
// gets all in OpenSlides available languages
|
||||
.factory('Languages', [
|
||||
'gettext',
|
||||
'gettextCatalog',
|
||||
function (gettext, gettextCatalog) {
|
||||
return {
|
||||
// get all available languages
|
||||
getLanguages: function () {
|
||||
var current = gettextCatalog.getCurrentLanguage();
|
||||
// Define here new languages...
|
||||
var languages = [
|
||||
{ code: 'en', name: gettext('English') },
|
||||
{ code: 'de', name: gettext('German') },
|
||||
{ code: 'fr', name: gettext('French') }
|
||||
];
|
||||
angular.forEach(languages, function (language) {
|
||||
if (language.code == current)
|
||||
language.selected = true;
|
||||
});
|
||||
return languages
|
||||
},
|
||||
// get detected browser language code
|
||||
getBrowserLanguage: function () {
|
||||
var lang = navigator.language || navigator.userLanguage;
|
||||
if (lang.indexOf('-') !== -1)
|
||||
lang = lang.split('-')[0];
|
||||
if (lang.indexOf('_') !== -1)
|
||||
lang = lang.split('_')[0];
|
||||
return lang;
|
||||
},
|
||||
// set current language and return updated languages object array
|
||||
setCurrentLanguage: function (lang) {
|
||||
var languages = this.getLanguages();
|
||||
angular.forEach(languages, function (language) {
|
||||
language.selected = false;
|
||||
if (language.code == lang) {
|
||||
language.selected = true;
|
||||
gettextCatalog.setCurrentLanguage(lang);
|
||||
if (lang != 'en') {
|
||||
gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
|
||||
}
|
||||
}
|
||||
});
|
||||
return languages;
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
.controller("LanguageCtrl", function ($scope, gettextCatalog, Languages, filterFilter) {
|
||||
$scope.languages = Languages.getLanguages();
|
||||
$scope.selectedLanguage = filterFilter($scope.languages, {selected: true});
|
||||
@ -689,7 +627,10 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
};
|
||||
$scope.editCurrentSlide = function () {
|
||||
$.each(Projector.get(1).elements, function(key, value) {
|
||||
if (value.name != 'core/clock' &&
|
||||
if (value.name == 'agenda/list-of-speakers') {
|
||||
$state.go('agenda.item.detail', {id: value.id});
|
||||
} else if (
|
||||
value.name != 'core/clock' &&
|
||||
value.name != 'core/countdown' &&
|
||||
value.name != 'core/message' ) {
|
||||
$state.go(value.name.replace('/', '.')+'.detail.update', {id: value.id});
|
||||
|
@ -169,7 +169,6 @@ angular.module('OpenSlidesApp.motions', ['OpenSlidesApp.users'])
|
||||
name: name,
|
||||
useClass: jsDataModel,
|
||||
verboseName: gettext('Motion'),
|
||||
agendaSupplement: this.verboseName,
|
||||
methods: {
|
||||
getResourceName: function () {
|
||||
return name;
|
||||
@ -200,7 +199,7 @@ angular.module('OpenSlidesApp.motions', ['OpenSlidesApp.users'])
|
||||
if (this.identifier) {
|
||||
value = ' ' + this.identifier;
|
||||
}
|
||||
return value + ': ' + this.getTitle();
|
||||
return "Motion " + value + ': ' + this.getTitle();
|
||||
},
|
||||
isAllowed: function (action) {
|
||||
/*
|
||||
|
@ -10,12 +10,13 @@ angular.module('OpenSlidesApp.motions.projector', ['OpenSlidesApp.motions'])
|
||||
});
|
||||
})
|
||||
|
||||
.controller('SlideMotionCtrl', function($scope, Motion) {
|
||||
.controller('SlideMotionCtrl', function($scope, Motion, User) {
|
||||
// Attention! Each object that is used here has to be dealt on server side.
|
||||
// Add it to the coresponding get_requirements method of the ProjectorElement
|
||||
// class.
|
||||
var id = $scope.element.id;
|
||||
Motion.find(id);
|
||||
User.findAll();
|
||||
Motion.bindOne(id, $scope, 'motion');
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user