From e251073a197511b99b5fb8d15e10de12d767ed2a Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 13 Feb 2020 10:38:52 +0100 Subject: [PATCH] Enable upload related classes for guests in accelerated mode These classes are required to support attachment in the contact form. --- wcfsetup/install/files/js/WCF.Attachment.js | 1314 ++++++++------- wcfsetup/install/files/js/WCF.js | 1595 +++++++++---------- 2 files changed, 1407 insertions(+), 1502 deletions(-) diff --git a/wcfsetup/install/files/js/WCF.Attachment.js b/wcfsetup/install/files/js/WCF.Attachment.js index b6ac5d74bd..0317265059 100644 --- a/wcfsetup/install/files/js/WCF.Attachment.js +++ b/wcfsetup/install/files/js/WCF.Attachment.js @@ -5,763 +5,715 @@ */ WCF.Attachment = {}; -if (COMPILER_TARGET_DEFAULT) { +/** + * Attachment upload function + * + * @see WCF.Upload + */ +WCF.Attachment.Upload = WCF.Upload.extend({ /** - * Attachment upload function - * - * @see WCF.Upload + * list of upload ids which should be automatically inserted + * @var array */ - WCF.Attachment.Upload = WCF.Upload.extend({ - /** - * list of upload ids which should be automatically inserted - * @var array - */ - _autoInsert: [], - - /** - * reference to 'Insert All' button - * @var jQuery - */ - _insertAllButton: null, - - /** - * object type of the object the uploaded attachments belong to - * @var string - */ - _objectType: '', - - /** - * id of the object the uploaded attachments belong to - * @var string - */ - _objectID: 0, + _autoInsert: [], + + /** + * reference to 'Insert All' button + * @var jQuery + */ + _insertAllButton: null, + + /** + * object type of the object the uploaded attachments belong to + * @var string + */ + _objectType: '', + + /** + * id of the object the uploaded attachments belong to + * @var string + */ + _objectID: 0, + + /** + * temporary hash to identify uploaded attachments + * @var string + */ + _tmpHash: '', + + /** + * id of the parent object of the object the uploaded attachments belongs to + * @var string + */ + _parentObjectID: 0, + + /** + * editor id + * @var string + */ + _editorId: '', + + /** + * replace img element on load + * @var Object + */ + _replaceOnLoad: {}, + + /** + * additional options + * @var Object + */ + _options: {}, + + /** + * @see WCF.Upload.init() + */ + init: function (buttonSelector, fileListSelector, objectType, objectID, tmpHash, parentObjectID, maxUploads, editorId, options) { + this._super(buttonSelector, fileListSelector, 'wcf\\data\\attachment\\AttachmentAction', { + multiple: true, + maxUploads: maxUploads + }); - /** - * temporary hash to identify uploaded attachments - * @var string - */ - _tmpHash: '', + this._autoInsert = []; + this._objectType = objectType; + this._objectID = parseInt(objectID); + this._tmpHash = tmpHash; + this._parentObjectID = parseInt(parentObjectID); + this._editorId = editorId; + this._options = $.extend(true, this._options, options || {}); - /** - * id of the parent object of the object the uploaded attachments belongs to - * @var string - */ - _parentObjectID: 0, + this._buttonSelector.children('p.button').click($.proxy(this._validateLimit, this)); + this._fileListSelector.find('.jsButtonInsertAttachment').click($.proxy(this._insert, this)); + this._fileListSelector.find('.jsButtonAttachmentInsertThumbnail').click($.proxy(this._insert, this)); + this._fileListSelector.find('.jsButtonAttachmentInsertFull').click($.proxy(this._insert, this)); - /** - * editor id - * @var string - */ - _editorId: '', + WCF.DOMNodeRemovedHandler.addCallback('WCF.Attachment.Upload', $.proxy(this._removeLimitError, this)); + WCF.System.Event.addListener('com.woltlab.wcf.action.delete', 'attachment_' + this._editorId, $.proxy(this._removeLimitError, this)); - /** - * replace img element on load - * @var Object - */ - _replaceOnLoad: {}, + this._makeSortable(); - /** - * additional options - * @var Object - */ - _options: {}, + // for backwards compatibility, the object is still created but only inserted + // if an editor is used + this._insertAllButton = $('

' + WCF.Language.get('wcf.attachment.insertAll') + '

').hide(); - /** - * @see WCF.Upload.init() - */ - init: function (buttonSelector, fileListSelector, objectType, objectID, tmpHash, parentObjectID, maxUploads, editorId, options) { - this._super(buttonSelector, fileListSelector, 'wcf\\data\\attachment\\AttachmentAction', { - multiple: true, - maxUploads: maxUploads - }); - - this._autoInsert = []; - this._objectType = objectType; - this._objectID = parseInt(objectID); - this._tmpHash = tmpHash; - this._parentObjectID = parseInt(parentObjectID); - this._editorId = editorId; - this._options = $.extend(true, this._options, options || {}); + if (this._editorId) { + this._insertAllButton.appendTo(this._buttonSelector); + this._insertAllButton.click($.proxy(this._insertAll, this)); - this._buttonSelector.children('p.button').click($.proxy(this._validateLimit, this)); - this._fileListSelector.find('.jsButtonInsertAttachment').click($.proxy(this._insert, this)); - this._fileListSelector.find('.jsButtonAttachmentInsertThumbnail').click($.proxy(this._insert, this)); - this._fileListSelector.find('.jsButtonAttachmentInsertFull').click($.proxy(this._insert, this)); - - WCF.DOMNodeRemovedHandler.addCallback('WCF.Attachment.Upload', $.proxy(this._removeLimitError, this)); - WCF.System.Event.addListener('com.woltlab.wcf.action.delete', 'attachment_' + this._editorId, $.proxy(this._removeLimitError, this)); - - this._makeSortable(); + if (this._fileListSelector.children('li:not(.uploadFailed)').length) { + this._insertAllButton.show(); + } - // for backwards compatibility, the object is still created but only inserted - // if an editor is used - this._insertAllButton = $('

' + WCF.Language.get('wcf.attachment.insertAll') + '

').hide(); + 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)); + WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'pasteFromClipboard_' + this._editorId, this._editorUpload.bind(this)); - if (this._editorId) { - this._insertAllButton.appendTo(this._buttonSelector); - this._insertAllButton.click($.proxy(this._insertAll, this)); - - if (this._fileListSelector.children('li:not(.uploadFailed)').length) { - this._insertAllButton.show(); + WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'autosaveMetaData_' + this._editorId, (function (data) { + if (!data.tmpHashes || !Array.isArray(data.tmpHashes)) { + data.tmpHashes = []; } - 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)); - WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'pasteFromClipboard_' + this._editorId, this._editorUpload.bind(this)); + var index = data.tmpHashes.indexOf(tmpHash); - WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'autosaveMetaData_' + this._editorId, (function (data) { - if (!data.tmpHashes || !Array.isArray(data.tmpHashes)) { - data.tmpHashes = []; + var count = this._fileListSelector.children('li:not(.uploadFailed)').length; + if (count > 0) { + if (index === -1) { + data.tmpHashes.push(tmpHash); } + } + else if (index !== -1) { + data.tmpHashes.splice(index); + } + }).bind(this)); + + var metacodeAttachUuid = WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'metacode_attach_' + this._editorId, (function (data) { + var images = this._getImageAttachments(); + var attachmentId = data.attributes[0] || 0; + if (images.hasOwnProperty(attachmentId)) { + var thumbnail = data.attributes[2]; + thumbnail = (thumbnail === true || thumbnail === 'true' || ~~thumbnail > 0); - var index = data.tmpHashes.indexOf(tmpHash); + var image = elCreate('img'); + image.className = 'woltlabAttachment'; + image.src = images[attachmentId][(thumbnail ? 'thumbnailUrl' : 'url')]; + elData(image, 'attachment-id', attachmentId); - var count = this._fileListSelector.children('li:not(.uploadFailed)').length; - if (count > 0) { - if (index === -1) { - data.tmpHashes.push(tmpHash); - } - } - else if (index !== -1) { - data.tmpHashes.splice(index); - } - }).bind(this)); - - var metacodeAttachUuid = WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'metacode_attach_' + this._editorId, (function (data) { - var images = this._getImageAttachments(); - var attachmentId = data.attributes[0] || 0; - if (images.hasOwnProperty(attachmentId)) { - var thumbnail = data.attributes[2]; - thumbnail = (thumbnail === true || thumbnail === 'true' || ~~thumbnail > 0); - - var image = elCreate('img'); - image.className = 'woltlabAttachment'; - image.src = images[attachmentId][(thumbnail ? 'thumbnailUrl' : 'url')]; - elData(image, 'attachment-id', attachmentId); - - var float = data.attributes[1] || 'none'; - if (float === 'left') image.classList.add('messageFloatObjectLeft'); - else if (float === 'right') image.classList.add('messageFloatObjectRight'); - - var metacode = data.metacode; - metacode.parentNode.insertBefore(image, metacode); - elRemove(metacode); - - data.cancel = true; - } - }).bind(this)); - - WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'destroy_' + this._editorId, (function () { - 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.removeAllListeners('com.woltlab.wcf.redactor2', 'pasteFromClipboard_' + this._editorId); - WCF.System.Event.removeAllListeners('com.woltlab.wcf.redactor2', 'autosaveMetaData_' + this._editorId); + var float = data.attributes[1] || 'none'; + if (float === 'left') image.classList.add('messageFloatObjectLeft'); + else if (float === 'right') image.classList.add('messageFloatObjectRight'); - WCF.System.Event.removeListener('com.woltlab.wcf.redactor2', 'metacode_attach_' + this._editorId, metacodeAttachUuid); - }).bind(this)); - } - }, - - /** - * Handles drag & drop uploads and clipboard paste. - * - * @param object data - */ - _editorUpload: function (data) { - var $uploadID, replace = null; - - // show tab - this._fileListSelector.closest('.messageTabMenu').messageTabMenu('showTab', 'attachments', true); - - var callbackUploadId = (function(uploadId) { - if (replace === null) { - this._autoInsert.push(uploadId); - } - else { - this._replaceOnLoad[uploadId] = replace; + var metacode = data.metacode; + metacode.parentNode.insertBefore(image, metacode); + elRemove(metacode); + + data.cancel = true; } - - data.uploadID = uploadId; - }).bind(this); + }).bind(this)); - if (data.file) { - $uploadID = this._upload(undefined, data.file, undefined, callbackUploadId); + WCF.System.Event.addListener('com.woltlab.wcf.redactor2', 'destroy_' + this._editorId, (function () { + 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.removeAllListeners('com.woltlab.wcf.redactor2', 'pasteFromClipboard_' + this._editorId); + WCF.System.Event.removeAllListeners('com.woltlab.wcf.redactor2', 'autosaveMetaData_' + this._editorId); + + WCF.System.Event.removeListener('com.woltlab.wcf.redactor2', 'metacode_attach_' + this._editorId, metacodeAttachUuid); + }).bind(this)); + } + }, + + /** + * Handles drag & drop uploads and clipboard paste. + * + * @param object data + */ + _editorUpload: function (data) { + var $uploadID, replace = null; + + // show tab + this._fileListSelector.closest('.messageTabMenu').messageTabMenu('showTab', 'attachments', true); + + var callbackUploadId = (function(uploadId) { + if (replace === null) { + this._autoInsert.push(uploadId); } else { - $uploadID = this._upload(undefined, undefined, data.blob, callbackUploadId); - replace = data.replace || null; + this._replaceOnLoad[uploadId] = replace; } - }, + + data.uploadID = uploadId; + }).bind(this); - /** - * Sets the attachments representing an image. - * - * @return {Object} - */ - _getImageAttachments: function () { - var images = {}; - - this._fileListSelector.children('li').each(function (index, attachment) { - var $attachment = $(attachment); - if ($attachment.data('isImage')) { - images[~~$attachment.data('objectID')] = { - thumbnailUrl: $attachment.find('.jsButtonAttachmentInsertThumbnail').data('url'), - url: $attachment.find('.jsButtonAttachmentInsertFull').data('url') - }; - } - }); - - return images; - }, + if (data.file) { + $uploadID = this._upload(undefined, data.file, undefined, callbackUploadId); + } + else { + $uploadID = this._upload(undefined, undefined, data.blob, callbackUploadId); + replace = data.replace || null; + } + }, + + /** + * Sets the attachments representing an image. + * + * @return {Object} + */ + _getImageAttachments: function () { + var images = {}; - /** - * Adds parameters for the inline editor. - * - * @param object data - */ - _submitInline: function (data) { - if (this._tmpHash) { - data.tmpHash = this._tmpHash; - - var metaData = {}; - WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'getMetaData_' + this._editorId, metaData); - if (metaData.tmpHashes && Array.isArray(metaData.tmpHashes) && metaData.tmpHashes.length > 0) { - data.tmpHash += ',' + metaData.tmpHashes.join(','); - } + this._fileListSelector.children('li').each(function (index, attachment) { + var $attachment = $(attachment); + if ($attachment.data('isImage')) { + images[~~$attachment.data('objectID')] = { + thumbnailUrl: $attachment.find('.jsButtonAttachmentInsertThumbnail').data('url'), + url: $attachment.find('.jsButtonAttachmentInsertFull').data('url') + }; } - }, + }); - /** - * Resets the attachment container. - */ - _reset: function () { - this._fileListSelector.hide().empty(); - this._insertAllButton.hide(); - this._validateLimit(); - }, - - /** - * Validates upload limits. - * - * @return boolean - */ - _validateLimit: function () { - var $innerError = this._buttonSelector.next('small.innerError'); + return images; + }, + + /** + * Adds parameters for the inline editor. + * + * @param object data + */ + _submitInline: function (data) { + if (this._tmpHash) { + data.tmpHash = this._tmpHash; - // check maximum uploads - var $max = this._options.maxUploads - this._fileListSelector.children('li:not(.uploadFailed)').length; - var $filesLength = (this._fileUpload) ? this._fileUpload.prop('files').length : 0; - if ($max <= 0 || $max < $filesLength) { - // reached limit - var $errorMessage = ($max <= 0) ? WCF.Language.get('wcf.attachment.upload.error.reachedLimit') : WCF.Language.get('wcf.attachment.upload.error.reachedRemainingLimit').replace(/#remaining#/, $max); - if (!$innerError.length) { - $innerError = $('').insertAfter(this._buttonSelector); - } - - $innerError.html($errorMessage); - - return false; + var metaData = {}; + WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'getMetaData_' + this._editorId, metaData); + if (metaData.tmpHashes && Array.isArray(metaData.tmpHashes) && metaData.tmpHashes.length > 0) { + data.tmpHash += ',' + metaData.tmpHashes.join(','); + } + } + }, + + /** + * Resets the attachment container. + */ + _reset: function () { + this._fileListSelector.hide().empty(); + this._insertAllButton.hide(); + this._validateLimit(); + }, + + /** + * Validates upload limits. + * + * @return boolean + */ + _validateLimit: function () { + var $innerError = this._buttonSelector.next('small.innerError'); + + // check maximum uploads + var $max = this._options.maxUploads - this._fileListSelector.children('li:not(.uploadFailed)').length; + var $filesLength = (this._fileUpload) ? this._fileUpload.prop('files').length : 0; + if ($max <= 0 || $max < $filesLength) { + // reached limit + var $errorMessage = ($max <= 0) ? WCF.Language.get('wcf.attachment.upload.error.reachedLimit') : WCF.Language.get('wcf.attachment.upload.error.reachedRemainingLimit').replace(/#remaining#/, $max); + if (!$innerError.length) { + $innerError = $('').insertAfter(this._buttonSelector); } - // remove previous errors - $innerError.remove(); + $innerError.html($errorMessage); - return true; - }, + return false; + } - /** - * Removes the limit error message. - * - * @param object data - */ - _removeLimitError: function (data) { - var $listItems = this._fileListSelector.children('li'); - if (!$listItems.filter(':not(.uploadFailed)').length) { - this._insertAllButton.hide(); - } + // remove previous errors + $innerError.remove(); + + return true; + }, + + /** + * Removes the limit error message. + * + * @param object data + */ + _removeLimitError: function (data) { + var $listItems = this._fileListSelector.children('li'); + if (!$listItems.filter(':not(.uploadFailed)').length) { + this._insertAllButton.hide(); + } + + if (!$listItems.length) { + this._fileListSelector.hide(); + } + + if (this._editorId && data.button) { + WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'deleteAttachment_' + this._editorId, { + attachmentId: data.button.data('objectID') + }); + } + }, + + /** + * @see WCF.Upload._upload() + */ + _upload: function (event, file, blob, callbackUploadId) { + var _super = this._super.bind(this); + + require([ + 'WoltLabSuite/Core/FileUtil', + 'WoltLabSuite/Core/Image/ImageUtil', + 'WoltLabSuite/Core/Image/Resizer', + 'WoltLabSuite/Core/Ajax/Status' + ], (function (FileUtil, ImageUtil, ImageResizer, AjaxStatus) { + AjaxStatus.show(); - if (!$listItems.length) { - this._fileListSelector.hide(); - } + var files = []; - if (this._editorId && data.button) { - WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'deleteAttachment_' + this._editorId, { - attachmentId: data.button.data('objectID') - }); + if (file) { + files.push(file); + } + else if (blob) { + files.push(FileUtil.blobToFile(blob, 'pasted-from-clipboard')); + } + else { + files = this._fileUpload.prop('files'); } - }, - - /** - * @see WCF.Upload._upload() - */ - _upload: function (event, file, blob, callbackUploadId) { - var _super = this._super.bind(this); - require([ - 'WoltLabSuite/Core/FileUtil', - 'WoltLabSuite/Core/Image/ImageUtil', - 'WoltLabSuite/Core/Image/Resizer', - 'WoltLabSuite/Core/Ajax/Status' - ], (function (FileUtil, ImageUtil, ImageResizer, AjaxStatus) { - AjaxStatus.show(); + // We resolve with the unaltered list of files in case auto scaling is disabled. + var promise = Promise.resolve(files); + + if (this._options.autoScale && this._options.autoScale.enable) { + var maxSize = this._buttonSelector.data('maxSize'); - var files = []; + var resizer = new ImageResizer(); - if (file) { - files.push(file); - } - else if (blob) { - files.push(FileUtil.blobToFile(blob, 'pasted-from-clipboard')); - } - else { - files = this._fileUpload.prop('files'); + // Resize the images in series. + // As our resizer is based on Pica it will use multiple workers per image if possible. + promise = Array.prototype.reduce.call(files, (function (acc, file) { + return acc.then((function (arr) { + var timeout = new Promise(function (resolve, reject) { + // We issue one timeout per image, thus multiple timeout + // handlers will run in parallel + setTimeout(function () { + resolve(file); + }, 10000); + }); + + var promise = resizer.loadFile(file) + .then((function (result) { + var exif = result.exif; + var maxWidth = this._options.autoScale.maxWidth; + var maxHeight = this._options.autoScale.maxHeight; + var quality = this._options.autoScale.quality; + + if (window.devicePixelRatio >= 2) { + var realWidth = window.screen.width * window.devicePixelRatio; + var realHeight = window.screen.height * window.devicePixelRatio; + // Check whether the width of the image is roughly the width of the physical screen, and + // the height of the image is at least the height of the physical screen. + if (realWidth - 10 < result.image.width && result.image.width < realWidth + 10 && realHeight - 10 < result.image.height) { + // This appears to be a screenshot from a HiDPI device in portrait mode: Scale to logical size + maxWidth = Math.min(maxWidth, window.screen.width); + } + } + + return resizer.resize(result.image, maxWidth, maxHeight, quality, file.size > maxSize, timeout) + .then((function (resizedImage) { + // Check whether the image actually was resized + if (resizedImage === undefined) { + return file; + } + + var fileType = this._options.autoScale.fileType; + + if (this._options.autoScale.fileType === 'keep' || ImageUtil.containsTransparentPixels(resizedImage)) { + fileType = file.type; + } + + return resizer.saveFile({ + exif: exif, + image: resizedImage + }, file.name, fileType, quality); + }).bind(this)) + .then(function (resizedFile) { + if (resizedFile.size > file.size) { + console.debug('[WCF.Attachment] File size of "' + file.name + '" increased, uploading untouched image.'); + return file; + } + + return resizedFile; + }); + }).bind(this)) + .catch(function (error) { + console.debug('[WCF.Attachment] Failed to resize image "' + file.name + '":', error); + return file; + }); + + return Promise.race([timeout, promise]) + .then(function (file) { + arr.push(file); + return arr; + }); + }).bind(this)); + }).bind(this), Promise.resolve([])); + } + + promise.then((function (files) { + var uploadID = undefined; + + if (this._validateLimit()) { + uploadID = _super(event, undefined, undefined, files); } - // We resolve with the unaltered list of files in case auto scaling is disabled. - var promise = Promise.resolve(files); + if (this._fileUpload) { + // remove and re-create the upload button since the 'files' property + // of the input field is readonly thus it can't be reset + this._removeButton(); + this._createButton(); + } - if (this._options.autoScale && this._options.autoScale.enable) { - var maxSize = this._buttonSelector.data('maxSize'); - - var resizer = new ImageResizer(); - - // Resize the images in series. - // As our resizer is based on Pica it will use multiple workers per image if possible. - promise = Array.prototype.reduce.call(files, (function (acc, file) { - return acc.then((function (arr) { - var timeout = new Promise(function (resolve, reject) { - // We issue one timeout per image, thus multiple timeout - // handlers will run in parallel - setTimeout(function () { - resolve(file); - }, 10000); - }); - - var promise = resizer.loadFile(file) - .then((function (result) { - var exif = result.exif; - var maxWidth = this._options.autoScale.maxWidth; - var maxHeight = this._options.autoScale.maxHeight; - var quality = this._options.autoScale.quality; - - if (window.devicePixelRatio >= 2) { - var realWidth = window.screen.width * window.devicePixelRatio; - var realHeight = window.screen.height * window.devicePixelRatio; - // Check whether the width of the image is roughly the width of the physical screen, and - // the height of the image is at least the height of the physical screen. - if (realWidth - 10 < result.image.width && result.image.width < realWidth + 10 && realHeight - 10 < result.image.height) { - // This appears to be a screenshot from a HiDPI device in portrait mode: Scale to logical size - maxWidth = Math.min(maxWidth, window.screen.width); - } - } - - return resizer.resize(result.image, maxWidth, maxHeight, quality, file.size > maxSize, timeout) - .then((function (resizedImage) { - // Check whether the image actually was resized - if (resizedImage === undefined) { - return file; - } - - var fileType = this._options.autoScale.fileType; - - if (this._options.autoScale.fileType === 'keep' || ImageUtil.containsTransparentPixels(resizedImage)) { - fileType = file.type; - } - - return resizer.saveFile({ - exif: exif, - image: resizedImage - }, file.name, fileType, quality); - }).bind(this)) - .then(function (resizedFile) { - if (resizedFile.size > file.size) { - console.debug('[WCF.Attachment] File size of "' + file.name + '" increased, uploading untouched image.'); - return file; - } - - return resizedFile; - }); - }).bind(this)) - .catch(function (error) { - console.debug('[WCF.Attachment] Failed to resize image "' + file.name + '":', error); - return file; - }); - - return Promise.race([timeout, promise]) - .then(function (file) { - arr.push(file); - return arr; - }); - }).bind(this)); - }).bind(this), Promise.resolve([])); + if (typeof callbackUploadId === 'function') { + callbackUploadId(uploadID); } - promise.then((function (files) { - var uploadID = undefined; - - if (this._validateLimit()) { - uploadID = _super(event, undefined, undefined, files); - } - - if (this._fileUpload) { - // remove and re-create the upload button since the 'files' property - // of the input field is readonly thus it can't be reset - this._removeButton(); - this._createButton(); - } - - if (typeof callbackUploadId === 'function') { - callbackUploadId(uploadID); - } - - return uploadID; - }).bind(this)) - .catch(function (error) { - console.debug('[WCF.Attachment] Failed to upload attachments:', error); - }) - .finally(AjaxStatus.hide); - }).bind(this), function (error) { - console.debug('[WCF.Attachment] Failed to load modules:', error); - }); - }, + return uploadID; + }).bind(this)) + .catch(function (error) { + console.debug('[WCF.Attachment] Failed to upload attachments:', error); + }) + .finally(AjaxStatus.hide); + }).bind(this), function (error) { + console.debug('[WCF.Attachment] Failed to load modules:', error); + }); + }, + + /** + * @see WCF.Upload._createUploadMatrix() + */ + _createUploadMatrix: function (files) { + // remove failed uploads + this._fileListSelector.children('li.uploadFailed').remove(); - /** - * @see WCF.Upload._createUploadMatrix() - */ - _createUploadMatrix: function (files) { - // remove failed uploads - this._fileListSelector.children('li.uploadFailed').remove(); - - return this._super(files); - }, + return this._super(files); + }, + + /** + * @see WCF.Upload._getParameters() + */ + _getParameters: function () { + return { + objectType: this._objectType, + objectID: this._objectID, + tmpHash: this._tmpHash, + parentObjectID: this._parentObjectID + }; + }, + + /** + * @see WCF.Upload._initFile() + */ + _initFile: function (file) { + var $li = $('
  • ' + file.name + '

    • ').data('filename', file.name); + this._fileListSelector.append($li); + this._fileListSelector.show(); - /** - * @see WCF.Upload._getParameters() - */ - _getParameters: function () { - return { - objectType: this._objectType, - objectID: this._objectID, - tmpHash: this._tmpHash, - parentObjectID: this._parentObjectID - }; - }, + // validate file size + if (this._buttonSelector.data('maxSize') < file.size) { + // remove progress bar + $li.find('progress').remove(); + + // upload icon + $li.children('.fa-spinner').removeClass('fa-spinner').addClass('fa-ban'); + + // error message + $li.find('div > div').append($('' + WCF.Language.get('wcf.attachment.upload.error.tooLarge') + '')); + $li.addClass('uploadFailed'); + } - /** - * @see WCF.Upload._initFile() - */ - _initFile: function (file) { - var $li = $('
    • ' + file.name + '

      • ').data('filename', file.name); - this._fileListSelector.append($li); - this._fileListSelector.show(); + return $li; + }, + + /** + * Returns true if thumbnails are enabled and should be + * used instead of the original images. + * + * @return {boolean} + * @protected + */ + _useThumbnail: function() { + return elDataBool(this._fileListSelector[0], 'enable-thumbnails'); + }, + + /** + * @see WCF.Upload._success() + */ + _success: function (uploadID, data) { + var attachmentData; + for (var $i in this._uploadMatrix[uploadID]) { + if (!this._uploadMatrix[uploadID].hasOwnProperty($i)) { + continue; + } - // validate file size - if (this._buttonSelector.data('maxSize') < file.size) { - // remove progress bar - $li.find('progress').remove(); + // get li + var $li = this._uploadMatrix[uploadID][$i]; + + // remove progress bar + $li.find('progress').remove(); + + // get filename and check result + var $filename = $li.data('filename'); + var $internalFileID = $li.data('internalFileID'); + if (data.returnValues && data.returnValues.attachments[$internalFileID]) { + attachmentData = data.returnValues.attachments[$internalFileID]; - // upload icon - $li.children('.fa-spinner').removeClass('fa-spinner').addClass('fa-ban'); + // show thumbnail + if (attachmentData.tinyURL) { + $li.children('.fa-spinner').replaceWith($('')); + + $li.data('height', attachmentData.height); + $li.data('width', attachmentData.width); + elData($li[0], 'is-image', attachmentData.isImage); + } + // show file icon + else { + $li.children('.fa-spinner').removeClass('fa-spinner').addClass('fa-' + attachmentData.iconName); + } - // error message - $li.find('div > div').append($('' + WCF.Language.get('wcf.attachment.upload.error.tooLarge') + '')); - $li.addClass('uploadFailed'); - } - - return $li; - }, - - /** - * Returns true if thumbnails are enabled and should be - * used instead of the original images. - * - * @return {boolean} - * @protected - */ - _useThumbnail: function() { - return elDataBool(this._fileListSelector[0], 'enable-thumbnails'); - }, - - /** - * @see WCF.Upload._success() - */ - _success: function (uploadID, data) { - var attachmentData; - for (var $i in this._uploadMatrix[uploadID]) { - if (!this._uploadMatrix[uploadID].hasOwnProperty($i)) { - continue; + // update attachment link + var $link = $(''); + $link.text($filename).attr('href', attachmentData.url); + $link[0].target = '_blank'; + + if (attachmentData.isImage != 0) { + $link.addClass('jsImageViewer').attr('title', $filename); } + $li.find('p').empty().append($link); - // get li - var $li = this._uploadMatrix[uploadID][$i]; + // update file size + $li.find('small').append(attachmentData.formattedFilesize); - // remove progress bar - $li.find('progress').remove(); + // init buttons + var $buttonList = $li.find('ul').addClass('buttonGroup'); + var $deleteButton = $('
      • ' + WCF.Language.get('wcf.global.button.delete') + '
      • '); + $buttonList.append($deleteButton); - // get filename and check result - var $filename = $li.data('filename'); - var $internalFileID = $li.data('internalFileID'); - if (data.returnValues && data.returnValues.attachments[$internalFileID]) { - attachmentData = data.returnValues.attachments[$internalFileID]; - - // show thumbnail - if (attachmentData.tinyURL) { - $li.children('.fa-spinner').replaceWith($('')); + $li.data('objectID', attachmentData.attachmentID); + + if (this._editorId) { + if (attachmentData.tinyURL || (!this._useThumbnail() && attachmentData.isImage)) { + if (attachmentData.thumbnailURL) { + var $insertThumbnail = $('
      • ' + WCF.Language.get('wcf.attachment.insertThumbnail') + '
      • ').appendTo($buttonList); + $insertThumbnail.children('span.button').click($.proxy(this._insert, this)); + } - $li.data('height', attachmentData.height); - $li.data('width', attachmentData.width); - elData($li[0], 'is-image', attachmentData.isImage); + var $insertOriginal = $('
      • ' + WCF.Language.get('wcf.attachment.insertFull') + '
      • ').appendTo($buttonList); + $insertOriginal.children('span.button').click($.proxy(this._insert, this)); } - // show file icon else { - $li.children('.fa-spinner').removeClass('fa-spinner').addClass('fa-' + attachmentData.iconName); - } - - // update attachment link - var $link = $(''); - $link.text($filename).attr('href', attachmentData.url); - $link[0].target = '_blank'; - - if (attachmentData.isImage != 0) { - $link.addClass('jsImageViewer').attr('title', $filename); - } - $li.find('p').empty().append($link); - - // update file size - $li.find('small').append(attachmentData.formattedFilesize); - - // init buttons - var $buttonList = $li.find('ul').addClass('buttonGroup'); - var $deleteButton = $('
      • ' + WCF.Language.get('wcf.global.button.delete') + '
      • '); - $buttonList.append($deleteButton); - - $li.data('objectID', attachmentData.attachmentID); - - if (this._editorId) { - if (attachmentData.tinyURL || (!this._useThumbnail() && attachmentData.isImage)) { - if (attachmentData.thumbnailURL) { - var $insertThumbnail = $('
      • ' + WCF.Language.get('wcf.attachment.insertThumbnail') + '
      • ').appendTo($buttonList); - $insertThumbnail.children('span.button').click($.proxy(this._insert, this)); - } - - var $insertOriginal = $('
      • ' + WCF.Language.get('wcf.attachment.insertFull') + '
      • ').appendTo($buttonList); - $insertOriginal.children('span.button').click($.proxy(this._insert, this)); - } - else { - var $insertPlain = $('
      • ' + WCF.Language.get('wcf.attachment.insert') + '
      • '); - $insertPlain.appendTo($buttonList).children('span.button').click($.proxy(this._insert, this)); - } - } - - if (this._replaceOnLoad.hasOwnProperty(uploadID)) { - if (!$li.hasClass('uploadFailed')) { - var img = this._replaceOnLoad[uploadID]; - if (img && img.parentNode) { - WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'replaceAttachment_' + this._editorId, { - attachmentId: attachmentData.attachmentID, - img: img, - src: (attachmentData.thumbnailURL) ? attachmentData.thumbnailURL : attachmentData.url - }); - } - } - - this._replaceOnLoad[uploadID] = null; + var $insertPlain = $('
      • ' + WCF.Language.get('wcf.attachment.insert') + '
      • '); + $insertPlain.appendTo($buttonList).children('span.button').click($.proxy(this._insert, this)); } } - else { - // upload icon - $li.children('.fa-spinner').removeClass('fa-spinner').addClass('fa-ban'); - var $errorMessage = ''; - - // error handling - if (data.returnValues && data.returnValues.errors[$internalFileID]) { - var errorData = data.returnValues.errors[$internalFileID]; - $errorMessage = errorData.errorType; - - if ($errorMessage === 'uploadFailed' && errorData.additionalData.phpLimitExceeded) { - $errorMessage = 'uploadPhpLimit'; + + if (this._replaceOnLoad.hasOwnProperty(uploadID)) { + if (!$li.hasClass('uploadFailed')) { + var img = this._replaceOnLoad[uploadID]; + if (img && img.parentNode) { + WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'replaceAttachment_' + this._editorId, { + attachmentId: attachmentData.attachmentID, + img: img, + src: (attachmentData.thumbnailURL) ? attachmentData.thumbnailURL : attachmentData.url + }); } } - else { - // unknown error - $errorMessage = 'uploadFailed'; - } - $li.find('div > div').append($('' + WCF.Language.get('wcf.attachment.upload.error.' + $errorMessage) + '')); - $li.addClass('uploadFailed'); + this._replaceOnLoad[uploadID] = null; } + } + else { + // upload icon + $li.children('.fa-spinner').removeClass('fa-spinner').addClass('fa-ban'); + var $errorMessage = ''; - if (WCF.inArray(uploadID, this._autoInsert)) { - this._autoInsert.splice(this._autoInsert.indexOf(uploadID), 1); + // error handling + if (data.returnValues && data.returnValues.errors[$internalFileID]) { + var errorData = data.returnValues.errors[$internalFileID]; + $errorMessage = errorData.errorType; - if (!$li.hasClass('uploadFailed')) { - var btn = $li.find('.jsButtonAttachmentInsertThumbnail'); - if (!btn.length) btn = $li.find('.jsButtonAttachmentInsertFull'); - - btn.trigger('click'); + if ($errorMessage === 'uploadFailed' && errorData.additionalData.phpLimitExceeded) { + $errorMessage = 'uploadPhpLimit'; } } + else { + // unknown error + $errorMessage = 'uploadFailed'; + } + + $li.find('div > div').append($('' + WCF.Language.get('wcf.attachment.upload.error.' + $errorMessage) + '')); + $li.addClass('uploadFailed'); } - this._makeSortable(); - - if (this._fileListSelector.children('li:not(.uploadFailed)').length) { - this._insertAllButton.show(); - } - else { - this._insertAllButton.hide(); + if (WCF.inArray(uploadID, this._autoInsert)) { + this._autoInsert.splice(this._autoInsert.indexOf(uploadID), 1); + + if (!$li.hasClass('uploadFailed')) { + var btn = $li.find('.jsButtonAttachmentInsertThumbnail'); + if (!btn.length) btn = $li.find('.jsButtonAttachmentInsertFull'); + + btn.trigger('click'); + } } - - WCF.DOMNodeInsertedHandler.execute(); - }, + } - /** - * Inserts an attachment into WYSIWYG editor contents. - * - * @param {Event} event - */ - _insert: function (event) { - WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'insertAttachment_' + this._editorId, { - attachmentId: elData(event.currentTarget, 'object-id'), - url: elData(event.currentTarget, 'url') - }); - }, + this._makeSortable(); - /** - * Inserts all attachments at once. - */ - _insertAll: function () { - var attachment, button, preferThumbnail = this._useThumbnail(); - for (var i = 0, length = this._fileListSelector[0].childNodes.length; i < length; i++) { - attachment = this._fileListSelector[0].childNodes[i]; - if (attachment.nodeName === 'LI' && !attachment.classList.contains('uploadFailed')) { - button = null; - if (preferThumbnail) { - button = elBySel('.jsButtonAttachmentInsertThumbnail, .jsButtonAttachmentInsertPlain', attachment); - } - - if (button === null) { - button = elBySel('.jsButtonAttachmentInsertFull, .jsButtonAttachmentInsertPlain', attachment); - } + if (this._fileListSelector.children('li:not(.uploadFailed)').length) { + this._insertAllButton.show(); + } + else { + this._insertAllButton.hide(); + } + + WCF.DOMNodeInsertedHandler.execute(); + }, + + /** + * Inserts an attachment into WYSIWYG editor contents. + * + * @param {Event} event + */ + _insert: function (event) { + WCF.System.Event.fireEvent('com.woltlab.wcf.redactor2', 'insertAttachment_' + this._editorId, { + attachmentId: elData(event.currentTarget, 'object-id'), + url: elData(event.currentTarget, 'url') + }); + }, + + /** + * Inserts all attachments at once. + */ + _insertAll: function () { + var attachment, button, preferThumbnail = this._useThumbnail(); + for (var i = 0, length = this._fileListSelector[0].childNodes.length; i < length; i++) { + attachment = this._fileListSelector[0].childNodes[i]; + if (attachment.nodeName === 'LI' && !attachment.classList.contains('uploadFailed')) { + button = null; + if (preferThumbnail) { + button = elBySel('.jsButtonAttachmentInsertThumbnail, .jsButtonAttachmentInsertPlain', attachment); + } - window.jQuery(button).trigger('click'); + if (button === null) { + button = elBySel('.jsButtonAttachmentInsertFull, .jsButtonAttachmentInsertPlain', attachment); } + + window.jQuery(button).trigger('click'); } - }, + } + }, + + /** + * @see WCF.Upload._error() + */ + _error: function (data) { + // mark uploads as failed + this._fileListSelector.find('li').each(function (index, listItem) { + var $listItem = $(listItem); + if ($listItem.children('.fa-spinner').length) { + // upload icon + $listItem.addClass('uploadFailed').children('.fa-spinner').removeClass('fa-spinner').addClass('fa-ban'); + $listItem.find('div > div').append($('' + (data.responseJSON && data.responseJSON.message ? data.responseJSON.message : WCF.Language.get('wcf.attachment.upload.error.uploadFailed')) + '')); + } + }); + }, + + /** + * Initializes sorting for uploaded attachments. + */ + _makeSortable: function () { + var $attachments = this._fileListSelector.children('li:not(.uploadFailed)'); + if (!$attachments.length) { + return; + } - /** - * @see WCF.Upload._error() - */ - _error: function (data) { - // mark uploads as failed - this._fileListSelector.find('li').each(function (index, listItem) { - var $listItem = $(listItem); - if ($listItem.children('.fa-spinner').length) { - // upload icon - $listItem.addClass('uploadFailed').children('.fa-spinner').removeClass('fa-spinner').addClass('fa-ban'); - $listItem.find('div > div').append($('' + (data.responseJSON && data.responseJSON.message ? data.responseJSON.message : WCF.Language.get('wcf.attachment.upload.error.uploadFailed')) + '')); - } - }); - }, + $attachments.addClass('sortableAttachment').children('img').addClass('sortableNode'); - /** - * Initializes sorting for uploaded attachments. - */ - _makeSortable: function () { - var $attachments = this._fileListSelector.children('li:not(.uploadFailed)'); - if (!$attachments.length) { - return; - } + if (!this._fileListSelector.hasClass('sortableList')) { + this._fileListSelector.addClass('sortableList'); - $attachments.addClass('sortableAttachment').children('img').addClass('sortableNode'); - - if (!this._fileListSelector.hasClass('sortableList')) { - this._fileListSelector.addClass('sortableList'); - - require(['Environment'], (function (Environment) { - if (Environment.platform() === 'desktop') { - new WCF.Sortable.List(this._fileListSelector.parent().wcfIdentify(), '', 0, { - axis: false, - items: 'li.sortableAttachment', - toleranceElement: null, - start: function (event, ui) { - ui.placeholder[0].style.setProperty('height', ui.helper[0].offsetHeight + 'px', ''); - }, - update: (function () { - var $attachmentIDs = []; - this._fileListSelector.children('li:not(.uploadFailed)').each(function (index, listItem) { - $attachmentIDs.push($(listItem).data('objectID')); - }); - - if ($attachmentIDs.length) { - new WCF.Action.Proxy({ - autoSend: true, - data: { - actionName: 'updatePosition', - className: 'wcf\\data\\attachment\\AttachmentAction', - parameters: { - attachmentIDs: $attachmentIDs, - objectID: this._objectID, - objectType: this._objectType, - tmpHash: this._tmpHash - } + require(['Environment'], (function (Environment) { + if (Environment.platform() === 'desktop') { + new WCF.Sortable.List(this._fileListSelector.parent().wcfIdentify(), '', 0, { + axis: false, + items: 'li.sortableAttachment', + toleranceElement: null, + start: function (event, ui) { + ui.placeholder[0].style.setProperty('height', ui.helper[0].offsetHeight + 'px', ''); + }, + update: (function () { + var $attachmentIDs = []; + this._fileListSelector.children('li:not(.uploadFailed)').each(function (index, listItem) { + $attachmentIDs.push($(listItem).data('objectID')); + }); + + if ($attachmentIDs.length) { + new WCF.Action.Proxy({ + autoSend: true, + data: { + actionName: 'updatePosition', + className: 'wcf\\data\\attachment\\AttachmentAction', + parameters: { + attachmentIDs: $attachmentIDs, + objectID: this._objectID, + objectType: this._objectType, + tmpHash: this._tmpHash } - }); - } - }).bind(this) - }, true); - } - }).bind(this)); - } + } + }); + } + }).bind(this) + }, true); + } + }).bind(this)); } - }); -} -else { - WCF.Attachment.Upload = WCF.Upload.extend({ - _autoInsert: {}, - _insertAllButton: {}, - _objectType: "", - _objectID: 0, - _tmpHash: "", - _parentObjectID: 0, - _editorId: "", - _replaceOnLoad: {}, - init: function() {}, - _editorUpload: function() {}, - _getImageAttachments: function() {}, - _submitInline: function() {}, - _reset: function() {}, - _validateLimit: function() {}, - _removeLimitError: function() {}, - _upload: function() {}, - _createUploadMatrix: function() {}, - _getParameters: function() {}, - _initFile: function() {}, - _success: function() {}, - _insert: function() {}, - _insertAll: function() {}, - _error: function() {}, - _makeSortable: function() {}, - _name: "", - _buttonSelector: {}, - _fileListSelector: {}, - _fileUpload: {}, - _className: "", - _iframe: {}, - _internalFileID: 0, - _options: {}, - _uploadMatrix: {}, - _supportsAJAXUpload: true, - _overlay: {}, - _createButton: function() {}, - _insertButton: function() {}, - _removeButton: function() {}, - _progress: function() {}, - _showOverlay: function() {}, - _evaluateResponse: function() {}, - _getFilename: function() {} - }); -} + } +}); diff --git a/wcfsetup/install/files/js/WCF.js b/wcfsetup/install/files/js/WCF.js index ed50680e94..239bb11564 100755 --- a/wcfsetup/install/files/js/WCF.js +++ b/wcfsetup/install/files/js/WCF.js @@ -1698,200 +1698,200 @@ WCF.Action.SimpleProxy = Class.extend({ } }); -if (COMPILER_TARGET_DEFAULT) { +/** + * Basic implementation for AJAXProxy-based deletion. + * + * @param string className + * @param string containerSelector + * @param string buttonSelector + */ +WCF.Action.Delete = Class.extend({ + /** + * delete button selector + * @var string + */ + _buttonSelector: '', + + /** + * callback function called prior to triggering the delete effect + * @var function + */ + _callback: null, + + /** + * action class name + * @var string + */ + _className: '', + /** - * Basic implementation for AJAXProxy-based deletion. + * container selector + * @var string + */ + _containerSelector: '', + + /** + * list of known container ids + * @var array + */ + _containers: [], + + /** + * Initializes 'delete'-Proxy. * * @param string className * @param string containerSelector * @param string buttonSelector */ - WCF.Action.Delete = Class.extend({ - /** - * delete button selector - * @var string - */ - _buttonSelector: '', - - /** - * callback function called prior to triggering the delete effect - * @var function - */ - _callback: null, - - /** - * action class name - * @var string - */ - _className: '', + init: function (className, containerSelector, buttonSelector) { + this._containerSelector = containerSelector; + this._className = className; + this._buttonSelector = (buttonSelector) ? buttonSelector : '.jsDeleteButton'; + this._callback = null; - /** - * container selector - * @var string - */ - _containerSelector: '', + this.proxy = new WCF.Action.Proxy({ + success: $.proxy(this._success, this) + }); - /** - * list of known container ids - * @var array - */ - _containers: [], + this._initElements(); - /** - * Initializes 'delete'-Proxy. - * - * @param string className - * @param string containerSelector - * @param string buttonSelector - */ - init: function (className, containerSelector, buttonSelector) { - this._containerSelector = containerSelector; - this._className = className; - this._buttonSelector = (buttonSelector) ? buttonSelector : '.jsDeleteButton'; - this._callback = null; - - this.proxy = new WCF.Action.Proxy({ - success: $.proxy(this._success, this) - }); - - this._initElements(); + WCF.DOMNodeInsertedHandler.addCallback('WCF.Action.Delete' + this._className.hashCode(), $.proxy(this._initElements, this)); + }, + + /** + * Initializes available element containers. + */ + _initElements: function () { + $(this._containerSelector).each((function (index, container) { + var $container = $(container); + var $containerID = $container.wcfIdentify(); - WCF.DOMNodeInsertedHandler.addCallback('WCF.Action.Delete' + this._className.hashCode(), $.proxy(this._initElements, this)); - }, - - /** - * Initializes available element containers. - */ - _initElements: function () { - $(this._containerSelector).each((function (index, container) { - var $container = $(container); - var $containerID = $container.wcfIdentify(); + if (!WCF.inArray($containerID, this._containers)) { + var $deleteButton = $container.find(this._buttonSelector); - if (!WCF.inArray($containerID, this._containers)) { - var $deleteButton = $container.find(this._buttonSelector); - - if ($deleteButton.length) { - this._containers.push($containerID); - $deleteButton.click($.proxy(this._click, this)); - } + if ($deleteButton.length) { + this._containers.push($containerID); + $deleteButton.click($.proxy(this._click, this)); } - }).bind(this)); - }, - - /** - * Sends AJAX request. - * - * @param object event - */ - _click: function (event) { - var $target = $(event.currentTarget); - event.preventDefault(); - - if ($target.data('confirmMessageHtml') || $target.data('confirmMessage')) { - WCF.System.Confirmation.show($target.data('confirmMessageHtml') ? $target.data('confirmMessageHtml') : $target.data('confirmMessage'), $.proxy(this._execute, this), {target: $target}, undefined, $target.data('confirmMessageHtml') ? true : false); - } - else { - WCF.LoadingOverlayHandler.updateIcon($target); - this._sendRequest($target); } - }, - - /** - * Is called if the delete effect has been triggered on the given element. - * - * @param jQuery element - */ - _didTriggerEffect: function (element) { - // does nothing - }, + }).bind(this)); + }, + + /** + * Sends AJAX request. + * + * @param object event + */ + _click: function (event) { + var $target = $(event.currentTarget); + event.preventDefault(); - /** - * Executes deletion. - * - * @param string action - * @param object parameters - */ - _execute: function (action, parameters) { - if (action === 'cancel') { - return; - } - - WCF.LoadingOverlayHandler.updateIcon(parameters.target); - this._sendRequest(parameters.target); - }, + if ($target.data('confirmMessageHtml') || $target.data('confirmMessage')) { + WCF.System.Confirmation.show($target.data('confirmMessageHtml') ? $target.data('confirmMessageHtml') : $target.data('confirmMessage'), $.proxy(this._execute, this), {target: $target}, undefined, $target.data('confirmMessageHtml') ? true : false); + } + else { + WCF.LoadingOverlayHandler.updateIcon($target); + this._sendRequest($target); + } + }, + + /** + * Is called if the delete effect has been triggered on the given element. + * + * @param jQuery element + */ + _didTriggerEffect: function (element) { + // does nothing + }, + + /** + * Executes deletion. + * + * @param string action + * @param object parameters + */ + _execute: function (action, parameters) { + if (action === 'cancel') { + return; + } - /** - * Sends the request - * - * @param jQuery object - */ - _sendRequest: function (object) { - this.proxy.setOption('data', { - actionName: 'delete', - className: this._className, - interfaceName: 'wcf\\data\\IDeleteAction', - objectIDs: [$(object).data('objectID')] - }); - - this.proxy.sendRequest(); - }, + WCF.LoadingOverlayHandler.updateIcon(parameters.target); + this._sendRequest(parameters.target); + }, + + /** + * Sends the request + * + * @param jQuery object + */ + _sendRequest: function (object) { + this.proxy.setOption('data', { + actionName: 'delete', + className: this._className, + interfaceName: 'wcf\\data\\IDeleteAction', + objectIDs: [$(object).data('objectID')] + }); - /** - * Deletes items from containers. - * - * @param object data - * @param string textStatus - * @param object jqXHR - */ - _success: function (data, textStatus, jqXHR) { - if (this._callback) { - this._callback(data.objectIDs); - } - - this.triggerEffect(data.objectIDs); - }, + this.proxy.sendRequest(); + }, + + /** + * Deletes items from containers. + * + * @param object data + * @param string textStatus + * @param object jqXHR + */ + _success: function (data, textStatus, jqXHR) { + if (this._callback) { + this._callback(data.objectIDs); + } - /** - * Sets a callback function called prior to triggering the delete effect. - * - * @param {function} callback - */ - setCallback: function (callback) { - if (typeof callback !== 'function') { - throw new TypeError("[WCF.Action.Delete] Expected a valid callback for '" + this._className + "'."); - } - - this._callback = callback; - }, + this.triggerEffect(data.objectIDs); + }, + + /** + * Sets a callback function called prior to triggering the delete effect. + * + * @param {function} callback + */ + setCallback: function (callback) { + if (typeof callback !== 'function') { + throw new TypeError("[WCF.Action.Delete] Expected a valid callback for '" + this._className + "'."); + } - /** - * Triggers the delete effect for the objects with the given ids. - * - * @param array objectIDs - */ - triggerEffect: function (objectIDs) { - for (var $index in this._containers) { - var $container = $('#' + this._containers[$index]); - var $button = $container.find(this._buttonSelector); - if (WCF.inArray($button.data('objectID'), objectIDs)) { - var self = this; - $container.wcfBlindOut('up', function () { - var $container = $(this).remove(); - self._containers.splice(self._containers.indexOf($container.wcfIdentify()), 1); - self._didTriggerEffect($container); - - if ($button.data('eventName')) { - WCF.System.Event.fireEvent('com.woltlab.wcf.action.delete', $button.data('eventName'), { - button: $button, - container: $container - }); - } - }); - } + this._callback = callback; + }, + + /** + * Triggers the delete effect for the objects with the given ids. + * + * @param array objectIDs + */ + triggerEffect: function (objectIDs) { + for (var $index in this._containers) { + var $container = $('#' + this._containers[$index]); + var $button = $container.find(this._buttonSelector); + if (WCF.inArray($button.data('objectID'), objectIDs)) { + var self = this; + $container.wcfBlindOut('up', function () { + var $container = $(this).remove(); + self._containers.splice(self._containers.indexOf($container.wcfIdentify()), 1); + self._didTriggerEffect($container); + + if ($button.data('eventName')) { + WCF.System.Event.fireEvent('com.woltlab.wcf.action.delete', $button.data('eventName'), { + button: $button, + container: $container + }); + } + }); } } - }); - + } +}); + +if (COMPILER_TARGET_DEFAULT) { /** * Basic implementation for deletion of nested elements. * @@ -2104,23 +2104,6 @@ if (COMPILER_TARGET_DEFAULT) { }); } else { - WCF.Action.Delete = Class.extend({ - _buttonSelector: "", - _callback: {}, - _className: "", - _containerSelector: "", - _containers: {}, - init: function() {}, - _initElements: function() {}, - _click: function() {}, - _didTriggerEffect: function() {}, - _execute: function() {}, - _sendRequest: function() {}, - _success: function() {}, - setCallback: function() {}, - triggerEffect: function() {} - }); - WCF.Action.NestedDelete = WCF.Action.Delete.extend({ triggerEffect: function() {}, _buttonSelector: "", @@ -5451,7 +5434,10 @@ if (COMPILER_TARGET_DEFAULT) { } // update progress - this._dialog.find('progress').attr('value', data.returnValues.progress).text(data.returnValues.progress + '%').next('span').text(data.returnValues.progress + '%'); + this._dialog.find('progress').attr( + 'value', + data.returnValues.progress + ).text(data.returnValues.progress + '%').next('span').text(data.returnValues.progress + '%'); // worker is still busy with its business, carry on if (data.returnValues.progress < 100) { @@ -5472,11 +5458,13 @@ if (COMPILER_TARGET_DEFAULT) { else { // exchange icon this._dialog.find('.fa-spinner').removeClass('fa-spinner').addClass('fa-check green'); - this._dialog.find('.contentHeader h1').text(WCF.Language.get('wcf.global.worker.completed')); + this._dialog.find('.contentHeader h1').text(WCF.Language.get( + 'wcf.global.worker.completed')); // display continue button var $formSubmit = $('
        ').appendTo(this._dialog); - $('').appendTo($formSubmit).focus().click(function () { + $('').appendTo( + $formSubmit).focus().click(function () { if (data.returnValues.redirectURL) { window.location = data.returnValues.redirectURL; } @@ -5577,7 +5565,10 @@ if (COMPILER_TARGET_DEFAULT) { this.rebuild(); - WCF.DOMNodeInsertedHandler.addCallback('WCF.InlineEditor' + this._elementSelector.hashCode(), $.proxy(this.rebuild, this)); + WCF.DOMNodeInsertedHandler.addCallback( + 'WCF.InlineEditor' + this._elementSelector.hashCode(), + $.proxy(this.rebuild, this) + ); this._proxy = new WCF.Action.Proxy({ success: $.proxy(this._success, this) @@ -5585,13 +5576,16 @@ if (COMPILER_TARGET_DEFAULT) { WCF.CloseOverlayHandler.addCallback('WCF.InlineEditor', $.proxy(this._closeAll, this)); - this._notification = new WCF.System.Notification(WCF.Language.get('wcf.global.success'), 'success'); + this._notification = new WCF.System.Notification( + WCF.Language.get('wcf.global.success'), + 'success' + ); }, /** * Identify new elements and adds the event listeners to them. */ - rebuild: function() { + rebuild: function () { var $elements = $(this._elementSelector); var self = this; $elements.each(function (index, element) { @@ -5605,10 +5599,16 @@ if (COMPILER_TARGET_DEFAULT) { return; } - $trigger.on(WCF_CLICK_EVENT, $.proxy(self._show, self)).data('elementID', $elementID); + $trigger.on(WCF_CLICK_EVENT, $.proxy(self._show, self)).data( + 'elementID', + $elementID + ); if (self._quickOption) { // simulate click on target action - $trigger.disableSelection().data('optionName', self._quickOption).dblclick($.proxy(self._click, self)); + $trigger.disableSelection().data( + 'optionName', + self._quickOption + ).dblclick($.proxy(self._click, self)); } // store reference @@ -5666,7 +5666,8 @@ if (COMPILER_TARGET_DEFAULT) { // build dropdown var $trigger = null; if (!this._dropdowns[$elementID]) { - this._triggerElements[$elementID] = $trigger = this._getTriggerElement(this._elements[$elementID]).addClass('dropdownToggle'); + this._triggerElements[$elementID] = $trigger = this._getTriggerElement(this._elements[$elementID]).addClass( + 'dropdownToggle'); var parent = $trigger[0].parentNode; if (parent && parent.nodeName === 'LI' && parent.childElementCount === 1) { // do not add a wrapper element if the trigger is the only child @@ -5692,9 +5693,18 @@ if (COMPILER_TARGET_DEFAULT) { $lastElementType = $option.optionName; } } - else if (this._validate($elementID, $option.optionName) || this._validateCallbacks($elementID, $option.optionName)) { + else if (this._validate($elementID, $option.optionName) || this._validateCallbacks( + $elementID, + $option.optionName + )) { var $listItem = $('
      • ' + $option.label + '
      • ').appendTo(this._dropdowns[$elementID]); - $listItem.data('elementID', $elementID).data('optionName', $option.optionName).data('isQuickOption', ($option.isQuickOption ? true : false)).click($.proxy(this._click, this)); + $listItem.data('elementID', $elementID).data( + 'optionName', + $option.optionName + ).data('isQuickOption', ($option.isQuickOption ? true : false)).click($.proxy( + this._click, + this + )); $hasOptions = true; $lastElementType = $option.optionName; @@ -5857,679 +5867,622 @@ if (COMPILER_TARGET_DEFAULT) { } } }); +} +else { + WCF.System.Worker = Class.extend({ + _aborted: false, + _actionName: "", + _callback: {}, + _className: "", + _dialog: {}, + _proxy: {}, + _title: "", + init: function() {}, + _success: function() {} + }); - /** - * Default implementation for ajax file uploads. - * - * @deprecated Use WoltLabSuite/Core/Upload - * - * @param jquery buttonSelector - * @param jquery fileListSelector - * @param string className - * @param jquery options - */ - WCF.Upload = Class.extend({ - /** - * name of the upload field - * @var string - */ - _name: '__files[]', - - /** - * button selector - * @var jQuery - */ - _buttonSelector: null, - - /** - * file list selector - * @var jQuery - */ - _fileListSelector: null, - - /** - * upload file - * @var jQuery - */ - _fileUpload: null, - - /** - * class name - * @var string - */ - _className: '', - - /** - * iframe for IE<10 fallback - * @var jQuery - */ - _iframe: null, - - /** - * internal file id - * @var integer - */ - _internalFileID: 0, - - /** - * additional options - * @var jQuery - */ + WCF.InlineEditor = Class.extend({ + _callbacks: {}, + _dropdowns: {}, + _elements: {}, + _notification: {}, _options: {}, + _proxy: {}, + _triggerElements: {}, + _updateData: {}, + init: function() {}, + _closeAll: function() {}, + _setOptions: function() {}, + registerCallback: function() {}, + _getTriggerElement: function() {}, + _show: function() {}, + _validate: function() {}, + _validateCallbacks: function() {}, + _success: function() {}, + _updateState: function() {}, + _click: function() {}, + _execute: function() {}, + _executeCallback: function() {}, + _hide: function() {} + }); +} + +/** + * Default implementation for ajax file uploads. + * + * @deprecated Use WoltLabSuite/Core/Upload + * + * @param jquery buttonSelector + * @param jquery fileListSelector + * @param string className + * @param jquery options + */ +WCF.Upload = Class.extend({ + /** + * name of the upload field + * @var string + */ + _name: '__files[]', + + /** + * button selector + * @var jQuery + */ + _buttonSelector: null, + + /** + * file list selector + * @var jQuery + */ + _fileListSelector: null, + + /** + * upload file + * @var jQuery + */ + _fileUpload: null, + + /** + * class name + * @var string + */ + _className: '', + + /** + * iframe for IE<10 fallback + * @var jQuery + */ + _iframe: null, + + /** + * internal file id + * @var integer + */ + _internalFileID: 0, + + /** + * additional options + * @var jQuery + */ + _options: {}, + + /** + * upload matrix + * @var array + */ + _uploadMatrix: [], + + /** + * true, if the active user's browser supports ajax file uploads + * @var boolean + */ + _supportsAJAXUpload: true, + + /** + * fallback overlay for stupid browsers + * @var jquery + */ + _overlay: null, + + /** + * Initializes a new upload handler. + * + * @param string buttonSelector + * @param string fileListSelector + * @param string className + * @param object options + */ + init: function (buttonSelector, fileListSelector, className, options) { + this._buttonSelector = buttonSelector; + this._fileListSelector = fileListSelector; + this._className = className; + this._internalFileID = 0; + this._options = $.extend(true, { + action: 'upload', + multiple: false, + url: 'index.php?ajax-upload/&t=' + SECURITY_TOKEN + }, options || {}); - /** - * upload matrix - * @var array - */ - _uploadMatrix: [], - - /** - * true, if the active user's browser supports ajax file uploads - * @var boolean - */ - _supportsAJAXUpload: true, - - /** - * fallback overlay for stupid browsers - * @var jquery - */ - _overlay: null, - - /** - * Initializes a new upload handler. - * - * @param string buttonSelector - * @param string fileListSelector - * @param string className - * @param object options - */ - init: function (buttonSelector, fileListSelector, className, options) { - this._buttonSelector = buttonSelector; - this._fileListSelector = fileListSelector; - this._className = className; - this._internalFileID = 0; - this._options = $.extend(true, { - action: 'upload', - multiple: false, - url: 'index.php?ajax-upload/&t=' + SECURITY_TOKEN - }, options || {}); - - this._options.url = WCF.convertLegacyURL(this._options.url); - if (this._options.url.indexOf('index.php') === 0) { - this._options.url = WSC_API_URL + this._options.url; - } - - // check for ajax upload support - var $xhr = new XMLHttpRequest(); - this._supportsAJAXUpload = ($xhr && ('upload' in $xhr) && ('onprogress' in $xhr.upload)); - - // create upload button - this._createButton(); - }, - - /** - * Creates the upload button. - */ - _createButton: function () { - if (this._supportsAJAXUpload) { - this._fileUpload = $(''); - this._fileUpload.change($.proxy(this._upload, this)); - var $button = $('

        ' + WCF.Language.get('wcf.global.button.upload') + '

        '); - elAttr($button[0], 'role', 'button'); - $button.prepend(this._fileUpload); - - this._fileUpload[0].addEventListener('focus', function() { - if (this.classList.contains('focus-visible')) { - $button[0].classList.add('active'); - } - }); - this._fileUpload[0].addEventListener('blur', function() { $button[0].classList.remove('active'); }); - } - else { - var $button = $('

        ' + WCF.Language.get('wcf.global.button.upload') + '

        '); - elAttr($button[0], 'role', 'button'); - elAttr($button[0], 'tabindex', '0'); - $button.click($.proxy(this._showOverlay, this)); - } - - this._insertButton($button); - }, - - /** - * Inserts the upload button. - * - * @param jQuery button - */ - _insertButton: function (button) { - this._buttonSelector.prepend(button); - }, - - /** - * Removes the upload button. - */ - _removeButton: function () { - var $selector = '.uploadButton'; - if (!this._supportsAJAXUpload) { - $selector = '.uploadFallbackButton'; - } - - this._buttonSelector.find($selector).remove(); - }, - - /** - * Callback for file uploads. - * - * @param object event - * @param File file - * @param Blob blob - * @param Array|FileList list of files - * @return integer - */ - _upload: function (event, file, blob, files) { - var $uploadID = null; - var $files = []; - - if (typeof files !== 'undefined') { - $files = files; - } - else { - if (file) { - $files.push(file); - } - else if (blob) { - var $ext = ''; - switch (blob.type) { - case 'image/png': - $ext = '.png'; - break; - - case 'image/jpeg': - $ext = '.jpg'; - break; - - case 'image/gif': - $ext = '.gif'; - break; - } - - $files.push({ - name: 'pasted-from-clipboard' + $ext - }); - } - else { - $files = this._fileUpload.prop('files'); - } - } - - if ($files.length) { - var $fd = new FormData(); - $uploadID = this._createUploadMatrix($files); - - // no more files left, abort - if (!this._uploadMatrix[$uploadID].length) { - return null; - } - - for (var $i = 0, $length = $files.length; $i < $length; $i++) { - if (this._uploadMatrix[$uploadID][$i]) { - var $internalFileID = this._uploadMatrix[$uploadID][$i].data('internalFileID'); - - if (blob) { - $fd.append('__files[' + $internalFileID + ']', blob, $files[$i].name); - } - else { - $fd.append('__files[' + $internalFileID + ']', $files[$i], $files[$i].name); - } - } - } - - $fd.append('actionName', this._options.action); - $fd.append('className', this._className); - var $additionalParameters = this._getParameters(); - for (var $name in $additionalParameters) { - $fd.append('parameters[' + $name + ']', $additionalParameters[$name]); - } - - var self = this; - $.ajax({ - type: 'POST', - url: this._options.url, - enctype: 'multipart/form-data', - data: $fd, - contentType: false, - processData: false, - success: function (data, textStatus, jqXHR) { - self._success($uploadID, data); - }, - error: $.proxy(this._error, this), - xhr: function () { - var $xhr = $.ajaxSettings.xhr(); - if ($xhr) { - $xhr.upload.addEventListener('progress', function (event) { - self._progress($uploadID, event); - }, false); - } - return $xhr; - }, - xhrFields: { - withCredentials: true - } - }); - } - - return $uploadID; - }, - - /** - * Creates upload matrix for provided files. - * - * @param array files - * @return integer - */ - _createUploadMatrix: function (files) { - if (files.length) { - var $uploadID = this._uploadMatrix.length; - this._uploadMatrix[$uploadID] = []; - - for (var $i = 0, $length = files.length; $i < $length; $i++) { - var $file = files[$i]; - var $li = this._initFile($file); - - if (!$li.hasClass('uploadFailed')) { - $li.data('filename', $file.name).data('internalFileID', this._internalFileID++); - this._uploadMatrix[$uploadID][$i] = $li; - } - } - - return $uploadID; - } - - return null; - }, - - /** - * Callback for success event. - * - * @param integer uploadID - * @param object data - */ - _success: function (uploadID, data) { - }, - - /** - * Callback for error event. - * - * @param jQuery jqXHR - * @param string textStatus - * @param string errorThrown - */ - _error: function (jqXHR, textStatus, errorThrown) { - }, - - /** - * Callback for progress event. - * - * @param integer uploadID - * @param object event - */ - _progress: function (uploadID, event) { - var $percentComplete = Math.round(event.loaded * 100 / event.total); - - for (var $i in this._uploadMatrix[uploadID]) { - this._uploadMatrix[uploadID][$i].find('progress').attr('value', $percentComplete); - } - }, - - /** - * Returns additional parameters. - * - * @return object - */ - _getParameters: function () { - return {}; - }, + this._options.url = WCF.convertLegacyURL(this._options.url); + if (this._options.url.indexOf('index.php') === 0) { + this._options.url = WSC_API_URL + this._options.url; + } - /** - * Initializes list item for uploaded file. - * - * @return jQuery - */ - _initFile: function (file) { - return $('
      • ' + file.name + ' (' + file.size + ')
      • ').appendTo(this._fileListSelector); - }, + // check for ajax upload support + var $xhr = new XMLHttpRequest(); + this._supportsAJAXUpload = ($xhr && ('upload' in $xhr) && ('onprogress' in $xhr.upload)); - /** - * Shows the fallback overlay (work in progress) - */ - _showOverlay: function () { - // create iframe - if (this._iframe === null) { - this._iframe = $('