Merge pull request #2117 from lesteenman/extendedMediaFileSupport

Initial attempt at support for image and video files.
This commit is contained in:
Norman Jäckel 2016-09-22 23:28:00 +02:00 committed by GitHub
commit 53ac7c2348
7 changed files with 145 additions and 15 deletions

View File

@ -430,3 +430,32 @@ tr.elected td {
.motion-text.line-numbers-none .os-line-number { .motion-text.line-numbers-none .os-line-number {
visibility: hidden; visibility: hidden;
} }
/*** Video and Image projection ***/
img.projector-image {
width: 100%;
}
div.projector-image {
width: 100%;
height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
}
.video-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.video-container > * {
flex: 1 1 auto;
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
}

View File

@ -40,6 +40,12 @@
margin-top: {{scroll}}px !important; margin-top: {{scroll}}px !important;
font-size: {{scale}}%; font-size: {{scale}}%;
} }
.mediascrollcontent {
margin-top: {{scroll/2}}em !important;
-webkit-transform: scale({{scale/100}});
-ms-transform: scale({{scale/100}});
transform: scale({{scale/100}});
}
</style> </style>
<div ng-repeat="element in elements | orderBy:'index'"> <div ng-repeat="element in elements | orderBy:'index'">
<div ng-include="element.template"></div> <div ng-include="element.template"></div>

View File

@ -38,14 +38,23 @@ angular.module('OpenSlidesApp.mediafiles', [])
}, },
}, },
computed: { computed: {
is_presentable: ['filetype', function (filetype) { is_pdf: ['filetype', function (filetype) {
var PRESENTABLE_FILE_TYPES = ['application/pdf']; var PDF_FILE_TYPES = ['application/pdf'];
return _.contains(PRESENTABLE_FILE_TYPES, filetype); return _.contains(PDF_FILE_TYPES, filetype);
}], }],
is_image: ['filetype', function (filetype) { is_image: ['filetype', function (filetype) {
var IMAGE_FILE_TYPES = ['image/png', 'image/jpeg', 'image/gif']; var IMAGE_FILE_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
return _.contains(IMAGE_FILE_TYPES, filetype); return _.contains(IMAGE_FILE_TYPES, filetype);
}], }],
is_video: ['filetype', function (filetype) {
var VIDEO_FILE_TYPES = [ 'video/quicktime', 'video/mp4', 'video/webm',
'video/ogg', 'video/x-flv', 'application/x-mpegURL', 'video/MP2T',
'video/3gpp', 'video/x-msvideo', 'video/x-ms-wmv', 'video/x-matroska' ];
return _.contains(VIDEO_FILE_TYPES, filetype);
}],
is_presentable: ['is_pdf', 'is_image', 'is_video', function (is_pdf, is_image, is_video) {
return is_pdf || is_image || is_video;
}],
mediafileUrl: [function () { mediafileUrl: [function () {
return this.media_url_prefix + this.mediafile.name; return this.media_url_prefix + this.mediafile.name;
}], }],

View File

@ -19,8 +19,22 @@ angular.module('OpenSlidesApp.mediafiles.projector', ['OpenSlidesApp.mediafiles'
function($scope, Mediafile) { function($scope, Mediafile) {
// load mediafile object // load mediafile object
var mediafile = Mediafile.get($scope.element.id); var mediafile = Mediafile.get($scope.element.id);
$scope.mediafile = mediafile;
// Allow the elements to render properly
setTimeout(function() {
if ($scope.mediafile.is_pdf) {
$scope.pdfName = mediafile.title; $scope.pdfName = mediafile.title;
$scope.pdfUrl = mediafile.mediafileUrl; $scope.pdfUrl = mediafile.mediafileUrl;
} else if ($scope.mediafile.is_video) {
var player = angular.element.find('#video-player')[0];
if ($scope.element.playing) {
player.play();
} else {
player.pause();
}
}
}, 0);
} }
]); ]);

View File

@ -138,7 +138,7 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp.
// ** PDF presentation functions **/ // ** PDF presentation functions **/
// show document on projector // show document on projector
$scope.showPdf = function (mediafile) { $scope.showMediafile = function (mediafile) {
var postUrl = '/rest/core/projector/1/prune_elements/'; var postUrl = '/rest/core/projector/1/prune_elements/';
var data = [{ var data = [{
name: 'mediafiles/mediafile', name: 'mediafiles/mediafile',
@ -147,7 +147,9 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp.
page: 1, page: 1,
scale: 'page-fit', scale: 'page-fit',
rotate: 0, rotate: 0,
visible: true visible: true,
playing: false,
fullscreen: mediafile.is_pdf
}]; }];
$http.post(postUrl, data); $http.post(postUrl, data);
}; };
@ -169,6 +171,11 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp.
return Mediafile.get(presentedMediafile.id).title; return Mediafile.get(presentedMediafile.id).title;
}; };
$scope.getType = function(presentedMediafile) {
var mediafile = Mediafile.get(presentedMediafile.id);
return mediafile.is_pdf ? 'pdf' : mediafile.is_image ? 'image' : 'video';
};
$scope.mediafileGoToPage = function (page) { $scope.mediafileGoToPage = function (page) {
var mediafileElement = getCurrentlyPresentedMediafile(); var mediafileElement = getCurrentlyPresentedMediafile();
if (parseInt(page) > 0) { if (parseInt(page) > 0) {
@ -219,6 +226,26 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp.
rotate: rotation rotate: rotation
}); });
}; };
$scope.mediafileScroll = function(scroll) {
var mediafileElement = getCurrentlyPresentedMediafile();
sendMediafileCommand({
scroll: scroll
});
};
var setFullscreen = function(fullscreen) {
sendMediafileCommand({
fullscreen: fullscreen
});
};
$scope.mediafileToggleFullscreen = function() {
var mediafileElement = getCurrentlyPresentedMediafile();
setFullscreen(!mediafileElement.fullscreen);
};
$scope.setPlaying = function(playing) {
sendMediafileCommand({
playing: playing
});
};
} }
]) ])

View File

@ -26,7 +26,7 @@
<div class="col-md-12"> <div class="col-md-12">
<div ng-repeat="presentedMediafile in presentedMediafiles"> <div ng-repeat="presentedMediafile in presentedMediafiles">
<h3>{{ getTitle(presentedMediafile) }}</h3> <h3>{{ getTitle(presentedMediafile) }}</h3>
<nav ng-class="getNavStyle(scroll)" class="form-inline"> <nav ng-show="getType(presentedMediafile) === 'pdf'" ng-class="getNavStyle(scroll)" class="form-inline">
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-default" ng-click="mediafileGoToPage(presentedMediafile.page - 1)" <button class="btn btn-default" ng-click="mediafileGoToPage(presentedMediafile.page - 1)"
ng-class="{ 'disabled': (presentedMediafile.page - 1) < 1 }" ng-class="{ 'disabled': (presentedMediafile.page - 1) < 1 }"
@ -63,9 +63,42 @@
</button> </button>
</div> </div>
</nav> </nav>
<nav ng-show="getType(presentedMediafile) === 'image'" ng-class="getNavStyle(scroll)" class="form-inline">
<div class="btn-group">
<button class="btn btn-default" ng-click="mediafileToggleFullscreen()" title="{{ 'Toggle fullscreen' | translate }}"
ng-class="presentedMediafile.fullscreen ? 'btn-primary' : 'btn-default'">
<i class="fa fa-arrows-alt"></i>
</button>
</div>
<div class="btn-group">
<button class="btn btn-default" ng-click="mediafileRotate()" title="{{ 'Rotate clockwise' | translate }}">
<i class="fa fa-repeat"></i>
</button>
</div>
</nav>
<nav ng-show="getType(presentedMediafile) === 'video'" ng-class="getNavStyle(scroll)" class="form-inline">
<div class="btn-group">
<button class="btn btn-default" ng-click="mediafileToggleFullscreen()" title="{{ 'Toggle fullscreen' | translate }}"
ng-class="presentedMediafile.fullscreen ? 'btn-primary' : 'btn-default'">
<i class="fa fa-arrows-alt"></i>
</button>
</div>
<div class="btn-group">
<button class="btn btn-default" ng-click="setPlaying(false)" title="{{ 'Stop' | translate }}"
ng-class="presentedMediafile.playing ? 'btn-default' : 'btn-primary'">
<i class="fa fa-stop"></i>
</button>
</div>
<div class="btn-group">
<button class="btn btn-default" ng-click="setPlaying(true)" title="{{ 'Play' | translate }}"
ng-class="presentedMediafile.playing ? 'btn-primary' : 'btn-default'">
<i class="fa fa-play"></i>
</button>
</div>
</nav>
</div> </div>
<div ng-show="!presentedMediafiles.length" class="spacer"> <div ng-show="!presentedMediafiles.length" class="spacer">
<i translate>No PDF file projected.</i> <i translate>No media file projected.</i>
</div> </div>
</div> </div>
</div> </div>
@ -163,9 +196,9 @@
<td ng-show="!isDeleteMode" <td ng-show="!isDeleteMode"
os-perms="core.can_manage_projector"> os-perms="core.can_manage_projector">
<a class="btn btn-default btn-sm" <a class="btn btn-default btn-sm"
ng-if="mediafile.mediafile.type == 'application/pdf'" ng-if="mediafile.is_presentable"
ng-class="{ 'btn-primary': mediafile.isProjected() }" ng-class="{ 'btn-primary': mediafile.isProjected() }"
ng-click="showPdf(mediafile)" ng-click="showMediafile(mediafile)"
title="{{ 'Project mediafile' | translate }}"> title="{{ 'Project mediafile' | translate }}">
<i class="fa fa-video-camera"></i> <i class="fa fa-video-camera"></i>
</a> </a>

View File

@ -1,6 +1,18 @@
<div ng-controller="SlideMediafileCtrl" class="content fullscreen"> <div ng-controller="SlideMediafileCtrl" class="content" ng-class="{'fullscreen': element.fullscreen, 'video-container': element.is_video}">
<ng-pdf template-url="/static/templates/mediafiles/slide_mediafile_partial.html" <!-- PDF -->
<ng-pdf ng-if="mediafile.is_pdf" template-url="/static/templates/mediafiles/slide_mediafile_partial.html"
ng-attr-scale="{{ element.scale }}" ng-attr-scale="{{ element.scale }}"
ng-attr-page="{{ element.page }}"> ng-attr-page="{{ element.page }}">
</ng-pdf> </ng-pdf>
<!-- Image -->
<img ng-if="mediafile.is_image && !element.fullscreen" class='projector-image rotate{{element.rotate}}'
ng-src='{{mediafile.mediafileUrl}}'></img>
<div ng-if="mediafile.is_image && element.fullscreen" class='projector-image rotate{{element.rotate}}'
style='background-image: url("{{mediafile.mediafileUrl}}")'></div>
<!-- Video -->
<div ng-if="mediafile.is_video" class='video-container'>
<video id='video-player' ng-src="{{mediafile.mediafileUrl}}"></video>
</div>
</div> </div>