Просмотр исходного кода

Improve file upload UX

Fix incorrect highlight logic

Fix transition on fileupload highlight

Handle drag leave

Fix draghover

Minor style improvements
Haocen Xu 7 лет назад
Родитель
Сommit
3a9730f883
5 измененных файлов с 168 добавлено и 28 удалено
  1. 27 4
      css/bootstrap/privatebin.css
  2. 31 3
      css/privatebin.css
  3. 96 21
      js/privatebin.js
  4. 7 0
      tpl/bootstrap.php
  5. 7 0
      tpl/page.php

+ 27 - 4
css/bootstrap/privatebin.css

@@ -80,10 +80,29 @@ body.loading {
 	margin-bottom: 20px;
 }
 
+#dropzone {
+	text-align: center;
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	z-index: 1000;
+	opacity: 0.6;
+	background-color: #99ccff;
+	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E");
+	background-repeat: no-repeat;
+	background-position: center;
+	background-size: 25vh;
+	outline: 2px dashed #228bff;
+	outline-offset: -50px;
+}
+
 .dragAndDropFile{
-	color:#777;
-	font-size:1em;
-	display:inline;
+	color: #777;
+	font-size: 1em;
+	display: inline;
+	white-space: normal;
 }
 
 #deletelink {
@@ -124,6 +143,10 @@ body.loading {
 	margin-bottom: 10px;
 }
 
+#filewrap {
+	transition: background-color 0.75s ease-out;
+}
+
 .comment {
 	border-left: 1px solid #ccc;
 	padding: 5px 0 5px 10px;
@@ -131,7 +154,7 @@ body.loading {
 	transition: background-color 0.75s ease-out;
 }
 
-.comment.highlight {
+.highlight {
 	background-color: #ffdd86;
 	transition: background-color 0.2s ease-in;
 }

+ 31 - 3
css/privatebin.css

@@ -115,10 +115,29 @@ h3.title {
 	margin-bottom: 20px;
 }
 
+#dropzone {
+	text-align: center;
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	z-index: 1000;
+	opacity: 0.6;
+	background-color: #99ccff;
+	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E");
+	background-repeat: no-repeat;
+	background-position: center;
+	background-size: 25vh;
+	outline: 2px dashed #228bff;
+	outline-offset: -50px;
+}
+
 .dragAndDropFile{
-        color:#777;
-        font-size:1em;
-        display:inline;
+	color: #777;
+	font-size: 1em;
+	display: inline;
+	white-space: normal;
 }
 
 #status {
@@ -405,6 +424,15 @@ h4.title {
 
 .commentdate { color: #bfcede; }
 
+#filewrap {
+	transition: background-color 0.75s ease-out;
+}
+
+.highlight {
+	background-color: #ffdd86;
+	transition: background-color 0.2s ease-in;
+}
+
 img.vizhash {
 	width: 16px;
 	height: 16px;

+ 96 - 21
js/privatebin.js

@@ -22,6 +22,27 @@
 /** global: showdown */
 /** global: kjua */
 
+jQuery.fn.draghover = function() {
+    return this.each(function() {
+        let collection = $(),
+            self = $(this);
+  
+        self.on('dragenter', function(e) {
+            if (collection.length === 0) {
+                self.trigger('draghoverstart');
+            }
+            collection = collection.add(e.target);
+        });
+  
+        self.on('dragleave drop', function(e) {
+            collection = collection.not(e.target);
+            if (collection.length === 0) {
+                self.trigger('draghoverend');
+            }
+        });
+    });
+};
+
 // main application start, called when DOM is fully loaded
 jQuery(document).ready(function() {
     'use strict';
@@ -2492,7 +2513,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             file,
             $fileInput,
             $dragAndDropFileName,
-            attachmentHasPreview = false;
+            attachmentHasPreview = false,
+            $dropzone;
 
         /**
          * sets the attachment but does not yet show it
@@ -2714,7 +2736,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 // revert loading status…
                 me.hideAttachment();
                 me.hideAttachmentPreview();
-                Alert.showError('Your browser does not support uploading encrypted files. Please use a newer browser.');
+                Alert.showError(
+                    I18n._('Your browser does not support uploading encrypted files. Please use a newer browser.')
+                );
                 return;
             }
 
@@ -2728,16 +2752,20 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
             file = loadedFile;
 
-            fileReader.onload = function (event) {
-                const dataURL = event.target.result;
-                attachmentData = dataURL;
+            if (typeof loadedFile !== 'undefined') {
+                fileReader.onload = function (event) {
+                    const dataURL = event.target.result;
+                    attachmentData = dataURL;
 
-                if (Editor.isPreview()) {
-                    me.setAttachment(dataURL, loadedFile.name || '');
-                    $attachmentPreview.removeClass('hidden');
-                }
-            };
-            fileReader.readAsDataURL(loadedFile);
+                    if (Editor.isPreview()) {
+                        me.handleAttachmentPreview($attachmentPreview, dataURL);
+                        $attachmentPreview.removeClass('hidden');
+                    }
+
+                    TopNav.highlightFileupload();
+                };
+                fileReader.readAsDataURL(loadedFile);
+            }
         }
 
         /**
@@ -2780,8 +2808,21 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                             .attr('src', blobUrl))
                     );
                 } else if (mimeType.match(/\/pdf/i)) {
+                    // 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 bearable
+                    if (data.length > 1398488) {
+                        Alert.showError(
+                            I18n._('File too large to display a preview. Please download the attachment.')
+                        ); //TODO: is this error really neccessary?
+                        return;
+                    }
+
                     // Fallback for browsers, that don't support the vh unit
-                    var clientHeight = $(window).height();
+                    const clientHeight = $(window).height();
 
                     $targetElement.html(
                         $(document.createElement('embed'))
@@ -2808,12 +2849,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 return;
             }
 
-            const ignoreDragDrop = function(event) {
+            const handleDragEnterOrOver = function(event) {
                 event.stopPropagation();
                 event.preventDefault();
             };
 
-            const drop = function(event) {
+            const handleDrop = function(event) {
                 const evt = event.originalEvent;
                 evt.stopPropagation();
                 evt.preventDefault();
@@ -2830,9 +2871,19 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 }
             };
 
-            $(document).on('drop', drop);
-            $(document).on('dragenter', ignoreDragDrop);
-            $(document).on('dragover', ignoreDragDrop);
+            $(document).draghover().on({
+                'draghoverstart': function() {
+                    // show dropzone to indicate drop support
+                    $dropzone.removeClass('hidden');
+                },
+                'draghoverend': function() {
+                    $dropzone.addClass('hidden');
+                }
+            });
+
+            $(document).on('drop', handleDrop);
+            $(document).on('dragenter dragover', handleDragEnterOrOver);
+
             $fileInput.on('change', function () {
                 readFileData();
             });
@@ -2920,6 +2971,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 $attachmentLink = $('#attachment a');
                 $attachmentPreview = $('#attachmentPreview');
                 $dragAndDropFileName = $('#dragAndDropFileName');
+                $dropzone = $('#dropzone');
 
                 $fileInput = $('#file');
                 addDragDropHandler();
@@ -3741,6 +3793,25 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             retryButtonCallback = callback;
         }
 
+        /**
+         * Highlight file upload
+         * 
+         * @name  TopNav.highlightFileupload
+         * @function
+         */
+        me.highlightFileupload = function()
+        {
+            // visually indicate file uploaded
+            const $attachDropdownToggle = $attach.children('.dropdown-toggle');
+            if ($attachDropdownToggle.attr('aria-expanded') === 'false') {
+                $attachDropdownToggle.click();
+            }
+            $fileWrap.addClass('highlight');
+            setTimeout(function () {
+                $fileWrap.removeClass('highlight');
+            }, 300);
+        }
+
         /**
          * init navigation manager
          *
@@ -4479,7 +4550,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
             // log detailed error, but display generic translation
             console.error(message);
-            Alert.showError('Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.');
+            Alert.showError(
+                I18n._('Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.')
+            );
 
             // reset password, so it can be re-entered
             Prompt.reset();
@@ -4548,8 +4621,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
      * @param  {object} document
      * @class
      */
-    var InitialCheck = (function () {
-        var me = {};
+    const InitialCheck = (function () {
+        const me = {};
 
         /**
          * blacklist of UserAgents (parts) known to belong to a bot
@@ -4762,7 +4835,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
                 // missing decryption key (or paste ID) in URL?
                 if (window.location.hash.length === 0) {
-                    Alert.showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)');
+                    Alert.showError(
+                        I18n._('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)')
+                    );
                     return;
                 }
             }

+ 7 - 0
tpl/bootstrap.php

@@ -552,6 +552,13 @@ if ($DISCUSSION):
 		</div>
 <?php
 endif;
+?>
+<?php
+if ($FILEUPLOAD):
+?>
+		<div id="dropzone" class="hidden" tabindex="-1" aria-hidden="true"></div>
+<?php
+endif;
 ?>
 	</body>
 </html>

+ 7 - 0
tpl/page.php

@@ -254,6 +254,13 @@ if ($DISCUSSION):
 		</div>
 <?php
 endif;
+?>
+<?php
+if ($FILEUPLOAD):
+?>
+		<div id="dropzone" class="hidden" tabindex="-1" aria-hidden="true"></div>
+<?php
+endif;
 ?>
 		<section class="container">
 			<div id="noscript" role="alert" class="nonworking alert alert-info noscript-hide"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true">