mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: Use new bookmark menu in topic footer buttons (#26670)
Followup to 67a8080e33
This commit makes it so the topic footer button for bookmarks
uses the new BookmarkMenu component, and makes some tweaks to
that component to allow for a label and CSS class options.
Also introduces a TopicBookmarkManager to manage the saving/editing/
deleting of the topic level bookmarks and the reactivity that happens
in the topic UI afterward.
Next commit should rip out old bookmark associated code in the
topic controller as it will no longer be needed.
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
This commit is contained in:
@@ -6,7 +6,6 @@ import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { inject as service } from "@ember/service";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import BookmarkModal from "discourse/components/modal/bookmark";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import {
|
||||
TIME_SHORTCUT_TYPES,
|
||||
@@ -59,18 +58,61 @@ export default class BookmarkMenu extends Component {
|
||||
return I18n.t("bookmarks.not_bookmarked");
|
||||
} else {
|
||||
if (this.existingBookmark.reminderAt) {
|
||||
return I18n.t("bookmarks.created_with_reminder", {
|
||||
return I18n.t("bookmarks.created_with_reminder_generic", {
|
||||
date: this.existingBookmark.formattedReminder(this.timezone),
|
||||
name: this.existingBookmark.name || "",
|
||||
});
|
||||
} else {
|
||||
return I18n.t("bookmarks.created", {
|
||||
return I18n.t("bookmarks.created_generic", {
|
||||
name: this.existingBookmark.name || "",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get buttonClasses() {
|
||||
let cssClasses = ["bookmark widget-button bookmark-menu__trigger"];
|
||||
|
||||
if (!this.args.showLabel) {
|
||||
cssClasses.push("btn-icon no-text");
|
||||
} else {
|
||||
cssClasses.push("btn-icon-text");
|
||||
}
|
||||
|
||||
if (this.args.buttonClasses) {
|
||||
cssClasses.push(this.args.buttonClasses);
|
||||
}
|
||||
|
||||
if (this.existingBookmark) {
|
||||
cssClasses.push("bookmarked");
|
||||
if (this.existingBookmark.reminderAt) {
|
||||
cssClasses.push("with-reminder");
|
||||
}
|
||||
}
|
||||
|
||||
return cssClasses.join(" ");
|
||||
}
|
||||
|
||||
get buttonIcon() {
|
||||
if (this.existingBookmark?.reminderAt) {
|
||||
return "discourse-bookmark-clock";
|
||||
} else {
|
||||
return "bookmark";
|
||||
}
|
||||
}
|
||||
|
||||
get buttonLabel() {
|
||||
if (!this.args.showLabel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.existingBookmark) {
|
||||
return I18n.t("bookmarked.edit_bookmark");
|
||||
} else {
|
||||
return I18n.t("bookmarked.title");
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
reminderShortcutTimeTitle(option) {
|
||||
if (!option.time) {
|
||||
@@ -196,25 +238,16 @@ export default class BookmarkMenu extends Component {
|
||||
{{didInsert this.setReminderShortcuts}}
|
||||
@identifier="bookmark-menu"
|
||||
@triggers={{array "click"}}
|
||||
class={{concatClass
|
||||
"bookmark widget-button btn-flat no-text btn-icon bookmark-menu__trigger"
|
||||
(if this.existingBookmark "bookmarked")
|
||||
(if this.existingBookmark.reminderAt "with-reminder")
|
||||
}}
|
||||
class={{this.buttonClasses}}
|
||||
@title={{this.buttonTitle}}
|
||||
@label={{this.buttonLabel}}
|
||||
@icon={{this.buttonIcon}}
|
||||
@onClose={{this.onCloseMenu}}
|
||||
@onShow={{this.onShowMenu}}
|
||||
@onRegisterApi={{this.onRegisterApi}}
|
||||
@modalForMobile={{true}}
|
||||
@arrow={{false}}
|
||||
>
|
||||
<:trigger>
|
||||
{{#if this.existingBookmark.reminderAt}}
|
||||
{{icon "discourse-bookmark-clock"}}
|
||||
{{else}}
|
||||
{{icon "bookmark"}}
|
||||
{{/if}}
|
||||
</:trigger>
|
||||
<:content>
|
||||
<div class="bookmark-menu__body">
|
||||
|
||||
|
||||
@@ -27,20 +27,27 @@
|
||||
|
||||
{{#each this.inlineActionables as |actionable|}}
|
||||
{{#if (eq actionable.type "inline-button")}}
|
||||
<DButton
|
||||
@action={{actionable.action}}
|
||||
@icon={{actionable.icon}}
|
||||
@translatedLabel={{actionable.label}}
|
||||
@translatedTitle={{actionable.title}}
|
||||
@translatedAriaLabel={{actionable.ariaLabel}}
|
||||
@disabled={{actionable.disabled}}
|
||||
id={{concat "topic-footer-button-" actionable.id}}
|
||||
class={{concat-class
|
||||
"btn-default"
|
||||
"topic-footer-button"
|
||||
actionable.classNames
|
||||
}}
|
||||
/>
|
||||
{{#if (eq actionable.id "bookmark")}}
|
||||
<BookmarkMenu
|
||||
@showLabel={{true}}
|
||||
@bookmarkManager={{this.topicBookmarkManager}}
|
||||
/>
|
||||
{{else}}
|
||||
<DButton
|
||||
@action={{actionable.action}}
|
||||
@icon={{actionable.icon}}
|
||||
@translatedLabel={{actionable.label}}
|
||||
@translatedTitle={{actionable.title}}
|
||||
@translatedAriaLabel={{actionable.ariaLabel}}
|
||||
@disabled={{actionable.disabled}}
|
||||
id={{concat "topic-footer-button-" actionable.id}}
|
||||
class={{concat-class
|
||||
"btn-default"
|
||||
"topic-footer-button"
|
||||
actionable.classNames
|
||||
}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<DropdownSelectBox
|
||||
@id={{concat "topic-footer-dropdown-" actionable.id}}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { getOwner } from "@ember/application";
|
||||
import Component from "@ember/component";
|
||||
import { computed } from "@ember/object";
|
||||
import { alias, or } from "@ember/object/computed";
|
||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import { getTopicFooterButtons } from "discourse/lib/register-topic-footer-button";
|
||||
import { getTopicFooterDropdowns } from "discourse/lib/register-topic-footer-dropdown";
|
||||
import TopicBookmarkManager from "discourse/lib/topic-bookmark-manager";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
@@ -34,6 +36,10 @@ export default Component.extend({
|
||||
}
|
||||
),
|
||||
|
||||
topicBookmarkManager: computed("topic", function () {
|
||||
return new TopicBookmarkManager(getOwner(this), this.topic);
|
||||
}),
|
||||
|
||||
// topic.assigned_to_user is for backward plugin support
|
||||
@discourseComputed("inlineButtons.[]", "topic.assigned_to_user")
|
||||
dropdownButtons(inlineButtons) {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { setOwner } from "@ember/application";
|
||||
import { inject as controller } from "@ember/controller";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { BookmarkFormData } from "discourse/lib/bookmark-form-data";
|
||||
import Bookmark from "discourse/models/bookmark";
|
||||
|
||||
export default class TopicBookmarkManager {
|
||||
@service currentUser;
|
||||
@service bookmarkApi;
|
||||
@controller("topic") topicController;
|
||||
@tracked trackedBookmark;
|
||||
@tracked bookmarkModel;
|
||||
|
||||
constructor(owner, topic) {
|
||||
setOwner(this, owner);
|
||||
|
||||
this.model = topic;
|
||||
this.type = "Topic";
|
||||
|
||||
this.bookmarkModel =
|
||||
this.topicController.model?.bookmarks.find(
|
||||
(bookmark) =>
|
||||
bookmark.bookmarkable_id === this.model.id &&
|
||||
bookmark.bookmarkable_type === this.type
|
||||
) || this.bookmarkApi.buildNewBookmark(this.type, this.model.id);
|
||||
this.trackedBookmark = new BookmarkFormData(this.bookmarkModel);
|
||||
}
|
||||
|
||||
create() {
|
||||
return this.bookmarkApi
|
||||
.create(this.trackedBookmark)
|
||||
.then((updatedBookmark) => {
|
||||
this.trackedBookmark = updatedBookmark;
|
||||
});
|
||||
}
|
||||
|
||||
delete() {
|
||||
return this.bookmarkApi.delete(this.trackedBookmark.id);
|
||||
}
|
||||
|
||||
save() {
|
||||
return this.bookmarkApi.update(this.trackedBookmark);
|
||||
}
|
||||
|
||||
// noop for topics
|
||||
afterModalClose() {
|
||||
return;
|
||||
}
|
||||
|
||||
afterSave(bookmarkFormData) {
|
||||
this.trackedBookmark = bookmarkFormData;
|
||||
this._syncBookmarks(bookmarkFormData.saveData);
|
||||
this.topicController.model.set("bookmarking", false);
|
||||
this.topicController.model.set("bookmarked", true);
|
||||
this.topicController.model.incrementProperty("bookmarksWereChanged");
|
||||
this.topicController.model.appEvents.trigger(
|
||||
"bookmarks:changed",
|
||||
bookmarkFormData.saveData,
|
||||
this.bookmarkModel.attachedTo()
|
||||
);
|
||||
return [this.model.id];
|
||||
}
|
||||
|
||||
afterDelete(deleteResponse, bookmarkId) {
|
||||
this.topicController.model.removeBookmark(bookmarkId);
|
||||
this.bookmarkModel = this.bookmarkApi.buildNewBookmark(
|
||||
this.type,
|
||||
this.model.id
|
||||
);
|
||||
this.trackedBookmark = new BookmarkFormData(this.bookmarkModel);
|
||||
}
|
||||
|
||||
_syncBookmarks(data) {
|
||||
if (!this.topicController.bookmarks) {
|
||||
this.topicController.set("bookmarks", []);
|
||||
}
|
||||
|
||||
const bookmark = this.topicController.bookmarks.findBy("id", data.id);
|
||||
if (!bookmark) {
|
||||
this.topicController.bookmarks.pushObject(Bookmark.create(data));
|
||||
} else {
|
||||
bookmark.reminder_at = data.reminder_at;
|
||||
bookmark.name = data.name;
|
||||
bookmark.auto_delete_preference = data.auto_delete_preference;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,5 @@ import { registerWidgetShim } from "discourse/widgets/render-glimmer";
|
||||
registerWidgetShim(
|
||||
"bookmark-menu-shim",
|
||||
"div.bookmark-menu-shim",
|
||||
hbs`<BookmarkMenu @bookmarkManager={{@data.bookmarkManager}} />`
|
||||
hbs`<BookmarkMenu @bookmarkManager={{@data.bookmarkManager}} @buttonClasses="btn-flat" />`
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user