DEV: Convert core components to native class syntax (batch 8) (#28602)

Changes made using the ember-native-class-codemod, plus some manual tweaks
This commit is contained in:
David Taylor 2024-08-28 16:20:04 +01:00 committed by GitHub
parent 4150ec960e
commit 54b281c4a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 605 additions and 545 deletions

View File

@ -1,23 +1,28 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { schedule } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import {
attributeBindings,
classNames,
tagName,
} from "@ember-decorators/component";
import { iconHTML } from "discourse-common/lib/icon-library"; import { iconHTML } from "discourse-common/lib/icon-library";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend({ @tagName("div")
tagName: "div", @classNames("directory-table__column-header", "sortable")
classNames: ["directory-table__column-header", "sortable"], @attributeBindings("title", "colspan", "ariaSort:aria-sort", "role")
attributeBindings: ["title", "colspan", "ariaSort:aria-sort", "role"], export default class TableHeaderToggle extends Component {
role: "columnheader", role = "columnheader";
labelKey: null, labelKey = null;
chevronIcon: null, chevronIcon = null;
columnIcon: null, columnIcon = null;
translated: false, translated = false;
automatic: false, automatic = false;
onActiveRender: null, onActiveRender = null;
pressedState: null, pressedState = null;
ariaLabel: null, ariaLabel = null;
@discourseComputed("order", "field", "asc") @discourseComputed("order", "field", "asc")
ariaSort() { ariaSort() {
@ -26,14 +31,16 @@ export default Component.extend({
} else { } else {
return "none"; return "none";
} }
}, }
toggleProperties() { toggleProperties() {
if (this.order === this.field) { if (this.order === this.field) {
this.set("asc", this.asc ? null : true); this.set("asc", this.asc ? null : true);
} else { } else {
this.setProperties({ order: this.field, asc: null }); this.setProperties({ order: this.field, asc: null });
} }
}, }
toggleChevron() { toggleChevron() {
if (this.order === this.field) { if (this.order === this.field) {
let chevron = iconHTML(this.asc ? "chevron-up" : "chevron-down"); let chevron = iconHTML(this.asc ? "chevron-up" : "chevron-down");
@ -41,32 +48,35 @@ export default Component.extend({
} else { } else {
this.set("chevronIcon", null); this.set("chevronIcon", null);
} }
}, }
click() { click() {
this.toggleProperties(); this.toggleProperties();
}, }
keyPress(e) { keyPress(e) {
if (e.which === 13) { if (e.which === 13) {
this.toggleProperties(); this.toggleProperties();
} }
}, }
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); super.didReceiveAttrs(...arguments);
if (!this.automatic && !this.translated) { if (!this.automatic && !this.translated) {
this.set("labelKey", this.field); this.set("labelKey", this.field);
} }
this.set("id", `table-header-toggle-${this.field.replace(/\s/g, "")}`); this.set("id", `table-header-toggle-${this.field.replace(/\s/g, "")}`);
this.toggleChevron(); this.toggleChevron();
this._updateA11yAttributes(); this._updateA11yAttributes();
}, }
didRender() { didRender() {
this._super(...arguments); super.didRender(...arguments);
if (this.onActiveRender && this.chevronIcon) { if (this.onActiveRender && this.chevronIcon) {
this.onActiveRender(this.element); this.onActiveRender(this.element);
} }
}, }
_updateA11yAttributes() { _updateA11yAttributes() {
let criteria = ""; let criteria = "";
@ -99,10 +109,11 @@ export default Component.extend({
} else { } else {
this.set("pressedState", "false"); this.set("pressedState", "false");
} }
}, }
_focusHeader() { _focusHeader() {
schedule("afterRender", () => { schedule("afterRender", () => {
document.getElementById(this.id)?.focus(); document.getElementById(this.id)?.focus();
}); });
}, }
}); }

View File

@ -1,18 +1,22 @@
import Component from "@ember/component"; import Component from "@ember/component";
import {
attributeBindings,
classNameBindings,
tagName,
} from "@ember-decorators/component";
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import getURL from "discourse-common/lib/get-url"; import getURL from "discourse-common/lib/get-url";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @tagName("a")
tagName: "a", @classNameBindings(
classNameBindings: [
":tag-badge-wrapper", ":tag-badge-wrapper",
":badge-wrapper", ":badge-wrapper",
":bullet", ":bullet",
"tagClass", "tagClass"
], )
attributeBindings: ["href"], @attributeBindings("href")
export default class TagDropLink extends Component {
@discourseComputed("tagId", "category") @discourseComputed("tagId", "category")
href(tagId, category) { href(tagId, category) {
let path; let path;
@ -24,16 +28,16 @@ export default Component.extend({
} }
return getURL(path); return getURL(path);
}, }
@discourseComputed("tagId") @discourseComputed("tagId")
tagClass(tagId) { tagClass(tagId) {
return "tag-" + tagId; return "tag-" + tagId;
}, }
click(e) { click(e) {
e.preventDefault(); e.preventDefault();
DiscourseURL.routeTo(this.href); DiscourseURL.routeTo(this.href);
return true; return true;
}, }
}); }

View File

@ -125,7 +125,7 @@
/> />
<DButton <DButton
@action={{action "destroy"}} @action={{this.destroyTagGroup}}
@disabled={{this.buffered.isNew}} @disabled={{this.buffered.isNew}}
@icon="far-trash-alt" @icon="far-trash-alt"
@label="tagging.groups.delete" @label="tagging.groups.delete"

View File

@ -1,28 +1,33 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { action } from "@ember/object";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { tagName } from "@ember-decorators/component";
import { bufferedProperty } from "discourse/mixins/buffered-content"; import { bufferedProperty } from "discourse/mixins/buffered-content";
import Group from "discourse/models/group"; import Group from "discourse/models/group";
import PermissionType from "discourse/models/permission-type"; import PermissionType from "discourse/models/permission-type";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend(bufferedProperty("model"), { @tagName("")
router: service(), export default class TagGroupsForm extends Component.extend(
dialog: service(), bufferedProperty("model")
tagName: "", ) {
allGroups: null, @service router;
@service dialog;
allGroups = null;
init() { init() {
this._super(...arguments); super.init(...arguments);
this.setGroupOptions(); this.setGroupOptions();
}, }
setGroupOptions() { setGroupOptions() {
Group.findAll().then((groups) => { Group.findAll().then((groups) => {
this.set("allGroups", groups); this.set("allGroups", groups);
}); });
}, }
@discourseComputed( @discourseComputed(
"buffered.name", "buffered.name",
@ -36,7 +41,7 @@ export default Component.extend(bufferedProperty("model"), {
(!this.everyoneSelected(permissions) && (!this.everyoneSelected(permissions) &&
isEmpty(this.selectedGroupNames(permissions))) isEmpty(this.selectedGroupNames(permissions)))
); );
}, }
@discourseComputed("buffered.permissions", "allGroups") @discourseComputed("buffered.permissions", "allGroups")
selectedGroupIds(permissions, allGroups) { selectedGroupIds(permissions, allGroups) {
@ -53,7 +58,7 @@ export default Component.extend(bufferedProperty("model"), {
}); });
return groupIds; return groupIds;
}, }
everyoneSelected(permissions) { everyoneSelected(permissions) {
if (!permissions) { if (!permissions) {
@ -61,7 +66,7 @@ export default Component.extend(bufferedProperty("model"), {
} }
return permissions.everyone === PermissionType.FULL; return permissions.everyone === PermissionType.FULL;
}, }
selectedGroupNames(permissions) { selectedGroupNames(permissions) {
if (!permissions) { if (!permissions) {
@ -69,9 +74,9 @@ export default Component.extend(bufferedProperty("model"), {
} }
return Object.keys(permissions).filter((name) => name !== "everyone"); return Object.keys(permissions).filter((name) => name !== "everyone");
}, }
actions: { @action
setPermissionsType(permissionName) { setPermissionsType(permissionName) {
let updatedPermissions = Object.assign( let updatedPermissions = Object.assign(
{}, {},
@ -87,8 +92,9 @@ export default Component.extend(bufferedProperty("model"), {
} }
this.buffered.set("permissions", updatedPermissions); this.buffered.set("permissions", updatedPermissions);
}, }
@action
setPermissionsGroups(groupIds) { setPermissionsGroups(groupIds) {
let updatedPermissions = Object.assign( let updatedPermissions = Object.assign(
{}, {},
@ -104,8 +110,9 @@ export default Component.extend(bufferedProperty("model"), {
}); });
this.buffered.set("permissions", updatedPermissions); this.buffered.set("permissions", updatedPermissions);
}, }
@action
save() { save() {
if (this.cannotSave) { if (this.cannotSave) {
this.dialog.alert(I18n.t("tagging.groups.cannot_save")); this.dialog.alert(I18n.t("tagging.groups.cannot_save"));
@ -137,9 +144,10 @@ export default Component.extend(bufferedProperty("model"), {
this.router.transitionTo("tagGroups.index"); this.router.transitionTo("tagGroups.index");
} }
}); });
}, }
destroy() { @action
destroyTagGroup() {
return this.dialog.yesNoConfirm({ return this.dialog.yesNoConfirm({
message: I18n.t("tagging.groups.confirm_delete"), message: I18n.t("tagging.groups.confirm_delete"),
didConfirm: () => { didConfirm: () => {
@ -150,6 +158,5 @@ export default Component.extend(bufferedProperty("model"), {
}); });
}, },
}); });
}, }
}, }
});

View File

@ -4,24 +4,27 @@ import { and, reads } from "@ember/object/computed";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { tagName } from "@ember-decorators/component";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend({ @tagName("")
dialog: service(), export default class TagInfo extends Component {
tagName: "", @service dialog;
loading: false, @service router;
tagInfo: null,
newSynonyms: null, loading = false;
showEditControls: false, tagInfo = null;
canAdminTag: reads("currentUser.staff"), newSynonyms = null;
editSynonymsMode: and("canAdminTag", "showEditControls"), showEditControls = false;
editing: false, editing = false;
newTagName: null, newTagName = null;
newTagDescription: null, newTagDescription = null;
router: service(),
@reads("currentUser.staff") canAdminTag;
@and("canAdminTag", "showEditControls") editSynonymsMode;
@discourseComputed("tagInfo.tag_group_names") @discourseComputed("tagInfo.tag_group_names")
tagGroupsInfo(tagGroupNames) { tagGroupsInfo(tagGroupNames) {
@ -29,14 +32,14 @@ export default Component.extend({
count: tagGroupNames.length, count: tagGroupNames.length,
tag_groups: tagGroupNames.join(", "), tag_groups: tagGroupNames.join(", "),
}); });
}, }
@discourseComputed("tagInfo.categories") @discourseComputed("tagInfo.categories")
categoriesInfo(categories) { categoriesInfo(categories) {
return I18n.t("tagging.category_restrictions", { return I18n.t("tagging.category_restrictions", {
count: categories.length, count: categories.length,
}); });
}, }
@discourseComputed( @discourseComputed(
"tagInfo.tag_group_names", "tagInfo.tag_group_names",
@ -45,25 +48,25 @@ export default Component.extend({
) )
nothingToShow(tagGroupNames, categories, synonyms) { nothingToShow(tagGroupNames, categories, synonyms) {
return isEmpty(tagGroupNames) && isEmpty(categories) && isEmpty(synonyms); return isEmpty(tagGroupNames) && isEmpty(categories) && isEmpty(synonyms);
}, }
@discourseComputed("newTagName") @discourseComputed("newTagName")
updateDisabled(newTagName) { updateDisabled(newTagName) {
const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
newTagName = newTagName ? newTagName.replace(filterRegexp, "").trim() : ""; newTagName = newTagName ? newTagName.replace(filterRegexp, "").trim() : "";
return newTagName.length === 0; return newTagName.length === 0;
}, }
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
this.loadTagInfo(); this.loadTagInfo();
}, }
didUpdateAttrs() { didUpdateAttrs() {
this._super(...arguments); super.didUpdateAttrs(...arguments);
this.set("tagInfo", null); this.set("tagInfo", null);
this.loadTagInfo(); this.loadTagInfo();
}, }
loadTagInfo() { loadTagInfo() {
if (this.loading) { if (this.loading) {
@ -81,7 +84,7 @@ export default Component.extend({
}) })
.finally(() => this.set("loading", false)) .finally(() => this.set("loading", false))
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
@action @action
edit(event) { edit(event) {
@ -95,7 +98,7 @@ export default Component.extend({
newTagName: this.tag.id, newTagName: this.tag.id,
newTagDescription: this.tagInfo.description, newTagDescription: this.tagInfo.description,
}); });
}, }
@action @action
unlinkSynonym(tag, event) { unlinkSynonym(tag, event) {
@ -105,7 +108,7 @@ export default Component.extend({
}) })
.then(() => this.tagInfo.synonyms.removeObject(tag)) .then(() => this.tagInfo.synonyms.removeObject(tag))
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
@action @action
deleteSynonym(tag, event) { deleteSynonym(tag, event) {
@ -122,17 +125,17 @@ export default Component.extend({
.catch(popupAjaxError); .catch(popupAjaxError);
}, },
}); });
}, }
@action @action
toggleEditControls() { toggleEditControls() {
this.toggleProperty("showEditControls"); this.toggleProperty("showEditControls");
}, }
@action @action
cancelEditing() { cancelEditing() {
this.set("editing", false); this.set("editing", false);
}, }
@action @action
finishedEditing() { finishedEditing() {
@ -151,7 +154,7 @@ export default Component.extend({
} }
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
@action @action
deleteTag() { deleteTag() {
@ -182,7 +185,7 @@ export default Component.extend({
} }
}, },
}); });
}, }
@action @action
addSynonyms() { addSynonyms() {
@ -217,5 +220,5 @@ export default Component.extend({
.catch(popupAjaxError); .catch(popupAjaxError);
}, },
}); });
}, }
}); }

View File

@ -1,34 +1,35 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { sort } from "@ember/object/computed"; import { sort } from "@ember/object/computed";
import { classNameBindings } from "@ember-decorators/component";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend({ @classNameBindings(
classNameBindings: [
":tags-list", ":tags-list",
":tag-list", ":tag-list",
"categoryClass", "categoryClass",
"tagGroupNameClass", "tagGroupNameClass"
], )
export default class TagList extends Component {
isPrivateMessage = false;
isPrivateMessage: false, @sort("tags", "sortProperties") sortedTags;
sortedTags: sort("tags", "sortProperties"),
@discourseComputed("titleKey") @discourseComputed("titleKey")
title(titleKey) { title(titleKey) {
return titleKey && I18n.t(titleKey); return titleKey && I18n.t(titleKey);
}, }
@discourseComputed("categoryId") @discourseComputed("categoryId")
category(categoryId) { category(categoryId) {
return categoryId && Category.findById(categoryId); return categoryId && Category.findById(categoryId);
}, }
@discourseComputed("category.fullSlug") @discourseComputed("category.fullSlug")
categoryClass(slug) { categoryClass(slug) {
return slug && `tag-list-${slug}`; return slug && `tag-list-${slug}`;
}, }
@discourseComputed("tagGroupName") @discourseComputed("tagGroupName")
tagGroupNameClass(groupName) { tagGroupNameClass(groupName) {
@ -39,5 +40,5 @@ export default Component.extend({
.toLowerCase(); .toLowerCase();
return groupName && `tag-group-${groupName}`; return groupName && `tag-group-${groupName}`;
} }
}, }
}); }

View File

@ -1,6 +1,7 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { classNames } from "@ember-decorators/component";
export default Component.extend({ @classNames("tap-tile-grid")
classNames: ["tap-tile-grid"], export default class TapTileGrid extends Component {
activeTile: null, activeTile = null;
}); }

View File

@ -1,30 +1,35 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { reads } from "@ember/object/computed"; import { reads } from "@ember/object/computed";
import {
attributeBindings,
classNameBindings,
classNames,
} from "@ember-decorators/component";
import { propertyEqual } from "discourse/lib/computed"; import { propertyEqual } from "discourse/lib/computed";
export default Component.extend({ @classNames("tap-tile")
init() { @classNameBindings("active")
this._super(...arguments); @attributeBindings("role", "ariaPressed", "tabIndex")
this.set("elementId", `tap_tile_${this.tileId}`); export default class TapTile extends Component {
}, role = "button";
tabIndex = 0;
classNames: ["tap-tile"], @reads("active") ariaPressed;
classNameBindings: ["active"], @propertyEqual("activeTile", "tileId") active;
attributeBindings: ["role", "ariaPressed", "tabIndex"],
role: "button", init() {
tabIndex: 0, super.init(...arguments);
ariaPressed: reads("active"), this.set("elementId", `tap_tile_${this.tileId}`);
}
click() { click() {
this.onChange(this.tileId); this.onChange(this.tileId);
}, }
keyDown(e) { keyDown(e) {
if (e.key === "Enter") { if (e.key === "Enter") {
e.stopPropagation(); e.stopPropagation();
this.onChange(this.tileId); this.onChange(this.tileId);
} }
}, }
}
active: propertyEqual("activeTile", "tileId"),
});

View File

@ -1,37 +1,33 @@
import { TextField } from "@ember/legacy-built-in-components"; import { TextField } from "@ember/legacy-built-in-components";
import { computed } from "@ember/object";
import { cancel, next } from "@ember/runloop"; import { cancel, next } from "@ember/runloop";
import { attributeBindings } from "@ember-decorators/component";
import discourseDebounce from "discourse-common/lib/debounce"; import discourseDebounce from "discourse-common/lib/debounce";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
const DEBOUNCE_MS = 500; const DEBOUNCE_MS = 500;
export default TextField.extend({ @attributeBindings(
attributeBindings: [
"autocorrect", "autocorrect",
"autocapitalize", "autocapitalize",
"autofocus", "autofocus",
"maxLength", "maxLength",
"dir", "dir",
"aria-label", "aria-label",
"aria-controls", "aria-controls"
], )
export default class DiscourseTextField extends TextField {
init() { _prevValue = null;
this._super(...arguments); _timer = null;
this._prevValue = null;
this._timer = null;
},
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); super.didReceiveAttrs(...arguments);
this._prevValue = this.value; this._prevValue = this.value;
}, }
didUpdateAttrs() { didUpdateAttrs() {
this._super(...arguments); super.didUpdateAttrs(...arguments);
if (this._prevValue !== this.value) { if (this._prevValue !== this.value) {
if (this.onChangeImmediate) { if (this.onChangeImmediate) {
@ -46,33 +42,32 @@ export default TextField.extend({
); );
} }
} }
}, }
_debouncedChange() { _debouncedChange() {
next(() => this.onChange(this.value)); next(() => this.onChange(this.value));
}, }
get dir() { get dir() {
if (this.siteSettings.support_mixed_text_direction) { if (this.siteSettings.support_mixed_text_direction) {
return "auto"; return "auto";
} }
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
cancel(this._timer); cancel(this._timer);
}, }
@discourseComputed("placeholderKey") @computed("placeholderKey", "_placeholder")
placeholder: { get placeholder() {
get() {
if (this._placeholder) { if (this._placeholder) {
return this._placeholder; return this._placeholder;
} }
return this.placeholderKey ? I18n.t(this.placeholderKey) : ""; return this.placeholderKey ? I18n.t(this.placeholderKey) : "";
}, }
set(value) {
return (this._placeholder = value); set placeholder(value) {
}, this.set("_placeholder", value);
}, }
}); }

View File

@ -2,6 +2,7 @@ import Component from "@ember/component";
import { action, computed } from "@ember/object"; import { action, computed } from "@ember/object";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import { isPresent } from "@ember/utils"; import { isPresent } from "@ember/utils";
import { classNames } from "@ember-decorators/component";
function convertMinutes(num) { function convertMinutes(num) {
return { hours: Math.floor(num / 60), minutes: num % 60 }; return { hours: Math.floor(num / 60), minutes: num % 60 };
@ -32,17 +33,14 @@ function convertMinutesToDurationString(n) {
return output; return output;
} }
export default Component.extend({ @classNames("d-time-input")
classNames: ["d-time-input"], export default class TimeInput extends Component {
hours = null;
hours: null, minutes = null;
relativeDate = null;
minutes: null,
relativeDate: null,
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); super.didReceiveAttrs(...arguments);
if (isPresent(this.date)) { if (isPresent(this.date)) {
this.setProperties({ this.setProperties({
@ -61,9 +59,10 @@ export default Component.extend({
minutes: null, minutes: null,
}); });
} }
}, }
minimumTime: computed("relativeDate", "date", function () { @computed("relativeDate", "date")
get minimumTime() {
if (this.relativeDate) { if (this.relativeDate) {
if (this.date) { if (this.date) {
if (!this.date.isSame(this.relativeDate, "day")) { if (!this.date.isSame(this.relativeDate, "day")) {
@ -75,9 +74,10 @@ export default Component.extend({
return this.relativeDate.hours() * 60 + this.relativeDate.minutes(); return this.relativeDate.hours() * 60 + this.relativeDate.minutes();
} }
} }
}), }
timeOptions: computed("minimumTime", "hours", "minutes", function () { @computed("minimumTime", "hours", "minutes")
get timeOptions() {
let options = []; let options = [];
const start = this.minimumTime const start = this.minimumTime
@ -136,20 +136,21 @@ export default Component.extend({
title: name, title: name,
}; };
}); });
}), }
time: computed("minimumTime", "hours", "minutes", function () { @computed("minimumTime", "hours", "minutes")
get time() {
if (isPresent(this.hours) && isPresent(this.minutes)) { if (isPresent(this.hours) && isPresent(this.minutes)) {
return parseInt(this.hours, 10) * 60 + parseInt(this.minutes, 10); return parseInt(this.hours, 10) * 60 + parseInt(this.minutes, 10);
} }
}), }
@action @action
onFocusIn(value, event) { onFocusIn(value, event) {
if (value && event.target) { if (value && event.target) {
event.target.select(); event.target.select();
} }
}, }
@action @action
onChangeTime(time) { onChangeTime(time) {
@ -182,5 +183,5 @@ export default Component.extend({
}); });
} }
} }
}, }
}); }

View File

@ -1,6 +1,8 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { and, equal } from "@ember/object/computed"; import { and, equal } from "@ember/object/computed";
import { tagName } from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object";
import { import {
defaultTimeShortcuts, defaultTimeShortcuts,
formatTime, formatTime,
@ -9,10 +11,7 @@ import {
TIME_SHORTCUT_TYPES, TIME_SHORTCUT_TYPES,
} from "discourse/lib/time-shortcut"; } from "discourse/lib/time-shortcut";
import { laterToday, now, parseCustomDatetime } from "discourse/lib/time-utils"; import { laterToday, now, parseCustomDatetime } from "discourse/lib/time-utils";
import discourseComputed, { import discourseComputed from "discourse-common/utils/decorators";
observes,
on,
} from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
const BINDINGS = { const BINDINGS = {
@ -40,30 +39,34 @@ const BINDINGS = {
"n r": { handler: "selectShortcut", args: [TIME_SHORTCUT_TYPES.NONE] }, "n r": { handler: "selectShortcut", args: [TIME_SHORTCUT_TYPES.NONE] },
}; };
export default Component.extend({ @tagName("")
tagName: "", export default class TimeShortcutPicker extends Component {
@equal("selectedShortcut", TIME_SHORTCUT_TYPES.CUSTOM) customDatetimeSelected;
@equal("selectedShortcut", TIME_SHORTCUT_TYPES.RELATIVE)
relativeTimeSelected;
@and("customDate", "customTime") customDatetimeFilled;
userTimezone: null, userTimezone = null;
onTimeSelected: null, onTimeSelected = null;
selectedShortcut: null, selectedShortcut = null;
selectedTime: null, selectedTime = null;
selectedDate: null, selectedDate = null;
selectedDatetime: null, selectedDatetime = null;
prefilledDatetime: null, prefilledDatetime = null;
selectedDurationMins: null, selectedDurationMins = null;
hiddenOptions: null, hiddenOptions = null;
customOptions: null, customOptions = null;
lastCustomDate: null, lastCustomDate = null;
lastCustomTime: null, lastCustomTime = null;
parsedLastCustomDatetime: null, parsedLastCustomDatetime = null;
customDate: null, customDate = null;
customTime: null, customTime = null;
_itsatrap: null, _itsatrap = null;
@on("init") @on("init")
_setupPicker() { _setupPicker() {
@ -79,7 +82,7 @@ export default Component.extend({
} }
this._bindKeyboardShortcuts(); this._bindKeyboardShortcuts();
}, }
@observes("prefilledDatetime") @observes("prefilledDatetime")
prefilledDatetimeChanged() { prefilledDatetimeChanged() {
@ -92,13 +95,13 @@ export default Component.extend({
selectedShortcut: null, selectedShortcut: null,
}); });
} }
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
this._itsatrap.unbind(Object.keys(BINDINGS)); this._itsatrap.unbind(Object.keys(BINDINGS));
}, }
parsePrefilledDatetime() { parsePrefilledDatetime() {
let parsedDatetime = parseCustomDatetime( let parsedDatetime = parseCustomDatetime(
@ -116,7 +119,7 @@ export default Component.extend({
customTime: parsedDatetime.format("HH:mm"), customTime: parsedDatetime.format("HH:mm"),
selectedShortcut: TIME_SHORTCUT_TYPES.CUSTOM, selectedShortcut: TIME_SHORTCUT_TYPES.CUSTOM,
}); });
}, }
_loadLastUsedCustomDatetime() { _loadLastUsedCustomDatetime() {
const lastTime = this.keyValueStore.lastCustomTime; const lastTime = this.keyValueStore.lastCustomTime;
@ -135,7 +138,7 @@ export default Component.extend({
parsedLastCustomDatetime: parsed, parsedLastCustomDatetime: parsed,
}); });
} }
}, }
_bindKeyboardShortcuts() { _bindKeyboardShortcuts() {
Object.keys(BINDINGS).forEach((shortcut) => { Object.keys(BINDINGS).forEach((shortcut) => {
@ -145,11 +148,7 @@ export default Component.extend({
return false; return false;
}); });
}); });
}, }
customDatetimeSelected: equal("selectedShortcut", TIME_SHORTCUT_TYPES.CUSTOM),
relativeTimeSelected: equal("selectedShortcut", TIME_SHORTCUT_TYPES.RELATIVE),
customDatetimeFilled: and("customDate", "customTime"),
@observes("customDate", "customTime") @observes("customDate", "customTime")
customDatetimeChanged() { customDatetimeChanged() {
@ -157,7 +156,7 @@ export default Component.extend({
return; return;
} }
this.selectShortcut(TIME_SHORTCUT_TYPES.CUSTOM); this.selectShortcut(TIME_SHORTCUT_TYPES.CUSTOM);
}, }
@discourseComputed( @discourseComputed(
"timeShortcuts", "timeShortcuts",
@ -203,7 +202,7 @@ export default Component.extend({
this._applyCustomLabels(options, customLabels); this._applyCustomLabels(options, customLabels);
options.forEach((o) => (o.timeFormatted = formatTime(o))); options.forEach((o) => (o.timeFormatted = formatTime(o)));
return options; return options;
}, }
@action @action
relativeTimeChanged(relativeTimeMins) { relativeTimeChanged(relativeTimeMins) {
@ -215,7 +214,7 @@ export default Component.extend({
}); });
this.onTimeSelected?.(TIME_SHORTCUT_TYPES.RELATIVE, dateTime); this.onTimeSelected?.(TIME_SHORTCUT_TYPES.RELATIVE, dateTime);
}, }
@action @action
selectShortcut(type) { selectShortcut(type) {
@ -259,7 +258,7 @@ export default Component.extend({
if (this.onTimeSelected) { if (this.onTimeSelected) {
this.onTimeSelected(type, dateTime); this.onTimeSelected(type, dateTime);
} }
}, }
_applyCustomLabels(options, customLabels) { _applyCustomLabels(options, customLabels) {
options.forEach((option) => { options.forEach((option) => {
@ -267,7 +266,7 @@ export default Component.extend({
option.label = customLabels[option.id]; option.label = customLabels[option.id];
} }
}); });
}, }
_formatTime(options) { _formatTime(options) {
options.forEach((option) => { options.forEach((option) => {
@ -275,9 +274,9 @@ export default Component.extend({
option.timeFormatted = option.time.format(I18n.t(option.timeFormatKey)); option.timeFormatted = option.time.format(I18n.t(option.timeFormatKey));
} }
}); });
}, }
_defaultCustomDateTime() { _defaultCustomDateTime() {
return moment.tz(this.userTimezone).add(1, "hour"); return moment.tz(this.userTimezone).add(1, "hour");
}, }
}); }

View File

@ -1,17 +1,17 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { classNames } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @classNames("top-title-buttons")
classNames: ["top-title-buttons"], export default class TopPeriodButtons extends Component {
@discourseComputed("period") @discourseComputed("period")
periods(period) { periods(period) {
return this.site.get("periods").filter((p) => p !== period); return this.site.get("periods").filter((p) => p !== period);
}, }
@action @action
changePeriod(p) { changePeriod(p) {
this.action(p); this.action(p);
}, }
}); }

View File

@ -1,3 +1,4 @@
import Component from "@ember/component"; import Component from "@ember/component";
// Injections don't occur without a class // Injections don't occur without a class
export default Component.extend(); export default class TopicCategory extends Component {}

View File

@ -1,6 +1,8 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { action } from "@ember/object";
import { scheduleOnce } from "@ember/runloop"; import { scheduleOnce } from "@ember/runloop";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { classNameBindings } from "@ember-decorators/component";
import $ from "jquery"; import $ from "jquery";
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import CleansUp from "discourse/mixins/cleans-up"; import CleansUp from "discourse/mixins/cleans-up";
@ -30,41 +32,50 @@ function entranceDate(dt, showTime) {
); );
} }
export default Component.extend(CleansUp, { @classNameBindings("visible::hidden")
router: service(), export default class TopicEntrance extends Component.extend(CleansUp) {
session: service(), @service router;
historyStore: service(), @service session;
elementId: "topic-entrance", @service historyStore;
classNameBindings: ["visible::hidden"],
topic: null, elementId = "topic-entrance";
visible: null, topic = null;
_position: null, visible = null;
_originalActiveElement: null, _position = null;
_activeButton: null, _originalActiveElement = null;
_activeButton = null;
@discourseComputed("topic.created_at") @discourseComputed("topic.created_at")
createdDate: (createdAt) => new Date(createdAt), createdDate(createdAt) {
return new Date(createdAt);
}
@discourseComputed("topic.bumped_at") @discourseComputed("topic.bumped_at")
bumpedDate: (bumpedAt) => new Date(bumpedAt), bumpedDate(bumpedAt) {
return new Date(bumpedAt);
}
@discourseComputed("createdDate", "bumpedDate") @discourseComputed("createdDate", "bumpedDate")
showTime(createdDate, bumpedDate) { showTime(createdDate, bumpedDate) {
return ( return (
bumpedDate.getTime() - createdDate.getTime() < 1000 * 60 * 60 * 24 * 2 bumpedDate.getTime() - createdDate.getTime() < 1000 * 60 * 60 * 24 * 2
); );
}, }
@discourseComputed("createdDate", "showTime") @discourseComputed("createdDate", "showTime")
topDate: (createdDate, showTime) => entranceDate(createdDate, showTime), topDate(createdDate, showTime) {
return entranceDate(createdDate, showTime);
}
@discourseComputed("bumpedDate", "showTime") @discourseComputed("bumpedDate", "showTime")
bottomDate: (bumpedDate, showTime) => entranceDate(bumpedDate, showTime), bottomDate(bumpedDate, showTime) {
return entranceDate(bumpedDate, showTime);
}
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
this.appEvents.on("topic-entrance:show", this, "_show"); this.appEvents.on("topic-entrance:show", this, "_show");
}, }
_setCSS() { _setCSS() {
const pos = this._position; const pos = this._position;
@ -79,7 +90,7 @@ export default Component.extend(CleansUp, {
pos.left = windowWidth - width - 15; pos.left = windowWidth - width - 15;
} }
$self.css(pos); $self.css(pos);
}, }
@bind @bind
_escListener(e) { _escListener(e) {
@ -96,42 +107,42 @@ export default Component.extend(CleansUp, {
e.preventDefault(); e.preventDefault();
} }
} }
}, }
_jumpTopButton() { _jumpTopButton() {
return this.element.querySelector(".jump-top"); return this.element.querySelector(".jump-top");
}, }
_jumpBottomButton() { _jumpBottomButton() {
return this.element.querySelector(".jump-bottom"); return this.element.querySelector(".jump-bottom");
}, }
_setupEscListener() { _setupEscListener() {
document.body.addEventListener("keydown", this._escListener); document.body.addEventListener("keydown", this._escListener);
}, }
_removeEscListener() { _removeEscListener() {
document.body.removeEventListener("keydown", this._escListener); document.body.removeEventListener("keydown", this._escListener);
}, }
_trapFocus() { _trapFocus() {
this._originalActiveElement = document.activeElement; this._originalActiveElement = document.activeElement;
this._jumpTopButton().focus(); this._jumpTopButton().focus();
this._activeButton = "top"; this._activeButton = "top";
}, }
_releaseFocus() { _releaseFocus() {
if (this._originalActiveElement) { if (this._originalActiveElement) {
this._originalActiveElement.focus(); this._originalActiveElement.focus();
this._originalActiveElement = null; this._originalActiveElement = null;
} }
}, }
_applyDomChanges() { _applyDomChanges() {
this._setCSS(); this._setCSS();
this._setupEscListener(); this._setupEscListener();
this._trapFocus(); this._trapFocus();
}, }
_show(data) { _show(data) {
this._position = data.position; this._position = data.position;
@ -152,34 +163,34 @@ export default Component.extend(CleansUp, {
} }
this.cleanUp(); this.cleanUp();
}); });
}, }
cleanUp() { cleanUp() {
this.setProperties({ topic: null, visible: false }); this.setProperties({ topic: null, visible: false });
$("html").off("mousedown.topic-entrance"); $("html").off("mousedown.topic-entrance");
this._removeEscListener(); this._removeEscListener();
this._releaseFocus(); this._releaseFocus();
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
this.appEvents.off("topic-entrance:show", this, "_show"); this.appEvents.off("topic-entrance:show", this, "_show");
}, }
_jumpTo(destination) { _jumpTo(destination) {
this.historyStore.set("lastTopicIdViewed", this.topic.id); this.historyStore.set("lastTopicIdViewed", this.topic.id);
this.cleanUp(); this.cleanUp();
DiscourseURL.routeTo(destination); DiscourseURL.routeTo(destination);
}, }
actions: { @action
enterTop() { enterTop() {
this._jumpTo(this.get("topic.url")); this._jumpTo(this.get("topic.url"));
}, }
@action
enterBottom() { enterBottom() {
this._jumpTo(this.get("topic.lastPostUrl")); this._jumpTo(this.get("topic.lastPostUrl"));
}, }
}, }
});

View File

@ -2,31 +2,33 @@ import Component from "@ember/component";
import { computed } from "@ember/object"; import { computed } from "@ember/object";
import { alias, or } from "@ember/object/computed"; import { alias, or } from "@ember/object/computed";
import { getOwner } from "@ember/owner"; import { getOwner } from "@ember/owner";
import { attributeBindings } from "@ember-decorators/component";
import { NotificationLevels } from "discourse/lib/notification-levels"; import { NotificationLevels } from "discourse/lib/notification-levels";
import { getTopicFooterButtons } from "discourse/lib/register-topic-footer-button"; import { getTopicFooterButtons } from "discourse/lib/register-topic-footer-button";
import { getTopicFooterDropdowns } from "discourse/lib/register-topic-footer-dropdown"; import { getTopicFooterDropdowns } from "discourse/lib/register-topic-footer-dropdown";
import TopicBookmarkManager from "discourse/lib/topic-bookmark-manager"; import TopicBookmarkManager from "discourse/lib/topic-bookmark-manager";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @attributeBindings("role")
elementId: "topic-footer-buttons", export default class TopicFooterButtons extends Component {
elementId = "topic-footer-buttons";
role = "region";
attributeBindings: ["role"], @getTopicFooterButtons() inlineButtons;
@getTopicFooterDropdowns() inlineDropdowns;
role: "region", @alias("currentUser.can_send_private_messages") canSendPms;
@alias("topic.details.can_invite_to") canInviteTo;
@alias("currentUser.user_option.enable_defer") canDefer;
@or("topic.archived", "topic.closed", "topic.deleted") inviteDisabled;
@discourseComputed("canSendPms", "topic.isPrivateMessage") @discourseComputed("canSendPms", "topic.isPrivateMessage")
canArchive(canSendPms, isPM) { canArchive(canSendPms, isPM) {
return canSendPms && isPM; return canSendPms && isPM;
}, }
inlineButtons: getTopicFooterButtons(), @computed("inlineButtons.[]", "inlineDropdowns.[]")
inlineDropdowns: getTopicFooterDropdowns(), get inlineActionables() {
inlineActionables: computed(
"inlineButtons.[]",
"inlineDropdowns.[]",
function () {
return this.inlineButtons return this.inlineButtons
.filterBy("dropdown", false) .filterBy("dropdown", false)
.filterBy("anonymousOnly", false) .filterBy("anonymousOnly", false)
@ -34,47 +36,47 @@ export default Component.extend({
.sortBy("priority") .sortBy("priority")
.reverse(); .reverse();
} }
),
topicBookmarkManager: computed("topic", function () { @computed("topic")
get topicBookmarkManager() {
return new TopicBookmarkManager(getOwner(this), this.topic); return new TopicBookmarkManager(getOwner(this), this.topic);
}), }
// topic.assigned_to_user is for backward plugin support // topic.assigned_to_user is for backward plugin support
@discourseComputed("inlineButtons.[]", "topic.assigned_to_user") @discourseComputed("inlineButtons.[]", "topic.assigned_to_user")
dropdownButtons(inlineButtons) { dropdownButtons(inlineButtons) {
return inlineButtons.filter((button) => button.dropdown); return inlineButtons.filter((button) => button.dropdown);
}, }
@discourseComputed("topic.isPrivateMessage") @discourseComputed("topic.isPrivateMessage")
showNotificationsButton(isPM) { showNotificationsButton(isPM) {
return !isPM || this.canSendPms; return !isPM || this.canSendPms;
}, }
@discourseComputed("topic.details.notification_level") @discourseComputed("topic.details.notification_level")
showNotificationUserTip(notificationLevel) { showNotificationUserTip(notificationLevel) {
return notificationLevel >= NotificationLevels.TRACKING; return notificationLevel >= NotificationLevels.TRACKING;
}, }
canSendPms: alias("currentUser.can_send_private_messages"),
canInviteTo: alias("topic.details.can_invite_to"),
canDefer: alias("currentUser.user_option.enable_defer"),
inviteDisabled: or("topic.archived", "topic.closed", "topic.deleted"),
@discourseComputed("topic.message_archived") @discourseComputed("topic.message_archived")
archiveIcon: (archived) => (archived ? "envelope" : "folder"), archiveIcon(archived) {
return archived ? "envelope" : "folder";
}
@discourseComputed("topic.message_archived") @discourseComputed("topic.message_archived")
archiveTitle: (archived) => archiveTitle(archived) {
archived ? "topic.move_to_inbox.help" : "topic.archive_message.help", return archived ? "topic.move_to_inbox.help" : "topic.archive_message.help";
}
@discourseComputed("topic.message_archived") @discourseComputed("topic.message_archived")
archiveLabel: (archived) => archiveLabel(archived) {
archived ? "topic.move_to_inbox.title" : "topic.archive_message.title", return archived
? "topic.move_to_inbox.title"
: "topic.archive_message.title";
}
@discourseComputed("topic.isPrivateMessage") @discourseComputed("topic.isPrivateMessage")
showBookmarkLabel: (isPM) => !isPM, showBookmarkLabel(isPM) {
}); return !isPM;
}
}

View File

@ -1,20 +1,22 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import { on } from "@ember/object/evented";
import { getOwner } from "@ember/owner"; import { getOwner } from "@ember/owner";
import { schedule } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import {
attributeBindings,
classNameBindings,
tagName,
} from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object";
import $ from "jquery"; import $ from "jquery";
import { topicTitleDecorators } from "discourse/components/topic-title"; import { topicTitleDecorators } from "discourse/components/topic-title";
import { wantsNewWindow } from "discourse/lib/intercept-click"; import { wantsNewWindow } from "discourse/lib/intercept-click";
import DiscourseURL, { groupPath } from "discourse/lib/url"; import DiscourseURL, { groupPath } from "discourse/lib/url";
import { RUNTIME_OPTIONS } from "discourse-common/lib/raw-handlebars-helpers"; import { RUNTIME_OPTIONS } from "discourse-common/lib/raw-handlebars-helpers";
import { findRawTemplate } from "discourse-common/lib/raw-templates"; import { findRawTemplate } from "discourse-common/lib/raw-templates";
import discourseComputed, { import discourseComputed, { bind } from "discourse-common/utils/decorators";
bind,
observes,
} from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export function showEntrance(e) { export function showEntrance(e) {
@ -44,18 +46,19 @@ export function navigateToTopic(topic, href) {
return false; return false;
} }
export default Component.extend({ @tagName("tr")
router: service(), @classNameBindings(":topic-list-item", "unboundClassNames", "topic.visited")
historyStore: service(), @attributeBindings("dataTopicId:data-topic-id", "role", "ariaLevel:aria-level")
tagName: "tr", export default class TopicListItem extends Component {
classNameBindings: [":topic-list-item", "unboundClassNames", "topic.visited"], @service router;
attributeBindings: ["data-topic-id", "role", "ariaLevel:aria-level"], @service historyStore;
"data-topic-id": alias("topic.id"),
@alias("topic.id") dataTopicId;
didReceiveAttrs() { didReceiveAttrs() {
this._super(...arguments); super.didReceiveAttrs(...arguments);
this.renderTopicListItem(); this.renderTopicListItem();
}, }
// Already-rendered topic is marked as highlighted // Already-rendered topic is marked as highlighted
// Ideally this should be a modifier... but we can't do that // Ideally this should be a modifier... but we can't do that
@ -65,7 +68,7 @@ export default Component.extend({
if (this.topic.highlight) { if (this.topic.highlight) {
this._highlightIfNeeded(); this._highlightIfNeeded();
} }
}, }
@observes("topic.pinned", "expandGloballyPinned", "expandAllPinned") @observes("topic.pinned", "expandGloballyPinned", "expandAllPinned")
renderTopicListItem() { renderTopicListItem() {
@ -91,10 +94,10 @@ export default Component.extend({
} }
}); });
} }
}, }
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
if (this.includeUnreadIndicator) { if (this.includeUnreadIndicator) {
this.messageBus.subscribe(this.unreadIndicatorChannel, this.onMessage); this.messageBus.subscribe(this.unreadIndicatorChannel, this.onMessage);
@ -110,10 +113,10 @@ export default Component.extend({
); );
} }
}); });
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
this.messageBus.unsubscribe(this.unreadIndicatorChannel, this.onMessage); this.messageBus.unsubscribe(this.unreadIndicatorChannel, this.onMessage);
@ -124,7 +127,7 @@ export default Component.extend({
title.removeEventListener("blur", this._onTitleBlur); title.removeEventListener("blur", this._onTitleBlur);
} }
} }
}, }
@bind @bind
onMessage(data) { onMessage(data) {
@ -133,7 +136,7 @@ export default Component.extend({
).classList; ).classList;
nodeClassList.toggle("read", !data.show_indicator); nodeClassList.toggle("read", !data.show_indicator);
}, }
@discourseComputed("topic.participant_groups") @discourseComputed("topic.participant_groups")
participantGroups(groupNames) { participantGroups(groupNames) {
@ -144,29 +147,29 @@ export default Component.extend({
return groupNames.map((name) => { return groupNames.map((name) => {
return { name, url: groupPath(name) }; return { name, url: groupPath(name) };
}); });
}, }
@discourseComputed("topic.id") @discourseComputed("topic.id")
unreadIndicatorChannel(topicId) { unreadIndicatorChannel(topicId) {
return `/private-messages/unread-indicator/${topicId}`; return `/private-messages/unread-indicator/${topicId}`;
}, }
@discourseComputed("topic.unread_by_group_member") @discourseComputed("topic.unread_by_group_member")
unreadClass(unreadByGroupMember) { unreadClass(unreadByGroupMember) {
return unreadByGroupMember ? "" : "read"; return unreadByGroupMember ? "" : "read";
}, }
@discourseComputed("topic.unread_by_group_member") @discourseComputed("topic.unread_by_group_member")
includeUnreadIndicator(unreadByGroupMember) { includeUnreadIndicator(unreadByGroupMember) {
return typeof unreadByGroupMember !== "undefined"; return typeof unreadByGroupMember !== "undefined";
}, }
@discourseComputed @discourseComputed
newDotText() { newDotText() {
return this.currentUser && this.currentUser.trust_level > 0 return this.currentUser && this.currentUser.trust_level > 0
? "" ? ""
: I18n.t("filters.new.lower_title"); : I18n.t("filters.new.lower_title");
}, }
@discourseComputed("topic", "lastVisitedTopic") @discourseComputed("topic", "lastVisitedTopic")
unboundClassNames(topic, lastVisitedTopic) { unboundClassNames(topic, lastVisitedTopic) {
@ -177,7 +180,7 @@ export default Component.extend({
} }
if (topic.get("tags")) { if (topic.get("tags")) {
topic.get("tags").forEach((tagName) => classes.push("tag-" + tagName)); topic.get("tags").forEach((tag) => classes.push("tag-" + tag));
} }
if (topic.get("hasExcerpt")) { if (topic.get("hasExcerpt")) {
@ -203,15 +206,15 @@ export default Component.extend({
} }
return classes.join(" "); return classes.join(" ");
}, }
hasLikes() { hasLikes() {
return this.get("topic.like_count") > 0; return this.get("topic.like_count") > 0;
}, }
hasOpLikes() { hasOpLikes() {
return this.get("topic.op_like_count") > 0; return this.get("topic.op_like_count") > 0;
}, }
@discourseComputed @discourseComputed
expandPinned() { expandPinned() {
@ -239,9 +242,11 @@ export default Component.extend({
} }
return false; return false;
}, }
showEntrance, showEntrance() {
return showEntrance.call(this, ...arguments);
}
click(e) { click(e) {
const result = this.showEntrance(e); const result = this.showEntrance(e);
@ -316,18 +321,20 @@ export default Component.extend({
} }
return this.unhandledRowClick(e, topic); return this.unhandledRowClick(e, topic);
}, }
unhandledRowClick() {}, unhandledRowClick() {}
keyDown(e) { keyDown(e) {
if (e.key === "Enter" && e.target.classList.contains("post-activity")) { if (e.key === "Enter" && e.target.classList.contains("post-activity")) {
e.preventDefault(); e.preventDefault();
return this.navigateToTopic(this.topic, e.target.getAttribute("href")); return this.navigateToTopic(this.topic, e.target.getAttribute("href"));
} }
}, }
navigateToTopic, navigateToTopic() {
return navigateToTopic.call(this, ...arguments);
}
highlight(opts = { isLastViewedTopic: false }) { highlight(opts = { isLastViewedTopic: false }) {
schedule("afterRender", () => { schedule("afterRender", () => {
@ -347,9 +354,10 @@ export default Component.extend({
this._titleElement()?.focus(); this._titleElement()?.focus();
} }
}); });
}, }
_highlightIfNeeded: on("didInsertElement", function () { @on("didInsertElement")
_highlightIfNeeded() {
// highlight the last topic viewed // highlight the last topic viewed
const lastViewedTopicId = this.historyStore.get("lastTopicIdViewed"); const lastViewedTopicId = this.historyStore.get("lastTopicIdViewed");
const isLastViewedTopic = lastViewedTopicId === this.topic.id; const isLastViewedTopic = lastViewedTopicId === this.topic.id;
@ -362,27 +370,27 @@ export default Component.extend({
this.set("topic.highlight", false); this.set("topic.highlight", false);
this.highlight(); this.highlight();
} }
}), }
@bind @bind
_onTitleFocus() { _onTitleFocus() {
if (this.element && !this.isDestroying && !this.isDestroyed) { if (this.element && !this.isDestroying && !this.isDestroyed) {
this.element.classList.add("selected"); this.element.classList.add("selected");
} }
}, }
@bind @bind
_onTitleBlur() { _onTitleBlur() {
if (this.element && !this.isDestroying && !this.isDestroyed) { if (this.element && !this.isDestroying && !this.isDestroyed) {
this.element.classList.remove("selected"); this.element.classList.remove("selected");
} }
}, }
_shouldFocusLastVisited() { _shouldFocusLastVisited() {
return this.site.desktopView && this.focusLastVisitedTopic; return this.site.desktopView && this.focusLastVisitedTopic;
}, }
_titleElement() { _titleElement() {
return this.element.querySelector(".main-link .title"); return this.element.querySelector(".main-link .title");
}, }
}); }

View File

@ -1,68 +1,75 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { dependentKeyCompat } from "@ember/object/compat"; import { dependentKeyCompat } from "@ember/object/compat";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import { on } from "@ember/object/evented";
import { service } from "@ember/service"; import { service } from "@ember/service";
import {
classNameBindings,
classNames,
tagName,
} from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object";
import LoadMore from "discourse/mixins/load-more"; import LoadMore from "discourse/mixins/load-more";
import discourseComputed, { observes } from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend(LoadMore, { @tagName("table")
modal: service(), @classNames("topic-list")
router: service(), @classNameBindings("bulkSelectEnabled:sticky-header")
siteSettings: service(), export default class TopicList extends Component.extend(LoadMore) {
@service modal;
@service router;
@service siteSettings;
tagName: "table", showTopicPostBadges = true;
classNames: ["topic-list"], listTitle = "topic.title";
classNameBindings: ["bulkSelectEnabled:sticky-header"], lastCheckedElementId = null;
showTopicPostBadges: true,
listTitle: "topic.title", // Overwrite this to perform client side filtering of topics, if desired
lastCheckedElementId: null, @alias("topics") filteredTopics;
get canDoBulkActions() { get canDoBulkActions() {
return ( return (
this.currentUser?.canManageTopic && this.bulkSelectHelper?.selected.length this.currentUser?.canManageTopic && this.bulkSelectHelper?.selected.length
); );
}, }
// Overwrite this to perform client side filtering of topics, if desired @on("init")
filteredTopics: alias("topics"), _init() {
_init: on("init", function () {
this.addObserver("hideCategory", this.rerender); this.addObserver("hideCategory", this.rerender);
this.addObserver("order", this.rerender); this.addObserver("order", this.rerender);
this.addObserver("ascending", this.rerender); this.addObserver("ascending", this.rerender);
this.refreshLastVisited(); this.refreshLastVisited();
}), }
get selected() { get selected() {
return this.bulkSelectHelper?.selected; return this.bulkSelectHelper?.selected;
}, }
@dependentKeyCompat // for the classNameBindings // for the classNameBindings
@dependentKeyCompat
get bulkSelectEnabled() { get bulkSelectEnabled() {
return this.bulkSelectHelper?.bulkSelectEnabled; return this.bulkSelectHelper?.bulkSelectEnabled;
}, }
get toggleInTitle() { get toggleInTitle() {
return ( return (
!this.bulkSelectHelper?.bulkSelectEnabled && this.get("canBulkSelect") !this.bulkSelectHelper?.bulkSelectEnabled && this.get("canBulkSelect")
); );
}, }
@discourseComputed @discourseComputed
sortable() { sortable() {
return !!this.changeSort; return !!this.changeSort;
}, }
@discourseComputed("order") @discourseComputed("order")
showLikes(order) { showLikes(order) {
return order === "likes"; return order === "likes";
}, }
@discourseComputed("order") @discourseComputed("order")
showOpLikes(order) { showOpLikes(order) {
return order === "op_likes"; return order === "op_likes";
}, }
@observes("topics.[]") @observes("topics.[]")
topicsAdded() { topicsAdded() {
@ -70,22 +77,22 @@ export default Component.extend(LoadMore, {
if (!this.lastVisitedTopic) { if (!this.lastVisitedTopic) {
this.refreshLastVisited(); this.refreshLastVisited();
} }
}, }
@observes("topics", "order", "ascending", "category", "top", "hot") @observes("topics", "order", "ascending", "category", "top", "hot")
lastVisitedTopicChanged() { lastVisitedTopicChanged() {
this.refreshLastVisited(); this.refreshLastVisited();
}, }
scrolled() { scrolled() {
this._super(...arguments); super.scrolled(...arguments);
let onScroll = this.onScroll; let onScroll = this.onScroll;
if (!onScroll) { if (!onScroll) {
return; return;
} }
onScroll.call(this); onScroll.call(this);
}, }
_updateLastVisitedTopic(topics, order, ascending, top, hot) { _updateLastVisitedTopic(topics, order, ascending, top, hot) {
this.set("lastVisitedTopic", null); this.set("lastVisitedTopic", null);
@ -145,7 +152,7 @@ export default Component.extend(LoadMore, {
} }
this.set("lastVisitedTopic", lastVisitedTopic); this.set("lastVisitedTopic", lastVisitedTopic);
}, }
refreshLastVisited() { refreshLastVisited() {
this._updateLastVisitedTopic( this._updateLastVisitedTopic(
@ -155,7 +162,7 @@ export default Component.extend(LoadMore, {
this.top, this.top,
this.hot this.hot
); );
}, }
click(e) { click(e) {
const onClick = (sel, callback) => { const onClick = (sel, callback) => {
@ -200,7 +207,7 @@ export default Component.extend(LoadMore, {
} }
this.rerender(); this.rerender();
}); });
}, }
keyDown(e) { keyDown(e) {
if (e.key === "Enter" || e.key === " ") { if (e.key === "Enter" || e.key === " ") {
@ -217,5 +224,5 @@ export default Component.extend(LoadMore, {
this.rerender(); this.rerender();
}); });
} }
}, }
}); }

View File

@ -1,14 +1,15 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @tagName("")
tagName: "", export default class TopicNavigationPopup extends Component {
popupId: null, popupId = null;
hidden: false, hidden = false;
init() { init() {
this._super(...arguments); super.init(...arguments);
if (this.popupKey) { if (this.popupKey) {
const value = this.keyValueStore.getItem(this.popupKey); const value = this.keyValueStore.getItem(this.popupKey);
@ -18,14 +19,14 @@ export default Component.extend({
this.keyValueStore.removeItem(this.popupKey); this.keyValueStore.removeItem(this.popupKey);
} }
} }
}, }
@discourseComputed("popupId") @discourseComputed("popupId")
popupKey(popupId) { popupKey(popupId) {
if (popupId) { if (popupId) {
return `dismiss_topic_nav_popup_${popupId}`; return `dismiss_topic_nav_popup_${popupId}`;
} }
}, }
@action @action
close() { close() {
@ -39,5 +40,5 @@ export default Component.extend({
this.keyValueStore.setItem(this.popupKey, true); this.keyValueStore.setItem(this.popupKey, true);
} }
} }
}, }
}); }

View File

@ -2,43 +2,40 @@ import Component from "@ember/component";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import { next } from "@ember/runloop"; import { next } from "@ember/runloop";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { classNameBindings } from "@ember-decorators/component";
import { observes } from "@ember-decorators/object";
import $ from "jquery"; import $ from "jquery";
import { headerOffset } from "discourse/lib/offset-calculator"; import { headerOffset } from "discourse/lib/offset-calculator";
import SwipeEvents from "discourse/lib/swipe-events"; import SwipeEvents from "discourse/lib/swipe-events";
import discourseDebounce from "discourse-common/lib/debounce"; import discourseDebounce from "discourse-common/lib/debounce";
import discourseLater from "discourse-common/lib/later"; import discourseLater from "discourse-common/lib/later";
import { bind, observes } from "discourse-common/utils/decorators"; import { bind } from "discourse-common/utils/decorators";
import JumpToPost from "./modal/jump-to-post"; import JumpToPost from "./modal/jump-to-post";
const MIN_WIDTH_TIMELINE = 925; const MIN_WIDTH_TIMELINE = 925;
const MIN_HEIGHT_TIMELINE = 325; const MIN_HEIGHT_TIMELINE = 325;
export default Component.extend({ @classNameBindings(
modal: service(),
classNameBindings: [
"info.topicProgressExpanded:topic-progress-expanded", "info.topicProgressExpanded:topic-progress-expanded",
"info.renderTimeline:with-timeline:with-topic-progress", "info.renderTimeline:with-timeline:with-topic-progress"
], )
composerOpen: null, export default class TopicNavigation extends Component {
info: null, @service modal;
canRender: true,
_lastTopicId: null,
_swipeEvents: null,
init() { composerOpen = null;
this._super(...arguments); info = EmberObject.create();
this.set("info", EmberObject.create()); canRender = true;
}, _lastTopicId = null;
_swipeEvents = null;
didUpdateAttrs() { didUpdateAttrs() {
this._super(...arguments); super.didUpdateAttrs(...arguments);
if (this._lastTopicId !== this.topic.id) { if (this._lastTopicId !== this.topic.id) {
this._lastTopicId = this.topic.id; this._lastTopicId = this.topic.id;
this.set("canRender", false); this.set("canRender", false);
next(() => this.set("canRender", true)); next(() => this.set("canRender", true));
} }
}, }
_performCheckSize() { _performCheckSize() {
if (!this.element || this.isDestroying || this.isDestroyed) { if (!this.element || this.isDestroying || this.isDestroyed) {
@ -60,17 +57,17 @@ export default Component.extend({
this.mediaQuery.matches && verticalSpace > MIN_HEIGHT_TIMELINE this.mediaQuery.matches && verticalSpace > MIN_HEIGHT_TIMELINE
); );
} }
}, }
@bind @bind
_checkSize() { _checkSize() {
discourseDebounce(this, this._performCheckSize, 200, true); discourseDebounce(this, this._performCheckSize, 200, true);
}, }
// we need to store this so topic progress has something to init with // we need to store this so topic progress has something to init with
_topicScrolled(event) { _topicScrolled(event) {
this.set("info.prevEvent", event); this.set("info.prevEvent", event);
}, }
@observes("info.topicProgressExpanded") @observes("info.topicProgressExpanded")
_expanded() { _expanded() {
@ -95,17 +92,17 @@ export default Component.extend({
$(window).off("click.hide-fullscreen"); $(window).off("click.hide-fullscreen");
} }
this._checkSize(); this._checkSize();
}, }
composerOpened() { composerOpened() {
this.set("composerOpen", true); this.set("composerOpen", true);
this._checkSize(); this._checkSize();
}, }
composerClosed() { composerClosed() {
this.set("composerOpen", false); this.set("composerOpen", false);
this._checkSize(); this._checkSize();
}, }
_collapseFullscreen(delay = 500) { _collapseFullscreen(delay = 500) {
if (this.get("info.topicProgressExpanded")) { if (this.get("info.topicProgressExpanded")) {
@ -119,7 +116,7 @@ export default Component.extend({
this._checkSize(); this._checkSize();
}, delay); }, delay);
} }
}, }
keyboardTrigger(e) { keyboardTrigger(e) {
if (e.type === "jump") { if (e.type === "jump") {
@ -131,7 +128,7 @@ export default Component.extend({
}, },
}); });
} }
}, }
@bind @bind
onSwipeStart(event) { onSwipeStart(event) {
@ -153,7 +150,7 @@ export default Component.extend({
} else if (e.direction === "up" || e.direction === "down") { } else if (e.direction === "up" || e.direction === "down") {
this.movingElement = document.querySelector(".timeline-container"); this.movingElement = document.querySelector(".timeline-container");
} }
}, }
@bind @bind
onSwipeCancel() { onSwipeCancel() {
@ -164,7 +161,7 @@ export default Component.extend({
fill: "forwards", fill: "forwards",
easing: "ease-out", easing: "ease-out",
}); });
}, }
@bind @bind
onSwipeEnd(event) { onSwipeEnd(event) {
@ -195,7 +192,7 @@ export default Component.extend({
easing: "ease-out", easing: "ease-out",
}); });
} }
}, }
@bind @bind
onSwipe(event) { onSwipe(event) {
@ -207,10 +204,10 @@ export default Component.extend({
[{ transform: `translate3d(0, ${this.pxClosed}px, 0)` }], [{ transform: `translate3d(0, ${this.pxClosed}px, 0)` }],
{ fill: "forwards" } { fill: "forwards" }
); );
}, }
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
this._lastTopicId = this.topic.id; this._lastTopicId = this.topic.id;
@ -237,10 +234,10 @@ export default Component.extend({
this.element.addEventListener("swipecancel", this.onSwipeCancel); this.element.addEventListener("swipecancel", this.onSwipeCancel);
this.element.addEventListener("swipe", this.onSwipe); this.element.addEventListener("swipe", this.onSwipe);
} }
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
this.appEvents this.appEvents
.off("topic:current-post-scrolled", this, this._topicScrolled) .off("topic:current-post-scrolled", this, this._topicScrolled)
@ -263,5 +260,5 @@ export default Component.extend({
this.element.removeEventListener("swipe", this.onSwipe); this.element.removeEventListener("swipe", this.onSwipe);
this._swipeEvents.removeTouchListeners(); this._swipeEvents.removeTouchListeners();
} }
}, }
}); }

View File

@ -2,20 +2,23 @@ import Component from "@ember/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import { scheduleOnce } from "@ember/runloop"; import { scheduleOnce } from "@ember/runloop";
import { classNameBindings } from "@ember-decorators/component";
import { isTesting } from "discourse-common/config/environment"; import { isTesting } from "discourse-common/config/environment";
import discourseLater from "discourse-common/lib/later"; import discourseLater from "discourse-common/lib/later";
import discourseComputed, { bind } from "discourse-common/utils/decorators"; import discourseComputed, { bind } from "discourse-common/utils/decorators";
const CSS_TRANSITION_DELAY = isTesting() ? 0 : 500; const CSS_TRANSITION_DELAY = isTesting() ? 0 : 500;
export default Component.extend({ @classNameBindings("docked", "withTransitions")
elementId: "topic-progress-wrapper", export default class TopicProgress extends Component {
classNameBindings: ["docked", "withTransitions"], elementId = "topic-progress-wrapper";
docked: false, docked = false;
withTransitions: null, withTransitions = null;
progressPosition: null, progressPosition = null;
postStream: alias("topic.postStream"),
_streamPercentage: null, @alias("topic.postStream") postStream;
_streamPercentage = null;
@discourseComputed( @discourseComputed(
"postStream.loaded", "postStream.loaded",
@ -25,14 +28,14 @@ export default Component.extend({
hideProgress(loaded, currentPost, filteredPostsCount) { hideProgress(loaded, currentPost, filteredPostsCount) {
const hideOnShortStream = this.site.desktopView && filteredPostsCount < 2; const hideOnShortStream = this.site.desktopView && filteredPostsCount < 2;
return !loaded || !currentPost || hideOnShortStream; return !loaded || !currentPost || hideOnShortStream;
}, }
@discourseComputed("postStream.filteredPostsCount") @discourseComputed("postStream.filteredPostsCount")
hugeNumberOfPosts(filteredPostsCount) { hugeNumberOfPosts(filteredPostsCount) {
return ( return (
filteredPostsCount >= this.siteSettings.short_progress_text_threshold filteredPostsCount >= this.siteSettings.short_progress_text_threshold
); );
}, }
@discourseComputed("progressPosition", "topic.last_read_post_id") @discourseComputed("progressPosition", "topic.last_read_post_id")
showBackButton(position, lastReadId) { showBackButton(position, lastReadId) {
@ -43,7 +46,7 @@ export default Component.extend({
const stream = this.get("postStream.stream"); const stream = this.get("postStream.stream");
const readPos = stream.indexOf(lastReadId) || 0; const readPos = stream.indexOf(lastReadId) || 0;
return readPos < stream.length - 1 && readPos > position; return readPos < stream.length - 1 && readPos > position;
}, }
_topicScrolled(event) { _topicScrolled(event) {
if (this.docked) { if (this.docked) {
@ -57,15 +60,15 @@ export default Component.extend({
_streamPercentage: (event.percent * 100).toFixed(2), _streamPercentage: (event.percent * 100).toFixed(2),
}); });
} }
}, }
@discourseComputed("_streamPercentage") @discourseComputed("_streamPercentage")
progressStyle(_streamPercentage) { progressStyle(_streamPercentage) {
return `--progress-bg-width: ${_streamPercentage || 0}%`; return `--progress-bg-width: ${_streamPercentage || 0}%`;
}, }
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
this.appEvents this.appEvents
.on("composer:resized", this, this._composerEvent) .on("composer:resized", this, this._composerEvent)
@ -79,15 +82,15 @@ export default Component.extend({
// start CSS transitions a tiny bit later // start CSS transitions a tiny bit later
// to avoid jumpiness on initial topic load // to avoid jumpiness on initial topic load
discourseLater(this._addCssTransitions, CSS_TRANSITION_DELAY); discourseLater(this._addCssTransitions, CSS_TRANSITION_DELAY);
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
this._topicBottomObserver?.disconnect(); this._topicBottomObserver?.disconnect();
this.appEvents this.appEvents
.off("composer:resized", this, this._composerEvent) .off("composer:resized", this, this._composerEvent)
.off("topic:current-post-scrolled", this, this._topicScrolled); .off("topic:current-post-scrolled", this, this._topicScrolled);
}, }
@bind @bind
_addCssTransitions() { _addCssTransitions() {
@ -95,7 +98,7 @@ export default Component.extend({
return; return;
} }
this.set("withTransitions", true); this.set("withTransitions", true);
}, }
_startObserver() { _startObserver() {
if ("IntersectionObserver" in window) { if ("IntersectionObserver" in window) {
@ -104,7 +107,7 @@ export default Component.extend({
document.querySelector("#topic-bottom") document.querySelector("#topic-bottom")
); );
} }
}, }
_setupObserver() { _setupObserver() {
// minimum 50px here ensures element is not docked when // minimum 50px here ensures element is not docked when
@ -117,7 +120,7 @@ export default Component.extend({
threshold: 1, threshold: 1,
rootMargin: `0px 0px -${bottomIntersectionMargin}px 0px`, rootMargin: `0px 0px -${bottomIntersectionMargin}px 0px`,
}); });
}, }
_composerEvent() { _composerEvent() {
// reinitializing needed to account for composer height // reinitializing needed to account for composer height
@ -127,7 +130,7 @@ export default Component.extend({
this._topicBottomObserver?.disconnect(); this._topicBottomObserver?.disconnect();
this._startObserver(); this._startObserver();
} }
}, }
@bind @bind
_intersectionHandler(entries) { _intersectionHandler(entries) {
@ -167,16 +170,16 @@ export default Component.extend({
} }
} }
} }
}, }
click(e) { click(e) {
if (e.target.closest("#topic-progress")) { if (e.target.closest("#topic-progress")) {
this.toggleProperty("expanded"); this.toggleProperty("expanded");
} }
}, }
@action @action
goBack() { goBack() {
this.jumpToPost(this.get("topic.last_read_post_number")); this.jumpToPost(this.get("topic.last_read_post_number"));
}, }
}); }

View File

@ -1,55 +1,58 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { cancel, next } from "@ember/runloop"; import { cancel, next } from "@ember/runloop";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import { classNames } from "@ember-decorators/component";
import { on } from "@ember-decorators/object";
import { DELETE_REPLIES_TYPE } from "discourse/components/modal/edit-topic-timer"; import { DELETE_REPLIES_TYPE } from "discourse/components/modal/edit-topic-timer";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import { isTesting } from "discourse-common/config/environment"; import { isTesting } from "discourse-common/config/environment";
import { iconHTML } from "discourse-common/lib/icon-library"; import { iconHTML } from "discourse-common/lib/icon-library";
import discourseLater from "discourse-common/lib/later"; import discourseLater from "discourse-common/lib/later";
import discourseComputed, { on } from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend({ @classNames("topic-timer-info")
classNames: ["topic-timer-info"], export default class TopicTimerInfo extends Component {
_delayedRerender: null, clockIcon = htmlSafe(`${iconHTML("far-clock")}`);
clockIcon: htmlSafe(`${iconHTML("far-clock")}`), trashLabel = I18n.t("post.controls.remove_timer");
trashLabel: I18n.t("post.controls.remove_timer"),
title: null, title = null;
notice: null, notice = null;
showTopicTimer: null, showTopicTimer = null;
showTopicTimerModal: null, showTopicTimerModal = null;
removeTopicTimer: null, removeTopicTimer = null;
_delayedRerender = null;
@on("didReceiveAttrs") @on("didReceiveAttrs")
setupRenderer() { setupRenderer() {
this.renderTopicTimer(); this.renderTopicTimer();
}, }
@on("willDestroyElement") @on("willDestroyElement")
cancelDelayedRenderer() { cancelDelayedRenderer() {
if (this._delayedRerender) { if (this._delayedRerender) {
cancel(this._delayedRerender); cancel(this._delayedRerender);
} }
}, }
@discourseComputed @discourseComputed
canModifyTimer() { canModifyTimer() {
return this.currentUser && this.currentUser.get("canManageTopic"); return this.currentUser && this.currentUser.get("canManageTopic");
}, }
@discourseComputed("canModifyTimer", "removeTopicTimer") @discourseComputed("canModifyTimer", "removeTopicTimer")
showTrashCan(canModifyTimer, removeTopicTimer) { showTrashCan(canModifyTimer, removeTopicTimer) {
return canModifyTimer && removeTopicTimer; return canModifyTimer && removeTopicTimer;
}, }
@discourseComputed("canModifyTimer", "showTopicTimerModal") @discourseComputed("canModifyTimer", "showTopicTimerModal")
showEdit(canModifyTimer, showTopicTimerModal) { showEdit(canModifyTimer, showTopicTimerModal) {
return canModifyTimer && showTopicTimerModal; return canModifyTimer && showTopicTimerModal;
}, }
additionalOpts() { additionalOpts() {
return {}; return {};
}, }
renderTopicTimer() { renderTopicTimer() {
const isDeleteRepliesType = this.statusType === DELETE_REPLIES_TYPE; const isDeleteRepliesType = this.statusType === DELETE_REPLIES_TYPE;
@ -130,7 +133,7 @@ export default Component.extend({
} else { } else {
this.set("showTopicTimer", null); this.set("showTopicTimer", null);
} }
}, }
rerenderDelay(minutesLeft) { rerenderDelay(minutesLeft) {
if (minutesLeft > 2160) { if (minutesLeft > 2160) {
@ -144,7 +147,7 @@ export default Component.extend({
} }
return 1000; return 1000;
}, }
_noticeKey() { _noticeKey() {
let statusType = this.statusType; let statusType = this.statusType;
@ -156,5 +159,5 @@ export default Component.extend({
} }
return `topic.status_update_notice.auto_${statusType}`; return `topic.status_update_notice.auto_${statusType}`;
}, }
}); }