Skip to content

Commit ce18374

Browse files
WIP: Bring back Clear Bookmarks functionality in topic
1 parent d9174e7 commit ce18374

File tree

8 files changed

+199
-28
lines changed

8 files changed

+199
-28
lines changed

app/assets/javascripts/discourse/app/components/bookmark-menu.gjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ export default class BookmarkMenu extends Component {
168168
async onRemoveBookmark() {
169169
try {
170170
const response = await this.bookmarkManager.delete();
171-
this.bookmarkManager.afterDelete(response, this.existingBookmark.id);
171+
if (this.existingBookmark) {
172+
this.bookmarkManager.afterDelete(response, this.existingBookmark.id);
173+
}
172174
this.toasts.success({
173175
duration: "short",
174176
data: {

app/assets/javascripts/discourse/app/components/post/menu/buttons/bookmark.gjs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Component from "@glimmer/component";
2-
import { cached } from "@glimmer/tracking";
32
import { getOwner } from "@ember/owner";
3+
import { service } from "@ember/service";
44
import BookmarkMenu from "discourse/components/bookmark-menu";
55
import PostBookmarkManager from "discourse/lib/post-bookmark-manager";
66

@@ -9,9 +9,31 @@ export default class PostMenuBookmarkButton extends Component {
99
return !!args.post.canBookmark;
1010
}
1111

12-
@cached
13-
get bookmarkManager() {
14-
return new PostBookmarkManager(getOwner(this), this.args.post);
12+
@service appEvents;
13+
14+
constructor() {
15+
super(...arguments);
16+
this.bookmarkManager = new PostBookmarkManager(
17+
getOwner(this),
18+
this.args.post
19+
);
20+
this.appEvents.on("bookmarks:changed", this, this.handleBookmarksChanged);
21+
}
22+
23+
willDestroyElement() {
24+
super.willDestroyElement(...arguments);
25+
this.appEvents.off("bookmarks:changed", this, this.handleBookmarksChanged);
26+
}
27+
28+
handleBookmarksChanged(data, other) {
29+
// if (other.targetId !== this.args.post.id || other.target !== "post") {
30+
// return;
31+
// }
32+
// // The bookmark has been deleted by "Clear Bookmarks"
33+
// if (!data) {
34+
// this.bookmarkManager.reset();
35+
// return;
36+
// }
1537
}
1638

1739
<template>

app/assets/javascripts/discourse/app/components/topic-footer-buttons.gjs

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Component from "@ember/component";
22
import { concat, hash } from "@ember/helper";
3-
import { computed } from "@ember/object";
3+
import { action, computed } from "@ember/object";
44
import { alias, or } from "@ember/object/computed";
55
import { getOwner } from "@ember/owner";
66
import { attributeBindings } from "@ember-decorators/component";
@@ -42,6 +42,39 @@ export default class TopicFooterButtons extends Component {
4242
@alias("currentUser.user_option.enable_defer") canDefer;
4343
@or("topic.archived", "topic.closed", "topic.deleted") inviteDisabled;
4444

45+
// init() {
46+
// super.init(...arguments);
47+
// this.topicBookmarkManager = new TopicBookmarkManager(
48+
// getOwner(this),
49+
// this.topic
50+
// );
51+
// // this.appEvents.on("bookmarks:changed", this, this.handleBookmarksChanged);
52+
// }
53+
54+
// willDestroyElement() {
55+
// super.willDestroyElement(...arguments);
56+
// this.appEvents.off("bookmarks:changed", this, this.handleBookmarksChanged);
57+
// }
58+
59+
// handleBookmarksChanged(data, other) {
60+
// console.log(data, other);
61+
// if (other.targetId !== this.topic.id || other.target !== "topic") {
62+
// return;
63+
// }
64+
65+
// // The bookmark has been deleted by "Clear Bookmarks"
66+
// if (!data) {
67+
// this.topicBookmarkManager.reset();
68+
// return;
69+
// }
70+
// }
71+
//
72+
//
73+
@computed("topic")
74+
get topicBookmarkManager() {
75+
return new TopicBookmarkManager(getOwner(this), this.topic);
76+
}
77+
4578
@discourseComputed("canSendPms", "topic.isPrivateMessage")
4679
canArchive(canSendPms, isPM) {
4780
return canSendPms && isPM;
@@ -57,11 +90,6 @@ export default class TopicFooterButtons extends Component {
5790
.reverse();
5891
}
5992

60-
@computed("topic")
61-
get topicBookmarkManager() {
62-
return new TopicBookmarkManager(getOwner(this), this.topic);
63-
}
64-
6593
// topic.assigned_to_user is for backward plugin support
6694
@discourseComputed("inlineButtons.[]", "topic.assigned_to_user")
6795
dropdownButtons(inlineButtons) {
@@ -105,6 +133,32 @@ export default class TopicFooterButtons extends Component {
105133
return !isPM;
106134
}
107135

136+
@action
137+
onShowBookmarkMenu() {
138+
console.log("onshow");
139+
this.set("_bookmarkMenuVisible", true);
140+
}
141+
142+
@action
143+
onCloseBookmarkMenu() {
144+
console.log("onclose");
145+
this.set("_bookmarkMenuVisible", false);
146+
}
147+
148+
@discourseComputed("_bookmarkMenuVisible")
149+
showBookmarkButton() {
150+
console.log("should show?", this._bookmarkMenuVisible);
151+
if (this._bookmarkMenuVisible) {
152+
return false;
153+
}
154+
155+
if (this.topic.bookmarkCount > 1) {
156+
return true;
157+
}
158+
159+
return false;
160+
}
161+
108162
<template>
109163
<div class="topic-footer-main-buttons">
110164
<div class="topic-footer-main-buttons__actions">

app/assets/javascripts/discourse/app/instance-initializers/topic-footer-buttons.js

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import ShareTopicModal from "discourse/components/modal/share-topic";
22
import { registerTopicFooterButton } from "discourse/lib/register-topic-footer-button";
3+
import {
4+
NO_REMINDER_ICON,
5+
WITH_REMINDER_ICON,
6+
} from "discourse/models/bookmark";
7+
import { i18n } from "discourse-i18n";
38

49
const SHARE_PRIORITY = 1000;
510
const BOOKMARK_PRIORITY = 900;
@@ -56,8 +61,7 @@ export default {
5661
dependentKeys: ["topic.details.can_flag_topic", "topic.isPrivateMessage"],
5762
displayed() {
5863
return (
59-
this.get("topic.details.can_flag_topic") &&
60-
!this.get("topic.isPrivateMessage")
64+
this.topic.details.can_flag_topic && !this.topic.isPrivateMessage
6165
);
6266
},
6367
});
@@ -70,11 +74,54 @@ export default {
7074

7175
// NOTE: These are null because the BookmarkMenu component is used
7276
// for this button instead in the template.
77+
7378
icon() {
74-
return null;
79+
if (this.topic.bookmarks.some((bookmark) => bookmark.reminder_at)) {
80+
return WITH_REMINDER_ICON;
81+
}
82+
return NO_REMINDER_ICON;
83+
},
84+
classNames() {
85+
return this.topic.bookmarked
86+
? ["bookmark", "bookmarked"]
87+
: ["bookmark"];
88+
},
89+
label() {
90+
if (!this.topic.isPrivateMessage || this.site.mobileView) {
91+
const topicBookmarkCount = this.topic.bookmarkCount;
92+
if (topicBookmarkCount === 0) {
93+
return "bookmarked.title";
94+
} else if (topicBookmarkCount === 1) {
95+
return "bookmarked.edit_bookmark";
96+
} else {
97+
return "bookmarked.clear_bookmarks";
98+
}
99+
}
75100
},
76101
translatedTitle() {
77-
return null;
102+
const topicBookmarkCount = this.topic.bookmarkCount;
103+
if (topicBookmarkCount === 0) {
104+
return i18n("bookmarked.help.bookmark");
105+
} else if (topicBookmarkCount === 1) {
106+
const anyTopicBookmarks = this.topic.bookmarks.some(
107+
(bookmark) => bookmark.bookmarkable_type === "Topic"
108+
);
109+
110+
if (anyTopicBookmarks) {
111+
return i18n("bookmarked.help.edit_bookmark_for_topic");
112+
} else {
113+
return i18n("bookmarked.help.edit_bookmark");
114+
}
115+
} else if (
116+
this.topic.bookmarks.some((bookmark) => bookmark.reminder_at)
117+
) {
118+
return i18n("bookmarked.help.unbookmark_with_reminder");
119+
} else {
120+
return i18n("bookmarked.help.unbookmark");
121+
}
122+
},
123+
dropdown() {
124+
return this.site.mobileView;
78125
},
79126
});
80127

app/assets/javascripts/discourse/app/lib/post-bookmark-manager.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Bookmark from "discourse/models/bookmark";
1212
export default class PostBookmarkManager {
1313
@service currentUser;
1414
@service bookmarkApi;
15+
@service appEvents;
1516
@controller("topic") topicController;
1617

1718
@tracked trackedBookmark;
@@ -29,6 +30,10 @@ export default class PostBookmarkManager {
2930
bookmark.bookmarkable_id === this.model.id &&
3031
bookmark.bookmarkable_type === this.type
3132
) || this.bookmarkApi.buildNewBookmark(this.type, this.model.id);
33+
this.reset();
34+
}
35+
36+
reset() {
3237
this.trackedBookmark = new BookmarkFormData(this.bookmarkModel);
3338
}
3439

@@ -37,15 +42,25 @@ export default class PostBookmarkManager {
3742
.create(this.trackedBookmark)
3843
.then((updatedBookmark) => {
3944
this.trackedBookmark = updatedBookmark;
45+
this._syncBookmarks(updatedBookmark.saveData);
46+
return this.trackedBookmark;
4047
});
4148
}
4249

4350
delete() {
44-
return this.bookmarkApi.delete(this.trackedBookmark.id);
51+
return this.bookmarkApi
52+
.delete(this.trackedBookmark.id)
53+
.then((deleteResponse) => {
54+
this.topicController.model.removeBookmark(this.trackedBookmark.id);
55+
return deleteResponse;
56+
});
4557
}
4658

4759
save() {
48-
return this.bookmarkApi.update(this.trackedBookmark);
60+
return this.bookmarkApi.update(this.trackedBookmark).then(() => {
61+
this._syncBookmarks(this.trackedBookmark.saveData);
62+
return this.trackedBookmark;
63+
});
4964
}
5065

5166
afterModalClose(closeData) {
@@ -58,7 +73,7 @@ export default class PostBookmarkManager {
5873
closeData.initiatedBy === CLOSE_INITIATED_BY_ESC ||
5974
closeData.initiatedBy === CLOSE_INITIATED_BY_BUTTON
6075
) {
61-
this.model.appEvents.trigger("post-stream:refresh", {
76+
this.appEvents.trigger("post-stream:refresh", {
6277
id: this.model.id,
6378
});
6479
}
@@ -68,6 +83,7 @@ export default class PostBookmarkManager {
6883
this.trackedBookmark = bookmarkFormData;
6984
this._syncBookmarks(bookmarkFormData.saveData);
7085
this.topicController.model.set("bookmarking", false);
86+
this.topicController.model.incrementProperty("bookmarksWereChanged");
7187
this.model.createBookmark(bookmarkFormData.saveData);
7288
this.topicController.model.afterPostBookmarked(
7389
this.model,
@@ -87,13 +103,14 @@ export default class PostBookmarkManager {
87103
}
88104

89105
_syncBookmarks(data) {
90-
if (!this.topicController.bookmarks) {
91-
this.topicController.set("bookmarks", []);
106+
if (!this.topicController.model.bookmarks) {
107+
this.topicController.model.set("bookmarks", []);
92108
}
93109

94-
const bookmark = this.topicController.bookmarks.findBy("id", data.id);
110+
const bookmark = this.topicController.model.bookmarks.findBy("id", data.id);
95111
if (!bookmark) {
96-
this.topicController.bookmarks.pushObject(Bookmark.create(data));
112+
this.topicController.model.bookmarks.pushObject(Bookmark.create(data));
113+
this.topicController.model.incrementProperty("bookmarksWereChanged");
97114
} else {
98115
bookmark.reminder_at = data.reminder_at;
99116
bookmark.name = data.name;

app/assets/javascripts/discourse/app/lib/topic-bookmark-manager.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ export default class TopicBookmarkManager {
2525
bookmark.bookmarkable_id === this.model.id &&
2626
bookmark.bookmarkable_type === this.type
2727
) || this.bookmarkApi.buildNewBookmark(this.type, this.model.id);
28+
this.reset();
29+
}
30+
31+
reset() {
2832
this.trackedBookmark = new BookmarkFormData(this.bookmarkModel);
2933
}
3034

@@ -33,15 +37,20 @@ export default class TopicBookmarkManager {
3337
.create(this.trackedBookmark)
3438
.then((updatedBookmark) => {
3539
this.trackedBookmark = updatedBookmark;
40+
this._syncBookmarks(updatedBookmark.saveData);
3641
});
3742
}
3843

3944
delete() {
40-
return this.bookmarkApi.delete(this.trackedBookmark.id);
45+
return this.bookmarkApi.delete(this.trackedBookmark.id).then(() => {
46+
this.topicController.model.removeBookmark(this.trackedBookmark.id);
47+
});
4148
}
4249

4350
save() {
44-
return this.bookmarkApi.update(this.trackedBookmark);
51+
return this.bookmarkApi.update(this.trackedBookmark).then(() => {
52+
this._syncBookmarks(this.trackedBookmark.saveData);
53+
});
4554
}
4655

4756
// noop for topics
@@ -73,13 +82,16 @@ export default class TopicBookmarkManager {
7382
}
7483

7584
_syncBookmarks(data) {
76-
if (!this.topicController.bookmarks) {
77-
this.topicController.set("bookmarks", []);
85+
if (!this.topicController.model.bookmarks) {
86+
this.topicController.model.set("bookmarks", []);
7887
}
7988

80-
const bookmark = this.topicController.bookmarks.findBy("id", data.id);
89+
const bookmark = this.topicController.model.bookmarks.find(
90+
(bm) => bm.id === data.id
91+
);
8192
if (!bookmark) {
82-
this.topicController.bookmarks.pushObject(Bookmark.create(data));
93+
this.topicController.model.bookmarks.pushObject(Bookmark.create(data));
94+
this.topicController.model.incrementProperty("bookmarksWereChanged");
8395
} else {
8496
bookmark.reminder_at = data.reminder_at;
8597
bookmark.name = data.name;

app/assets/javascripts/discourse/app/models/topic.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,10 @@ export default class Topic extends RestModel {
728728
}
729729
});
730730
this.set("bookmarks", []);
731+
this.appEvents.trigger("bookmarks:changed", null, {
732+
target: "topic",
733+
targetId: this.id,
734+
});
731735

732736
return postIds;
733737
}

spec/system/bookmarks_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ def open_bookmark_menu(post, expand_actions: true)
8989
)
9090
end
9191

92+
it "clears all topic bookmarks from the topic bookmark button if more than one post is bookmarked" do
93+
Fabricate(:bookmark, bookmarkable: post, user: current_user)
94+
Fabricate(:bookmark, bookmarkable: post_2, user: current_user)
95+
topic_page.visit_topic(topic)
96+
topic_page.click_topic_footer_button(:bookmark)
97+
dialog = PageObjects::Components::Dialog.new
98+
expect(dialog).to have_content(I18n.t("js.bookmarks.confirm_clear"))
99+
dialog.click_yes
100+
expect(dialog).to be_closed
101+
expect(topic_page).to have_no_bookmarks
102+
expect(Bookmark.where(user: current_user).count).to eq(0)
103+
end
104+
92105
describe "topic level bookmarks" do
93106
it "allows the topic to be bookmarked" do
94107
topic_page.visit_topic(topic)

0 commit comments

Comments
 (0)