mirror of
https://github.com/discourse/discourse.git
synced 2025-02-20 22:26:10 +08:00
FEATURE: add image delete button in preview. (#17624)
This commit adds a delete button to the composer preview next to the image scale buttons. Reference: https://meta.discourse.org/t/image-remover-button-to-composer-preview/233005
This commit is contained in:
parent
46f43d4f7c
commit
2d6bd30dd8
@ -594,6 +594,8 @@ export default Component.extend(ComposerUploadUppy, {
|
||||
|
||||
resetImageControls(buttonWrapper) {
|
||||
const imageResize = buttonWrapper.querySelector(".scale-btn-container");
|
||||
const imageDelete = buttonWrapper.querySelector(".delete-image-button");
|
||||
|
||||
const readonlyContainer = buttonWrapper.querySelector(
|
||||
".alt-text-readonly-container"
|
||||
);
|
||||
@ -602,6 +604,8 @@ export default Component.extend(ComposerUploadUppy, {
|
||||
);
|
||||
|
||||
imageResize.removeAttribute("hidden");
|
||||
imageDelete.removeAttribute("hidden");
|
||||
|
||||
readonlyContainer.removeAttribute("hidden");
|
||||
buttonWrapper.removeAttribute("editing");
|
||||
editContainer.setAttribute("hidden", "true");
|
||||
@ -647,6 +651,7 @@ export default Component.extend(ComposerUploadUppy, {
|
||||
|
||||
const buttonWrapper = event.target.closest(".button-wrapper");
|
||||
const imageResize = buttonWrapper.querySelector(".scale-btn-container");
|
||||
const imageDelete = buttonWrapper.querySelector(".delete-image-button");
|
||||
|
||||
const readonlyContainer = buttonWrapper.querySelector(
|
||||
".alt-text-readonly-container"
|
||||
@ -660,6 +665,7 @@ export default Component.extend(ComposerUploadUppy, {
|
||||
|
||||
buttonWrapper.setAttribute("editing", "true");
|
||||
imageResize.setAttribute("hidden", "true");
|
||||
imageDelete.setAttribute("hidden", "true");
|
||||
readonlyContainer.setAttribute("hidden", "true");
|
||||
editContainerInput.value = altText.textContent;
|
||||
editContainer.removeAttribute("hidden");
|
||||
@ -687,10 +693,30 @@ export default Component.extend(ComposerUploadUppy, {
|
||||
this.resetImageControls(buttonWrapper);
|
||||
},
|
||||
|
||||
@bind
|
||||
_handleImageDeleteButtonClick(event) {
|
||||
if (!event.target.classList.contains("delete-image-button")) {
|
||||
return;
|
||||
}
|
||||
const index = parseInt(
|
||||
event.target.closest(".button-wrapper").dataset.imageIndex,
|
||||
10
|
||||
);
|
||||
const matchingPlaceholder =
|
||||
this.get("composer.reply").match(IMAGE_MARKDOWN_REGEX);
|
||||
this.appEvents.trigger(
|
||||
"composer:replace-text",
|
||||
matchingPlaceholder[index],
|
||||
"",
|
||||
{ regex: IMAGE_MARKDOWN_REGEX, index }
|
||||
);
|
||||
},
|
||||
|
||||
_registerImageAltTextButtonClick(preview) {
|
||||
preview.addEventListener("click", this._handleAltTextEditButtonClick);
|
||||
preview.addEventListener("click", this._handleAltTextOkButtonClick);
|
||||
preview.addEventListener("click", this._handleAltTextCancelButtonClick);
|
||||
preview.addEventListener("click", this._handleImageDeleteButtonClick);
|
||||
preview.addEventListener("keypress", this._handleAltTextInputKeypress);
|
||||
},
|
||||
|
||||
|
@ -340,4 +340,39 @@ acceptance("Composer - Image Preview", function (needs) {
|
||||
"alt text updated"
|
||||
);
|
||||
});
|
||||
|
||||
test("Image delete button", async function (assert) {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
let uploads = [
|
||||
"",
|
||||
"",
|
||||
];
|
||||
|
||||
await fillIn(".d-editor-input", uploads.join("\n"));
|
||||
|
||||
uploads[0] = ""; // delete the first image.
|
||||
|
||||
//click on the remove button of the first image
|
||||
await click(".button-wrapper[data-image-index='0'] .delete-image-button");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".d-editor-input").value,
|
||||
uploads.join("\n"),
|
||||
"Image should be removed from the editor"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
query(".d-editor-input").value.includes("image_example_0"),
|
||||
false,
|
||||
"It shouldn't have the first image"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
query(".d-editor-input").value.includes("image_example_1"),
|
||||
true,
|
||||
"It should have the second image"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -70,12 +70,13 @@ function buildScaleButton(selectedScale, scale) {
|
||||
function buildImageShowAltTextControls(altText) {
|
||||
return `
|
||||
<span class="alt-text-readonly-container">
|
||||
<span class="alt-text" aria-label="${I18n.t(
|
||||
"composer.image_alt_text.aria_label"
|
||||
)}">${altText}</span>
|
||||
<span class="alt-text-edit-btn">
|
||||
<svg aria-hidden="true" class="fa d-icon d-icon-pencil svg-icon svg-string"><use href="#pencil-alt"></use></svg>
|
||||
</span>
|
||||
<span class="alt-text-edit-btn">
|
||||
<svg aria-hidden="true" class="fa d-icon d-icon-pencil svg-icon svg-string"><use href="#pencil-alt"></use></svg>
|
||||
</span>
|
||||
|
||||
<span class="alt-text" aria-label="${I18n.t(
|
||||
"composer.image_alt_text.aria_label"
|
||||
)}">${altText}</span>
|
||||
</span>
|
||||
`;
|
||||
}
|
||||
@ -94,6 +95,17 @@ function buildImageEditAltTextControls(altText) {
|
||||
`;
|
||||
}
|
||||
|
||||
function buildImageDeleteButton() {
|
||||
return `
|
||||
<span class="delete-image-button" aria-label="${I18n.t(
|
||||
"composer.delete_image_button"
|
||||
)}">
|
||||
<svg class="fa d-icon d-icon-trash-alt svg-icon svg-string" xmlns="http://www.w3.org/2000/svg">
|
||||
<use href="#far-trash-alt"></use>
|
||||
</svg>
|
||||
</span>
|
||||
`;
|
||||
}
|
||||
// We need this to load after `upload-protocol` which is priority 0
|
||||
export const priority = 1;
|
||||
|
||||
@ -112,13 +124,6 @@ function ruleWithImageControls(oldRule) {
|
||||
result += oldRule(tokens, idx, options, env, slf);
|
||||
|
||||
result += `<span class="button-wrapper" data-image-index="${index}">`;
|
||||
|
||||
result += `<span class="scale-btn-container">`;
|
||||
result += SCALES.map((scale) =>
|
||||
buildScaleButton(selectedScale, scale)
|
||||
).join("");
|
||||
result += `</span>`;
|
||||
|
||||
result += buildImageShowAltTextControls(
|
||||
token.attrs[token.attrIndex("alt")][1]
|
||||
);
|
||||
@ -126,6 +131,13 @@ function ruleWithImageControls(oldRule) {
|
||||
token.attrs[token.attrIndex("alt")][1]
|
||||
);
|
||||
|
||||
result += `<span class="scale-btn-container">`;
|
||||
result += SCALES.map((scale) =>
|
||||
buildScaleButton(selectedScale, scale)
|
||||
).join("");
|
||||
result += `</span>`;
|
||||
result += buildImageDeleteButton();
|
||||
|
||||
result += "</span></span>";
|
||||
|
||||
return result;
|
||||
@ -148,16 +160,17 @@ export function setup(helper) {
|
||||
"span.scale-btn[data-scale]",
|
||||
"span.button-wrapper[data-image-index]",
|
||||
"span[aria-label]",
|
||||
|
||||
"span[class=delete-image-button]",
|
||||
"span.alt-text-container",
|
||||
|
||||
"span.alt-text-readonly-container",
|
||||
"span.alt-text-readonly-container.alt-text",
|
||||
"span.alt-text-readonly-container.alt-text-edit-btn",
|
||||
"svg[class=fa d-icon d-icon-pencil svg-icon svg-string]",
|
||||
"use[href=#pencil-alt]",
|
||||
"use[href=#far-trash-alt]",
|
||||
|
||||
"span.alt-text-edit-container",
|
||||
"span.delete-image-button",
|
||||
"span[hidden=true]",
|
||||
"input[type=text]",
|
||||
"input[class=alt-text-input]",
|
||||
@ -166,6 +179,7 @@ export function setup(helper) {
|
||||
"use[href=#check]",
|
||||
"button[class=alt-text-edit-cancel btn-default]",
|
||||
"svg[class=fa d-icon d-icon-times svg-icon svg-string]",
|
||||
"svg[class=fa d-icon d-icon-trash-alt svg-icon svg-string]",
|
||||
"use[href=#times]",
|
||||
]);
|
||||
|
||||
|
@ -200,7 +200,8 @@
|
||||
|
||||
.scale-btn-container,
|
||||
.alt-text-readonly-container,
|
||||
.alt-text-edit-container {
|
||||
.alt-text-edit-container,
|
||||
.delete-image-button {
|
||||
background: var(--secondary);
|
||||
display: flex;
|
||||
height: var(--resizer-height);
|
||||
@ -245,6 +246,7 @@
|
||||
|
||||
.alt-text-edit-btn {
|
||||
cursor: pointer;
|
||||
color: var(--tertiary);
|
||||
|
||||
svg {
|
||||
padding-right: 0.5em;
|
||||
@ -282,6 +284,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.delete-image-button {
|
||||
cursor: pointer;
|
||||
color: var(--danger);
|
||||
|
||||
.d-icon-trash-alt {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -2304,6 +2304,8 @@ en:
|
||||
image_alt_text:
|
||||
aria_label: Alt text for image
|
||||
|
||||
delete_image_button: Delete Image
|
||||
|
||||
notifications:
|
||||
tooltip:
|
||||
regular:
|
||||
|
Loading…
x
Reference in New Issue
Block a user