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

Merge branch 'Haocen-317', fixes #317, fixes #487

El RIDO 7 лет назад
Родитель
Сommit
388655fdd1
7 измененных файлов с 162 добавлено и 31 удалено
  1. 2 0
      CHANGELOG.md
  2. 1 0
      CREDITS.md
  3. 27 4
      css/bootstrap/privatebin.css
  4. 31 3
      css/privatebin.css
  5. 85 22
      js/privatebin.js
  6. 8 1
      tpl/bootstrap.php
  7. 8 1
      tpl/page.php

+ 2 - 0
CHANGELOG.md

@@ -4,10 +4,12 @@
     * ADDED: Translation for Bulgarian (#455)
     * ADDED: Translation for Bulgarian (#455)
     * CHANGED: Improved mobile UI - obscured send button and hard to click shortener button (#477)
     * CHANGED: Improved mobile UI - obscured send button and hard to click shortener button (#477)
     * CHANGED: Enhanced URL shortener integration (#479)
     * CHANGED: Enhanced URL shortener integration (#479)
+    * CHANGED: Improved file upload drag & drop UI (#317)
     * FIXED: Clicking 'New' on a previously submitted paste does not blank address bar (#354)
     * FIXED: Clicking 'New' on a previously submitted paste does not blank address bar (#354)
     * FIXED: Clear address bar when create new paste from existing paste (#479)
     * FIXED: Clear address bar when create new paste from existing paste (#479)
     * FIXED: Discussion section not hiding when new/clone paste is clicked on (#484)
     * FIXED: Discussion section not hiding when new/clone paste is clicked on (#484)
     * FIXED: Showdown.js error when posting svg qrcode (#485)
     * FIXED: Showdown.js error when posting svg qrcode (#485)
+    * FIXED: Failed to handle the case where user cancelled attachment selection properly (#487)
   * **1.3 (2019-07-09)**
   * **1.3 (2019-07-09)**
     * ADDED: Translation for Czech (#424)
     * ADDED: Translation for Czech (#424)
     * ADDED: Threat modeled the application (#177)
     * ADDED: Threat modeled the application (#177)

+ 1 - 0
CREDITS.md

@@ -25,6 +25,7 @@ Sébastien Sauvage - original idea and main developer
 * PunKeel - first docker container
 * PunKeel - first docker container
 * thororm - Display of video, audio & PDF, drag & drop, preview of attachments
 * thororm - Display of video, audio & PDF, drag & drop, preview of attachments
 * Harald Leithner - base58 encoding of key
 * Harald Leithner - base58 encoding of key
+* Haocen - lots of bugfixes and UI improvements
 
 
 ## Translations
 ## Translations
 * Hexalyse - French
 * Hexalyse - French

+ 27 - 4
css/bootstrap/privatebin.css

@@ -80,10 +80,29 @@ body.loading {
 	margin-bottom: 20px;
 	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{
 .dragAndDropFile{
-	color:#777;
-	font-size:1em;
-	display:inline;
+	color: #777;
+	font-size: 1em;
+	display: inline;
+	white-space: normal;
 }
 }
 
 
 #deletelink {
 #deletelink {
@@ -124,6 +143,10 @@ body.loading {
 	margin-bottom: 10px;
 	margin-bottom: 10px;
 }
 }
 
 
+#filewrap {
+	transition: background-color 0.75s ease-out;
+}
+
 .comment {
 .comment {
 	border-left: 1px solid #ccc;
 	border-left: 1px solid #ccc;
 	padding: 5px 0 5px 10px;
 	padding: 5px 0 5px 10px;
@@ -131,7 +154,7 @@ body.loading {
 	transition: background-color 0.75s ease-out;
 	transition: background-color 0.75s ease-out;
 }
 }
 
 
-.comment.highlight {
+.highlight {
 	background-color: #ffdd86;
 	background-color: #ffdd86;
 	transition: background-color 0.2s ease-in;
 	transition: background-color 0.2s ease-in;
 }
 }

+ 31 - 3
css/privatebin.css

@@ -115,10 +115,29 @@ h3.title {
 	margin-bottom: 20px;
 	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{
 .dragAndDropFile{
-        color:#777;
-        font-size:1em;
-        display:inline;
+	color: #777;
+	font-size: 1em;
+	display: inline;
+	white-space: normal;
 }
 }
 
 
 #status {
 #status {
@@ -405,6 +424,15 @@ h4.title {
 
 
 .commentdate { color: #bfcede; }
 .commentdate { color: #bfcede; }
 
 
+#filewrap {
+	transition: background-color 0.75s ease-out;
+}
+
+.highlight {
+	background-color: #ffdd86;
+	transition: background-color 0.2s ease-in;
+}
+
 img.vizhash {
 img.vizhash {
 	width: 16px;
 	width: 16px;
 	height: 16px;
 	height: 16px;

+ 85 - 22
js/privatebin.js

@@ -22,6 +22,27 @@
 /** global: showdown */
 /** global: showdown */
 /** global: kjua */
 /** 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
 // main application start, called when DOM is fully loaded
 jQuery(document).ready(function() {
 jQuery(document).ready(function() {
     'use strict';
     'use strict';
@@ -2492,7 +2513,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             file,
             file,
             $fileInput,
             $fileInput,
             $dragAndDropFileName,
             $dragAndDropFileName,
-            attachmentHasPreview = false;
+            attachmentHasPreview = false,
+            $dropzone;
 
 
         /**
         /**
          * sets the attachment but does not yet show it
          * sets the attachment but does not yet show it
@@ -2714,7 +2736,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 // revert loading status…
                 // revert loading status…
                 me.hideAttachment();
                 me.hideAttachment();
                 me.hideAttachmentPreview();
                 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;
                 return;
             }
             }
 
 
@@ -2726,18 +2750,23 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 $dragAndDropFileName.text(loadedFile.name);
                 $dragAndDropFileName.text(loadedFile.name);
             }
             }
 
 
-            file = loadedFile;
+            if (typeof loadedFile !== 'undefined') {
+                file = loadedFile;
+                fileReader.onload = function (event) {
+                    const dataURL = event.target.result;
+                    attachmentData = dataURL;
 
 
-            fileReader.onload = function (event) {
-                const dataURL = event.target.result;
-                attachmentData = dataURL;
+                    if (Editor.isPreview()) {
+                        me.handleAttachmentPreview($attachmentPreview, dataURL);
+                        $attachmentPreview.removeClass('hidden');
+                    }
 
 
-                if (Editor.isPreview()) {
-                    me.setAttachment(dataURL, loadedFile.name || '');
-                    $attachmentPreview.removeClass('hidden');
-                }
-            };
-            fileReader.readAsDataURL(loadedFile);
+                    TopNav.highlightFileupload();
+                };
+                fileReader.readAsDataURL(loadedFile);
+            } else {
+                me.removeAttachmentData();
+            }
         }
         }
 
 
         /**
         /**
@@ -2781,7 +2810,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                     );
                     );
                 } else if (mimeType.match(/\/pdf/i)) {
                 } else if (mimeType.match(/\/pdf/i)) {
                     // Fallback for browsers, that don't support the vh unit
                     // Fallback for browsers, that don't support the vh unit
-                    var clientHeight = $(window).height();
+                    const clientHeight = $(window).height();
 
 
                     $targetElement.html(
                     $targetElement.html(
                         $(document.createElement('embed'))
                         $(document.createElement('embed'))
@@ -2808,12 +2837,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 return;
                 return;
             }
             }
 
 
-            const ignoreDragDrop = function(event) {
+            const handleDragEnterOrOver = function(event) {
                 event.stopPropagation();
                 event.stopPropagation();
                 event.preventDefault();
                 event.preventDefault();
             };
             };
 
 
-            const drop = function(event) {
+            const handleDrop = function(event) {
                 const evt = event.originalEvent;
                 const evt = event.originalEvent;
                 evt.stopPropagation();
                 evt.stopPropagation();
                 evt.preventDefault();
                 evt.preventDefault();
@@ -2830,9 +2859,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 () {
             $fileInput.on('change', function () {
                 readFileData();
                 readFileData();
             });
             });
@@ -2920,6 +2959,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 $attachmentLink = $('#attachment a');
                 $attachmentLink = $('#attachment a');
                 $attachmentPreview = $('#attachmentPreview');
                 $attachmentPreview = $('#attachmentPreview');
                 $dragAndDropFileName = $('#dragAndDropFileName');
                 $dragAndDropFileName = $('#dragAndDropFileName');
+                $dropzone = $('#dropzone');
 
 
                 $fileInput = $('#file');
                 $fileInput = $('#file');
                 addDragDropHandler();
                 addDragDropHandler();
@@ -3741,6 +3781,25 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             retryButtonCallback = callback;
             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
          * init navigation manager
          *
          *
@@ -4479,7 +4538,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
 
             // log detailed error, but display generic translation
             // log detailed error, but display generic translation
             console.error(message);
             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
             // reset password, so it can be re-entered
             Prompt.reset();
             Prompt.reset();
@@ -4548,8 +4609,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
      * @param  {object} document
      * @param  {object} document
      * @class
      * @class
      */
      */
-    var InitialCheck = (function () {
-        var me = {};
+    const InitialCheck = (function () {
+        const me = {};
 
 
         /**
         /**
          * blacklist of UserAgents (parts) known to belong to a bot
          * blacklist of UserAgents (parts) known to belong to a bot
@@ -4762,7 +4823,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
 
                 // missing decryption key (or paste ID) in URL?
                 // missing decryption key (or paste ID) in URL?
                 if (window.location.hash.length === 0) {
                 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;
                     return;
                 }
                 }
             }
             }

+ 8 - 1
tpl/bootstrap.php

@@ -71,7 +71,7 @@ if ($MARKDOWN):
 endif;
 endif;
 ?>
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-kQMNNeXI+TANiKlYOXFhSIpjoNl8++VpBHLsXMlCH4GTBLFc3cWSGo9ZbOSzctTZn3HFlnAfbOjvuK/qmRbWDA==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-9Da8DaTfUn0f3a/cW0wWDekZ97HkdI+Qpt4rT551a/JPMbHP3L0wG8OYwRxHn6qRgsMDBwzlE2yA1ZkDHlWe+Q==" crossorigin="anonymous"></script>
 		<!--[if IE]>
 		<!--[if IE]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
 		<![endif]-->
 		<![endif]-->
@@ -552,6 +552,13 @@ if ($DISCUSSION):
 		</div>
 		</div>
 <?php
 <?php
 endif;
 endif;
+?>
+<?php
+if ($FILEUPLOAD):
+?>
+		<div id="dropzone" class="hidden" tabindex="-1" aria-hidden="true"></div>
+<?php
+endif;
 ?>
 ?>
 	</body>
 	</body>
 </html>
 </html>

+ 8 - 1
tpl/page.php

@@ -49,7 +49,7 @@ if ($MARKDOWN):
 endif;
 endif;
 ?>
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.11.js" integrity="sha512-p7UyJuyBkhMcMgE4mDsgK0Lz70OvetLefua1oXs1OujWv9gOxh4xy8InFux7bZ4/DAZsTmO4rgVwZW9BHKaTaw==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-kQMNNeXI+TANiKlYOXFhSIpjoNl8++VpBHLsXMlCH4GTBLFc3cWSGo9ZbOSzctTZn3HFlnAfbOjvuK/qmRbWDA==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-9Da8DaTfUn0f3a/cW0wWDekZ97HkdI+Qpt4rT551a/JPMbHP3L0wG8OYwRxHn6qRgsMDBwzlE2yA1ZkDHlWe+Q==" crossorigin="anonymous"></script>
 		<!--[if IE]>
 		<!--[if IE]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
 		<![endif]-->
 		<![endif]-->
@@ -254,6 +254,13 @@ if ($DISCUSSION):
 		</div>
 		</div>
 <?php
 <?php
 endif;
 endif;
+?>
+<?php
+if ($FILEUPLOAD):
+?>
+		<div id="dropzone" class="hidden" tabindex="-1" aria-hidden="true"></div>
+<?php
+endif;
 ?>
 ?>
 		<section class="container">
 		<section class="container">
 			<div id="noscript" role="alert" class="nonworking alert alert-info noscript-hide"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true">
 			<div id="noscript" role="alert" class="nonworking alert alert-info noscript-hide"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true">