FEATURE: use native file picker in composer (#13552)

We want to remove completely our custom modal for uploading files in composer and directly trigger the system file picker.

This PR makes it happen. The fix is pretty simple since we already weren't using our custom modal on mobile. We just need to start using the same hidden <input type="file"> that we already use on mobile.

It seems to be pretty tricky to test opening a system modal so I haven't added new tests. We already have other tests for file uploading though. We directly trigger jquery-File-Upload plugin hooks in those tests - 3dda926cb2/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js (L89).
This commit is contained in:
Andrei Prigorshnev
2021-06-30 12:45:47 +04:00
committed by GitHub
parent b63c9febe8
commit a2e0da16a7
12 changed files with 14 additions and 240 deletions

View File

@@ -831,10 +831,12 @@ export default Component.extend({
});
if (this.site.mobileView) {
$("#reply-control .mobile-file-upload").on("click.uploader", function () {
// redirect the click on the hidden file input
$("#mobile-uploader").click();
});
const uploadButton = document.getElementById("mobile-file-upload");
uploadButton.addEventListener(
"click",
() => document.getElementById("file-uploader").click(),
false
);
}
},

View File

@@ -1,69 +0,0 @@
import {
allowsAttachments,
authorizedExtensions,
uploadIcon,
} from "discourse/lib/uploads";
import Controller from "@ember/controller";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import discourseComputed from "discourse-common/utils/decorators";
import { equal } from "@ember/object/computed";
export default Controller.extend(ModalFunctionality, {
imageUrl: null,
local: equal("selection", "local"),
remote: equal("selection", "remote"),
selection: "local",
@discourseComputed()
allowAdditionalFormats() {
return allowsAttachments(this.currentUser.staff, this.siteSettings);
},
@discourseComputed()
uploadIcon() {
return uploadIcon(this.currentUser.staff, this.siteSettings);
},
@discourseComputed("allowAdditionalFormats")
title(allowAdditionalFormats) {
const suffix = allowAdditionalFormats ? "_with_attachments" : "";
return `upload_selector.title${suffix}`;
},
@discourseComputed("selection", "allowAdditionalFormats")
tip(selection, allowAdditionalFormats) {
const suffix = allowAdditionalFormats ? "_with_attachments" : "";
return I18n.t(`upload_selector.${selection}_tip${suffix}`);
},
@discourseComputed()
supportedFormats() {
const extensions = authorizedExtensions(
this.currentUser.staff,
this.siteSettings
);
return `(${extensions})`;
},
actions: {
upload() {
if (this.local) {
$(".wmd-controls").fileupload("add", {
fileInput: $("#filename-input"),
});
} else {
const imageUrl = this.imageUrl || "";
const toolbarEvent = this.toolbarEvent;
if (imageUrl.match(/\.(jpg|jpeg|png|gif|heic|heif|webp)$/)) {
toolbarEvent.addText(`![](${imageUrl})`);
} else {
toolbarEvent.addText(imageUrl);
}
}
this.send("closeModal");
},
},
});

View File

@@ -137,11 +137,8 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, {
showModal("not-activated", { title: "log_in" }).setProperties(props);
},
showUploadSelector(toolbarEvent) {
showModal("uploadSelector").setProperties({
toolbarEvent,
imageUrl: null,
});
showUploadSelector() {
document.getElementById("file-uploader").click();
},
showKeyboardShortcutsHelp() {

View File

@@ -19,6 +19,4 @@
disabled=disableTextarea
outletArgs=(hash composer=composer editorType="composer")}}
{{#if site.mobileView}}
<input type="file" id="mobile-uploader" multiple>
{{/if}}
<input type="file" id="file-uploader" multiple>

View File

@@ -200,7 +200,7 @@
{{plugin-outlet name="composer-mobile-buttons-bottom" connectorTagName="" args=(hash model=model)}}
{{#if allowUpload}}
<a class="btn btn-default no-text mobile-file-upload {{if isUploading "hidden"}}" aria-label={{i18n "composer.upload_title"}}>
<a id="mobile-file-upload" class="btn btn-default no-text mobile-file-upload {{if isUploading "hidden"}}" aria-label={{i18n "composer.upload_title"}}>
{{d-icon uploadIcon}}
</a>
{{/if}}

View File

@@ -1,45 +0,0 @@
{{#d-modal-body title=title class="upload-selector"}}
<div class="radios">
{{radio-button name="upload" id="local" value="local" selection=selection}}
<label class="radio" for="local">{{i18n "upload_selector.from_my_computer"}}</label>
{{#if local}}
<div class="inputs">
<input type="file" id="filename-input" multiple><br>
<span class="description">{{tip}}</span>
{{#if allowAdditionalFormats}}
{{hidden-details label="upload_selector.supported_formats" details=supportedFormats}}
{{/if}}
</div>
{{/if}}
</div>
<div class="radios">
{{radio-button name="upload" id="remote" value="remote" selection=selection}}
<label class="radio" for="remote">{{i18n "upload_selector.from_the_web"}}</label>
{{#if remote}}
<div class="inputs">
{{input value=imageUrl placeholder="http://example.com/image.png"}}
<span class="description">{{tip}}</span>
{{#if allowAdditionalFormats}}
{{hidden-details label="upload_selector.supported_formats" details=supportedFormats}}
{{/if}}
</div>
{{/if}}
</div>
<div class="radios">
<div class="inputs">
<p class="hint">
{{#if capabilities.canPasteImages}}
{{i18n "upload_selector.hint"}}
{{else}}
{{i18n "upload_selector.hint_for_supported_browsers"}}
{{/if}}
</p>
</div>
</div>
{{/d-modal-body}}
<div class="modal-footer">
{{d-button action=(action "upload") class="btn-primary" icon=uploadIcon label="upload"}}
{{plugin-outlet name="upload-actions"}}
{{d-modal-cancel close=(route-action "closeModal")}}
</div>

View File

@@ -362,6 +362,10 @@
#file-uploading {
color: var(--primary-high);
}
#file-uploader {
display: none;
}
}
.autocomplete {

View File

@@ -1,49 +1,3 @@
.upload-selector {
label {
display: inline-block;
padding-left: 10px;
}
&.modal-body {
width: 460px;
}
.radios {
min-height: 60px;
display: flex;
align-items: flex-start;
label {
flex: 1 0 auto;
margin-right: 1em;
margin-top: 1px;
}
.inputs {
width: 100%;
input {
width: 90%;
margin: 0 0 5px 0;
}
input[type="file"] {
font-size: $font-0;
line-height: $line-height-medium;
}
.description,
.hint {
color: var(--primary-med-or-secondary-med);
display: block;
}
.hint {
font-style: italic;
margin: 5px 0 0 0;
}
.label {
margin: 0 0 5px 0;
}
}
}
.radios:last-child {
min-height: 20px;
}
}
.uploaded-image-preview {
height: 270px;
width: 400px;

View File

@@ -171,10 +171,6 @@
}
}
#mobile-uploader {
display: none;
}
.title-and-category,
.user-selector {
margin: 0;

View File

@@ -1,37 +1,3 @@
.upload-selector {
input[type="text"] {
width: calc(100% - 20px);
}
input[type="file"] {
font-size: $font-0;
line-height: $line-height-medium;
}
.description {
color: var(--primary-medium);
}
.radios {
display: flex;
flex-wrap: wrap;
align-items: center;
&:first-of-type {
margin-bottom: 1em;
}
input,
label {
min-height: 20px;
line-height: $line-height-medium;
margin: 0;
}
.radio {
padding-left: 5px;
}
.inputs {
margin-top: 10px;
width: 100%;
}
}
}
.uploaded-image-preview {
height: 150px;
}