Added preview for

- Video (HTML5)
- Audio (HTML5)
- PDF (Browser capabilities)
attachment.
Added drag & drop functionality
Added attachment preview to preview before submitting
This commit is contained in:
thororm 2017-02-12 15:35:37 +01:00
parent dd721c651b
commit faf596aeb7
8 changed files with 238 additions and 58 deletions

View File

@ -64,7 +64,7 @@ languageselection = false
; scripts or run your site behind certain DDoS-protection services. ; scripts or run your site behind certain DDoS-protection services.
; Check the documentation at https://content-security-policy.com/ ; Check the documentation at https://content-security-policy.com/
; Note: If you use a bootstrap theme, you can remove the allow-popups from the sandbox restrictions. ; Note: If you use a bootstrap theme, you can remove the allow-popups from the sandbox restrictions.
; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; referrer no-referrer; sandbox allow-same-origin allow-scripts allow-forms allow-popups" ; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; media-src 'self' data:; object-src 'self' data:; Referrer-Policy: 'no-referrer'"
; stay compatible with PrivateBin Alpha 0.19, less secure ; stay compatible with PrivateBin Alpha 0.19, less secure
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of

View File

@ -64,12 +64,25 @@ body.navbar-spacing {
margin-right: 8px; margin-right: 8px;
} }
#image img { #attachmentPreview img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
margin-bottom: 20px; margin-bottom: 20px;
} }
#attachmentPreview .pdfPreview {
width: 100%;
height: 100vh;
margin-bottom: 20px;
}
.dragAndDropFile{
color:#777;
font-size:1em;
display:inline;
}
#deletelink { #deletelink {
float: right; float: right;
} }

View File

@ -72,13 +72,13 @@ h3.title {
bottom: 8px; bottom: 8px;
} }
#aboutbox { #aboutbox {
color: #94a3b4; color: #94a3b4;
padding: 4px 8px 4px 16px; padding: 4px 8px 4px 16px;
position: relative; position: relative;
top: 10px; top: 10px;
border-left: 2px solid #94a3b4; border-left: 2px solid #94a3b4;
float: right; float: right;
width: 60%; width: 60%;
} }
@ -104,17 +104,29 @@ h3.title {
font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace; font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace;
} }
#image img { #attachmentPreview img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
#status { #attachmentPreview .pdfPreview {
width: 100%;
height: 100vh;
margin-bottom: 20px;
}
.dragAndDropFile{
color:#777;
font-size:1em;
display:inline;
}
#status {
clear: both; clear: both;
padding: 5px 10px; padding: 5px 10px;
} }
#pasteresult { #pasteresult {
background-color: #1F2833; background-color: #1F2833;
color: #fff; color: #fff;
padding: 4px 12px; padding: 4px 12px;
@ -249,7 +261,7 @@ input {
font-weight: bold !important; font-weight: bold !important;
} }
#image, .nonworking { #attachmentPreview, .nonworking {
background-color: #fff; background-color: #fff;
color: #000; color: #000;
width: 100%; width: 100%;

View File

@ -131,6 +131,8 @@
"Download attachment": "Anhang herunterladen", "Download attachment": "Anhang herunterladen",
"Cloned file attached.": "Kopierte Datei angehängt.", "Cloned file attached.": "Kopierte Datei angehängt.",
"Attach a file": "Datei anhängen", "Attach a file": "Datei anhängen",
"or drag & drop file": "oder per Drag & Drop einfügen",
"File too large, to display a preview. Please download the attachment.": "Datei zu groß, um als Vorschau angezeigt zu werden. Bitte Anhang herunterladen.",
"Remove attachment": "Anhang entfernen", "Remove attachment": "Anhang entfernen",
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Your browser does not support uploading encrypted files. Please use a newer browser.":
"Dein Browser unterstützt das hochladen von verschlüsselten Dateien nicht. Bitte verwende einen neueren Browser.", "Dein Browser unterstützt das hochladen von verschlüsselten Dateien nicht. Bitte verwende einen neueren Browser.",

View File

@ -339,6 +339,180 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
} }
}; };
/**
* static attachment helper methods
*
* @name helper
* @class
*/
var attachmentHelpers = {
attachmentData: undefined,
file: undefined,
/*
* Read file data as dataURL using the FileReader API
* https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()
*/
readFileData: function (file) {
if (typeof FileReader === undefined) {
// revert loading status…
this.stateNewPaste();
this.showError(i18n._('Your browser does not support uploading encrypted files. Please use a newer browser.'));
return;
}
var fr = new FileReader();
if (file === undefined) {
file = controller.fileInput[0].files[0];
$('#dragAndDropFileName').text('');
} else {
$('#dragAndDropFileName').text(file.name);
}
attachmentHelpers.file = file;
fr.onload = function (e) {
var dataURL = e.target.result;
attachmentHelpers.attachmentData = dataURL;
if (controller.messagePreview.parent().hasClass('active')) {
attachmentHelpers.handleFilePreviews(controller.attachmentPreview, dataURL);
}
};
fr.readAsDataURL(file);
},
/**
* Handle the preview of files.
* @argument {DOM Element} element where the preview should be appended.
* @argument {File Data} data of the file to be displayed.
*/
handleFilePreviews: function (element, data) {
if (data) {
var mimeType = this.getMimeTypeFromDataURL(data);
if (mimeType.match(/image\//i)) {
this.showImagePreview(element, data);
} else if (mimeType.match(/video\//i)) {
this.showVideoPreview(element, data, mimeType);
} else if (mimeType.match(/audio\//i)) {
this.showAudioPreview(element, data, mimeType);
} else if (mimeType.match(/\/pdf/i)) {
this.showPDFPreview(element, data);
}
//else {
//console.log("file but no image/video/audio/pdf");
//}
}
},
/**
* Get Mime Type from a DataURL
*
* @param {type} dataURL
* @returns Mime Type from a dataURL as obtained for a file using the FileReader API https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()
*/
getMimeTypeFromDataURL: function (dataURL) {
return dataURL.slice(dataURL.indexOf('data:') + 5, dataURL.indexOf(';base64,'));
},
showImagePreview: function (element, image) {
element.html(
$(document.createElement('img'))
.attr('src', image)
.attr('class', 'img-thumbnail')
);
element.removeClass('hidden');
},
showVideoPreview: function (element, video, mimeType) {
var videoPlayer = $(document.createElement('video'))
.attr('controls', 'true')
.attr('autoplay', 'true')
.attr('loop', 'true')
.attr('class', 'img-thumbnail');
videoPlayer.append($(document.createElement('source'))
.attr('type', mimeType)
.attr('src', video));
element.html(videoPlayer);
element.removeClass('hidden');
},
showAudioPreview: function (element, audio, mimeType) {
var audioPlayer = $(document.createElement('audio'))
.attr('controls', 'true')
.attr('autoplay', 'true');
audioPlayer.append($(document.createElement('source'))
.attr('type', mimeType)
.attr('src', audio));
element.html(audioPlayer);
element.removeClass('hidden');
},
showPDFPreview: function (element, pdf) {
//PDFs are only displayed if the filesize is smaller than about 1MB (after base64 encoding).
//Bigger filesizes currently cause crashes in various browsers.
//See also: https://code.google.com/p/chromium/issues/detail?id=69227
//Firefox crashes with files that are about 1.5MB
//The performance with 1MB files is bareable
if (pdf.length < 1398488) {
//Fallback for browsers, that don't support the vh unit
var clientHeight = $(window).height();
element.html(
$(document.createElement('embed'))
.attr('src', pdf)
.attr('type', 'application/pdf')
.attr('class', 'pdfPreview')
.css('height', clientHeight)
);
element.removeClass('hidden');
} else {
controller.showError(i18n._('File too large, to display a preview. Please download the attachment.'));
}
},
addDragDropHandler: function () {
var fileInput = controller.fileInput;
if (fileInput.length === 0) {
return;
}
function ignoreDragDrop(e) {
e.stopPropagation();
e.preventDefault();
}
function drop(e) {
e.stopPropagation();
e.preventDefault();
if (fileInput) {
var file = e.dataTransfer.files[0];
//Clear the file input:
fileInput.wrap('<form>').closest('form').get(0).reset();
fileInput.unwrap();
//Only works in Chrome:
//fileInput[0].files = e.dataTransfer.files;
attachmentHelpers.readFileData(file);
}
}
document.addEventListener("drop", drop, false);
document.addEventListener("dragenter", ignoreDragDrop, false);
document.addEventListener("dragover", ignoreDragDrop, false);
fileInput.on("change", function () {
attachmentHelpers.readFileData();
});
}
};
/** /**
* internationalization methods * internationalization methods
* *
@ -748,18 +922,8 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
} }
this.attachmentLink.attr('href', attachment); this.attachmentLink.attr('href', attachment);
this.attachment.removeClass('hidden'); this.attachment.removeClass('hidden');
attachmentHelpers.handleFilePreviews(this.attachmentPreview, attachment);
// if the attachment is an image, display it
var imagePrefix = 'data:image/';
if (attachment.substring(0, imagePrefix.length) === imagePrefix)
{
this.image.html(
$(document.createElement('img'))
.attr('src', attachment)
.attr('class', 'img-thumbnail')
);
this.image.removeClass('hidden');
}
} }
var cleartext = filter.decipher(key, password, paste.data); var cleartext = filter.decipher(key, password, paste.data);
if (cleartext.length === 0 && password.length === 0 && !paste.attachment) if (cleartext.length === 0 && password.length === 0 && !paste.attachment)
@ -1018,11 +1182,12 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
sendData: function(event) sendData: function(event)
{ {
event.preventDefault(); event.preventDefault();
var file = document.getElementById('file'),
files = (file && file.files) ? file.files : null; // FileList object var fileName = attachmentHelpers.file ? attachmentHelpers.file.name : this.attachmentLink.attr('download');
var attachmentData = attachmentHelpers.attachmentData || this.attachmentLink.attr('href');
// do not send if no data. // do not send if no data.
if (this.message.val().length === 0 && !(files && files[0])) if (this.message.val().length === 0 && !(fileName && attachmentData))
{ {
return; return;
} }
@ -1045,35 +1210,12 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0), var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0),
password = this.passwordInput.val(); password = this.passwordInput.val();
if(files && files[0]) if(fileName)
{ {
if(typeof FileReader === undefined) controller.sendDataContinue(
{
// revert loading status…
this.stateNewPaste();
this.showError(i18n._('Your browser does not support uploading encrypted files. Please use a newer browser.'));
return;
}
var reader = new FileReader();
// closure to capture the file information
reader.onload = (function(theFile)
{
return function(e) {
controller.sendDataContinue(
randomkey,
filter.cipher(randomkey, password, e.target.result),
filter.cipher(randomkey, password, theFile.name)
);
};
})(files[0]);
reader.readAsDataURL(files[0]);
}
else if(this.attachmentLink.attr('href'))
{
this.sendDataContinue(
randomkey, randomkey,
filter.cipher(randomkey, password, this.attachmentLink.attr('href')), filter.cipher(randomkey, password, attachmentData),
this.attachmentLink.attr('download') filter.cipher(randomkey, password, fileName)
); );
} }
else else
@ -1199,6 +1341,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
{ {
this.message.text(''); this.message.text('');
this.attachment.addClass('hidden'); this.attachment.addClass('hidden');
this.attachmentPreview.addClass('hidden');
this.cloneButton.addClass('hidden'); this.cloneButton.addClass('hidden');
this.rawTextButton.addClass('hidden'); this.rawTextButton.addClass('hidden');
this.remainingTime.addClass('hidden'); this.remainingTime.addClass('hidden');
@ -1317,6 +1460,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
this.preview.addClass('hidden'); this.preview.addClass('hidden');
} }
this.attachmentPreview.removeClass('hidden');
this.pasteResult.addClass('hidden'); this.pasteResult.addClass('hidden');
this.message.addClass('hidden'); this.message.addClass('hidden');
this.clearText.addClass('hidden'); this.clearText.addClass('hidden');
@ -1547,6 +1691,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
this.message.focus(); this.message.focus();
this.stateExistingPaste(true); this.stateExistingPaste(true);
this.formatPaste($('#pasteFormatter').val(), this.message.val()); this.formatPaste($('#pasteFormatter').val(), this.message.val());
attachmentHelpers.handleFilePreviews(this.attachmentPreview, attachmentHelpers.attachmentData);
}, },
/** /**
@ -1602,6 +1747,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
this.message.text(''); this.message.text('');
this.changeBurnAfterReading(); this.changeBurnAfterReading();
this.changeOpenDisc(); this.changeOpenDisc();
attachmentHelpers.addDragDropHandler();
}, },
/** /**
@ -1618,6 +1764,9 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
// the only way to deselect the file is to recreate the input // the only way to deselect the file is to recreate the input
this.fileWrap.html(this.fileWrap.html()); this.fileWrap.html(this.fileWrap.html());
this.fileWrap.removeClass('hidden'); this.fileWrap.removeClass('hidden');
attachmentHelpers.file = undefined;
attachmentHelpers.attachmentData = undefined;
}, },
/** /**
@ -1776,7 +1925,8 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
this.fileRemoveButton = $('#fileremovebutton'); this.fileRemoveButton = $('#fileremovebutton');
this.fileWrap = $('#filewrap'); this.fileWrap = $('#filewrap');
this.formatter = $('#formatter'); this.formatter = $('#formatter');
this.image = $('#image'); this.attachmentPreview = $('#attachmentPreview');
this.fileInput = $('#file');
this.loadingIndicator = $('#loadingindicator'); this.loadingIndicator = $('#loadingindicator');
this.message = $('#message'); this.message = $('#message');
this.messageEdit = $('#messageedit'); this.messageEdit = $('#messageedit');
@ -1846,6 +1996,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
return { return {
helper: helper, helper: helper,
attachmentHelpers: attachmentHelpers,
i18n: i18n, i18n: i18n,
filter: filter, filter: filter,
controller: controller controller: controller

View File

@ -51,7 +51,7 @@ class Configuration
'languagedefault' => '', 'languagedefault' => '',
'urlshortener' => '', 'urlshortener' => '',
'icon' => 'identicon', 'icon' => 'identicon',
'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:; referrer no-referrer; sandbox allow-same-origin allow-scripts allow-forms allow-popups', 'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:; media-src \'self\' data:; object-src \'self\' data:; Referrer-Policy: \'no-referrer\'',
'zerobincompatibility' => false, 'zerobincompatibility' => false,
), ),
'expire' => array( 'expire' => array(

View File

@ -69,7 +69,7 @@ if ($MARKDOWN):
<?php <?php
endif; endif;
?> ?>
<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-vYYJYraxQNOf41XtehLBU2JbIQ2Uffe+n8TjHyWkpqoZdZX4aL5zyABrUNvRUP02+AxoRsmNJkpvIbmeQqcIXg==" crossorigin="anonymous"></script> <script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-/n0xL/OCmeki+nYzqkpLjJNaoEcEBR3cVxvjXF9ESuqVuD81WpicSm2ZF/bHA+pjNuC0QzMBzsKaQwBI96/6JA==" crossorigin="anonymous"></script>
<!--[if lt IE 10]> <!--[if lt IE 10]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style> <style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
<![endif]--> <![endif]-->
@ -292,8 +292,9 @@ if ($FILEUPLOAD):
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li id="filewrap"> <li id="filewrap">
<div> <div>
<input type="file" id="file" name="file" /> <input type="file" id="file" name="file"/>
</div> </div>
<div id="dragAndDropFileName" class="dragAndDropFile"><?php echo I18n::_('or drag & drop file'); ?></div>
</li> </li>
<li> <li>
<a id="fileremovebutton" href="#"> <a id="fileremovebutton" href="#">
@ -447,7 +448,7 @@ endif;
</header> </header>
<section class="container"> <section class="container">
<article class="row"> <article class="row">
<div id="image" class="col-md-12 text-center hidden"></div> <div id="attachmentPreview" class="col-md-12 text-center hidden"></div>
<div id="prettymessage" class="col-md-12 hidden"> <div id="prettymessage" class="col-md-12 hidden">
<pre id="prettyprint" class="col-md-12 prettyprint linenums:1"></pre> <pre id="prettyprint" class="col-md-12 prettyprint linenums:1"></pre>
</div> </div>

View File

@ -47,7 +47,7 @@ if ($MARKDOWN):
<?php <?php
endif; endif;
?> ?>
<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-vYYJYraxQNOf41XtehLBU2JbIQ2Uffe+n8TjHyWkpqoZdZX4aL5zyABrUNvRUP02+AxoRsmNJkpvIbmeQqcIXg==" crossorigin="anonymous"></script> <script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-/n0xL/OCmeki+nYzqkpLjJNaoEcEBR3cVxvjXF9ESuqVuD81WpicSm2ZF/bHA+pjNuC0QzMBzsKaQwBI96/6JA==" crossorigin="anonymous"></script>
<!--[if lt IE 10]> <!--[if lt IE 10]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style> <style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
<![endif]--> <![endif]-->
@ -203,6 +203,7 @@ if ($FILEUPLOAD):
<div id="attach" class="hidden"> <div id="attach" class="hidden">
<span id="clonedfile" class="hidden"><?php echo I18n::_('Cloned file attached.'); ?></span> <span id="clonedfile" class="hidden"><?php echo I18n::_('Cloned file attached.'); ?></span>
<span id="filewrap"><?php echo I18n::_('Attach a file'); ?>: <input type="file" id="file" name="file" /></span> <span id="filewrap"><?php echo I18n::_('Attach a file'); ?>: <input type="file" id="file" name="file" /></span>
<span id="dragAndDropFileName" class="dragAndDropFile"><?php echo I18n::_('or drag & drop file'); ?></span>
<button id="fileremovebutton"><?php echo I18n::_('Remove attachment'); ?></button> <button id="fileremovebutton"><?php echo I18n::_('Remove attachment'); ?></button>
</div> </div>
<?php <?php
@ -212,7 +213,7 @@ endif;
<button id="messageedit"><?php echo I18n::_('Editor'); ?></button> <button id="messageedit"><?php echo I18n::_('Editor'); ?></button>
<button id="messagepreview"><?php echo I18n::_('Preview'); ?></button> <button id="messagepreview"><?php echo I18n::_('Preview'); ?></button>
</div> </div>
<div id="image" class="hidden"></div> <div id="attachmentPreview" class="hidden"></div>
<div id="prettymessage" class="hidden"> <div id="prettymessage" class="hidden">
<pre id="prettyprint" class="prettyprint linenums:1"></pre> <pre id="prettyprint" class="prettyprint linenums:1"></pre>
</div> </div>