DEV: Convert quote-button to a glimmer component (#22787)

Native class, glimmer, no jQ, async/await

Co-authored-by: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com>
This commit is contained in:
Jarek Radosz
2023-07-26 11:50:55 +02:00
committed by GitHub
co-authored by Isaac Janzen
parent 25138db433
commit 62d3979870
9 changed files with 351 additions and 351 deletions
@@ -14,6 +14,6 @@
@label="composer.save_edit"
@translatedTitle={{this.buttonTitle}}
@isLoading={{this.isSaving}}
@disabled={{eq @initialValue this.value}}
@disabled={{this.disabled}}
/>
</div>
@@ -15,11 +15,19 @@ export default class FastEdit extends Component {
modifier: translateModKey("Meta+"),
});
get disabled() {
return this.value === this.args.initialValue;
}
@action
onKeydown(event) {
if (event.key === "Escape") {
this.args.close();
} else if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
} else if (
event.key === "Enter" &&
(event.ctrlKey || event.metaKey) &&
!this.disabled
) {
this.save();
}
}
@@ -1,62 +1,71 @@
<div class="buttons">
{{#if this.embedQuoteButton}}
<DButton
@class="btn-flat insert-quote"
@action={{this.insertQuote}}
@icon="quote-left"
@label="post.quote_reply"
@title="post.quote_reply_shortcut"
/>
{{/if}}
{{#if this.siteSettings.enable_fast_edit}}
{{#if this._canEditPost}}
<div
{{did-insert this.didInsert}}
class={{concat-class
"quote-button"
(if this.visible "visible")
(if this.displayFastEditInput "fast-editing")
(if this.animated "animated")
}}
>
<div class="buttons">
{{#if this.embedQuoteButton}}
<DButton
@icon="pencil-alt"
@action={{this._toggleFastEditForm}}
@label="post.quote_edit"
@class="btn-flat quote-edit-label"
@title="post.quote_edit_shortcut"
@action={{this.insertQuote}}
@icon="quote-left"
@label="post.quote_reply"
@title="post.quote_reply_shortcut"
class="btn-flat insert-quote"
/>
{{/if}}
{{/if}}
{{#if this.quoteSharingEnabled}}
<span class="quote-sharing">
{{#if this.quoteSharingShowLabel}}
<DButton
@icon="share"
@label="post.quote_share"
@class="btn-flat quote-share-label"
/>
{{/if}}
{{#if this.canEditPost}}
<DButton
@icon="pencil-alt"
@action={{this.toggleFastEditForm}}
@label="post.quote_edit"
@title="post.quote_edit_shortcut"
class="btn-flat quote-edit-label"
/>
{{/if}}
<span class="quote-share-buttons">
{{#each this.quoteSharingSources as |source|}}
{{#if this.quoteSharingEnabled}}
<span class="quote-sharing">
{{#if this.quoteSharingShowLabel}}
<DButton
@class="btn-flat"
@action={{action "share" source}}
@translatedTitle={{source.title}}
@icon={{source.icon}}
@icon="share"
@label="post.quote_share"
class="btn-flat quote-share-label"
/>
{{/each}}
<PluginOutlet
@name="quote-share-buttons-after"
@connectorTagName="div"
/>
{{/if}}
<span class="quote-share-buttons">
{{#each this.quoteSharingSources as |source|}}
<DButton
@action={{fn this.share source}}
@translatedTitle={{source.title}}
@icon={{source.icon}}
class="btn-flat"
/>
{{/each}}
<PluginOutlet
@name="quote-share-buttons-after"
@connectorTagName="span"
/>
</span>
</span>
</span>
{{/if}}
</div>
{{/if}}
</div>
<div class="extra">
{{#if this._displayFastEditInput}}
<FastEdit
@initialValue={{this._fastEditInitialSelection}}
@post={{this.post}}
@close={{this._hideButton}}
/>
{{/if}}
<div class="extra">
{{#if this.displayFastEditInput}}
<FastEdit
@initialValue={{this.fastEditInitialSelection}}
@post={{this.post}}
@close={{this.hideButton}}
/>
{{/if}}
<PluginOutlet @name="quote-button-after" @connectorTagName="div" />
<PluginOutlet @name="quote-button-after" @connectorTagName="div" />
</div>
</div>
@@ -1,17 +1,17 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { ajax } from "discourse/lib/ajax";
import {
postUrl,
selectedElement,
selectedNode,
selectedRange,
selectedText,
setCaretPosition,
} from "discourse/lib/utilities";
import Component from "@ember/component";
import { INPUT_DELAY } from "discourse-common/config/environment";
import Sharing from "discourse/lib/sharing";
import { action, computed } from "@ember/object";
import { alias } from "@ember/object/computed";
import discourseComputed, { bind } from "discourse-common/utils/decorators";
import { action } from "@ember/object";
import { bind } from "discourse-common/utils/decorators";
import discourseDebounce from "discourse-common/lib/debounce";
import { getAbsoluteURL } from "discourse-common/lib/get-url";
import { next, schedule } from "@ember/runloop";
@@ -42,88 +42,90 @@ export function fixQuotes(str) {
return str.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'");
}
export default Component.extend({
modal: service(),
export default class QuoteButton extends Component {
@service appEvents;
@service capabilities;
@service currentUser;
@service modal;
@service site;
@service siteSettings;
classNames: ["quote-button"],
classNameBindings: [
"visible",
"_displayFastEditInput:fast-editing",
"animated",
],
visible: false,
animated: false,
privateCategory: alias("topic.category.read_restricted"),
editPost: null,
_popper: null,
popperPlacement: "top-start",
popperOffset: [0, 3],
@tracked visible = false;
@tracked animated = false;
@tracked isFastEditable = false;
@tracked displayFastEditInput = false;
@tracked fastEditInitialSelection;
_isFastEditable: false,
_displayFastEditInput: false,
_fastEditInitialSelection: null,
_canEditPost: false,
_isMouseDown: false,
_reselected: false,
isMouseDown = false;
reselected = false;
prevSelection;
element;
popper;
popperPlacement = "top-start";
popperOffset = [0, 3];
@bind
_hideButton() {
this.quoteState.clear();
this.set("visible", false);
this.set("animated", false);
hideButton() {
this.args.quoteState.clear();
this.set("_isFastEditable", false);
this.set("_displayFastEditInput", false);
this.set("_fastEditInitialSelection", null);
this._teardownSelectionListeners();
},
this.visible = false;
this.animated = false;
this.isFastEditable = false;
this.displayFastEditInput = false;
this.fastEditInitialSelection = null;
_selectionChanged() {
if (this._displayFastEditInput) {
this.teardownSelectionListeners();
}
selectionChanged() {
if (this.displayFastEditInput) {
this.textRange = virtualElementFromTextRange();
return;
}
const quoteState = this.quoteState;
const selection = window.getSelection();
if (selection.isCollapsed) {
if (this.visible) {
this._hideButton();
this.hideButton();
}
return;
}
// ensure we selected content inside 1 post *only*
let firstRange, postId;
let postId;
for (let r = 0; r < selection.rangeCount; r++) {
const range = selection.getRangeAt(r);
const $selectionStart = $(range.startContainer);
const $ancestor = $(range.commonAncestorContainer);
const selectionStart =
range.startContainer.nodeType === Node.ELEMENT_NODE
? range.startContainer
: range.startContainer.parentElement;
const ancestor =
range.commonAncestorContainer.nodeType === Node.ELEMENT_NODE
? range.commonAncestorContainer
: range.commonAncestorContainer.parentElement;
if ($selectionStart.closest(".cooked").length === 0) {
if (!selectionStart.closest(".cooked")) {
return;
}
firstRange = firstRange || range;
postId = postId || $ancestor.closest(".boxed, .reply").data("post-id");
postId ||= ancestor.closest(".boxed, .reply")?.dataset?.postId;
if ($ancestor.closest(".contents").length === 0 || !postId) {
if (!ancestor.closest(".contents") || !postId) {
if (this.visible) {
this._hideButton();
this.hideButton();
}
return;
}
}
const _selectedElement = selectedElement();
const _selectedElement =
selectedNode().nodeType === Node.ELEMENT_NODE
? selectedNode()
: selectedNode().parentElement;
const _selectedText = selectedText();
const $selectedElement = $(_selectedElement);
const cooked =
$selectedElement.find(".cooked")[0] ||
$selectedElement.closest(".cooked")[0];
_selectedElement.querySelector(".cooked") ||
_selectedElement.closest(".cooked");
// computing markdown takes a lot of time on long posts
// this code attempts to compute it only when we can't fast track
@@ -147,40 +149,37 @@ export default Component.extend({
}
}
const quoteState = this.args.quoteState;
quoteState.selected(postId, _selectedText, opts);
this.set("visible", quoteState.buffer.length > 0);
this.visible = quoteState.buffer.length > 0;
if (this.siteSettings.enable_fast_edit) {
this.set("_canEditPost", this.post?.can_edit);
if (this.canEditPost) {
const regexp = new RegExp(escapeRegExp(quoteState.buffer), "gi");
const matches = cooked.innerHTML.match(regexp);
const non_ascii_regex = /[^\x00-\x7F]/;
if (this._canEditPost) {
const regexp = new RegExp(escapeRegExp(quoteState.buffer), "gi");
const matches = cooked.innerHTML.match(regexp);
const non_ascii_regex = /[^\x00-\x7F]/;
if (
quoteState.buffer.length < 1 ||
quoteState.buffer.includes("|") || // tables are too complex
quoteState.buffer.match(/\n/g) || // linebreaks are too complex
matches?.length > 1 || // duplicates are too complex
non_ascii_regex.test(quoteState.buffer) // non-ascii chars break fast-edit
) {
this.set("_isFastEditable", false);
this.set("_fastEditInitialSelection", null);
} else if (matches?.length === 1) {
this.set("_isFastEditable", true);
this.set("_fastEditInitialSelection", quoteState.buffer);
}
if (
quoteState.buffer.length === 0 ||
quoteState.buffer.includes("|") || // tables are too complex
quoteState.buffer.match(/\n/g) || // linebreaks are too complex
matches?.length > 1 || // duplicates are too complex
non_ascii_regex.test(quoteState.buffer) // non-ascii chars break fast-edit
) {
this.isFastEditable = false;
this.fastEditInitialSelection = null;
} else if (matches?.length === 1) {
this.isFastEditable = true;
this.fastEditInitialSelection = quoteState.buffer;
}
}
// avoid hard loops in quote selection unconditionally
// this can happen if you triple click text in firefox
if (this._prevSelection === _selectedText) {
if (this.prevSelection === _selectedText) {
return;
}
this._prevSelection = _selectedText;
this.prevSelection = _selectedText;
// on Desktop, shows the button at the beginning of the selection
// on Mobile, shows the button at the end of the selection
@@ -200,9 +199,9 @@ export default Component.extend({
}
this.textRange = virtualElementFromTextRange();
this._setupSelectionListeners();
this.setupSelectionListeners();
this._popper = createPopper(this.textRange, this.element, {
this.popper = createPopper(this.textRange, this.element, {
placement: this.popperPlacement,
modifiers: [
{
@@ -223,162 +222,174 @@ export default Component.extend({
if (!this.animated) {
// We only enable CSS transitions after the initial positioning
// otherwise the button can appear to fly in from off-screen
next(() => this.set("animated", true));
next(() => (this.animated = true));
}
});
},
}
@bind
_updateRect() {
updateRect() {
this.textRange?.updateRect();
},
}
_setupSelectionListeners() {
document.body.addEventListener("mouseup", this._updateRect);
window.addEventListener("scroll", this._updateRect);
document.scrollingElement.addEventListener("scroll", this._updateRect);
},
setupSelectionListeners() {
document.body.addEventListener("mouseup", this.updateRect);
window.addEventListener("scroll", this.updateRect);
document.scrollingElement.addEventListener("scroll", this.updateRect);
}
_teardownSelectionListeners() {
document.body.removeEventListener("mouseup", this._updateRect);
window.removeEventListener("scroll", this._updateRect);
document.scrollingElement.removeEventListener("scroll", this._updateRect);
},
didInsertElement() {
this._super(...arguments);
teardownSelectionListeners() {
document.body.removeEventListener("mouseup", this.updateRect);
window.removeEventListener("scroll", this.updateRect);
document.scrollingElement.removeEventListener("scroll", this.updateRect);
}
@bind
onSelectionChanged() {
const { isWinphone, isAndroid } = this.capabilities;
const wait = isWinphone || isAndroid ? INPUT_DELAY : 25;
const onSelectionChanged = () => {
discourseDebounce(this, this._selectionChanged, wait);
};
discourseDebounce(this, this.selectionChanged, wait);
}
$(document)
.on("mousedown.quote-button", (e) => {
this._prevSelection = null;
this._isMouseDown = true;
this._reselected = false;
@bind
mousedown(e) {
this.prevSelection = null;
this.isMouseDown = true;
this.reselected = false;
// prevents fast-edit input event to trigger mousedown
if (e.target.classList.contains("fast-edit-input")) {
return;
}
if (
$(e.target).closest(".quote-button, .create, .share, .reply-new")
.length === 0
) {
this._hideButton();
}
})
.on("mouseup.quote-button", (e) => {
// prevents fast-edit input event to trigger mouseup
if (e.target.classList.contains("fast-edit-input")) {
return;
}
this._prevSelection = null;
this._isMouseDown = false;
onSelectionChanged();
})
.on("selectionchange.quote-button", () => {
if (!this._isMouseDown && !this._reselected) {
onSelectionChanged();
}
});
this.appEvents.on("quote-button:quote", this, "insertQuote");
this.appEvents.on("quote-button:edit", this, "_toggleFastEditForm");
},
willDestroyElement() {
this._popper?.destroy();
$(document)
.off("mousedown.quote-button")
.off("mouseup.quote-button")
.off("selectionchange.quote-button");
this.appEvents.off("quote-button:quote", this, "insertQuote");
this.appEvents.off("quote-button:edit", this, "_toggleFastEditForm");
this._teardownSelectionListeners();
},
@computed("topic", "quoteState.postId")
get post() {
return this.topic.postStream.findLoadedPost(this.quoteState.postId);
},
@discourseComputed("topic.{isPrivateMessage,invisible,category}")
quoteSharingEnabled(topic) {
if (
this.site.mobileView ||
this.siteSettings.share_quote_visibility === "none" ||
(this.currentUser &&
this.siteSettings.share_quote_visibility === "anonymous") ||
this.quoteSharingSources.length === 0 ||
this.privateCategory ||
(this.currentUser && topic.invisible)
) {
return false;
// prevents fast-edit input event from triggering mousedown
if (e.target.classList.contains("fast-edit-input")) {
return;
}
return true;
},
if (!e.target.closest(".quote-button, .create, .share, .reply-new")) {
this.hideButton();
}
}
@discourseComputed("topic.isPrivateMessage")
quoteSharingSources(isPM) {
@bind
mouseup(e) {
// prevents fast-edit input event from triggering mouseup
if (e.target.classList.contains("fast-edit-input")) {
return;
}
this.prevSelection = null;
this.isMouseDown = false;
this.onSelectionChanged();
}
@bind
selectionchange() {
if (!this.isMouseDown && !this.reselected) {
this.onSelectionChanged();
}
}
@action
didInsert(element) {
this.element = element;
document.addEventListener("mousedown", this.mousedown);
document.addEventListener("mouseup", this.mouseup);
document.addEventListener("selectionchange", this.selectionchange);
this.appEvents.on("quote-button:quote", this, "insertQuote");
this.appEvents.on("quote-button:edit", this, "toggleFastEditForm");
}
willDestroy() {
super.willDestroy(...arguments);
this.popper?.destroy();
document.removeEventListener("mousedown", this.mousedown);
document.removeEventListener("mouseup", this.mouseup);
document.removeEventListener("selectionchange", this.selectionchange);
this.appEvents.off("quote-button:quote", this, "insertQuote");
this.appEvents.off("quote-button:edit", this, "toggleFastEditForm");
this.teardownSelectionListeners();
}
get post() {
return this.args.topic.postStream.findLoadedPost(
this.args.quoteState.postId
);
}
get quoteSharingEnabled() {
return (
this.site.desktopView &&
this.quoteSharingSources.length > 0 &&
!this.args.topic.invisible &&
!this.args.topic.category?.read_restricted &&
(this.siteSettings.share_quote_visibility === "all" ||
(this.siteSettings.share_quote_visibility === "anonymous" &&
!this.currentUser))
);
}
get quoteSharingSources() {
return Sharing.activeSources(
this.siteSettings.share_quote_buttons,
this.siteSettings.login_required || isPM
this.siteSettings.login_required || this.args.topic.isPrivateMessage
);
},
}
@discourseComputed("topic.{isPrivateMessage,invisible,category}")
quoteSharingShowLabel() {
get quoteSharingShowLabel() {
return this.quoteSharingSources.length > 1;
},
}
@computed("topic.{id,slug}", "post")
get shareUrl() {
return getAbsoluteURL(
postUrl(this.topic.slug, this.topic.id, this.post.post_number)
postUrl(this.args.topic.slug, this.args.topic.id, this.post.post_number)
);
},
}
get embedQuoteButton() {
const canCreatePost = this.args.topic.details.can_create_post;
const canReplyAsNewTopic = this.args.topic.details.can_reply_as_new_topic;
@discourseComputed(
"topic.details.can_create_post",
"topic.details.can_reply_as_new_topic"
)
embedQuoteButton(canCreatePost, canReplyAsNewTopic) {
return (
(canCreatePost || canReplyAsNewTopic) &&
this.currentUser?.get("user_option.enable_quoting")
);
},
}
get canEditPost() {
return this.siteSettings.enable_fast_edit && this.post?.can_edit;
}
@action
insertQuote() {
this.attrs.selectText().then(() => this._hideButton());
},
async insertQuote() {
await this.args.selectText();
this.hideButton();
}
@action
async _toggleFastEditForm() {
if (this._isFastEditable) {
async toggleFastEditForm() {
if (this.isFastEditable) {
if (this.site.desktopView) {
this.toggleProperty("_displayFastEditInput");
this.displayFastEditInput = !this.displayFastEditInput;
} else {
this.modal.show(FastEditModal, {
model: {
initialValue: this._fastEditInitialSelection,
initialValue: this.fastEditInitialSelection,
post: this.post,
},
});
this._hideButton();
this.hideButton();
}
return;
}
const result = await ajax(`/posts/${this.post.id}`, { cache: false });
const result = await ajax(`/posts/${this.post.id}`);
if (this.isDestroying || this.isDestroyed) {
return;
}
let bestIndex = 0;
const rows = result.raw.split("\n");
@@ -386,7 +397,7 @@ export default Component.extend({
// "* " at the beginning of the buffer, we remove it to be able
// to find it in row
const buffer = fixQuotes(
this.quoteState.buffer.split("\n")[0].replace(/^\* /, "")
this.args.quoteState.buffer.split("\n")[0].replace(/^\* /, "")
);
rows.some((row, index) => {
@@ -396,7 +407,7 @@ export default Component.extend({
}
});
this.editPost(this.post);
this.args.editPost(this.post);
document
.querySelector("#reply-control")
@@ -418,14 +429,14 @@ export default Component.extend({
textarea.blur();
textarea.focus();
});
},
}
@action
share(source) {
Sharing.shareSource(source, {
url: this.shareUrl,
title: this.topic.title,
title: this.args.topic.title,
quote: window.getSelection().toString(),
});
},
});
}
}
@@ -314,7 +314,7 @@ export default {
},
quoteReply() {
if (this.isPostTextSelected()) {
if (this.isPostTextSelected) {
this.appEvents.trigger("quote-button:quote");
return false;
}
@@ -330,7 +330,7 @@ export default {
},
editPost() {
if (this.siteSettings.enable_fast_edit && this.isPostTextSelected()) {
if (this.siteSettings.enable_fast_edit && this.isPostTextSelected) {
this.appEvents.trigger("quote-button:edit");
return false;
} else {
@@ -556,9 +556,9 @@ export default {
}
},
isPostTextSelected() {
get isPostTextSelected() {
const topicController = getOwner(this).lookup("controller:topic");
return !!topicController?.get("quoteState")?.postId;
return !!topicController.quoteState.postId;
},
sendToSelectedPost(action, elem) {
@@ -1,13 +1,9 @@
import { tracked } from "@glimmer/tracking";
export default class QuoteState {
@tracked postId;
@tracked buffer;
@tracked opts;
constructor() {
this.clear();
}
@tracked postId = null;
@tracked buffer = "";
@tracked opts = null;
selected(postId, buffer, opts) {
this.postId = postId;
@@ -162,7 +162,7 @@ export function selectedText() {
return toMarkdown($div.html());
}
export function selectedElement() {
export function selectedNode() {
return selectedRange()?.commonAncestorContainer;
}
@@ -595,6 +595,5 @@
@selectText={{action "selectText"}}
@editPost={{action "editPost"}}
@topic={{this.model}}
@composerVisible={{this.composer.visible}}
/>
</DiscourseTopic>
@@ -1,6 +1,5 @@
import {
acceptance,
chromeTest,
exists,
query,
queryAll,
@@ -12,7 +11,6 @@ import { cloneJSON } from "discourse-common/lib/object";
import topicFixtures from "discourse/tests/fixtures/topic";
import { test } from "qunit";
// This tests are flaky on Firefox. Fails with `calling set on destroyed object`
acceptance("Topic - Quote button - logged in", function (needs) {
needs.user();
needs.settings({
@@ -33,50 +31,41 @@ acceptance("Topic - Quote button - logged in", function (needs) {
);
});
chromeTest(
"Does not show the quote share buttons by default",
async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
assert.ok(exists(".insert-quote"), "it shows the quote button");
assert.ok(!exists(".quote-sharing"), "it does not show quote sharing");
}
);
test("Does not show the quote share buttons by default", async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
assert.ok(exists(".insert-quote"), "it shows the quote button");
assert.ok(!exists(".quote-sharing"), "it does not show quote sharing");
});
chromeTest(
"Shows quote share buttons with the right site settings",
async function (assert) {
this.siteSettings.share_quote_visibility = "all";
test("Shows quote share buttons with the right site settings", async function (assert) {
this.siteSettings.share_quote_visibility = "all";
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
assert.ok(exists(".quote-sharing"), "it shows the quote sharing options");
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.twitter")}']`),
"it includes the twitter share button"
);
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.email")}']`),
"it includes the email share button"
);
}
);
assert.ok(exists(".quote-sharing"), "it shows the quote sharing options");
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.twitter")}']`),
"it includes the twitter share button"
);
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.email")}']`),
"it includes the email share button"
);
});
chromeTest(
"Quoting a Onebox should not copy the formatting of the rendered Onebox",
async function (assert) {
await visit("/t/topic-for-group-moderators/2480");
await selectText("#post_3 aside.onebox p");
await click(".insert-quote");
test("Quoting a Onebox should not copy the formatting of the rendered Onebox", async function (assert) {
await visit("/t/topic-for-group-moderators/2480");
await selectText("#post_3 aside.onebox p");
await click(".insert-quote");
assert.strictEqual(
query(".d-editor-input").value.trim(),
'[quote="group_moderator, post:3, topic:2480"]\nhttps://example.com/57350945\n[/quote]',
"quote only contains a link"
);
}
);
assert.strictEqual(
query(".d-editor-input").value.trim(),
'[quote="group_moderator, post:3, topic:2480"]\nhttps://example.com/57350945\n[/quote]',
"quote only contains a link"
);
});
});
acceptance("Closed Topic - Quote button - logged in", function (needs) {
@@ -90,7 +79,7 @@ acceptance("Closed Topic - Quote button - logged in", function (needs) {
server.get("/t/280.json", () => helper.response(topicResponse));
});
chromeTest("Shows quote button in closed topics", async function (assert) {
test("Shows quote button in closed topics", async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_1 .cooked p:first-child");
assert.ok(exists(".insert-quote"), "it shows the quote button");
@@ -111,60 +100,48 @@ acceptance("Topic - Quote button - anonymous", function (needs) {
share_quote_buttons: "twitter|email",
});
chromeTest(
"Shows quote share buttons with the right site settings",
async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
test("Shows quote share buttons with the right site settings", async function (assert) {
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
assert.ok(
queryAll(".quote-sharing"),
"it shows the quote sharing options"
);
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.twitter")}']`),
"it includes the twitter share button"
);
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.email")}']`),
"it includes the email share button"
);
assert.ok(!exists(".insert-quote"), "it does not show the quote button");
}
);
assert.ok(queryAll(".quote-sharing"), "it shows the quote sharing options");
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.twitter")}']`),
"it includes the twitter share button"
);
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.email")}']`),
"it includes the email share button"
);
assert.ok(!exists(".insert-quote"), "it does not show the quote button");
});
chromeTest(
"Shows single share button when site setting only has one item",
async function (assert) {
this.siteSettings.share_quote_buttons = "twitter";
test("Shows single share button when site setting only has one item", async function (assert) {
this.siteSettings.share_quote_buttons = "twitter";
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
assert.ok(exists(".quote-sharing"), "it shows the quote sharing options");
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.twitter")}']`),
"it includes the twitter share button"
);
assert.ok(
!exists(".quote-share-label"),
"it does not show the Share label"
);
}
);
assert.ok(exists(".quote-sharing"), "it shows the quote sharing options");
assert.ok(
exists(`.quote-sharing .btn[title='${I18n.t("share.twitter")}']`),
"it includes the twitter share button"
);
assert.ok(
!exists(".quote-share-label"),
"it does not show the Share label"
);
});
chromeTest(
"Shows nothing when visibility is disabled",
async function (assert) {
this.siteSettings.share_quote_visibility = "none";
test("Shows nothing when visibility is disabled", async function (assert) {
this.siteSettings.share_quote_visibility = "none";
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
await visit("/t/internationalization-localization/280");
await selectText("#post_5 blockquote");
assert.ok(!exists(".quote-sharing"), "it does not show quote sharing");
assert.ok(!exists(".insert-quote"), "it does not show the quote button");
}
);
assert.ok(!exists(".quote-sharing"), "it does not show quote sharing");
assert.ok(!exists(".insert-quote"), "it does not show the quote button");
});
});
acceptance("Topic - Quote button - keyboard shortcut", function (needs) {