Merge pull request #1720 from boehlke/master

Add upload feature to mediafiles module
This commit is contained in:
Oskar Hahn 2016-01-27 15:16:03 +01:00
commit 2d1077ddad
8 changed files with 221 additions and 5 deletions

View File

@ -31,6 +31,10 @@
"ckeditor": "~4.5.4", "ckeditor": "~4.5.4",
"angular-ckeditor": "~1.0.0", "angular-ckeditor": "~1.0.0",
"roboto-condensed": "~0.3.0", "roboto-condensed": "~0.3.0",
"open-sans-fontface": "https://github.com/OpenSlides/open-sans.git#1.4.2.post1" "open-sans-fontface": "https://github.com/OpenSlides/open-sans.git#1.4.2.post1",
"angular-pdf": "~1.3.0"
},
"resolutions": {
"angular": ">= 1.4.9"
} }
} }

View File

@ -2,6 +2,7 @@ import mimetypes
from django.conf import settings from django.conf import settings
from django.db import models as dbmodels from django.db import models as dbmodels
from PyPDF2 import PdfFileReader
from ..utils.rest_api import FileField, ModelSerializer, SerializerMethodField from ..utils.rest_api import FileField, ModelSerializer, SerializerMethodField
from .models import Mediafile from .models import Mediafile
@ -17,10 +18,14 @@ class AngularCompatibleFileField(FileField):
def to_representation(self, value): def to_representation(self, value):
if value is None: if value is None:
return None return None
return { filetype = mimetypes.guess_type(value.path)[0]
result = {
'name': value.name, 'name': value.name,
'type': mimetypes.guess_type(value.path)[0] 'type': filetype
} }
if filetype == 'application/pdf':
result['pages'] = PdfFileReader(open(value.path, 'rb')).getNumPages()
return result
class MediafileSerializer(ModelSerializer): class MediafileSerializer(ModelSerializer):

View File

@ -4,4 +4,62 @@
angular.module('OpenSlidesApp.mediafiles.projector', ['OpenSlidesApp.mediafiles']); angular.module('OpenSlidesApp.mediafiles.projector', ['OpenSlidesApp.mediafiles']);
}()); .config([
'slidesProvider',
function(slidesProvider) {
slidesProvider.registerSlide('mediafiles/mediafile', {
template: 'static/templates/mediafiles/slide_mediafile.html'
});
}
])
.controller('SlideMediafileCtrl', [
'$scope',
'Mediafile',
function($scope, Mediafile) {
var id = $scope.element.mediafile;
$scope.page = $scope.element.page;
function updateScale() {
if($scope.element.pageFit) {
$scope.scale = 'page-fit';
} else {
$scope.scale = $scope.element.scale;
}
}
$scope.$watch(function() {
return $scope.element.scale;
}, updateScale);
updateScale();
var mediafile = Mediafile.find(id);
mediafile.then(function(mediafile) {
$scope.pdfName = mediafile.title;
$scope.pdfUrl = mediafile.mediafileUrl;
})
$scope.scroll = 0;
$scope.getNavStyle = function(scroll) {
if(scroll > 100) return 'pdf-controls fixed';
else return 'pdf-controls';
};
$scope.onError = function(error) {
console.log(error);
};
$scope.onLoad = function() {
$scope.loading = '';
};
$scope.onProgress = function(progress) {
console.log(progress);
};
}
]);
})();

View File

@ -59,6 +59,20 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp.
$scope.sortColumn = 'title'; $scope.sortColumn = 'title';
$scope.filterPresent = ''; $scope.filterPresent = '';
$scope.reverse = false; $scope.reverse = false;
function updatePresentedMediafiles() {
var projectorElements = _.map(Projector.get(1).elements, function(element) { return element });
$scope.presentedMediafiles = _.filter(projectorElements, function (element) {
return element.name === 'mediafiles/mediafile';
});
}
$scope.$watch(function() {
return Projector.get(1).elements;
}, updatePresentedMediafiles);
updatePresentedMediafiles();
// function to sort by clicked column // function to sort by clicked column
$scope.toggleSort = function ( column ) { $scope.toggleSort = function ( column ) {
if ( $scope.sortColumn === column ) { if ( $scope.sortColumn === column ) {
@ -111,6 +125,110 @@ angular.module('OpenSlidesApp.mediafiles.site', ['ngFileUpload', 'OpenSlidesApp.
$scope.delete = function (mediafile) { $scope.delete = function (mediafile) {
Mediafile.destroy(mediafile.id); Mediafile.destroy(mediafile.id);
}; };
// show document on projector
$scope.showPdf = function (mediafile) {
var postUrl,
data;
if($scope.presentedMediafiles.length > 0) {
// update first mediafile, at the moment there should not be more
var uuid = $scope.presentedMediafiles[0].uuid;
postUrl = '/rest/core/projector/1/update_elements/';
data = {};
data[uuid] = {
mediafile: mediafile.id,
numPages: mediafile.mediafile.pages,
page: 1,
pageFit: true,
scale: 1,
visible: true
};
} else {
postUrl = '/rest/core/projector/1/activate_elements/';
data = [{
name: 'mediafiles/mediafile',
visible: true,
numPages: mediafile.mediafile.pages,
pageFit: true,
scale: 1,
mediafile: mediafile.id,
page: 1
}];
}
$http.post(postUrl, data);
};
function sendMediafileCommand(data) {
var mediafileElement = getCurrentlyPresentedMediafile();
var updateData = _.extend({}, mediafileElement);
_.extend(updateData, data);
var postData = {};
postData[mediafileElement.uuid] = updateData;
$http.post('/rest/core/projector/1/update_elements/', postData);
}
function getCurrentlyPresentedMediafile() {
return $scope.presentedMediafiles[0];
}
$scope.mediafileGoPrevious = function () {
var mediafileElement = getCurrentlyPresentedMediafile();
if (mediafileElement.page <= 1) {
return;
}
sendMediafileCommand({
page: parseInt(mediafileElement.page) - 1
});
};
$scope.mediafileGoNext = function () {
var mediafileElement = getCurrentlyPresentedMediafile();
if (mediafileElement.page >= mediafileElement.numPages) {
return;
}
sendMediafileCommand({
page: parseInt(mediafileElement.page) + 1
});
};
$scope.mediafileZoomIn = function () {
var mediafileElement = getCurrentlyPresentedMediafile();
sendMediafileCommand({
pageFit: false,
scale: parseFloat(mediafileElement.scale) + 0.2
});
};
$scope.mediafileFit = function () {
sendMediafileCommand({
pageFit: true
});
};
$scope.mediafileZoomOut = function () {
var mediafileElement = getCurrentlyPresentedMediafile();
sendMediafileCommand({
pageFit: false,
scale: parseFloat(mediafileElement.scale) - 0.2
});
};
$scope.mediafileChangePage = function(pageNum) {
sendMediafileCommand({
pageToDisplay: pageNum
});
};
$scope.mediafileRotate = function () {
var rotation;
var currentRotation = $scope.mediafile.rotation;
if (currentRotation === 0) {
rotation = 90;
} else if (currentRotation === 90) {
rotation = 180;
} else if (currentRotation === 180) {
rotation = 270;
} else {
rotation = 0;
}
sendMediafileCommand({
rotation: rotation
});
};
} }
]) ])

View File

@ -10,6 +10,27 @@
</div> </div>
</div> </div>
<!-- mediafile pdf controls -->
<div os-perms-lite="core.can_manage_projector" ng-if="presentedMediafiles.length">
<div ng-repeat="presentedMediafile in presentedMediafiles">
<h3 translate>PDF controls</h3>
<nav ng-class="getNavStyle(scroll)">
<button ng-click="mediafileGoPrevious()"><</span></button>
<button ng-click="mediafileGoNext()">></span></button>
<button ng-click="mediafileZoomIn()">+</span></button>
<button ng-click="mediafileFit()">100%</span></button>
<button ng-click="mediafileZoomOut()">-</span></button>
<span>Page: </span>
<input type="text" min=1 ng-model="presentedMediafile.page">
<span> / {{presentedMediafile.numPages}}</span>
</nav>
</div>
</div>
<div class="details"> <div class="details">
<div class="row form-group"> <div class="row form-group">
<div class="col-sm-6"> <div class="col-sm-6">

View File

@ -0,0 +1,8 @@
<div ng-controller="SlideMediafileCtrl" class="content">
<ng-pdf template-url="/static/templates/mediafiles/slide_mediafile_partial.html"
scale="page-fit"
ng-attr-scale="{{ scale }}"
ng-attr-page="{{ page }}"
debug="true">
</ng-pdf>
</div>

View File

@ -0,0 +1 @@
<canvas id="pdf-canvas" class="rotate0"></canvas>

View File

@ -9,4 +9,5 @@ reportlab>=3.0,<3.3
roman>=2.0,<2.1 roman>=2.0,<2.1
setuptools>=2.2,<20.0 setuptools>=2.2,<20.0
sockjs-tornado>=1.0,<1.1 sockjs-tornado>=1.0,<1.1
Whoosh>=2.7,<2.8 Whoosh>=2.7.0,<2.8
PyPDF2==1.25.1