mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Convert core components to native class syntax (batch 3) (#28517)
Changes made using the ember-native-class-codemod, plus some manual tweaks
This commit is contained in:
parent
9b83ae7d55
commit
7bf3727663
@ -1,5 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import { service } from "@ember/service";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import { setLogoffCallback } from "discourse/lib/ajax";
|
||||
import { clearAllBodyScrollLocks } from "discourse/lib/body-scroll-lock";
|
||||
import logout from "discourse/lib/logout";
|
||||
@ -11,14 +12,15 @@ export function addPluginDocumentTitleCounter(counterFunction) {
|
||||
pluginCounterFunctions.push(counterFunction);
|
||||
}
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
documentTitle: service(),
|
||||
dialog: service(),
|
||||
_showingLogout: false,
|
||||
@tagName("")
|
||||
export default class DDocument extends Component {
|
||||
@service documentTitle;
|
||||
@service dialog;
|
||||
|
||||
_showingLogout = false;
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
this.documentTitle.setTitle(document.title);
|
||||
document.addEventListener("visibilitychange", this._focusChanged);
|
||||
@ -28,10 +30,10 @@ export default Component.extend({
|
||||
|
||||
this.appEvents.on("notifications:changed", this, this._updateNotifications);
|
||||
setLogoffCallback(() => this.displayLogoff());
|
||||
},
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
super.willDestroyElement(...arguments);
|
||||
|
||||
setLogoffCallback(null);
|
||||
document.removeEventListener("visibilitychange", this._focusChanged);
|
||||
@ -43,7 +45,7 @@ export default Component.extend({
|
||||
this,
|
||||
this._updateNotifications
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_updateNotifications(opts) {
|
||||
if (!this.currentUser) {
|
||||
@ -56,7 +58,7 @@ export default Component.extend({
|
||||
count += this.currentUser.unseen_reviewable_count;
|
||||
}
|
||||
this.documentTitle.updateNotificationCount(count, { forced: opts?.forced });
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_focusChanged() {
|
||||
@ -70,7 +72,7 @@ export default Component.extend({
|
||||
} else if (!this.hasFocus) {
|
||||
this.documentTitle.setFocus(true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
displayLogoff() {
|
||||
if (this._showingLogout) {
|
||||
@ -86,5 +88,5 @@ export default Component.extend({
|
||||
didConfirm: () => logout(),
|
||||
didCancel: () => logout(),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +64,8 @@
|
||||
@aria-label={{this.placeholderTranslated}}
|
||||
@disabled={{this.disabled}}
|
||||
@input={{this.change}}
|
||||
@focusIn={{action "focusIn"}}
|
||||
@focusOut={{action "focusOut"}}
|
||||
@focusIn={{this.handleFocusIn}}
|
||||
@focusOut={{this.handleFocusOut}}
|
||||
class="d-editor-input"
|
||||
@id={{this.textAreaId}}
|
||||
/>
|
||||
|
@ -3,6 +3,8 @@ import { action, computed } from "@ember/object";
|
||||
import { schedule, scheduleOnce } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import ItsATrap from "@discourse/itsatrap";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { observes, on } from "@ember-decorators/object";
|
||||
import $ from "jquery";
|
||||
import { emojiSearch, isSkinTonableEmoji } from "pretty-text/emoji";
|
||||
import { translations } from "pretty-text/emoji/data";
|
||||
@ -32,11 +34,7 @@ import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { getRegister } from "discourse-common/lib/get-owner";
|
||||
import { findRawTemplate } from "discourse-common/lib/raw-templates";
|
||||
import discourseComputed, {
|
||||
bind,
|
||||
observes,
|
||||
on,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
function getButtonLabel(labelKey, defaultLabel) {
|
||||
@ -233,39 +231,47 @@ export function onToolbarCreate(func) {
|
||||
addToolbarCallback(func);
|
||||
}
|
||||
|
||||
export default Component.extend(TextareaTextManipulation, {
|
||||
emojiStore: service("emoji-store"),
|
||||
modal: service(),
|
||||
@classNames("d-editor")
|
||||
export default class DEditor extends Component.extend(
|
||||
TextareaTextManipulation
|
||||
) {
|
||||
@service("emoji-store") emojiStore;
|
||||
@service modal;
|
||||
|
||||
classNames: ["d-editor"],
|
||||
ready: false,
|
||||
lastSel: null,
|
||||
_itsatrap: null,
|
||||
showLink: true,
|
||||
emojiPickerIsActive: false,
|
||||
emojiFilter: "",
|
||||
isEditorFocused: false,
|
||||
processPreview: true,
|
||||
composerFocusSelector: "#reply-control .d-editor-input",
|
||||
|
||||
selectedFormTemplateId: computed("formTemplateIds", {
|
||||
get() {
|
||||
if (this._selectedFormTemplateId) {
|
||||
return this._selectedFormTemplateId;
|
||||
}
|
||||
|
||||
return this.formTemplateId || this.formTemplateIds?.[0];
|
||||
ready = false;
|
||||
lastSel = null;
|
||||
showLink = true;
|
||||
emojiPickerIsActive = false;
|
||||
emojiFilter = "";
|
||||
isEditorFocused = false;
|
||||
processPreview = true;
|
||||
composerFocusSelector = "#reply-control .d-editor-input";
|
||||
morphingOptions = {
|
||||
beforeAttributeUpdated: (element, attributeName) => {
|
||||
// Don't morph the open attribute of <details> elements
|
||||
return !(element.tagName === "DETAILS" && attributeName === "open");
|
||||
},
|
||||
};
|
||||
|
||||
set(key, value) {
|
||||
return (this._selectedFormTemplateId = value);
|
||||
},
|
||||
}),
|
||||
_itsatrap = null;
|
||||
|
||||
@computed("formTemplateIds")
|
||||
get selectedFormTemplateId() {
|
||||
if (this._selectedFormTemplateId) {
|
||||
return this._selectedFormTemplateId;
|
||||
}
|
||||
|
||||
return this.formTemplateId || this.formTemplateIds?.[0];
|
||||
}
|
||||
|
||||
set selectedFormTemplateId(value) {
|
||||
this._selectedFormTemplateId = value;
|
||||
}
|
||||
|
||||
@action
|
||||
updateSelectedFormTemplateId(formTemplateId) {
|
||||
this.selectedFormTemplateId = formTemplateId;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("formTemplateIds", "replyingToTopic", "editingPost")
|
||||
showFormTemplateForm(formTemplateIds, replyingToTopic, editingPost) {
|
||||
@ -275,7 +281,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("placeholder")
|
||||
placeholderTranslated(placeholder) {
|
||||
@ -283,7 +289,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
return I18n.t(placeholder);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
_readyNow() {
|
||||
this.set("ready", true);
|
||||
@ -291,16 +297,16 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
if (this.autofocus) {
|
||||
this._textarea.focus();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
super.init(...arguments);
|
||||
|
||||
this.register = getRegister(this);
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
this._previewMutationObserver = this._disablePreviewTabIndex();
|
||||
|
||||
@ -374,14 +380,14 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
"indentSelection"
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
onBeforeInputSmartList(event) {
|
||||
// This inputType is much more consistently fired in `beforeinput`
|
||||
// rather than `input`.
|
||||
this.handleSmartListAutocomplete = event.inputType === "insertLineBreak";
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
onInputSmartList() {
|
||||
@ -389,7 +395,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
this.maybeContinueList();
|
||||
}
|
||||
this.handleSmartListAutocomplete = false;
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handlePreviewLinkClick(event) {
|
||||
@ -417,7 +423,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@on("willDestroyElement")
|
||||
_shutDown() {
|
||||
@ -455,7 +461,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
}
|
||||
|
||||
this._cachedCookFunction = null;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed()
|
||||
toolbar() {
|
||||
@ -476,12 +482,12 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
}
|
||||
|
||||
return toolbar;
|
||||
},
|
||||
}
|
||||
|
||||
async cachedCookAsync(text, options) {
|
||||
this._cachedCookFunction ||= await generateCookFunction(options || {});
|
||||
return await this._cachedCookFunction(text);
|
||||
},
|
||||
}
|
||||
|
||||
async _updatePreview() {
|
||||
if (
|
||||
@ -556,14 +562,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
this.previewUpdated(previewElement, unseenMentions, unseenHashtags);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
morphingOptions: {
|
||||
beforeAttributeUpdated: (element, attributeName) => {
|
||||
// Don't morph the open attribute of <details> elements
|
||||
return !(element.tagName === "DETAILS" && attributeName === "open");
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@observes("ready", "value", "processPreview")
|
||||
async _watchForChanges() {
|
||||
@ -577,7 +576,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
} else {
|
||||
discourseDebounce(this, this._updatePreview, 30);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_applyHashtagAutocomplete() {
|
||||
setupHashtagAutocomplete(
|
||||
@ -591,7 +590,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_applyEmojiAutocomplete($textarea) {
|
||||
if (!this.siteSettings.enable_emoji) {
|
||||
@ -713,7 +712,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
triggerRule: async (textarea) =>
|
||||
!(await inCodeBlock(textarea.value, caretPosition(textarea))),
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_applyList(sel, head, exampleKey, opts) {
|
||||
if (sel.value.includes("\n")) {
|
||||
@ -736,12 +735,12 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
this.set("value", `${preLines}${number}${post}`);
|
||||
this.selectText(preLines.length, number.length);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_applySurround(head, tail, exampleKey, opts) {
|
||||
const selected = this.getSelected();
|
||||
this.applySurround(selected, head, tail, exampleKey, opts);
|
||||
},
|
||||
}
|
||||
|
||||
_toggleDirection() {
|
||||
let currentDir = this._$textarea.attr("dir")
|
||||
@ -750,7 +749,7 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
newDir = currentDir === "ltr" ? "rtl" : "ltr";
|
||||
|
||||
this._$textarea.attr("dir", newDir).focus();
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
rovingButtonBar(event) {
|
||||
@ -789,14 +788,14 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onEmojiPickerClose() {
|
||||
if (!(this.isDestroyed || this.isDestroying)) {
|
||||
this.set("emojiPickerIsActive", false);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
newToolbarEvent(trimLeading) {
|
||||
const selected = this.getSelected(trimLeading);
|
||||
@ -815,105 +814,110 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
replaceText: (oldVal, newVal, opts) =>
|
||||
this.replaceText(oldVal, newVal, opts),
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
emoji() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
@action
|
||||
emoji() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("emojiPickerIsActive", !this.emojiPickerIsActive);
|
||||
},
|
||||
this.set("emojiPickerIsActive", !this.emojiPickerIsActive);
|
||||
}
|
||||
|
||||
toolbarButton(button) {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
@action
|
||||
toolbarButton(button) {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toolbarEvent = this.newToolbarEvent(button.trimLeading);
|
||||
if (button.sendAction) {
|
||||
return button.sendAction(toolbarEvent);
|
||||
} else {
|
||||
button.perform(toolbarEvent);
|
||||
}
|
||||
},
|
||||
const toolbarEvent = this.newToolbarEvent(button.trimLeading);
|
||||
if (button.sendAction) {
|
||||
return button.sendAction(toolbarEvent);
|
||||
} else {
|
||||
button.perform(toolbarEvent);
|
||||
}
|
||||
}
|
||||
|
||||
showLinkModal(toolbarEvent) {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
@action
|
||||
showLinkModal(toolbarEvent) {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let linkText = "";
|
||||
this._lastSel = toolbarEvent.selected;
|
||||
let linkText = "";
|
||||
this._lastSel = toolbarEvent.selected;
|
||||
|
||||
if (this._lastSel) {
|
||||
linkText = this._lastSel.value;
|
||||
}
|
||||
if (this._lastSel) {
|
||||
linkText = this._lastSel.value;
|
||||
}
|
||||
|
||||
this.modal.show(InsertHyperlink, {
|
||||
model: {
|
||||
linkText,
|
||||
toolbarEvent,
|
||||
},
|
||||
});
|
||||
},
|
||||
this.modal.show(InsertHyperlink, {
|
||||
model: {
|
||||
linkText,
|
||||
toolbarEvent,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
formatCode() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
@action
|
||||
formatCode() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sel = this.getSelected("", { lineVal: true });
|
||||
const selValue = sel.value;
|
||||
const hasNewLine = selValue.includes("\n");
|
||||
const isBlankLine = sel.lineVal.trim().length === 0;
|
||||
const isFourSpacesIndent =
|
||||
this.siteSettings.code_formatting_style === FOUR_SPACES_INDENT;
|
||||
const sel = this.getSelected("", { lineVal: true });
|
||||
const selValue = sel.value;
|
||||
const hasNewLine = selValue.includes("\n");
|
||||
const isBlankLine = sel.lineVal.trim().length === 0;
|
||||
const isFourSpacesIndent =
|
||||
this.siteSettings.code_formatting_style === FOUR_SPACES_INDENT;
|
||||
|
||||
if (!hasNewLine) {
|
||||
if (selValue.length === 0 && isBlankLine) {
|
||||
if (isFourSpacesIndent) {
|
||||
const example = I18n.t(`composer.code_text`);
|
||||
this.set("value", `${sel.pre} ${example}${sel.post}`);
|
||||
return this.selectText(sel.pre.length + 4, example.length);
|
||||
} else {
|
||||
return this.applySurround(sel, "```\n", "\n```", "paste_code_text");
|
||||
}
|
||||
} else {
|
||||
return this.applySurround(sel, "`", "`", "code_title");
|
||||
}
|
||||
} else {
|
||||
if (!hasNewLine) {
|
||||
if (selValue.length === 0 && isBlankLine) {
|
||||
if (isFourSpacesIndent) {
|
||||
return this.applySurround(sel, " ", "", "code_text");
|
||||
const example = I18n.t(`composer.code_text`);
|
||||
this.set("value", `${sel.pre} ${example}${sel.post}`);
|
||||
return this.selectText(sel.pre.length + 4, example.length);
|
||||
} else {
|
||||
const preNewline = sel.pre[-1] !== "\n" && sel.pre !== "" ? "\n" : "";
|
||||
const postNewline = sel.post[0] !== "\n" ? "\n" : "";
|
||||
return this.addText(
|
||||
sel,
|
||||
`${preNewline}\`\`\`\n${sel.value}\n\`\`\`${postNewline}`
|
||||
);
|
||||
return this.applySurround(sel, "```\n", "\n```", "paste_code_text");
|
||||
}
|
||||
} else {
|
||||
return this.applySurround(sel, "`", "`", "code_title");
|
||||
}
|
||||
},
|
||||
} else {
|
||||
if (isFourSpacesIndent) {
|
||||
return this.applySurround(sel, " ", "", "code_text");
|
||||
} else {
|
||||
const preNewline = sel.pre[-1] !== "\n" && sel.pre !== "" ? "\n" : "";
|
||||
const postNewline = sel.post[0] !== "\n" ? "\n" : "";
|
||||
return this.addText(
|
||||
sel,
|
||||
`${preNewline}\`\`\`\n${sel.value}\n\`\`\`${postNewline}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insertCurrentTime() {
|
||||
const sel = this.getSelected("", { lineVal: true });
|
||||
const timezone = this.currentUser.user_option.timezone;
|
||||
const time = moment().format("HH:mm:ss");
|
||||
const date = moment().format("YYYY-MM-DD");
|
||||
@action
|
||||
insertCurrentTime() {
|
||||
const sel = this.getSelected("", { lineVal: true });
|
||||
const timezone = this.currentUser.user_option.timezone;
|
||||
const time = moment().format("HH:mm:ss");
|
||||
const date = moment().format("YYYY-MM-DD");
|
||||
|
||||
this.addText(sel, `[date=${date} time=${time} timezone="${timezone}"]`);
|
||||
},
|
||||
this.addText(sel, `[date=${date} time=${time} timezone="${timezone}"]`);
|
||||
}
|
||||
|
||||
focusIn() {
|
||||
this.set("isEditorFocused", true);
|
||||
},
|
||||
@action
|
||||
handleFocusIn() {
|
||||
this.set("isEditorFocused", true);
|
||||
}
|
||||
|
||||
focusOut() {
|
||||
this.set("isEditorFocused", false);
|
||||
},
|
||||
},
|
||||
@action
|
||||
handleFocusOut() {
|
||||
this.set("isEditorFocused", false);
|
||||
}
|
||||
|
||||
_disablePreviewTabIndex() {
|
||||
const observer = new MutationObserver(function () {
|
||||
@ -930,5 +934,5 @@ export default Component.extend(TextareaTextManipulation, {
|
||||
});
|
||||
|
||||
return observer;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,26 @@ import { action } from "@ember/object";
|
||||
import { dependentKeyCompat } from "@ember/object/compat";
|
||||
import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import { filterTypeForMode } from "discourse/lib/filter-mode";
|
||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import NavItem from "discourse/models/nav-item";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
router: service(),
|
||||
dialog: service(),
|
||||
tagName: "",
|
||||
filterMode: tracked(),
|
||||
fixedCategoryPositions: setting("fixed_category_positions"),
|
||||
@tagName("")
|
||||
export default class DNavigation extends Component {
|
||||
@service router;
|
||||
@service dialog;
|
||||
|
||||
@tracked filterMode;
|
||||
|
||||
@setting("fixed_category_positions") fixedCategoryPositions;
|
||||
|
||||
@dependentKeyCompat
|
||||
get filterType() {
|
||||
return filterTypeForMode(this.filterMode);
|
||||
},
|
||||
}
|
||||
|
||||
// Should be a `readOnly` instead but some themes/plugins still pass
|
||||
// the `categories` property into this component
|
||||
@ -42,12 +45,12 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
return categories;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("category")
|
||||
showCategoryNotifications(category) {
|
||||
return category && this.currentUser;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("category.notification_level")
|
||||
categoryNotificationLevel(notificationLevel) {
|
||||
@ -60,20 +63,20 @@ export default Component.extend({
|
||||
} else {
|
||||
return notificationLevel;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// don't show tag notification menu on tag intersections
|
||||
@discourseComputed("tagNotification", "additionalTags")
|
||||
showTagNotifications(tagNotification, additionalTags) {
|
||||
return tagNotification && !additionalTags;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("category", "createTopicDisabled")
|
||||
categoryReadOnlyBanner(category, createTopicDisabled) {
|
||||
if (category && this.currentUser && createTopicDisabled) {
|
||||
return category.read_only_banner;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed(
|
||||
"createTopicDisabled",
|
||||
@ -95,7 +98,7 @@ export default Component.extend({
|
||||
return false;
|
||||
}
|
||||
return createTopicDisabled;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("categoryReadOnlyBanner", "hasDraft")
|
||||
createTopicClass(categoryReadOnlyBanner, hasDraft) {
|
||||
@ -106,20 +109,22 @@ export default Component.extend({
|
||||
classNames.push("disabled");
|
||||
}
|
||||
return classNames.join(" ");
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("hasDraft")
|
||||
createTopicLabel(hasDraft) {
|
||||
return hasDraft ? "topic.open_draft" : "topic.create";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("category.can_edit")
|
||||
showCategoryEdit: (canEdit) => canEdit,
|
||||
showCategoryEdit(canEdit) {
|
||||
return canEdit;
|
||||
}
|
||||
|
||||
@discourseComputed("additionalTags", "category", "tag.id")
|
||||
showToggleInfo(additionalTags, category, tagId) {
|
||||
return !additionalTags && !category && tagId !== "none";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed(
|
||||
"filterType",
|
||||
@ -145,12 +150,12 @@ export default Component.extend({
|
||||
siteSettings: this.siteSettings,
|
||||
skipCategoriesNavItem,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("filterType")
|
||||
notCategoriesRoute(filterType) {
|
||||
return filterType !== "categories";
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
async changeTagNotificationLevel(notificationLevel) {
|
||||
@ -169,30 +174,31 @@ export default Component.extend({
|
||||
muted_tags: payload.muted_tags,
|
||||
regular_tags: payload.regular_tags,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
changeCategoryNotificationLevel(notificationLevel) {
|
||||
this.category.setNotification(notificationLevel);
|
||||
},
|
||||
@action
|
||||
changeCategoryNotificationLevel(notificationLevel) {
|
||||
this.category.setNotification(notificationLevel);
|
||||
}
|
||||
|
||||
selectCategoryAdminDropdownAction(actionId) {
|
||||
switch (actionId) {
|
||||
case "create":
|
||||
this.createCategory();
|
||||
break;
|
||||
case "reorder":
|
||||
this.reorderCategories();
|
||||
break;
|
||||
}
|
||||
},
|
||||
@action
|
||||
selectCategoryAdminDropdownAction(actionId) {
|
||||
switch (actionId) {
|
||||
case "create":
|
||||
this.createCategory();
|
||||
break;
|
||||
case "reorder":
|
||||
this.reorderCategories();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clickCreateTopicButton() {
|
||||
if (this.categoryReadOnlyBanner && !this.hasDraft) {
|
||||
this.dialog.alert({ message: htmlSafe(this.categoryReadOnlyBanner) });
|
||||
} else {
|
||||
this.createTopic();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
@action
|
||||
clickCreateTopicButton() {
|
||||
if (this.categoryReadOnlyBanner && !this.hasDraft) {
|
||||
this.dialog.alert({ message: htmlSafe(this.categoryReadOnlyBanner) });
|
||||
} else {
|
||||
this.createTopic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { TextArea } from "@ember/legacy-built-in-components";
|
||||
import { attributeBindings } from "@ember-decorators/component";
|
||||
|
||||
export default TextArea.extend({
|
||||
attributeBindings: ["aria-label"],
|
||||
});
|
||||
@attributeBindings("aria-label")
|
||||
export default class DTextarea extends TextArea {}
|
||||
|
@ -1,10 +1,12 @@
|
||||
/* global Pikaday:true */
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { action, computed } from "@ember/object";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import { Promise } from "rsvp";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
function isInputDateSupported() {
|
||||
@ -15,24 +17,23 @@ function isInputDateSupported() {
|
||||
return input.value !== value;
|
||||
}
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["d-date-input"],
|
||||
date: null,
|
||||
_picker: null,
|
||||
@classNames("d-date-input")
|
||||
export default class DateInput extends Component {
|
||||
date = null;
|
||||
useNativePicker = isInputDateSupported();
|
||||
_picker = null;
|
||||
|
||||
@discourseComputed("site.mobileView")
|
||||
inputType() {
|
||||
return this.useNativePicker ? "date" : "text";
|
||||
},
|
||||
|
||||
useNativePicker: isInputDateSupported(),
|
||||
}
|
||||
|
||||
click(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
schedule("afterRender", () => {
|
||||
if (!this.element || this.isDestroying || this.isDestroying) {
|
||||
@ -58,10 +59,10 @@ export default Component.extend({
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
didUpdateAttrs() {
|
||||
this._super(...arguments);
|
||||
super.didUpdateAttrs(...arguments);
|
||||
|
||||
if (this._picker && this.date) {
|
||||
const parsedDate =
|
||||
@ -81,7 +82,7 @@ export default Component.extend({
|
||||
if (this._picker && !this.date) {
|
||||
this._picker.setDate(null);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_loadPikadayPicker(container) {
|
||||
return loadScript("/javascripts/pikaday.js").then(() => {
|
||||
@ -107,7 +108,7 @@ export default Component.extend({
|
||||
|
||||
return new Pikaday({ ...defaultOptions, ...this._opts() });
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_loadNativePicker(container) {
|
||||
const wrapper = container || this.element;
|
||||
@ -131,7 +132,7 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
return Promise.resolve(picker);
|
||||
},
|
||||
}
|
||||
|
||||
_handleSelection(value) {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
@ -141,7 +142,7 @@ export default Component.extend({
|
||||
if (this.onChange) {
|
||||
this.onChange(value ? moment(value) : null);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@on("willDestroyElement")
|
||||
_destroy() {
|
||||
@ -149,26 +150,23 @@ export default Component.extend({
|
||||
this._picker.destroy();
|
||||
this._picker = null;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("_placeholder")
|
||||
placeholder: {
|
||||
get(_placeholder) {
|
||||
return _placeholder || I18n.t("dates.placeholder");
|
||||
},
|
||||
@computed("_placeholder")
|
||||
get placeholder() {
|
||||
return this._placeholder || I18n.t("dates.placeholder");
|
||||
}
|
||||
|
||||
set(value) {
|
||||
this.set("_placeholder", value);
|
||||
return value;
|
||||
},
|
||||
},
|
||||
set placeholder(value) {
|
||||
this.set("_placeholder", value);
|
||||
}
|
||||
|
||||
_opts() {
|
||||
return null;
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeDate(event) {
|
||||
this._handleSelection(event.target.value);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import DatePicker from "discourse/components/date-picker";
|
||||
|
||||
export default DatePicker.extend({
|
||||
export default class DatePickerFuture extends DatePicker {
|
||||
_opts() {
|
||||
return {
|
||||
defaultDate: this.defaultDate || moment().add(1, "day").toDate(),
|
||||
setDefaultDate: !!this.defaultDate,
|
||||
minDate: this.minDate || moment().toDate(),
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import DatePicker from "discourse/components/date-picker";
|
||||
|
||||
export default DatePicker.extend({
|
||||
export default class DatePickerPast extends DatePicker {
|
||||
_opts() {
|
||||
return {
|
||||
defaultDate:
|
||||
@ -8,5 +8,5 @@ export default DatePicker.extend({
|
||||
setDefaultDate: !!this.defaultDate,
|
||||
maxDate: new Date(),
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,24 @@
|
||||
import Component from "@ember/component";
|
||||
import { schedule } from "@ember/runloop";
|
||||
/* global Pikaday:true */
|
||||
import Component from "@ember/component";
|
||||
import { computed } from "@ember/object";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
const DATE_FORMAT = "YYYY-MM-DD";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["date-picker-wrapper"],
|
||||
_picker: null,
|
||||
value: null,
|
||||
@classNames("date-picker-wrapper")
|
||||
export default class DatePicker extends Component {
|
||||
value = null;
|
||||
_picker = null;
|
||||
|
||||
@discourseComputed("site.mobileView")
|
||||
inputType(mobileView) {
|
||||
return mobileView ? "date" : "text";
|
||||
},
|
||||
}
|
||||
|
||||
@on("didInsertElement")
|
||||
_loadDatePicker() {
|
||||
@ -25,7 +28,7 @@ export default Component.extend({
|
||||
const container = document.getElementById(this.containerId);
|
||||
this._loadPikadayPicker(container);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_loadPikadayPicker(container) {
|
||||
loadScript("/javascripts/pikaday.js").then(() => {
|
||||
@ -49,7 +52,7 @@ export default Component.extend({
|
||||
this._picker = new Pikaday(Object.assign(options, this._opts()));
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_loadNativePicker() {
|
||||
const picker = this.element.querySelector("input.date-picker");
|
||||
@ -61,7 +64,7 @@ export default Component.extend({
|
||||
/* do nothing for native */
|
||||
};
|
||||
this._picker = picker;
|
||||
},
|
||||
}
|
||||
|
||||
_handleSelection(value) {
|
||||
const formattedDate = moment(value).format(DATE_FORMAT);
|
||||
@ -73,7 +76,7 @@ export default Component.extend({
|
||||
if (this.onSelect) {
|
||||
this.onSelect(formattedDate);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@on("willDestroyElement")
|
||||
_destroy() {
|
||||
@ -81,21 +84,18 @@ export default Component.extend({
|
||||
this._picker.destroy();
|
||||
this._picker = null;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("_placeholder")
|
||||
placeholder: {
|
||||
get(_placeholder) {
|
||||
return _placeholder || I18n.t("dates.placeholder");
|
||||
},
|
||||
@computed("_placeholder")
|
||||
get placeholder() {
|
||||
return this._placeholder || I18n.t("dates.placeholder");
|
||||
}
|
||||
|
||||
set(value) {
|
||||
this.set("_placeholder", value);
|
||||
return value;
|
||||
},
|
||||
},
|
||||
set placeholder(value) {
|
||||
this.set("_placeholder", value);
|
||||
}
|
||||
|
||||
_opts() {
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["d-date-time-input-range"],
|
||||
from: null,
|
||||
to: null,
|
||||
onChangeTo: null,
|
||||
onChangeFrom: null,
|
||||
toTimeFirst: false,
|
||||
showToTime: true,
|
||||
showFromTime: true,
|
||||
clearable: false,
|
||||
@classNames("d-date-time-input-range")
|
||||
export default class DateTimeInputRange extends Component {
|
||||
from = null;
|
||||
to = null;
|
||||
onChangeTo = null;
|
||||
onChangeFrom = null;
|
||||
toTimeFirst = false;
|
||||
showToTime = true;
|
||||
showFromTime = true;
|
||||
clearable = false;
|
||||
|
||||
@action
|
||||
onChangeRanges(options, value) {
|
||||
@ -42,5 +43,5 @@ export default Component.extend({
|
||||
const newState = { ...state, ...diff };
|
||||
this.onChange(newState);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,28 @@
|
||||
import Component from "@ember/component";
|
||||
import { action, computed } from "@ember/object";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["d-date-time-input"],
|
||||
date: null,
|
||||
relativeDate: null,
|
||||
showTime: true,
|
||||
clearable: false,
|
||||
@classNames("d-date-time-input")
|
||||
export default class DateTimeInput extends Component {
|
||||
date = null;
|
||||
relativeDate = null;
|
||||
showTime = true;
|
||||
clearable = false;
|
||||
|
||||
hours: computed("date", "showTime", function () {
|
||||
@computed("date", "showTime")
|
||||
get hours() {
|
||||
return this.date && this.get("showTime") ? this.date.hours() : null;
|
||||
}),
|
||||
}
|
||||
|
||||
minutes: computed("date", "showTime", function () {
|
||||
@computed("date", "showTime")
|
||||
get minutes() {
|
||||
return this.date && this.get("showTime") ? this.date.minutes() : null;
|
||||
}),
|
||||
}
|
||||
|
||||
@action
|
||||
onClear() {
|
||||
this.onChange(null);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeTime(time) {
|
||||
@ -43,7 +46,7 @@ export default Component.extend({
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeDate(date) {
|
||||
@ -64,10 +67,10 @@ export default Component.extend({
|
||||
this.resolvedTimezone
|
||||
)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@computed("timezone")
|
||||
get resolvedTimezone() {
|
||||
return this.timezone || moment.tz.guess();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
import Component from "@ember/component";
|
||||
import {
|
||||
classNameBindings,
|
||||
classNames,
|
||||
tagName,
|
||||
} from "@ember-decorators/component";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "div",
|
||||
classNames: ["directory-table__row"],
|
||||
classNameBindings: ["me"],
|
||||
me: propertyEqual("item.user.id", "currentUser.id"),
|
||||
columns: null,
|
||||
});
|
||||
@tagName("div")
|
||||
@classNames("directory-table__row")
|
||||
@classNameBindings("me")
|
||||
export default class DirectoryItem extends Component {
|
||||
@propertyEqual("item.user.id", "currentUser.id") me;
|
||||
columns = null;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Component.extend({
|
||||
_table: null,
|
||||
export default class DirectoryTable extends Component {
|
||||
_table = null;
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
this.setProperties({
|
||||
_table: this.element.querySelector(".directory-table"),
|
||||
_columnCount: this.showTimeRead
|
||||
@ -14,7 +14,7 @@ export default Component.extend({
|
||||
});
|
||||
|
||||
this._table.style.gridTemplateColumns = `minmax(15em, 3fr) repeat(${this._columnCount}, minmax(max-content, 1fr))`;
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
setActiveHeader(header) {
|
||||
@ -28,5 +28,5 @@ export default Component.extend({
|
||||
if (scrollPixels > 0) {
|
||||
this._table.scrollLeft = scrollPixels;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ import { action } from "@ember/object";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
hide: false,
|
||||
export default class DiscourseBanner extends Component {
|
||||
hide = false;
|
||||
|
||||
banner: readOnly("site.banner"),
|
||||
@readOnly("site.banner") banner;
|
||||
|
||||
@discourseComputed("banner.html")
|
||||
content(bannerHtml) {
|
||||
@ -16,7 +16,7 @@ export default Component.extend({
|
||||
el.removeAttribute("id");
|
||||
});
|
||||
return newDiv.innerHTML;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("currentUser.dismissed_banner_key", "banner.key", "hide")
|
||||
visible(dismissedBannerKey, bannerKey, hide) {
|
||||
@ -31,7 +31,7 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
return !hide && bannerKey && dismissedBannerKey !== bannerKey;
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
dismiss() {
|
||||
@ -44,10 +44,10 @@ export default Component.extend({
|
||||
value: this.get("banner.key"),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
this.appEvents.trigger("decorate-non-stream-cooked-element", this.element);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
import Component from "@ember/component";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "span",
|
||||
|
||||
@tagName("span")
|
||||
export default class DiscourseLinkedText extends Component {
|
||||
@discourseComputed("text", "textParams")
|
||||
translatedText(text) {
|
||||
if (text) {
|
||||
return I18n.t(...arguments);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
click(event) {
|
||||
if (event.target.tagName.toUpperCase() === "A") {
|
||||
@ -18,5 +18,5 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import { classNames, tagName } from "@ember-decorators/component";
|
||||
|
||||
let componentArgs = { tagName: "div", classNames: ["discourse-root"] };
|
||||
|
||||
export default Component.extend(componentArgs);
|
||||
@tagName("div")
|
||||
@classNames("discourse-root")
|
||||
export default class DiscourseRoot extends Component {}
|
||||
|
@ -1,19 +1,23 @@
|
||||
import Component from "@ember/component";
|
||||
import {
|
||||
attributeBindings,
|
||||
classNameBindings,
|
||||
tagName,
|
||||
} from "@ember-decorators/component";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "a",
|
||||
classNameBindings: [":discourse-tag", "style", "tagClass"],
|
||||
attributeBindings: ["href"],
|
||||
|
||||
@tagName("a")
|
||||
@classNameBindings(":discourse-tag", "style", "tagClass")
|
||||
@attributeBindings("href")
|
||||
export default class DiscourseTagBound extends Component {
|
||||
@discourseComputed("tagRecord.id")
|
||||
tagClass(tagRecordId) {
|
||||
return "tag-" + tagRecordId;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("tagRecord.id")
|
||||
href(tagRecordId) {
|
||||
return getURL("/tag/" + tagRecordId);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -3,26 +3,28 @@ import { alias } from "@ember/object/computed";
|
||||
import { getOwner } from "@ember/owner";
|
||||
import { schedule, scheduleOnce } from "@ember/runloop";
|
||||
import { isBlank } from "@ember/utils";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import $ from "jquery";
|
||||
import ClickTrack from "discourse/lib/click-track";
|
||||
import { highlightPost } from "discourse/lib/utilities";
|
||||
import Scrolling from "discourse/mixins/scrolling";
|
||||
import { bind, observes } from "discourse-common/utils/decorators";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend(Scrolling, {
|
||||
userFilters: alias("topic.userFilters"),
|
||||
classNameBindings: [
|
||||
"multiSelect",
|
||||
"topic.archetype",
|
||||
"topic.is_warning",
|
||||
"topic.category.read_restricted:read_restricted",
|
||||
"topic.deleted:deleted-topic",
|
||||
],
|
||||
menuVisible: true,
|
||||
SHORT_POST: 1200,
|
||||
@classNameBindings(
|
||||
"multiSelect",
|
||||
"topic.archetype",
|
||||
"topic.is_warning",
|
||||
"topic.category.read_restricted:read_restricted",
|
||||
"topic.deleted:deleted-topic"
|
||||
)
|
||||
export default class DiscourseTopic extends Component.extend(Scrolling) {
|
||||
@alias("topic.userFilters") userFilters;
|
||||
@alias("topic.postStream") postStream;
|
||||
|
||||
postStream: alias("topic.postStream"),
|
||||
dockAt: 0,
|
||||
menuVisible = true;
|
||||
SHORT_POST = 1200;
|
||||
dockAt = 0;
|
||||
|
||||
@observes("enteredAt")
|
||||
_enteredTopic() {
|
||||
@ -33,22 +35,22 @@ export default Component.extend(Scrolling, {
|
||||
schedule("afterRender", this.scrolled);
|
||||
this.set("lastEnteredAt", this.enteredAt);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_highlightPost(postNumber, options = {}) {
|
||||
if (isBlank(options.jump) || options.jump !== false) {
|
||||
scheduleOnce("afterRender", null, highlightPost, postNumber);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
super.init(...arguments);
|
||||
this.appEvents.on("discourse:focus-changed", this, "gotFocus");
|
||||
this.appEvents.on("post:highlight", this, "_highlightPost");
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
this.bindScrolling();
|
||||
window.addEventListener("resize", this.scrolled);
|
||||
@ -57,31 +59,31 @@ export default Component.extend(Scrolling, {
|
||||
".cooked a, a.track-link",
|
||||
(e) => ClickTrack.trackClick(e, getOwner(this))
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
this._super(...arguments);
|
||||
super.willDestroy(...arguments);
|
||||
|
||||
// this happens after route exit, stuff could have trickled in
|
||||
this.appEvents.off("discourse:focus-changed", this, "gotFocus");
|
||||
this.appEvents.off("post:highlight", this, "_highlightPost");
|
||||
},
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
super.willDestroyElement(...arguments);
|
||||
|
||||
this.unbindScrolling();
|
||||
window.removeEventListener("resize", this.scrolled);
|
||||
|
||||
// Unbind link tracking
|
||||
$(this.element).off("click.discourse-redirect", ".cooked a, a.track-link");
|
||||
},
|
||||
}
|
||||
|
||||
gotFocus(hasFocus) {
|
||||
if (hasFocus) {
|
||||
this.scrolled();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// The user has scrolled the window, or it is finished rendering and ready for processing.
|
||||
@bind
|
||||
@ -95,5 +97,5 @@ export default Component.extend(Scrolling, {
|
||||
|
||||
// Trigger a scrolled event
|
||||
this.appEvents.trigger("topic:scrolled", offset);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +1,40 @@
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { observes, on } from "@ember-decorators/object";
|
||||
import $ from "jquery";
|
||||
import { applyBehaviorTransformer } from "discourse/lib/transformer";
|
||||
import LoadMore from "discourse/mixins/load-more";
|
||||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend(LoadMore, {
|
||||
classNames: ["contents"],
|
||||
eyelineSelector: ".topic-list-item",
|
||||
appEvents: service(),
|
||||
documentTitle: service(),
|
||||
@classNames("contents")
|
||||
export default class DiscoveryTopicsList extends Component.extend(LoadMore) {
|
||||
@service appEvents;
|
||||
@service documentTitle;
|
||||
eyelineSelector = ".topic-list-item";
|
||||
|
||||
@on("didInsertElement")
|
||||
_monitorTrackingState() {
|
||||
this.stateChangeCallbackId = this.topicTrackingState.onStateChange(() =>
|
||||
this._updateTrackingTopics()
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@on("willDestroyElement")
|
||||
_removeTrackingStateChangeMonitor() {
|
||||
if (this.stateChangeCallbackId) {
|
||||
this.topicTrackingState.offStateChange(this.stateChangeCallbackId);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_updateTrackingTopics() {
|
||||
this.topicTrackingState.updateTopics(this.model.topics);
|
||||
},
|
||||
}
|
||||
|
||||
@observes("incomingCount")
|
||||
_updateTitle() {
|
||||
this.documentTitle.updateContextCount(this.incomingCount);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
@ -58,5 +59,5 @@ export default Component.extend(LoadMore, {
|
||||
},
|
||||
{ model: this.model }
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user