Merge pull request #1560 from emanuelschuetze/projector

Projector templates.
This commit is contained in:
Norman Jäckel 2015-06-22 21:37:07 +02:00
commit 447f7581b8
13 changed files with 476 additions and 22 deletions

View File

@ -189,6 +189,40 @@ th.sortable:hover {
}
/* iframe for live view */
#iframe {
width: 1024px;
height: 768px;
-moz-transform-origin: 0 0;
-webkit-transform-origin: 0 0;
-o-transform-origin: 0 0;
transform-origin: 0 0 0;
-moz-transform: scale(0.25);
-webkit-transform: scale(0.25);
-o-transform: scale(0.25);
transform: scale(0.25);
/* IE8+ - must be on one line, unfortunately */
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.25, M12=0, M21=0, M22=0.25, SizingMethod='auto expand')";
}
#iframewrapper {
width: 256px;
height: 192px;
position: relative;
overflow: hidden;
border: 1px solid #D5D5D5;
margin-bottom: 10px;
}
#iframeoverlay {
width: 256px;
height: 192px;
position: absolute;
top: 0px;
left: 0px;
display: block;
z-index: 1;
}
/* Log */
#log {
padding-left: 14px;
@ -203,6 +237,9 @@ div.import .label {
div.import > div > input[type="text"] {
width: 30px;
}
.white-space-pre-line {
white-space: pre-line;
}
tr.offline td, li.offline {

View File

@ -0,0 +1,202 @@
/*
* OpenSlides default projector styles
*
*/
body{
font-size: 20px !important;
line-height: 24px !important;
overflow: hidden;
}
/*** HEADER ***/
#header {
box-shadow: 0 0 7px rgba(0,0,0,0.6);
height: 70px;
margin-bottom: 20px;
}
#logo {
position: relative;
left: 75px;
top: 4px;
height: 60px;
margin-right: 35px;
float: left;
}
#eventdata {
position: relative;
left: 75px;
top: 12px;
height: 50px;
overflow: hidden;
}
#eventdata .title {
font-size: 26px;
font-weight: bold;
}
#eventdata .title.titleonly {
position: relative;
top: 12px;
}
#eventdata .description {
font-size: 18px;
opacity: 0.5;
}
#currentTime {
border:0 solid #000000;
font-size:24px;
position:absolute;
text-align:right;
top:110px;
right:40px;
padding-left:30px;
background: url(../img/glyphicons_054_clock_big.png) no-repeat scroll 0px 0px;
}
/*** CONTENT with base style elements ***/
.content {
position: absolute;
left: 75px;
top: 150px;
right: 40px;
z-index: -1;
line-height: normal;
transition-property: margin, font-size;
transition-duration: 1s;
}
h1 {
font-size: 2.25em;
margin-bottom: 40px;
line-height: 1.1em;
padding-bottom: 10px;
border-bottom: 1px solid #e6e6e6;
}
h1.title_only {
text-align: center;
font-size: 2.75em;
line-height: 1.3em;
border: 0px;
padding: 40px;
margin-left: -35px; /* see #content position 'left' - 'right' for real centering */
}
h1 small {
font-size: 0.55em;
margin-top: 15px;
display: block;
}
h3 {
font-size: 1.2em;
}
#sidebar {
width: 255px;
float: right;
margin: 0 0 20px 10px;
}
ul, ol {
margin: 0 0 10px 2em;
}
li {
line-height: normal;
}
.well h4 {
margin: 20px 0 2px 0;
}
.well h4.first {
margin-top: 0;
}
.well .result {
line-height: 30px;
}
.well .result hr {
border-top: 1px solid;
margin: 5px 0;
width: 10em;
}
.result.big {
font-size: 120%;
line-height: 40px;
}
.result .bold {
font-weight: bold;
}
hr {
margin: 10px 0;
}
.nobr {
white-space: nowrap;
}
/*** Overlay ***/
#overlay_transparent {
background-color: #777777;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#overlay_countdown_inner {
position: fixed;
right: 40px;
height: 30px;
width: 215px;
margin: 0;
top: 0;
font-size: 4em;
font-weight: bold;
text-align: center;
border-radius: 0 0 0.2em 0.2em;
}
#overlay_countdown_inner.negative {
color: #CC0000;
}
#overlay_message_inner {
position: fixed;
top: 35%;
left: 10%;
width: 80%;
text-align: center;
border-radius: 0.5em;
background: #FFFFFF;
font-size: 2.75em;
padding: 0.2em 0;
line-height: normal !important;
}
/*** Table style ***/
table {
border-collapse:collapse;
border-color:#CCCCCC -moz-use-text-color #CCCCCC #CCCCCC;
border-style:solid none solid solid;
border-width:1px medium 1px 1px;
margin:0;
border-spacing:0px;
}
table th {
border-right:1px solid #CCCCCC;
color:#333333;
font-weight:normal;
padding:10px 10px 10px 10px;
text-align:left;
text-transform:uppercase;
}
table tr.odd td {
background:none repeat scroll 0 0 #F1F1F1;
}
table td {
background:none repeat scroll 0 0 #F7F7F7;
border-right:1px solid #CCCCCC;
line-height:120%;
padding: 10px 10px;
vertical-align:middle;
}
tr.total td {
border-top: 1px solid #333333;
background-color: #e3e3e3;
}
tr.elected td {
background-color: #BED4DE !important;
}

View File

@ -206,6 +206,32 @@ angular.module('OpenSlidesApp.core.site', ['OpenSlidesApp.core'])
abstract: true,
template: "<ui-view/>",
})
// customslide
.state('core.customslide', {
url: '/customslide',
abstract: true,
template: "<ui-view/>",
})
.state('core.customslide.list', {
resolve: {
customslides: function(Customslide) {
return Customslide.findAll();
}
}
})
.state('core.customslide.create', {})
.state('core.customslide.detail', {
resolve: {
customslide: function(Customslide, $stateParams) {
return Customslide.find($stateParams.id);
}
}
})
.state('core.customslide.detail.update', {
views: {
'@core.customslide': {}
}
})
// tag
.state('core.tag', {
url: '/tag',
@ -327,12 +353,67 @@ angular.module('OpenSlidesApp.core.site', ['OpenSlidesApp.core'])
};
})
// Customslide Controller
.controller('CustomslideListCtrl', function($scope, Customslide) {
Customslide.bindAll({}, $scope, 'customslides');
// setup table sorting
$scope.sortColumn = 'title';
$scope.reverse = false;
// function to sort by clicked column
$scope.toggleSort = function ( column ) {
if ( $scope.sortColumn === column ) {
$scope.reverse = !$scope.reverse;
}
$scope.sortColumn = column;
};
// save changed customslide
$scope.save = function (customslide) {
Customslide.save(customslide);
};
$scope.delete = function (customslide) {
//TODO: add confirm message
Customslide.destroy(customslide.id).then(
function(success) {
//TODO: success message
}
);
};
})
.controller('CustomslideDetailCtrl', function($scope, Customslide, customslide) {
Customslide.bindOne(customslide.id, $scope, 'customslide');
})
.controller('CustomslideCreateCtrl', function($scope, $state, Customslide) {
$scope.customslide = {};
$scope.save = function (customslide) {
Customslide.create(customslide).then(
function(success) {
$state.go('core.customslide.list');
}
);
};
})
.controller('CustomslideUpdateCtrl', function($scope, $state, Customslide, customslide) {
$scope.customslide = customslide;
$scope.save = function (customslide) {
Customslide.save(customslide).then(
function(success) {
$state.go('core.customslide.list');
}
);
};
})
// Tag Controller
.controller('TagListCtrl', function($scope, Tag) {
Tag.bindAll({}, $scope, 'tags');
// setup table sorting
$scope.sortColumn = 'name';
$scope.filterPresent = '';
$scope.reverse = false;
// function to sort by clicked column
$scope.toggleSort = function ( column ) {

View File

@ -0,0 +1,22 @@
<h1>{{ customslide.title }}</h1>
<div id="submenu">
<a ui-sref="core.customslide.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
<!-- projector, TODO: add link to activate slide-->
<a href="#TODO" os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
title="{{ 'Show' | translate }}">
<i class="fa fa-video-camera"></i>
</a>
<!-- edit -->
<a ui-sref="core.customslide.detail.update({id: customslide.id })" os-perms="core.can_mange_projector"
class="btn btn-default btn-sm"
title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i>
</a>
</div>
<div class="white-space-pre-line">{{ customslide.text }}</div>

View File

@ -0,0 +1,27 @@
<h1 ng-if="customslide.id" translate>Edit custom slide</h1>
<h1 ng-if="!customslide.id" translate>New custom slide</h1>
<div id="submenu">
<a ui-sref="core.customslide.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<form name="customslideForm">
<div class="form-group" >
<label for="inputTitle" translate>Title</label>
<input type="text" ng-model="customslide.title" class="form-control" name="inputTitle" required>
</div>
<div class="form-group">
<label for="textareaDesciption" translate>Text</label>
<textarea ng-model="customslide.text" class="form-control" name="textareaText" />
</div>
<button type="submit" ng-click="save(customslide)" class="btn btn-primary" translate>
Save
</button>
<button ui-sref="core.customslide.list" class="btn btn-default" translate>
Cancel
</button>
</form>

View File

@ -0,0 +1,56 @@
<h1 translate>Custom slides</h1>
<div id="submenu">
<a ui-sref="core.customslide.create" os-perms="core.can_manage_projector" class="btn btn-primary btn-sm">
<i class="fa fa-plus fa-lg"></i>
<translate>New</translate>
</a>
</div>
<div class="row form-group">
<div class="col-sm-8" os-perms="core.can_manage_projector">
<p><input type="text" os-focus-me ng-model="filter.search" class="form-control"
placeholder="{{ 'Filter' | translate}}">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th ng-click="toggleSort('title')" class="sortable">
<translate>Title</translate>
<i class="pull-right fa" ng-show="sortColumn === 'title' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i>
<th os-perms="core.can_manage_projector" class="minimum">
<translate>Actions</translate>
<tbody>
<tr ng-repeat="customslide in customslides | filter: filter.search |
orderBy: sortColumn:reverse">
<td><a ui-sref="core.customslide.detail({id: customslide.id})">{{ customslide.title }}</a>
<td os-perms="core.can_manage_projector" class="nobr">
<!-- edit -->
<a ui-sref="core.customslide.detail.update({id: customslide.id })"
class="btn btn-default btn-sm"
title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i>
</a>
<!-- delete -->
<a ng-click="delete(customslide)" class="btn btn-danger btn-sm"
title="{{ 'Delete' | translate }}">
<i class="fa fa-trash-o"></i>
</a>
</table>
</div>
<div class="col-sm-4">
<!-- projector live view -->
<div class="well">
<h4 translate>Projector live view</h4>
<a ui-sref="projector" target="_blank">
<div id="iframewrapper">
<iframe id="iframe" src="/projector" frameborder="0"></iframe>
<div id="iframeoverlay"></div>
</div>
</a>
</div>
</div>
</div>

View File

@ -1,3 +1,4 @@
<div ng-controller="SlideClockCtr">
{{ serverOffset | osServertime | date:'HH:mm' }} Uhr
<div ng-controller="SlideClockCtr" id="currentTime">
<i class="fa fa-clock-o"></i>
{{ serverOffset | osServertime | date:'HH:mm' }}
</div>

View File

@ -1,4 +1,4 @@
<div ng-controller="SlideCustomSlideCtr">
<h1>{{ customslide.title }}</h1>
{{ customslide.text }}
<div ng-controller="SlideCustomSlideCtr" class="content">
<h1>{{ customslide.title }}</h1>
{{ customslide.text }}
</div>

View File

@ -9,9 +9,9 @@
</div>
<form name="tagForm">
<div class="form-group" ng-class="{'has-error has-feedback': tagForm.inputName.$error.required}">
<div class="form-group">
<label for="inputName" translate>Name</label>
<input type="text" ng-model="tag.name" class="form-control" name="inputName" ng-required="true">
<input type="text" ng-model="tag.name" class="form-control" name="inputName" required>
</div>
<button type="submit" ng-click="save(tag)" class="btn btn-primary" translate>

View File

@ -31,13 +31,13 @@
<td>{{ tag.name }}
<td os-perms="core.can_manage_tags" class="nobr">
<!-- edit -->
<a ui-sref="core.tag.detail.update({id: tag.id })" os-perms="core.can_manage_tags"
<a ui-sref="core.tag.detail.update({id: tag.id })"
class="btn btn-default btn-sm"
title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i>
</a>
<!-- delete -->
<a ng-click="delete(tag)" os-perms="core.can_manage_tags" class="btn btn-danger btn-sm"
<a ng-click="delete(tag)"class="btn btn-danger btn-sm"
title="{{ 'Delete' | translate }}">
<i class="fa fa-trash-o"></i>
</a>

View File

@ -1,7 +1,3 @@
<h1>Dashboard</h1>
<ul>
<li><a ui-sref="agenda.item.list">Agenda</a>
<li><a ui-sref="motions.motion.list">Motions</a>
<li><a ui-sref="assignments.assignment.list">Assignments</a>
<li><a ui-sref="users.user.list">Participants</a>
</ul>
<h1>{{ config('projector_welcome_title') }}</h1>
{{ config('projector_welcome_text') }}

View File

@ -133,7 +133,7 @@
<span class="text" translate>Home</span>
</a>
<li>
<a ui-sref="projector">
<a ui-sref="core.customslide.list">
<span class="ico"><i class="fa fa-video-camera fa-lg"></i></span>
<span class="text" translate>Projector</span>
</a>

View File

@ -7,13 +7,45 @@
<link rel="stylesheet" href="static/css/projector.css">
<script src="static/js/openslides-libs.js"></script>
<style type="text/css" ng-if="config('projector_backgroundcolor2')">
#header {
background-image: -moz-linear-gradient(top, {{ config('projector_backgroundcolor1') }}, {{ config('projector_backgroundcolor2') }});
background-image: -ms-linear-gradient(top, {{ config('projector_backgroundcolor1') }}, {{ config('projector_backgroundcolor2') }});
background-image: -webkit-gradient(linear, 0 0, 0 100%, from({{ config('projector_backgroundcolor1') }}), to({{ config('projector_backgroundcolor2') }}));
background-image: -webkit-linear-gradient(top, {{ config('projector_backgroundcolor1') }}, {{ config('projector_backgroundcolor2') }});
background-image: -o-linear-gradient(top, {{ config('projector_backgroundcolor1') }}, {{ config('projector_backgroundcolor2') }});
background-image: linear-gradient(top, {{ config('projector_backgroundcolor1') }}, {{ config('projector_backgroundcolor2') }});
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='{{ config('projector_backgroundcolor1') }}', encColorstr='{{ config('projector_backgroundcolor2') }}')"; /* IE 8+ */
}
</style>
<style type="text/css" ng-if="!config('projector_backgroundcolor2')">
#header {
background-color: {{ config('projector_backgroundcolor1') }};
}
</style>
<style type="text/css" ng-if="config('projector_fontcolor')">
#eventdata {
color: {{ config('projector_fontcolor') }};
}
</style>
<div id="header">
<img id="logo" src="/static/img/logo.png" alt="OpenSlides" />
<span class="navbar-text optional">{{ config('general_event_name') }}</span>
<img id="logo" src="/static/img/logo.png" alt="OpenSlides" />
<div id="eventdata">
<div class="title">
{{ config('general_event_name') }}
</div>
<div ng-if="config('general_event_description')" class="description">
{{ config('general_event_description') }}
</div>
</div>
</div>
<div id="content" ng-controller="ProjectorCtrl">
<div ng-repeat="element in elements"><div ng-include="element.template"></div></div>
<div ng-controller="ProjectorCtrl">
<div ng-repeat="element in elements">
<div ng-include="element.template"></div>
</div>
</div>
<script src="static/js/app.js"></script>