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. 164
      static/js/directives/presentation.js
  3. 23
      static/partials/presentation.html

71
src/styles/components/_presentation.scss

@ -76,6 +76,7 @@ @@ -76,6 +76,7 @@
canvas {
position: relative;
display: block;
margin: 0 auto;
}
}
@ -86,7 +87,11 @@ @@ -86,7 +87,11 @@
text-align: center;
}
.presentation .overlaybar a.btn {
.presentation .overlaybar .overlaybar-content {
max-width: 100%;
}
.presentation .overlaybar a.overlaybar-button {
position: absolute;
font-size: 20px;
padding: 4px 6px;
@ -100,13 +105,69 @@ @@ -100,13 +105,69 @@
.presentation .overlaybar a.btn-next {
right: 0px;
}
.presentation .overlaybar span {
line-height: 30px;
left: auto;
}
.pageinfo input {
display: inline;
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;
}

164
static/js/directives/presentation.js

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
*/
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) {
@ -39,10 +39,40 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -39,10 +39,40 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
$scope.downloading = false;
$scope.downloadSize = 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.hideControlsBar = true;
$scope.hideControlsBar = !keepControlsBar;
$scope.currentFileInfo = null;
$scope.currentPage = null;
$scope.receivedPage = null;
@ -85,15 +115,31 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -85,15 +115,31 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
finishDownloadPresentation();
});
downloadScope.$on("writeComplete", function(event, url, fileInfo) {
event.stopPropagation();
if (url.indexOf("blob:") === 0) {
$scope.openFileInfo = function(fileInfo) {
var url = fileInfo.url;
if (url && url.indexOf("blob:") === 0) {
$scope.$emit("openPdf", url);
} else {
fileInfo.file.file(function(fp) {
$scope.$emit("openPdf", fp);
});
var file = fileInfo.file;
if (file.hasOwnProperty("writer")) {
$scope.$emit("openPdf", file);
} else {
file.file(function(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() {
@ -107,14 +153,23 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -107,14 +153,23 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
var downloadPresentation = function(fileInfo, from) {
finishDownloadPresentation();
var token = fileInfo.id;
$scope.presentationLoaded = false;
$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%';
$scope.downloadProgress = 0;
$scope.downloadSize = fileInfo.size;
$scope.downloading = true;
downloadScope.info = fileInfo;
downloadScope.handler = mediaStream.tokens.on(token, function(event, currenttoken, to, data, type, to2, from, xfer) {
//console.log("Presentation token request", currenttoken, data, type);
fileDownload.handleRequest($scope, xfer, data);
@ -123,21 +178,14 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -123,21 +178,14 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
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) {
finishUploadPresentation();
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;
var session = fileUpload.startUpload(uploadScope, token);
// This binds the token to transfer and ui.
@ -159,7 +207,15 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -159,7 +207,15 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
console.log("Received presentation file request", data);
$scope.$apply(function(scope) {
scope.resetProperties();
downloadPresentation(data.FileInfo, from);
if (data.FileInfo) {
downloadPresentation(data.FileInfo, from);
} else {
// close currently visible PDF
finishDownloadPresentation();
$scope.$emit("closePdf");
$scope.resetProperties();
// TODO(fancycode): also cleanup downloaded file
}
});
break;
@ -287,8 +343,9 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -287,8 +343,9 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
alertify.dialog.alert(errorMessage);
});
$scope.startPresentingFile = function(file, fileInfo) {
console.log("Advertising file", file, fileInfo);
$scope.startPresentingFile = function(file) {
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
mediaStream.webrtc.callForEachCall(function(peercall) {
mediaStreamSendPresentation(peercall, currentToken, {
@ -301,6 +358,8 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -301,6 +358,8 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
$scope.currentFileInfo = fileInfo;
$scope.receivedPage = null;
$scope.$emit("openPdf", file);
addVisibleSharedFile(file);
$scope.sharedFilesCache[fileInfo.id] = file;
};
var filesSelected = function(files) {
@ -310,15 +369,15 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -310,15 +369,15 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
}
_.each(files, function(f) {
var info = $.extend({
id: f.id
}, f.info);
if (info.type !== "application/pdf") {
console.log("Not sharing file", f, info);
if (!f.info.hasOwnProperty("id")) {
f.info.id = f.id;
}
if (f.info.type !== "application/pdf") {
console.log("Not sharing file", f);
alertify.dialog.alert(translation._("Only PDF documents can be shared at this time."));
return;
}
$scope.startPresentingFile(f, info);
$scope.startPresentingFile(f);
});
};
@ -383,7 +442,6 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -383,7 +442,6 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
currentToken = null;
}
$scope.$emit("closePdf");
finishUploadPresentation();
finishDownloadPresentation();
$scope.resetProperties();
$scope.layout.presentation = false;
@ -392,6 +450,46 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($, @@ -392,6 +450,46 @@ define(['jquery', 'underscore', 'text!partials/presentation.html'], function($,
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) {
if (!$scope.layout.presentation) {
return;

23
static/partials/presentation.html

@ -19,10 +19,23 @@ @@ -19,10 +19,23 @@
</div>
<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>
<form class="overlaybar-content form-group" ng-show="maxPageNumber !== -1 && !downloading">
<a class="btn btn-prev" ng-click="prevPage()" ng-show="currentPageNumber &gt; 1" title="{{_('Prev')}}"><i class="fa fa-backward"></i></a>
<span class="pageinfo"><input class="form-control input-sm" type="number" ng-model="currentPageNumber" /> / {{ maxPageNumber }}</span>
<a class="btn btn-next" ng-click="nextPage()" ng-show="currentPageNumber &lt; maxPageNumber" title="{{_('Next')}}"><i class="fa fa-forward"></i></a>
</form>
<div class="overlaybar-content">
<div class="clearfix" ng-show="maxPageNumber !== -1 && !downloading">
<a class="overlaybar-button btn-prev" ng-click="prevPage()" ng-show="currentPageNumber &gt; 1" title="{{_('Prev')}}"><i class="fa fa-backward"></i></a>
<div class="pageinfo center-block"><input class="form-control input-sm" type="number" ng-model="currentPageNumber" /> / {{ maxPageNumber }}</div>
<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>

Loading…
Cancel
Save