mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user