'{@$__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}',
], 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}',
'WoltLabClean',
'WoltLabCode',
'WoltLabColor',
+ 'WoltLabDragAndDrop',
'WoltLabDropdown',
'WoltLabFont',
'WoltLabImage',
'{@$__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}',
], 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}',
'WoltLabClean',
'WoltLabCode',
'WoltLabColor',
+ 'WoltLabDragAndDrop',
'WoltLabDropdown',
'WoltLabFont',
'WoltLabImage',
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();
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));
}
},
--- /dev/null
+/**
+ * Drag and Drop file uploads.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2016 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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;
+ }
+ };
+});