DEV: Drop jQuery file uploader and old upload components (#15376)
This commit removes jQuery file uploader from Discourse, completing the transition to Uppy. The image-uploader and UploadMixin components are also removed in this commit as they have already been replaced and are the only things using jQuery file upload. .-'~~~`-. .' `. | R I P | | jquery | | file | | upload | | | \\| 2013-2021 |// -----------------
This commit is contained in:
parent
72ad5bf8bd
commit
667a8a63b3
|
@ -1,135 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import UploadMixin from "discourse/mixins/upload";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { getURLWithCDN } from "discourse-common/lib/get-url";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import lightbox from "discourse/lib/lightbox";
|
||||
import { next } from "@ember/runloop";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Component.extend(UploadMixin, {
|
||||
classNames: ["image-uploader"],
|
||||
loadingLightbox: false,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
// TODO (martin) (2022-01-22) Remove this component.
|
||||
deprecated(
|
||||
"image-uploader will be removed in a future version, use uppy-image-uploader instead (the API is the same)"
|
||||
);
|
||||
this._applyLightbox();
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
const elem = $("a.lightbox");
|
||||
if (elem && typeof elem.magnificPopup === "function") {
|
||||
$("a.lightbox").magnificPopup("close");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("imageUrl", "placeholderUrl")
|
||||
showingPlaceholder(imageUrl, placeholderUrl) {
|
||||
return !imageUrl && placeholderUrl;
|
||||
},
|
||||
|
||||
@discourseComputed("placeholderUrl")
|
||||
placeholderStyle(url) {
|
||||
if (isEmpty(url)) {
|
||||
return "".htmlSafe();
|
||||
}
|
||||
return `background-image: url(${url})`.htmlSafe();
|
||||
},
|
||||
|
||||
@discourseComputed("imageUrl")
|
||||
imageCDNURL(url) {
|
||||
if (isEmpty(url)) {
|
||||
return "".htmlSafe();
|
||||
}
|
||||
|
||||
return getURLWithCDN(url);
|
||||
},
|
||||
|
||||
@discourseComputed("imageCDNURL")
|
||||
backgroundStyle(url) {
|
||||
return `background-image: url(${url})`.htmlSafe();
|
||||
},
|
||||
|
||||
@discourseComputed("imageUrl")
|
||||
imageBaseName(imageUrl) {
|
||||
if (isEmpty(imageUrl)) {
|
||||
return;
|
||||
}
|
||||
return imageUrl.split("/").slice(-1)[0];
|
||||
},
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return { imagesOnly: true };
|
||||
},
|
||||
|
||||
uploadDone(upload) {
|
||||
this.setProperties({
|
||||
imageUrl: upload.url,
|
||||
imageId: upload.id,
|
||||
imageFilesize: upload.human_filesize,
|
||||
imageFilename: upload.original_filename,
|
||||
imageWidth: upload.width,
|
||||
imageHeight: upload.height,
|
||||
});
|
||||
|
||||
this._applyLightbox();
|
||||
|
||||
if (this.onUploadDone) {
|
||||
this.onUploadDone(upload);
|
||||
}
|
||||
},
|
||||
|
||||
_openLightbox() {
|
||||
next(() =>
|
||||
$(this.element.querySelector("a.lightbox")).magnificPopup("open")
|
||||
);
|
||||
},
|
||||
|
||||
_applyLightbox() {
|
||||
if (this.imageUrl) {
|
||||
next(() => lightbox(this.element, this.siteSettings));
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleLightbox() {
|
||||
if (this.imageFilename) {
|
||||
this._openLightbox();
|
||||
} else {
|
||||
this.set("loadingLightbox", true);
|
||||
|
||||
ajax(`/uploads/lookup-metadata`, {
|
||||
type: "POST",
|
||||
data: { url: this.imageUrl },
|
||||
})
|
||||
.then((json) => {
|
||||
this.setProperties({
|
||||
imageFilename: json.original_filename,
|
||||
imageFilesize: json.human_filesize,
|
||||
imageWidth: json.width,
|
||||
imageHeight: json.height,
|
||||
});
|
||||
|
||||
this._openLightbox();
|
||||
this.set("loadingLightbox", false);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
},
|
||||
|
||||
trash() {
|
||||
this.setProperties({ imageUrl: null, imageId: null });
|
||||
|
||||
if (this.onUploadDeleted) {
|
||||
this.onUploadDeleted();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,134 +0,0 @@
|
|||
import {
|
||||
displayErrorForUpload,
|
||||
validateUploadedFiles,
|
||||
} from "discourse/lib/uploads";
|
||||
import I18n from "I18n";
|
||||
import Mixin from "@ember/object/mixin";
|
||||
import bootbox from "bootbox";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
import { on } from "@ember/object/evented";
|
||||
import { warn } from "@ember/debug";
|
||||
|
||||
export default Mixin.create({
|
||||
uploading: false,
|
||||
uploadProgress: 0,
|
||||
|
||||
uploadDone() {
|
||||
warn("You should implement `uploadDone`", {
|
||||
id: "discourse.upload.missing-upload-done",
|
||||
});
|
||||
},
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return {};
|
||||
},
|
||||
|
||||
calculateUploadUrl() {
|
||||
return (
|
||||
getUrl(this.getWithDefault("uploadUrl", "/uploads")) +
|
||||
".json?client_id=" +
|
||||
(this.messageBus && this.messageBus.clientId) +
|
||||
this.uploadUrlParams
|
||||
);
|
||||
},
|
||||
|
||||
uploadUrlParams: "",
|
||||
|
||||
uploadOptions() {
|
||||
return {};
|
||||
},
|
||||
|
||||
_initialize: on("didInsertElement", function () {
|
||||
const $upload = $(this.element);
|
||||
const reset = () => {
|
||||
this.setProperties({ uploading: false, uploadProgress: 0 });
|
||||
document.getElementsByClassName("hidden-upload-field")[0].value = "";
|
||||
};
|
||||
const maxFiles = this.getWithDefault(
|
||||
"maxFiles",
|
||||
this.siteSettings.simultaneous_uploads
|
||||
);
|
||||
|
||||
$upload.on("fileuploaddone", (e, data) => {
|
||||
let upload = data.result;
|
||||
this.uploadDone(upload);
|
||||
reset();
|
||||
});
|
||||
|
||||
$upload.fileupload(
|
||||
deepMerge(
|
||||
{
|
||||
url: this.calculateUploadUrl(),
|
||||
dataType: "json",
|
||||
replaceFileInput: false,
|
||||
dropZone: $upload,
|
||||
pasteZone: $upload,
|
||||
},
|
||||
this.uploadOptions()
|
||||
)
|
||||
);
|
||||
|
||||
$upload.on("fileuploaddrop", (e, data) => {
|
||||
if (maxFiles > 0 && data.files.length > maxFiles) {
|
||||
bootbox.alert(
|
||||
I18n.t("post.errors.too_many_dragged_and_dropped_files", {
|
||||
count: maxFiles,
|
||||
})
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
$upload.on("fileuploadsubmit", (e, data) => {
|
||||
const opts = deepMerge(
|
||||
{
|
||||
bypassNewUserRestriction: true,
|
||||
user: this.currentUser,
|
||||
siteSettings: this.siteSettings,
|
||||
},
|
||||
this.validateUploadedFilesOptions()
|
||||
);
|
||||
const isValid = validateUploadedFiles(data.files, opts);
|
||||
const type = this.type;
|
||||
let form = type ? { type } : {};
|
||||
|
||||
if (this.data) {
|
||||
form = Object.assign(form, this.data);
|
||||
}
|
||||
|
||||
data.formData = form;
|
||||
this.setProperties({ uploadProgress: 0, uploading: isValid });
|
||||
|
||||
return isValid;
|
||||
});
|
||||
|
||||
$upload.on("fileuploadprogressall", (e, data) => {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const progress = parseInt((data.loaded / data.total) * 100, 10);
|
||||
this.set("uploadProgress", progress);
|
||||
});
|
||||
|
||||
$upload.on("fileuploadfail", (e, data) => {
|
||||
displayErrorForUpload(data, this.siteSettings, data.files[0].name);
|
||||
reset();
|
||||
});
|
||||
}),
|
||||
|
||||
_destroy: on("willDestroyElement", function () {
|
||||
this.messageBus && this.messageBus.unsubscribe("/uploads/" + this.type);
|
||||
|
||||
const $upload = $(this.element);
|
||||
try {
|
||||
$upload.fileupload("destroy");
|
||||
} catch (e) {
|
||||
/* wasn't initialized yet */
|
||||
}
|
||||
$upload.off();
|
||||
}),
|
||||
});
|
|
@ -1,45 +0,0 @@
|
|||
<div class="uploaded-image-preview input-xxlarge" style={{backgroundStyle}}>
|
||||
{{#if showingPlaceholder}}
|
||||
<div class="placeholder-overlay" style={{placeholderStyle}}></div>
|
||||
{{/if}}
|
||||
<div class="image-upload-controls">
|
||||
<label class="btn btn-default pad-left no-text {{if uploading "disabled"}}">
|
||||
{{d-icon "far-image"}}
|
||||
<input class="hidden-upload-field" disabled={{uploading}} type="file" accept="image/*">
|
||||
</label>
|
||||
|
||||
{{#if imageUrl}}
|
||||
{{d-button
|
||||
action=(action "trash")
|
||||
class="btn-danger pad-left no-text"
|
||||
icon="far-trash-alt"
|
||||
type="button"
|
||||
}}
|
||||
|
||||
{{d-button
|
||||
icon="discourse-expand"
|
||||
title="expand"
|
||||
type="button"
|
||||
class="image-uploader-lightbox-btn no-text"
|
||||
action=(action "toggleLightbox")
|
||||
disabled=loadingLightbox
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
<span class="btn {{unless uploading "hidden"}}">{{i18n "upload_selector.uploading"}} {{uploadProgress}}%</span>
|
||||
</div>
|
||||
|
||||
{{#if imageUrl}}
|
||||
<a class="lightbox"
|
||||
href={{imageCDNURL}}
|
||||
title={{imageFilename}}
|
||||
rel="nofollow ugc noopener">
|
||||
|
||||
<div class="meta">
|
||||
<span class="informations">
|
||||
{{imageWidth}}x{{imageHeight}} {{imageFilesize}}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -42,8 +42,6 @@ module.exports = function (defaults) {
|
|||
app.import(vendorJs + "bootbox.js");
|
||||
app.import(vendorJs + "bootstrap-modal.js");
|
||||
app.import(vendorJs + "jquery.ui.widget.js");
|
||||
app.import(vendorJs + "jquery.fileupload.js");
|
||||
app.import(vendorJs + "jquery.fileupload-process.js");
|
||||
app.import(vendorJs + "caret_position.js");
|
||||
app.import("node_modules/ember-source/dist/ember-template-compiler.js", {
|
||||
type: "test",
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import {
|
||||
count,
|
||||
discourseModule,
|
||||
exists,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click } from "@ember/test-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
|
||||
discourseModule("Integration | Component | image-uploader", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("with image", {
|
||||
template: hbs`
|
||||
{{image-uploader imageUrl='/images/avatar.png' placeholderUrl='/not/used.png'}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
assert.strictEqual(
|
||||
count(".d-icon-far-image"),
|
||||
1,
|
||||
"it displays the upload icon"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
count(".d-icon-far-trash-alt"),
|
||||
1,
|
||||
"it displays the trash icon"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".placeholder-overlay"),
|
||||
"it does not display the placeholder image"
|
||||
);
|
||||
|
||||
await click(".image-uploader-lightbox-btn");
|
||||
|
||||
assert.strictEqual(
|
||||
document.querySelectorAll(".mfp-container").length,
|
||||
1,
|
||||
"it displays the image lightbox"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("without image", {
|
||||
template: hbs`{{image-uploader}}`,
|
||||
|
||||
test(assert) {
|
||||
assert.strictEqual(
|
||||
count(".d-icon-far-image"),
|
||||
1,
|
||||
"it displays the upload icon"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".d-icon-far-trash-alt"),
|
||||
"it does not display trash icon"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".image-uploader-lightbox-btn"),
|
||||
"it does not display the button to open image lightbox"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("with placeholder", {
|
||||
template: hbs`{{image-uploader placeholderUrl='/images/avatar.png'}}`,
|
||||
|
||||
test(assert) {
|
||||
assert.strictEqual(
|
||||
count(".d-icon-far-image"),
|
||||
1,
|
||||
"it displays the upload icon"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".d-icon-far-trash-alt"),
|
||||
"it does not display trash icon"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".image-uploader-lightbox-btn"),
|
||||
"it does not display the button to open image lightbox"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
count(".placeholder-overlay"),
|
||||
1,
|
||||
"it displays the placeholder image"
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
|
@ -18,9 +18,6 @@
|
|||
//= require popper.js
|
||||
//= require bootstrap-modal.js
|
||||
//= require caret_position
|
||||
//= require jquery.fileupload.js
|
||||
//= require jquery.iframe-transport.js
|
||||
//= require jquery.fileupload-process.js
|
||||
//= require jquery.sortable.js
|
||||
//= require lodash.js
|
||||
//= require itsatrap.js
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
//= require popper.js
|
||||
//= require bootstrap-modal.js
|
||||
//= require caret_position
|
||||
//= require jquery.fileupload.js
|
||||
//= require jquery.iframe-transport.js
|
||||
//= require jquery.fileupload-process.js
|
||||
//= require jquery.sortable.js
|
||||
//= require lodash.js
|
||||
//= require itsatrap.js
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//= require ember_jquery
|
||||
//= require template_include.js
|
||||
//= require jquery.ui.widget.js
|
||||
//= require jquery.fileupload.js
|
||||
//= require uppy.js
|
||||
//= require bootstrap-modal.js
|
||||
//= require bootbox.js
|
||||
|
|
|
@ -103,14 +103,6 @@ def dependencies
|
|||
}, {
|
||||
source: '@highlightjs/cdn-assets/.',
|
||||
destination: 'highlightjs'
|
||||
}, {
|
||||
source: 'blueimp-file-upload/js/jquery.fileupload.js',
|
||||
}, {
|
||||
source: 'blueimp-file-upload/js/jquery.iframe-transport.js',
|
||||
}, {
|
||||
source: 'blueimp-file-upload/js/jquery.fileupload-process.js',
|
||||
}, {
|
||||
source: 'blueimp-file-upload/js/vendor/jquery.ui.widget.js',
|
||||
}, {
|
||||
source: 'jquery/dist/jquery.js'
|
||||
}, {
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
* jQuery File Upload Processing Plugin
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2012, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* global define, require */
|
||||
|
||||
(function (factory) {
|
||||
'use strict';
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// Register as an anonymous AMD module:
|
||||
define(['jquery', './jquery.fileupload'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node/CommonJS:
|
||||
factory(require('jquery'), require('./jquery.fileupload'));
|
||||
} else {
|
||||
// Browser globals:
|
||||
factory(window.jQuery);
|
||||
}
|
||||
})(function ($) {
|
||||
'use strict';
|
||||
|
||||
var originalAdd = $.blueimp.fileupload.prototype.options.add;
|
||||
|
||||
// The File Upload Processing plugin extends the fileupload widget
|
||||
// with file processing functionality:
|
||||
$.widget('blueimp.fileupload', $.blueimp.fileupload, {
|
||||
options: {
|
||||
// The list of processing actions:
|
||||
processQueue: [
|
||||
/*
|
||||
{
|
||||
action: 'log',
|
||||
type: 'debug'
|
||||
}
|
||||
*/
|
||||
],
|
||||
add: function (e, data) {
|
||||
var $this = $(this);
|
||||
data.process(function () {
|
||||
return $this.fileupload('process', data);
|
||||
});
|
||||
originalAdd.call(this, e, data);
|
||||
}
|
||||
},
|
||||
|
||||
processActions: {
|
||||
/*
|
||||
log: function (data, options) {
|
||||
console[options.type](
|
||||
'Processing "' + data.files[data.index].name + '"'
|
||||
);
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
_processFile: function (data, originalData) {
|
||||
var that = this,
|
||||
// eslint-disable-next-line new-cap
|
||||
dfd = $.Deferred().resolveWith(that, [data]),
|
||||
chain = dfd.promise();
|
||||
this._trigger('process', null, data);
|
||||
$.each(data.processQueue, function (i, settings) {
|
||||
var func = function (data) {
|
||||
if (originalData.errorThrown) {
|
||||
// eslint-disable-next-line new-cap
|
||||
return $.Deferred().rejectWith(that, [originalData]).promise();
|
||||
}
|
||||
return that.processActions[settings.action].call(
|
||||
that,
|
||||
data,
|
||||
settings
|
||||
);
|
||||
};
|
||||
chain = chain.then(func, settings.always && func);
|
||||
});
|
||||
chain
|
||||
.done(function () {
|
||||
that._trigger('processdone', null, data);
|
||||
that._trigger('processalways', null, data);
|
||||
})
|
||||
.fail(function () {
|
||||
that._trigger('processfail', null, data);
|
||||
that._trigger('processalways', null, data);
|
||||
});
|
||||
return chain;
|
||||
},
|
||||
|
||||
// Replaces the settings of each processQueue item that
|
||||
// are strings starting with an "@", using the remaining
|
||||
// substring as key for the option map,
|
||||
// e.g. "@autoUpload" is replaced with options.autoUpload:
|
||||
_transformProcessQueue: function (options) {
|
||||
var processQueue = [];
|
||||
$.each(options.processQueue, function () {
|
||||
var settings = {},
|
||||
action = this.action,
|
||||
prefix = this.prefix === true ? action : this.prefix;
|
||||
$.each(this, function (key, value) {
|
||||
if ($.type(value) === 'string' && value.charAt(0) === '@') {
|
||||
settings[key] =
|
||||
options[
|
||||
value.slice(1) ||
|
||||
(prefix
|
||||
? prefix + key.charAt(0).toUpperCase() + key.slice(1)
|
||||
: key)
|
||||
];
|
||||
} else {
|
||||
settings[key] = value;
|
||||
}
|
||||
});
|
||||
processQueue.push(settings);
|
||||
});
|
||||
options.processQueue = processQueue;
|
||||
},
|
||||
|
||||
// Returns the number of files currently in the processsing queue:
|
||||
processing: function () {
|
||||
return this._processing;
|
||||
},
|
||||
|
||||
// Processes the files given as files property of the data parameter,
|
||||
// returns a Promise object that allows to bind callbacks:
|
||||
process: function (data) {
|
||||
var that = this,
|
||||
options = $.extend({}, this.options, data);
|
||||
if (options.processQueue && options.processQueue.length) {
|
||||
this._transformProcessQueue(options);
|
||||
if (this._processing === 0) {
|
||||
this._trigger('processstart');
|
||||
}
|
||||
$.each(data.files, function (index) {
|
||||
var opts = index ? $.extend({}, options) : options,
|
||||
func = function () {
|
||||
if (data.errorThrown) {
|
||||
// eslint-disable-next-line new-cap
|
||||
return $.Deferred().rejectWith(that, [data]).promise();
|
||||
}
|
||||
return that._processFile(opts, data);
|
||||
};
|
||||
opts.index = index;
|
||||
that._processing += 1;
|
||||
that._processingQueue = that._processingQueue
|
||||
.then(func, func)
|
||||
.always(function () {
|
||||
that._processing -= 1;
|
||||
if (that._processing === 0) {
|
||||
that._trigger('processstop');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return this._processingQueue;
|
||||
},
|
||||
|
||||
_create: function () {
|
||||
this._super();
|
||||
this._processing = 0;
|
||||
// eslint-disable-next-line new-cap
|
||||
this._processingQueue = $.Deferred().resolveWith(this).promise();
|
||||
}
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue