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:
parent
4150ec960e
commit
54b281c4a2
|
@ -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();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"), {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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}`;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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;
|
||||||
});
|
}
|
||||||
|
|
|
@ -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"),
|
|
||||||
});
|
|
||||||
|
|
|
@ -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);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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"));
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -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}`;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
Loading…
Reference in New Issue