Browse Source

Merge pull request #71 from fancycode/presentation_file_cache

Keep list of presentations uploaded to the call.
pull/72/head
Simon Eisenmann 11 years ago
parent
commit
f2d27b009e
  1. 71
      src/styles/components/_presentation.scss
  2. 158
      static/js/directives/presentation.js
  3. 23
      static/partials/presentation.html

71
src/styles/components/_presentation.scss

@ -76,6 +76,7 @@
canvas { canvas {
position: relative; position: relative;
display: block; display: block;
margin: 0 auto;
} }
} }
@ -86,7 +87,11 @@
text-align: center; text-align: center;
} }
.presentation .overlaybar a.btn { .presentation .overlaybar .overlaybar-content {
max-width: 100%;
}
.presentation .overlaybar a.overlaybar-button {
position: absolute; position: absolute;
font-size: 20px; font-size: 20px;
padding: 4px 6px; padding: 4px 6px;
@ -100,13 +105,69 @@
.presentation .overlaybar a.btn-next { .presentation .overlaybar a.btn-next {
right: 0px; right: 0px;
} left: auto;
.presentation .overlaybar span {
line-height: 30px;
} }
.pageinfo input { .pageinfo input {
display: inline; display: inline;
width: 70px; width: 70px;
} }
.presentation .thumbnail {
text-shadow: none;
color: #333;
margin-top: 20px;
width: 160px;
display: inline-block;
margin-left: 20px;
cursor: pointer;
position: relative;
}
.presentation .thumbnail:first-child {
margin-left: 0;
}
.presentation .thumbnail .caption {
padding-bottom: 0;
text-overflow: ellipsis;
overflow: hidden;
}
.presentation .thumbnail .caption .size {
font-size: 10px;
}
.presentation .thumbnail .active {
font-size: 10em;
color: #84b819;
opacity: 0.7;
position: absolute;
left: 0;
right: 0;
text-align: center;
}
.presentation .thumbnail .delete {
position: absolute;
top: 1px;
right: 1px;
display: none;
}
.presentation .thumbnail:hover .delete {
display: block;
}
.presentation .thumbnail .filetype {
font-size: 5em;
}
.presentations {
height: 156px;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
margin-right: 10px;
margin-left: -25px;
}

158
static/js/directives/presentation.js

@ -20,7 +20,7 @@
*/ */
define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, _, template) { define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, _, template) {
return ["$window", "mediaStream", "fileUpload", "fileDownload", "alertify", "translation", "randomGen", function($window, mediaStream, fileUpload, fileDownload, alertify, translation, randomGen) { return ["$window", "mediaStream", "fileUpload", "fileDownload", "alertify", "translation", "randomGen", "fileData", function($window, mediaStream, fileUpload, fileDownload, alertify, translation, randomGen, fileData) {
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
@ -39,10 +39,40 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
$scope.downloading = false; $scope.downloading = false;
$scope.downloadSize = 0; $scope.downloadSize = 0;
$scope.downloadProgress = 0; $scope.downloadProgress = 0;
$scope.sharedFilesCache = {};
$scope.visibleSharedFiles = [];
$scope.resetProperties = function() { var addVisibleSharedFile = function(file) {
if (file.writer) {
// only show files the user has uploaded
return;
} else if ($scope.sharedFilesCache[file.info.id]) {
// already added
return;
}
$scope.visibleSharedFiles.push({
"id": file.info.id,
"name": file.info.name,
"size": file.info.size,
"file": file,
"sortkey": (file.info.name || "").toLowerCase()
});
};
var removeVisibleSharedFile = function(fileInfo) {
var i;
for (i=0; i<$scope.visibleSharedFiles.length; i++) {
var file = $scope.visibleSharedFiles[i];
if (file.id === fileInfo.id) {
$scope.visibleSharedFiles.splice(i, 1);
break;
}
}
};
$scope.resetProperties = function(keepControlsBar) {
$scope.isPresenter = false; $scope.isPresenter = false;
$scope.hideControlsBar = true; $scope.hideControlsBar = !keepControlsBar;
$scope.currentFileInfo = null; $scope.currentFileInfo = null;
$scope.currentPage = null; $scope.currentPage = null;
$scope.receivedPage = null; $scope.receivedPage = null;
@ -85,15 +115,31 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
finishDownloadPresentation(); finishDownloadPresentation();
}); });
downloadScope.$on("writeComplete", function(event, url, fileInfo) { $scope.openFileInfo = function(fileInfo) {
event.stopPropagation(); var url = fileInfo.url;
if (url.indexOf("blob:") === 0) { if (url && url.indexOf("blob:") === 0) {
$scope.$emit("openPdf", url); $scope.$emit("openPdf", url);
} else { } else {
fileInfo.file.file(function(fp) { var file = fileInfo.file;
if (file.hasOwnProperty("writer")) {
$scope.$emit("openPdf", file);
} else {
file.file(function(fp) {
$scope.$emit("openPdf", fp); $scope.$emit("openPdf", fp);
}); });
} }
}
};
downloadScope.$on("writeComplete", function(event, url, fileInfo) {
event.stopPropagation();
// need to store for internal file it and received token
// to allow cleanup and prevent duplicate download
fileInfo.url = url;
$scope.sharedFilesCache[fileInfo.id] = fileInfo;
$scope.sharedFilesCache[fileInfo.info.id] = fileInfo;
addVisibleSharedFile(fileInfo);
$scope.openFileInfo(fileInfo);
}); });
var finishDownloadPresentation = function() { var finishDownloadPresentation = function() {
@ -107,14 +153,23 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
var downloadPresentation = function(fileInfo, from) { var downloadPresentation = function(fileInfo, from) {
finishDownloadPresentation(); finishDownloadPresentation();
var token = fileInfo.id;
$scope.presentationLoaded = false; $scope.presentationLoaded = false;
$scope.pendingPageRequest = null; $scope.pendingPageRequest = null;
var token = fileInfo.id;
var existing = $scope.sharedFilesCache[token];
if (existing) {
console.log("Found existing file", existing);
$scope.openFileInfo(existing);
return;
}
downloadProgressBar.style.width = '0%'; downloadProgressBar.style.width = '0%';
$scope.downloadProgress = 0; $scope.downloadProgress = 0;
$scope.downloadSize = fileInfo.size; $scope.downloadSize = fileInfo.size;
$scope.downloading = true; $scope.downloading = true;
downloadScope.info = fileInfo; downloadScope.info = fileInfo;
downloadScope.handler = mediaStream.tokens.on(token, function(event, currenttoken, to, data, type, to2, from, xfer) { downloadScope.handler = mediaStream.tokens.on(token, function(event, currenttoken, to, data, type, to2, from, xfer) {
//console.log("Presentation token request", currenttoken, data, type); //console.log("Presentation token request", currenttoken, data, type);
fileDownload.handleRequest($scope, xfer, data); fileDownload.handleRequest($scope, xfer, data);
@ -123,21 +178,14 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
fileDownload.startDownload(downloadScope, from, token); fileDownload.startDownload(downloadScope, from, token);
}; };
var uploadScope = $scope.$new();
var finishUploadPresentation = function() {
if (uploadScope.info) {
uploadScope.$emit("cancelUpload");
mediaStream.tokens.off(uploadScope.info.id, uploadScope.handler);
uploadScope.info = null;
uploadScope.handler = null;
}
};
var uploadPresentation = function(fileInfo) { var uploadPresentation = function(fileInfo) {
finishUploadPresentation();
var token = fileInfo.id; var token = fileInfo.id;
if ($scope.sharedFilesCache.hasOwnProperty(token)) {
console.log("Already have an upload token for that presentation.");
return;
}
var uploadScope = $scope.$new();
uploadScope.info = fileInfo; uploadScope.info = fileInfo;
var session = fileUpload.startUpload(uploadScope, token); var session = fileUpload.startUpload(uploadScope, token);
// This binds the token to transfer and ui. // This binds the token to transfer and ui.
@ -159,7 +207,15 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
console.log("Received presentation file request", data); console.log("Received presentation file request", data);
$scope.$apply(function(scope) { $scope.$apply(function(scope) {
scope.resetProperties(); scope.resetProperties();
if (data.FileInfo) {
downloadPresentation(data.FileInfo, from); downloadPresentation(data.FileInfo, from);
} else {
// close currently visible PDF
finishDownloadPresentation();
$scope.$emit("closePdf");
$scope.resetProperties();
// TODO(fancycode): also cleanup downloaded file
}
}); });
break; break;
@ -287,8 +343,9 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
alertify.dialog.alert(errorMessage); alertify.dialog.alert(errorMessage);
}); });
$scope.startPresentingFile = function(file, fileInfo) { $scope.startPresentingFile = function(file) {
console.log("Advertising file", file, fileInfo); console.log("Advertising file", file);
var fileInfo = file.info;
// TODO(fancycode): other peers should either request the file or subscribe rendered images (e.g. for mobile app), for now we send the whole file // TODO(fancycode): other peers should either request the file or subscribe rendered images (e.g. for mobile app), for now we send the whole file
mediaStream.webrtc.callForEachCall(function(peercall) { mediaStream.webrtc.callForEachCall(function(peercall) {
mediaStreamSendPresentation(peercall, currentToken, { mediaStreamSendPresentation(peercall, currentToken, {
@ -301,6 +358,8 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
$scope.currentFileInfo = fileInfo; $scope.currentFileInfo = fileInfo;
$scope.receivedPage = null; $scope.receivedPage = null;
$scope.$emit("openPdf", file); $scope.$emit("openPdf", file);
addVisibleSharedFile(file);
$scope.sharedFilesCache[fileInfo.id] = file;
}; };
var filesSelected = function(files) { var filesSelected = function(files) {
@ -310,15 +369,15 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
} }
_.each(files, function(f) { _.each(files, function(f) {
var info = $.extend({ if (!f.info.hasOwnProperty("id")) {
id: f.id f.info.id = f.id;
}, f.info); }
if (info.type !== "application/pdf") { if (f.info.type !== "application/pdf") {
console.log("Not sharing file", f, info); console.log("Not sharing file", f);
alertify.dialog.alert(translation._("Only PDF documents can be shared at this time.")); alertify.dialog.alert(translation._("Only PDF documents can be shared at this time."));
return; return;
} }
$scope.startPresentingFile(f, info); $scope.startPresentingFile(f);
}); });
}; };
@ -383,7 +442,6 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
currentToken = null; currentToken = null;
} }
$scope.$emit("closePdf"); $scope.$emit("closePdf");
finishUploadPresentation();
finishDownloadPresentation(); finishDownloadPresentation();
$scope.resetProperties(); $scope.resetProperties();
$scope.layout.presentation = false; $scope.layout.presentation = false;
@ -392,6 +450,46 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
mediaStream.webrtc.e.off("statechange", updater); mediaStream.webrtc.e.off("statechange", updater);
}; };
$scope.selectPresentation = function(fileInfo) {
if ($scope.currentFileInfo && fileInfo.id === $scope.currentFileInfo.id) {
// switch back to first page when clicked on current presentation
$scope.$emit("showPdfPage", 1);
return;
}
console.log("Selected", fileInfo);
$scope.startPresentingFile(fileInfo.file);
};
$scope.deletePresentation = function($event, fileInfo) {
$event.preventDefault();
var token = fileInfo.id;
fileData.purgeFile(token);
delete $scope.sharedFilesCache[token];
if (fileInfo.info) {
delete $scope.sharedFilesCache[fileInfo.info.id];
}
removeVisibleSharedFile(fileInfo);
mediaStream.tokens.off(token);
if ($scope.currentFileInfo && fileInfo.id === $scope.currentFileInfo.id) {
mediaStream.webrtc.callForEachCall(function(peercall) {
mediaStreamSendPresentation(peercall, currentToken, {
Type: "FileInfo",
FileInfo: null
});
});
$scope.$emit("closePdf");
$scope.resetProperties($scope.visibleSharedFiles.length > 0);
}
};
mediaStream.webrtc.e.on("done", function() {
_.each($scope.sharedFilesCache, function(file, id) {
fileData.purgeFile(id);
});
$scope.sharedFilesCache = {};
$scope.visibleSharedFiles = [];
});
$(document).on("keyup", function(event) { $(document).on("keyup", function(event) {
if (!$scope.layout.presentation) { if (!$scope.layout.presentation) {
return; return;

23
static/partials/presentation.html

@ -19,10 +19,23 @@
</div> </div>
<div class="overlaybar form-horizontal" ng-class="{notvisible: hideControlsBar}"> <div class="overlaybar form-horizontal" ng-class="{notvisible: hideControlsBar}">
<a class="overlaybar-button" ng-model="hideControlsBar" btn-checkbox btn-checkbox btn-checkbox-true="0" btn-checkbox-false="1" title="{{_('Presentation controls')}}"><i class="fa fa-cogs"></i></a> <a class="overlaybar-button" ng-model="hideControlsBar" btn-checkbox btn-checkbox btn-checkbox-true="0" btn-checkbox-false="1" title="{{_('Presentation controls')}}"><i class="fa fa-cogs"></i></a>
<form class="overlaybar-content form-group" ng-show="maxPageNumber !== -1 && !downloading"> <div class="overlaybar-content">
<a class="btn btn-prev" ng-click="prevPage()" ng-show="currentPageNumber &gt; 1" title="{{_('Prev')}}"><i class="fa fa-backward"></i></a> <div class="clearfix" ng-show="maxPageNumber !== -1 && !downloading">
<span class="pageinfo"><input class="form-control input-sm" type="number" ng-model="currentPageNumber" /> / {{ maxPageNumber }}</span> <a class="overlaybar-button btn-prev" ng-click="prevPage()" ng-show="currentPageNumber &gt; 1" title="{{_('Prev')}}"><i class="fa fa-backward"></i></a>
<a class="btn btn-next" ng-click="nextPage()" ng-show="currentPageNumber &lt; maxPageNumber" title="{{_('Next')}}"><i class="fa fa-forward"></i></a> <div class="pageinfo center-block"><input class="form-control input-sm" type="number" ng-model="currentPageNumber" /> / {{ maxPageNumber }}</div>
</form> <a class="overlaybar-button btn-next" ng-click="nextPage()" ng-show="currentPageNumber &lt; maxPageNumber" title="{{_('Next')}}"><i class="fa fa-forward"></i></a>
</div>
<div class="presentations nicescroll" ng-show="visibleSharedFiles.length">
<div class="thumbnail" ng-repeat="info in visibleSharedFiles | orderBy : 'sortkey'" ng-click="selectPresentation(info)" title="{{ info.name }}">
<div class="fa active fa-check" ng-show="info.id === currentFileInfo.id"></div>
<a class="btn btn-danger delete" ng-click="deletePresentation($event, info)"><i class="fa fa-trash-o fa-lg"></i></a>
<div class="fa filetype fa-file-pdf-o"></div>
<div class="caption">
<span class="name">{{ info.name }}</span><br>
<span class="size">{{ info.size|humanizeFilesize }}</span>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>

Loading…
Cancel
Save