diff --git a/app/assets/javascripts/discourse/controllers/bookmark.js b/app/assets/javascripts/discourse/controllers/bookmark.js index ec384d54ae..9f630ee913 100644 --- a/app/assets/javascripts/discourse/controllers/bookmark.js +++ b/app/assets/javascripts/discourse/controllers/bookmark.js @@ -41,15 +41,16 @@ const BOOKMARK_BINDINGS = { }, "n m": { handler: "selectReminderType", args: [REMINDER_TYPES.NEXT_MONTH] }, "c r": { handler: "selectReminderType", args: [REMINDER_TYPES.CUSTOM] }, - "n r": { handler: "selectReminderType", args: [REMINDER_TYPES.NONE] } + "n r": { handler: "selectReminderType", args: [REMINDER_TYPES.NONE] }, + "d d": { handler: "delete" } }; export default Controller.extend(ModalFunctionality, { loading: false, errorMessage: null, selectedReminderType: null, - closeWithoutSaving: false, - isSavingBookmarkManually: false, + _closeWithoutSaving: false, + _savingBookmarkManually: false, onCloseWithoutSaving: null, customReminderDate: null, customReminderTime: null, @@ -62,20 +63,20 @@ export default Controller.extend(ModalFunctionality, { this.setProperties({ errorMessage: null, selectedReminderType: REMINDER_TYPES.NONE, - closeWithoutSaving: false, - isSavingBookmarkManually: false, + _closeWithoutSaving: false, + _savingBookmarkManually: false, customReminderDate: null, - customReminderTime: this.defaultCustomReminderTime(), + customReminderTime: this._defaultCustomReminderTime(), lastCustomReminderDate: null, lastCustomReminderTime: null, userTimezone: this.currentUser.resolvedTimezone() }); - this.bindKeyboardShortcuts(); - this.loadLastUsedCustomReminderDatetime(); + this._bindKeyboardShortcuts(); + this._loadLastUsedCustomReminderDatetime(); - if (this.editingExistingBookmark()) { - this.initializeExistingBookmarkData(); + if (this._editingExistingBookmark()) { + this._initializeExistingBookmarkData(); } }, @@ -84,19 +85,19 @@ export default Controller.extend(ModalFunctionality, { * clicks the save or cancel button to mimic browser behaviour. */ onClose() { - this.unbindKeyboardShortcuts(); - this.restoreGlobalShortcuts(); - if (!this.closeWithoutSaving && !this.isSavingBookmarkManually) { - this.saveBookmark().catch(e => this.handleSaveError(e)); + this._unbindKeyboardShortcuts(); + this._restoreGlobalShortcuts(); + if (!this._closeWithoutSaving && !this._savingBookmarkManually) { + this._saveBookmark().catch(e => this._handleSaveError(e)); } - if (this.onCloseWithoutSaving && this.closeWithoutSaving) { + if (this.onCloseWithoutSaving && this._closeWithoutSaving) { this.onCloseWithoutSaving(); } }, - initializeExistingBookmarkData() { - if (this.existingBookmarkHasReminder()) { - let parsedReminderAt = this.parseCustomDateTime(this.model.reminderAt); + _initializeExistingBookmarkData() { + if (this._existingBookmarkHasReminder()) { + let parsedReminderAt = this._parseCustomDateTime(this.model.reminderAt); this.setProperties({ customReminderDate: parsedReminderAt.format("YYYY-MM-DD"), customReminderTime: parsedReminderAt.format("HH:mm"), @@ -105,20 +106,20 @@ export default Controller.extend(ModalFunctionality, { } }, - editingExistingBookmark() { + _editingExistingBookmark() { return isPresent(this.model) && isPresent(this.model.id); }, - existingBookmarkHasReminder() { + _existingBookmarkHasReminder() { return isPresent(this.model) && isPresent(this.model.reminderAt); }, - loadLastUsedCustomReminderDatetime() { + _loadLastUsedCustomReminderDatetime() { let lastTime = localStorage.lastCustomBookmarkReminderTime; let lastDate = localStorage.lastCustomBookmarkReminderDate; if (lastTime && lastDate) { - let parsed = this.parseCustomDateTime(lastDate, lastTime); + let parsed = this._parseCustomDateTime(lastDate, lastTime); // can't set reminders in the past if (parsed < this.now()) { @@ -133,7 +134,7 @@ export default Controller.extend(ModalFunctionality, { } }, - bindKeyboardShortcuts() { + _bindKeyboardShortcuts() { KeyboardShortcuts.pause(GLOBAL_SHORTCUTS_TO_PAUSE); Object.keys(BOOKMARK_BINDINGS).forEach(shortcut => { KeyboardShortcuts.addShortcut(shortcut, () => { @@ -146,11 +147,11 @@ export default Controller.extend(ModalFunctionality, { }); }, - unbindKeyboardShortcuts() { + _unbindKeyboardShortcuts() { KeyboardShortcuts.unbind(BOOKMARK_BINDINGS); }, - restoreGlobalShortcuts() { + _restoreGlobalShortcuts() { KeyboardShortcuts.unpause(GLOBAL_SHORTCUTS_TO_PAUSE); }, @@ -159,6 +160,11 @@ export default Controller.extend(ModalFunctionality, { return isPresent(existingReminderAt); }, + @discourseComputed("model.id") + showDelete(id) { + return isPresent(id); + }, + @discourseComputed() showAtDesktop() { return ( @@ -247,8 +253,8 @@ export default Controller.extend(ModalFunctionality, { return !_.isEmpty(userTimezone); }, - saveBookmark() { - const reminderAt = this.reminderAt(); + _saveBookmark() { + const reminderAt = this._reminderAt(); const reminderAtISO = reminderAt ? reminderAt.toISOString() : null; if (this.selectedReminderType === REMINDER_TYPES.CUSTOM) { @@ -277,34 +283,54 @@ export default Controller.extend(ModalFunctionality, { id: this.model.id }; - if (this.editingExistingBookmark()) { + if (this._editingExistingBookmark()) { return ajax("/bookmarks/" + this.model.id, { type: "PUT", data }).then(() => { if (this.afterSave) { - this.afterSave(reminderAtISO, this.selectedReminderType); + this.afterSave({ + reminderAt: reminderAtISO, + reminderType: this.selectedReminderType, + id: this.model.id, + name: this.model.name + }); } }); } else { - return ajax("/bookmarks", { type: "POST", data }).then(() => { + return ajax("/bookmarks", { type: "POST", data }).then(response => { if (this.afterSave) { - this.afterSave(reminderAtISO, this.selectedReminderType); + this.afterSave({ + reminderAt: reminderAtISO, + reminderType: this.selectedReminderType, + id: response.id, + name: this.model.name + }); } }); } }, - parseCustomDateTime(date, time) { + _deleteBookmark() { + return ajax("/bookmarks/" + this.model.id, { + type: "DELETE" + }).then(response => { + if (this.afterDelete) { + this.afterDelete(response.topic_bookmarked); + } + }); + }, + + _parseCustomDateTime(date, time) { let dateTime = isPresent(time) ? date + " " + time : date; return moment.tz(dateTime, this.userTimezone); }, - defaultCustomReminderTime() { + _defaultCustomReminderTime() { return `0${START_OF_DAY_HOUR}:00`; }, - reminderAt() { + _reminderAt() { if (!this.selectedReminderType) { return; } @@ -329,9 +355,9 @@ export default Controller.extend(ModalFunctionality, { case REMINDER_TYPES.CUSTOM: this.set( "customReminderTime", - this.customReminderTime || this.defaultCustomReminderTime() + this.customReminderTime || this._defaultCustomReminderTime() ); - const customDateTime = this.parseCustomDateTime( + const customDateTime = this._parseCustomDateTime( this.customReminderDate, this.customReminderTime ); @@ -385,8 +411,8 @@ export default Controller.extend(ModalFunctionality, { return this.startOfDay(this.now().add(2, "days")); }, - handleSaveError(e) { - this.isSavingBookmarkManually = false; + _handleSaveError(e) { + this._savingBookmarkManually = false; if (typeof e === "string") { bootbox.alert(e); } else { @@ -396,20 +422,35 @@ export default Controller.extend(ModalFunctionality, { actions: { saveAndClose() { - if (this.saving) { + if (this._saving || this._deleting) { return; } - this.saving = true; - this.isSavingBookmarkManually = true; - this.saveBookmark() + this._saving = true; + this._savingBookmarkManually = true; + this._saveBookmark() .then(() => this.send("closeModal")) - .catch(e => this.handleSaveError(e)) - .finally(() => (this.saving = false)); + .catch(e => this._handleSaveError(e)) + .finally(() => (this._saving = false)); + }, + + delete() { + this._deleting = true; + bootbox.confirm(I18n.t("bookmarks.confirm_delete"), result => { + if (result) { + this._closeWithoutSaving = true; + this._deleteBookmark() + .then(() => { + this._deleting = false; + this.send("closeModal"); + }) + .catch(e => this._handleSaveError(e)); + } + }); }, closeWithoutSavingBookmark() { - this.closeWithoutSaving = true; + this._closeWithoutSaving = true; this.send("closeModal"); }, diff --git a/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js b/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js index 85ee690151..a0d42ac061 100644 --- a/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js +++ b/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js @@ -170,6 +170,10 @@ export default Controller.extend(ModalFunctionality, { none: buildShortcut("bookmarks.none", { keys1: ["n", "r"], shortcutsDelimiter: "space" + }), + delete: buildShortcut("bookmarks.delete", { + keys1: ["d", "d"], + shortcutsDelimiter: "space" }) }, actions: { diff --git a/app/assets/javascripts/discourse/controllers/user-activity-bookmarks-with-reminders.js b/app/assets/javascripts/discourse/controllers/user-activity-bookmarks-with-reminders.js index a2176a7a2b..9611aceced 100644 --- a/app/assets/javascripts/discourse/controllers/user-activity-bookmarks-with-reminders.js +++ b/app/assets/javascripts/discourse/controllers/user-activity-bookmarks-with-reminders.js @@ -61,7 +61,11 @@ export default Controller.extend({ actions: { removeBookmark(bookmark) { - return bookmark.destroy().then(() => this.loadItems()); + bootbox.confirm(I18n.t("bookmarks.confirm_delete"), result => { + if (result) { + return bookmark.destroy().then(() => this.loadItems()); + } + }); }, editBookmark(bookmark) { diff --git a/app/assets/javascripts/discourse/models/post.js b/app/assets/javascripts/discourse/models/post.js index f3ae53a606..550a1fbfac 100644 --- a/app/assets/javascripts/discourse/models/post.js +++ b/app/assets/javascripts/discourse/models/post.js @@ -336,48 +336,49 @@ const Post = RestModel.extend({ }, toggleBookmarkWithReminder() { - this.toggleProperty("bookmarked_with_reminder"); - if (this.bookmarked_with_reminder) { - return new Promise(resolve => { - let controller = showModal("bookmark", { - model: { - postId: this.id - }, - title: "post.bookmarks.create", - modalClass: "bookmark-with-reminder" - }); - controller.setProperties({ - onCloseWithoutSaving: () => { - this.toggleProperty("bookmarked_with_reminder"); - resolve({ closedWithoutSaving: true }); - this.appEvents.trigger("post-stream:refresh", { id: this.id }); - }, - afterSave: (reminderAtISO, reminderType) => { - this.setProperties({ - "topic.bookmarked": true, - bookmark_reminder_at: reminderAtISO, - bookmark_reminder_type: reminderType - }); - resolve({ closedWithoutSaving: false }); - this.appEvents.trigger("post-stream:refresh", { id: this.id }); - } - }); + return new Promise(resolve => { + let controller = showModal("bookmark", { + model: { + postId: this.id, + id: this.bookmark_id, + reminderAt: this.bookmark_reminder_at, + name: this.bookmark_name + }, + title: this.bookmark_id + ? "post.bookmarks.edit" + : "post.bookmarks.create", + modalClass: "bookmark-with-reminder" }); - } else { - this.setProperties({ - bookmark_reminder_at: null, - bookmark_reminder_type: null - }); - return Post.destroyBookmark(this.id) - .then(result => { - this.set("topic.bookmarked", result.topic_bookmarked); + controller.setProperties({ + onCloseWithoutSaving: () => { + resolve({ closedWithoutSaving: true }); + this.appEvents.trigger("post-stream:refresh", { id: this.id }); + }, + afterSave: savedData => { + this.setProperties({ + "topic.bookmarked": true, + bookmarked_with_reminder: true, + bookmark_reminder_at: savedData.reminderAt, + bookmark_reminder_type: savedData.reminderType, + bookmark_name: savedData.name, + bookmark_id: savedData.id + }); + resolve({ closedWithoutSaving: false }); + this.appEvents.trigger("post-stream:refresh", { id: this.id }); + }, + afterDelete: topicBookmarked => { + this.set("topic.bookmarked", topicBookmarked); + this.setProperties({ + bookmark_reminder_at: null, + bookmark_reminder_type: null, + bookmark_name: null, + bookmark_id: null, + bookmarked_with_reminder: false + }); this.appEvents.trigger("page:bookmark-post-toggled", this); - }) - .catch(error => { - this.toggleProperty("bookmarked_with_reminder"); - throw new Error(error); - }); - } + } + }); + }); }, updateActionsSummary(json) { diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js index ce951d6edc..6ad8de27ec 100644 --- a/app/assets/javascripts/discourse/models/topic.js +++ b/app/assets/javascripts/discourse/models/topic.js @@ -461,6 +461,12 @@ const Topic = RestModel.extend({ .then(() => { this.toggleProperty("bookmarked"); this.set("bookmark_reminder_at", null); + let clearedBookmarkProps = { + bookmarked_with_reminder: false, + bookmark_id: null, + bookmark_name: null, + bookmark_reminder_at: null + }; if (posts) { const updated = []; posts.forEach(post => { @@ -472,11 +478,11 @@ const Topic = RestModel.extend({ this.siteSettings.enable_bookmarks_with_reminders && post.bookmarked_with_reminder ) { - post.set("bookmarked_with_reminder", false); + post.setProperties(clearedBookmarkProps); updated.push(post.id); } }); - firstPost.set("bookmarked_with_reminder", false); + firstPost.setProperties(clearedBookmarkProps); return updated; } }) diff --git a/app/assets/javascripts/discourse/templates/modal/bookmark.hbs b/app/assets/javascripts/discourse/templates/modal/bookmark.hbs index 8e20711ef3..3a5075ebc9 100644 --- a/app/assets/javascripts/discourse/templates/modal/bookmark.hbs +++ b/app/assets/javascripts/discourse/templates/modal/bookmark.hbs @@ -9,7 +9,7 @@ {{/if}}