From: Alexander Ebert Date: Sun, 11 Sep 2016 10:01:00 +0000 (+0200) Subject: Added drag & drop support X-Git-Tag: 3.0.0_Beta_1~226 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=26c8f1c31c4d5ed3b78d240a0eb18f085162f324;p=GitHub%2FWoltLab%2FWCF.git Added drag & drop support --- diff --git a/com.woltlab.wcf/templates/wysiwyg.tpl b/com.woltlab.wcf/templates/wysiwyg.tpl index efbad3efaa..3b1d51de44 100644 --- a/com.woltlab.wcf/templates/wysiwyg.tpl +++ b/com.woltlab.wcf/templates/wysiwyg.tpl @@ -17,6 +17,7 @@ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabClean.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabCode.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabColor.js?v={@LAST_UPDATE_TIME}', + '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDragAndDrop.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDropdown.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabEvent.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabFont.js?v={@LAST_UPDATE_TIME}', @@ -50,6 +51,9 @@ ], function () { require(['Environment', 'Language', 'WoltLabSuite/Core/Ui/Redactor/Autosave', 'WoltLabSuite/Core/Ui/Redactor/Metacode'], function(Environment, Language, UiRedactorAutosave, UiRedactorMetacode) { Language.addObject({ + 'wcf.attachment.dragAndDrop.dropHere': '{lang}wcf.attachment.dragAndDrop.dropHere{/lang}', + 'wcf.attachment.dragAndDrop.dropNow': '{lang}wcf.attachment.dragAndDrop.dropNow{/lang}', + 'wcf.editor.code.edit': '{lang}wcf.editor.code.edit{/lang}', 'wcf.editor.code.file': '{lang}wcf.editor.code.file{/lang}', 'wcf.editor.code.file.description': '{lang}wcf.editor.code.file.description{/lang}', @@ -180,6 +184,7 @@ 'WoltLabClean', 'WoltLabCode', 'WoltLabColor', + 'WoltLabDragAndDrop', 'WoltLabDropdown', 'WoltLabFont', 'WoltLabImage', diff --git a/wcfsetup/install/files/acp/templates/wysiwyg.tpl b/wcfsetup/install/files/acp/templates/wysiwyg.tpl index efbad3efaa..3b1d51de44 100644 --- a/wcfsetup/install/files/acp/templates/wysiwyg.tpl +++ b/wcfsetup/install/files/acp/templates/wysiwyg.tpl @@ -17,6 +17,7 @@ '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabClean.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabCode.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabColor.js?v={@LAST_UPDATE_TIME}', + '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDragAndDrop.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDropdown.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabEvent.js?v={@LAST_UPDATE_TIME}', '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabFont.js?v={@LAST_UPDATE_TIME}', @@ -50,6 +51,9 @@ ], function () { require(['Environment', 'Language', 'WoltLabSuite/Core/Ui/Redactor/Autosave', 'WoltLabSuite/Core/Ui/Redactor/Metacode'], function(Environment, Language, UiRedactorAutosave, UiRedactorMetacode) { Language.addObject({ + 'wcf.attachment.dragAndDrop.dropHere': '{lang}wcf.attachment.dragAndDrop.dropHere{/lang}', + 'wcf.attachment.dragAndDrop.dropNow': '{lang}wcf.attachment.dragAndDrop.dropNow{/lang}', + 'wcf.editor.code.edit': '{lang}wcf.editor.code.edit{/lang}', 'wcf.editor.code.file': '{lang}wcf.editor.code.file{/lang}', 'wcf.editor.code.file.description': '{lang}wcf.editor.code.file.description{/lang}', @@ -180,6 +184,7 @@ 'WoltLabClean', 'WoltLabCode', 'WoltLabColor', + 'WoltLabDragAndDrop', 'WoltLabDropdown', 'WoltLabFont', 'WoltLabImage', diff --git a/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabDragAndDrop.js b/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabDragAndDrop.js new file mode 100644 index 0000000000..384923ce0a --- /dev/null +++ b/wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabDragAndDrop.js @@ -0,0 +1,11 @@ +$.Redactor.prototype.WoltLabDragAndDrop = function() { + "use strict"; + + return { + init: function() { + require(['WoltLabSuite/Core/Ui/Redactor/DragAndDrop'], (function (UiRedactorDragAndDrop) { + UiRedactorDragAndDrop.init(this); + }).bind(this)); + } + }; +}; diff --git a/wcfsetup/install/files/js/WCF.Attachment.js b/wcfsetup/install/files/js/WCF.Attachment.js index 954227665d..5d3ad7c120 100644 --- a/wcfsetup/install/files/js/WCF.Attachment.js +++ b/wcfsetup/install/files/js/WCF.Attachment.js @@ -86,6 +86,7 @@ WCF.Attachment.Upload = WCF.Upload.extend({ if (this._editorId) { WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'submit_' + this._editorId, this._submitInline.bind(this)); WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'reset_' + this._editorId, this._reset.bind(this)); + WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'dragAndDrop_' + this._editorId, this._editorUpload.bind(this)); var metacodeAttachUuid = WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'metacode_attach', (function(data) { var images = this._getImageAttachments(); @@ -115,12 +116,10 @@ WCF.Attachment.Upload = WCF.Upload.extend({ WCF.System.Event.removeAllListeners('com.woltlab.wcf.redactor2', 'submit_' + this._editorId); WCF.System.Event.removeAllListeners('com.woltlab.wcf.redactor2', 'reset_' + this._editorId); WCF.System.Event.removeAllListeners('com.woltlab.wcf.redactor2', 'insertAttachment_' + this._editorId); + WCF.System.Event.removeAllListeners('com.woltlab.wcf.redactor2', 'dragAndDrop_' + this._editorId); WCF.System.Event.removeListener('com.woltlab.wcf.redactor2', 'metacode_attach', metacodeAttachUuid); }).bind(this)); - - // TODO - //WCF.System.Event.addListener('com.woltlab.wcf.redactor', 'upload_' + this._editorId, $.proxy(this._editorUpload, this)); } }, diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js new file mode 100644 index 0000000000..f57b8062b4 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js @@ -0,0 +1,200 @@ +/** + * Drag and Drop file uploads. + * + * @author Alexander Ebert + * @copyright 2001-2016 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Ui/Redactor/DragAndDrop + */ +define(['Dictionary', 'EventHandler', 'Language'], function (Dictionary, EventHandler, Language) { + "use strict"; + + var _didInit = false; + var _dragArea = new Dictionary(); + var _isDragging = false; + var _isFile = false; + var _timerLeave = null; + + /** + * @exports WoltLabSuite/Core/Ui/Redactor/DragAndDrop + */ + return { + /** + * Initializes drag and drop support for provided editor instance. + * + * @param {$.Redactor} editor editor instance + */ + init: function (editor) { + if (!_didInit) { + this._setup(); + } + + _dragArea.set(editor.uuid, { + editor: editor, + element: null + }); + }, + + /** + * Handles items dragged into the browser window. + * + * @param {Event} event drag event + */ + _dragOver: function (event) { + event.preventDefault(); + + //noinspection JSUnresolvedVariable + if (!event.dataTransfer || !event.dataTransfer.types) { + return; + } + + var isFirefox = false; + //noinspection JSUnresolvedVariable + for (var property in event.dataTransfer) { + //noinspection JSUnresolvedVariable + if (event.dataTransfer.hasOwnProperty(property) && property.match(/^moz/)) { + isFirefox = true; + break; + } + } + + // IE and WebKit set 'Files', Firefox sets 'application/x-moz-file' for files being dragged + // and Safari just provides 'Files' along with a huge list of garbage + _isFile = false; + if (isFirefox) { + // Firefox sets the 'Files' type even if the user is just dragging an on-page element + //noinspection JSUnresolvedVariable + if (event.dataTransfer.types[0] === 'application/x-moz-file') { + _isFile = true; + } + } + else { + //noinspection JSUnresolvedVariable + for (var i = 0; i < event.dataTransfer.types.length; i++) { + //noinspection JSUnresolvedVariable + if (event.dataTransfer.types[i] === 'Files') { + _isFile = true; + break; + } + } + } + + if (!_isFile) { + // user is just dragging around some garbage, ignore it + return; + } + + if (_isDragging) { + // user is still dragging the file around + return; + } + + _isDragging = true; + + _dragArea.forEach((function (data, uuid) { + var editor = data.editor.$editor[0]; + if (!editor.parentNode) { + _dragArea.delete(uuid); + return; + } + + var element = data.element; + if (element === null) { + element = elCreate('div'); + element.className = 'redactorDropArea'; + elData(element, 'element-id', data.editor.$element[0].id); + elData(element, 'drop-here', Language.get('wcf.attachment.dragAndDrop.dropHere')); + elData(element, 'drop-now', Language.get('Drop now to upload')); + + element.addEventListener('dragover', function () { element.classList.add('active'); }); + element.addEventListener('dragleave', function () { element.classList.remove('active'); }); + element.addEventListener('drop', this._drop.bind(this)); + + data.element = element; + } + + editor.parentNode.insertBefore(element, editor); + element.style.setProperty('top', editor.offsetTop + 'px', ''); + }).bind(this)); + }, + + /** + * Handles items dropped onto an editor's drop area + * + * @param {Event} event drop event + * @protected + */ + _drop: function (event) { + if (!_isFile) { + return; + } + + //noinspection JSUnresolvedVariable + if (!event.dataTransfer || !event.dataTransfer.files.length) { + return; + } + + event.preventDefault(); + + //noinspection JSCheckFunctionSignatures + var elementId = elData(event.currentTarget, 'element-id'); + + //noinspection JSUnresolvedVariable + for (var i = 0, length = event.dataTransfer.files.length; i < length; i++) { + //noinspection JSUnresolvedVariable + EventHandler.fire('com.woltlab.wcf.redactor2', 'dragAndDrop_' + elementId, { + file: event.dataTransfer.files[i] + }); + } + + // this will reset all drop areas + this._dragLeave(); + }, + + /** + * Invoked whenever the item is no longer dragged or was dropped. + * + * @protected + */ + _dragLeave: function () { + if (!_isDragging || !_isFile) { + return; + } + + if (_timerLeave !== null) { + window.clearTimeout(_timerLeave); + } + + _timerLeave = window.setTimeout(function () { + if (!_isDragging) { + _dragArea.forEach(function (data) { + if (data.element && data.element.parentNode) { + data.element.classList.remove('active'); + elRemove(data.element); + } + }); + } + + _timerLeave = null; + }, 100); + + _isDragging = false; + }, + + /** + * Binds listeners to global events. + * + * @protected + */ + _setup: function () { + // discard garbage events + window.addEventListener('dragstart', function (event) { event.preventDefault(); }); + window.addEventListener('dragend', function (event) { event.preventDefault(); }); + + window.addEventListener('dragover', this._dragOver.bind(this)); + window.addEventListener('dragleave', this._dragLeave.bind(this)); + + _didInit = true; + } + }; +}); diff --git a/wcfsetup/install/files/style/ui/redactor.scss b/wcfsetup/install/files/style/ui/redactor.scss index 10e4fc3cde..df7c19fe16 100644 --- a/wcfsetup/install/files/style/ui/redactor.scss +++ b/wcfsetup/install/files/style/ui/redactor.scss @@ -332,18 +332,31 @@ } .redactorDropArea { - background-color: rgba(255, 255, 204, 1); - border: 5px dashed rgba(255, 204, 0); - box-sizing: border-box; - font-size: 1.4rem; // TODO + align-items: center; + background-color: $wcfStatusInfoBackground; + border: 5px dashed currentColor; + bottom: 0; + color: $wcfStatusInfoText; + display: flex; + justify-content: center; + left: 0; position: absolute; - text-align: center; - vertical-align: middle; + right: 0; z-index: 360; + @include wcfFontSection; + + &::before { + content: attr(data-drop-here); + } + &.active { - background-color: #CEF6CE; - border-color: #04B404; + background-color: $wcfStatusSuccessBackground; + color: $wcfStatusSuccessText; + + &::before { + content: attr(data-drop-now); + } } }