mirror of
https://github.com/discourse/discourse.git
synced 2025-01-19 02:22:46 +08:00
DEV: Convert core components to native class syntax (batch 2) (#28515)
Changes made using the ember-native-class-codemod, plus some manual tweaks
This commit is contained in:
parent
31c0a08f8a
commit
66b061a5a8
|
@ -1,4 +1,5 @@
|
|||
import Component from "@ember/component";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const LIST_TYPE = {
|
||||
|
@ -6,10 +7,10 @@ const LIST_TYPE = {
|
|||
MUTED: "muted",
|
||||
};
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
category: null,
|
||||
listType: LIST_TYPE.NORMAL,
|
||||
@tagName("")
|
||||
export default class CategoryListItem extends Component {
|
||||
category = null;
|
||||
listType = LIST_TYPE.NORMAL;
|
||||
|
||||
@discourseComputed("category.isHidden", "category.hasMuted", "listType")
|
||||
isHidden(isHiddenCategory, hasMuted, listType) {
|
||||
|
@ -17,7 +18,7 @@ export default Component.extend({
|
|||
(isHiddenCategory && listType === LIST_TYPE.NORMAL) ||
|
||||
(!hasMuted && listType === LIST_TYPE.MUTED)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("category.isMuted", "listType")
|
||||
isMuted(isMutedCategory, listType) {
|
||||
|
@ -25,20 +26,20 @@ export default Component.extend({
|
|||
(isMutedCategory && listType === LIST_TYPE.NORMAL) ||
|
||||
(!isMutedCategory && listType === LIST_TYPE.MUTED)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("topicTrackingState.messageCount")
|
||||
unreadTopicsCount() {
|
||||
return this.category.unreadTopicsCount;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("topicTrackingState.messageCount")
|
||||
newTopicsCount() {
|
||||
return this.category.newTopicsCount;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("category.path")
|
||||
slugPath(categoryPath) {
|
||||
return categoryPath.substring("/c/".length);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({});
|
||||
export default class CategoryNameFields extends Component {}
|
||||
|
|
|
@ -1,43 +1,45 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { alias, equal } from "@ember/object/computed";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
const EVERYONE = "everyone";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["permission-row", "row-body"],
|
||||
canCreate: equal("type", PermissionType.FULL),
|
||||
everyonePermissionType: alias("everyonePermission.permission_type"),
|
||||
@classNames("permission-row", "row-body")
|
||||
export default class CategoryPermissionRow extends Component {
|
||||
@equal("type", PermissionType.FULL) canCreate;
|
||||
@alias("everyonePermission.permission_type") everyonePermissionType;
|
||||
|
||||
@discourseComputed("type")
|
||||
canReply(value) {
|
||||
return (
|
||||
value === PermissionType.CREATE_POST || value === PermissionType.FULL
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("type")
|
||||
canReplyIcon() {
|
||||
return this.canReply ? "check-square" : "far-square";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("type")
|
||||
canCreateIcon() {
|
||||
return this.canCreate ? "check-square" : "far-square";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("type")
|
||||
replyGranted() {
|
||||
return this.type <= PermissionType.CREATE_POST ? "reply-granted" : "";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("type")
|
||||
createGranted() {
|
||||
return this.type === PermissionType.FULL ? "create-granted" : "";
|
||||
},
|
||||
}
|
||||
|
||||
@observes("everyonePermissionType")
|
||||
inheritFromEveryone() {
|
||||
|
@ -49,7 +51,7 @@ export default Component.extend({
|
|||
if (this.everyonePermissionType < this.type) {
|
||||
this.updatePermission(this.everyonePermissionType);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("everyonePermissionType", "type")
|
||||
replyDisabled(everyonePermissionType) {
|
||||
|
@ -61,14 +63,14 @@ export default Component.extend({
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("replyDisabled")
|
||||
replyTooltip(replyDisabled) {
|
||||
return replyDisabled
|
||||
? I18n.t("category.permissions.inherited")
|
||||
: I18n.t("category.permissions.toggle_reply");
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("everyonePermissionType", "type")
|
||||
createDisabled(everyonePermissionType) {
|
||||
|
@ -80,47 +82,47 @@ export default Component.extend({
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("createDisabled")
|
||||
createTooltip(createDisabled) {
|
||||
return createDisabled
|
||||
? I18n.t("category.permissions.inherited")
|
||||
: I18n.t("category.permissions.toggle_full");
|
||||
},
|
||||
}
|
||||
|
||||
updatePermission(type) {
|
||||
this.category.updatePermission(this.group_name, type);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
removeRow(event) {
|
||||
event?.preventDefault();
|
||||
this.category.removePermission(this.group_name);
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
setPermissionReply() {
|
||||
if (this.type <= PermissionType.CREATE_POST) {
|
||||
this.updatePermission(PermissionType.READONLY);
|
||||
} else {
|
||||
this.updatePermission(PermissionType.CREATE_POST);
|
||||
}
|
||||
},
|
||||
@action
|
||||
setPermissionReply() {
|
||||
if (this.type <= PermissionType.CREATE_POST) {
|
||||
this.updatePermission(PermissionType.READONLY);
|
||||
} else {
|
||||
this.updatePermission(PermissionType.CREATE_POST);
|
||||
}
|
||||
}
|
||||
|
||||
setPermissionFull() {
|
||||
if (
|
||||
this.group_name !== EVERYONE &&
|
||||
this.everyonePermissionType === PermissionType.FULL
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@action
|
||||
setPermissionFull() {
|
||||
if (
|
||||
this.group_name !== EVERYONE &&
|
||||
this.everyonePermissionType === PermissionType.FULL
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.type === PermissionType.FULL) {
|
||||
this.updatePermission(PermissionType.CREATE_POST);
|
||||
} else {
|
||||
this.updatePermission(PermissionType.FULL);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
if (this.type === PermissionType.FULL) {
|
||||
this.updatePermission(PermissionType.CREATE_POST);
|
||||
} else {
|
||||
this.updatePermission(PermissionType.FULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ import Component from "@ember/component";
|
|||
import { and } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
export default class CategoryReadOnlyBanner extends Component {
|
||||
@and("category.read_only_banner", "readOnly", "user") shouldShow;
|
||||
|
||||
@discourseComputed
|
||||
user() {
|
||||
return this.currentUser;
|
||||
},
|
||||
shouldShow: and("category.read_only_banner", "readOnly", "user"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
});
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
|
||||
@tagName("")
|
||||
export default class CategoryTitleBefore extends Component {}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "h3",
|
||||
// icon name defined here so it can be easily overridden in theme components
|
||||
lockIcon: "lock",
|
||||
});
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
|
||||
@tagName("h3")
|
||||
export default class CategoryTitleLink extends Component {}
|
||||
|
||||
// icon name defined on prototype so it can be easily overridden in theme components
|
||||
CategoryTitleLink.prototype.lockIcon = "lock";
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "span",
|
||||
classNames: ["category__badges"],
|
||||
});
|
||||
import { classNames, tagName } from "@ember-decorators/component";
|
||||
|
||||
@tagName("span")
|
||||
@classNames("category__badges")
|
||||
export default class CategoryUnread extends Component {}
|
||||
|
|
|
@ -2,14 +2,15 @@ import Component from "@ember/component";
|
|||
import { action, get } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import $ from "jquery";
|
||||
import { searchForTerm } from "discourse/lib/search";
|
||||
import { debounce, observes } from "discourse-common/utils/decorators";
|
||||
import { debounce } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
loading: null,
|
||||
noResults: null,
|
||||
messages: null,
|
||||
export default class ChooseMessage extends Component {
|
||||
loading = null;
|
||||
noResults = null;
|
||||
messages = null;
|
||||
|
||||
@observes("messageTitle")
|
||||
messageTitleChanged() {
|
||||
|
@ -19,7 +20,7 @@ export default Component.extend({
|
|||
selectedTopicId: null,
|
||||
});
|
||||
this.search(this.messageTitle);
|
||||
},
|
||||
}
|
||||
|
||||
@observes("messages")
|
||||
messagesChanged() {
|
||||
|
@ -28,7 +29,7 @@ export default Component.extend({
|
|||
this.set("noResults", messages.length === 0);
|
||||
}
|
||||
this.set("loading", false);
|
||||
},
|
||||
}
|
||||
|
||||
@debounce(300)
|
||||
search(title) {
|
||||
|
@ -53,7 +54,7 @@ export default Component.extend({
|
|||
this.setProperties({ messages: null, loading: false });
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
chooseMessage(message, event) {
|
||||
|
@ -61,5 +62,5 @@ export default Component.extend({
|
|||
const messageId = get(message, "id");
|
||||
this.set("selectedTopicId", messageId);
|
||||
next(() => $(`#choose-message-${messageId}`).prop("checked", "true"));
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,34 @@
|
|||
import Component from "@ember/component";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import {
|
||||
attributeBindings,
|
||||
classNameBindings,
|
||||
tagName,
|
||||
} from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "button",
|
||||
attributeBindings: ["style", "title"],
|
||||
classNameBindings: [":colorpicker", "isUsed:used-color:unused-color"],
|
||||
|
||||
@tagName("button")
|
||||
@attributeBindings("style", "title")
|
||||
@classNameBindings(":colorpicker", "isUsed:used-color:unused-color")
|
||||
export default class ColorPickerChoice extends Component {
|
||||
@discourseComputed("color", "usedColors")
|
||||
isUsed(color, usedColors) {
|
||||
return (usedColors || []).includes(color.toUpperCase());
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("isUsed")
|
||||
title(isUsed) {
|
||||
return isUsed ? I18n.t("category.already_used") : null;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("color")
|
||||
style(color) {
|
||||
return htmlSafe(`background-color: #${color};`);
|
||||
},
|
||||
}
|
||||
|
||||
click(e) {
|
||||
e.preventDefault();
|
||||
this.selectColor(this.color);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
classNames: "colors-container",
|
||||
import { action } from "@ember/object";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
|
||||
actions: {
|
||||
selectColor(color) {
|
||||
this.set("value", color);
|
||||
},
|
||||
},
|
||||
});
|
||||
@classNames("colors-container")
|
||||
export default class ColorPicker extends Component {
|
||||
@action
|
||||
selectColor(color) {
|
||||
this.set("value", color);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Component from "@ember/component";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import {
|
||||
CREATE_SHARED_DRAFT,
|
||||
CREATE_TOPIC,
|
||||
|
@ -21,10 +22,10 @@ const TITLES = {
|
|||
[EDIT_SHARED_DRAFT]: "composer.edit_shared_draft",
|
||||
};
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["composer-action-title"],
|
||||
options: alias("model.replyOptions"),
|
||||
action: alias("model.action"),
|
||||
@classNames("composer-action-title")
|
||||
export default class ComposerActionTitle extends Component {
|
||||
@alias("model.replyOptions") options;
|
||||
@alias("model.action") action;
|
||||
|
||||
// Note we update when some other attributes like tag/category change to allow
|
||||
// text customizations to use those.
|
||||
|
@ -57,7 +58,7 @@ export default Component.extend({
|
|||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_formatEditUserPost(userAvatar, userLink, postLink, originalUser) {
|
||||
let editTitle = `
|
||||
|
@ -75,7 +76,7 @@ export default Component.extend({
|
|||
}
|
||||
|
||||
return htmlSafe(editTitle);
|
||||
},
|
||||
}
|
||||
|
||||
_formatReplyToTopic(link) {
|
||||
return htmlSafe(
|
||||
|
@ -83,12 +84,12 @@ export default Component.extend({
|
|||
"model.topic.id"
|
||||
)}">${link.anchor}</a>`
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_formatReplyToUserPost(avatar, link) {
|
||||
const htmlLink = `<a class="user-link" href="${link.href}">${escape(
|
||||
link.anchor
|
||||
)}</a>`;
|
||||
return htmlSafe(`${avatar}${htmlLink}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import Component from "@ember/component";
|
||||
import { cancel, schedule, throttle } from "@ember/runloop";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||
import positioningWorkaround from "discourse/lib/safari-hacks";
|
||||
import { isiPad } from "discourse/lib/utilities";
|
||||
import Composer from "discourse/models/composer";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import discourseLater from "discourse-common/lib/later";
|
||||
import discourseComputed, {
|
||||
bind,
|
||||
observes,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||
|
||||
const START_DRAG_EVENTS = ["touchstart", "mousedown"];
|
||||
const DRAG_EVENTS = ["touchmove", "mousemove"];
|
||||
|
@ -21,37 +20,36 @@ function mouseYPos(e) {
|
|||
return e.clientY || (e.touches && e.touches[0] && e.touches[0].clientY);
|
||||
}
|
||||
|
||||
export default Component.extend({
|
||||
elementId: "reply-control",
|
||||
|
||||
classNameBindings: [
|
||||
"composer.creatingPrivateMessage:private-message",
|
||||
"composeState",
|
||||
"composer.loading",
|
||||
"prefixedComposerAction",
|
||||
"composer.canEditTitle:edit-title",
|
||||
"composer.createdPost:created-post",
|
||||
"composer.creatingTopic:topic",
|
||||
"composer.whisper:composing-whisper",
|
||||
"composer.sharedDraft:composing-shared-draft",
|
||||
"showPreview:show-preview:hide-preview",
|
||||
"currentUserPrimaryGroupClass",
|
||||
],
|
||||
@classNameBindings(
|
||||
"composer.creatingPrivateMessage:private-message",
|
||||
"composeState",
|
||||
"composer.loading",
|
||||
"prefixedComposerAction",
|
||||
"composer.canEditTitle:edit-title",
|
||||
"composer.createdPost:created-post",
|
||||
"composer.creatingTopic:topic",
|
||||
"composer.whisper:composing-whisper",
|
||||
"composer.sharedDraft:composing-shared-draft",
|
||||
"showPreview:show-preview:hide-preview",
|
||||
"currentUserPrimaryGroupClass"
|
||||
)
|
||||
export default class ComposerBody extends Component {
|
||||
elementId = "reply-control";
|
||||
|
||||
@discourseComputed("composer.action")
|
||||
prefixedComposerAction(action) {
|
||||
return action ? `composer-action-${action}` : "";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("currentUser.primary_group_name")
|
||||
currentUserPrimaryGroupClass(primaryGroupName) {
|
||||
return primaryGroupName && `group-${primaryGroupName}`;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("composer.composeState")
|
||||
composeState(composeState) {
|
||||
return composeState || Composer.CLOSED;
|
||||
},
|
||||
}
|
||||
|
||||
keyUp() {
|
||||
this.typed();
|
||||
|
@ -68,14 +66,14 @@ export default Component.extend({
|
|||
}
|
||||
this.appEvents.trigger("composer:find-similar");
|
||||
}, 1000);
|
||||
},
|
||||
}
|
||||
|
||||
@observes("composeState")
|
||||
disableFullscreen() {
|
||||
if (this.composeState !== Composer.OPEN && positioningWorkaround.blur) {
|
||||
positioningWorkaround.blur();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setupComposerResizeEvents() {
|
||||
this.origComposerSize = 0;
|
||||
|
@ -88,7 +86,7 @@ export default Component.extend({
|
|||
passive: false,
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
performDragHandler() {
|
||||
|
@ -112,14 +110,14 @@ export default Component.extend({
|
|||
);
|
||||
|
||||
this._triggerComposerResized();
|
||||
},
|
||||
}
|
||||
|
||||
@observes("composeState", "composer.{action,canEditTopicFeaturedLink}")
|
||||
_triggerComposerResized() {
|
||||
schedule("afterRender", () => {
|
||||
discourseDebounce(this, this.composerResized, 300);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
composerResized() {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
|
@ -127,7 +125,7 @@ export default Component.extend({
|
|||
}
|
||||
|
||||
this.appEvents.trigger("composer:resized");
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
startDragHandler(event) {
|
||||
|
@ -145,7 +143,7 @@ export default Component.extend({
|
|||
});
|
||||
|
||||
this.appEvents.trigger("composer:resize-started");
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
endDragHandler() {
|
||||
|
@ -161,16 +159,16 @@ export default Component.extend({
|
|||
|
||||
this.element.classList.remove("clear-transitions");
|
||||
this.element.focus();
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
throttledPerformDrag(event) {
|
||||
event.preventDefault();
|
||||
throttle(this, this.performDragHandler, event, THROTTLE_RATE);
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
this.setupComposerResizeEvents();
|
||||
|
||||
|
@ -188,10 +186,10 @@ export default Component.extend({
|
|||
});
|
||||
|
||||
positioningWorkaround(this.element);
|
||||
},
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
super.willDestroyElement(...arguments);
|
||||
|
||||
START_DRAG_EVENTS.forEach((startDragEvent) => {
|
||||
this.element
|
||||
|
@ -200,11 +198,11 @@ export default Component.extend({
|
|||
});
|
||||
|
||||
cancel(this._lastKeyTimeout);
|
||||
},
|
||||
}
|
||||
|
||||
click() {
|
||||
this.openIfDraft();
|
||||
},
|
||||
}
|
||||
|
||||
keyDown(e) {
|
||||
if (e.key === "Escape") {
|
||||
|
@ -220,5 +218,5 @@ export default Component.extend({
|
|||
e.preventDefault();
|
||||
this.save(undefined, e);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
@previewUpdated={{action "previewUpdated"}}
|
||||
@markdownOptions={{this.markdownOptions}}
|
||||
@extraButtons={{action "extraButtons"}}
|
||||
@importQuote={{action "importQuote"}}
|
||||
@importQuote={{this.importQuote}}
|
||||
@showUploadModal={{this.showUploadModal}}
|
||||
@togglePreview={{action "togglePreview"}}
|
||||
@togglePreview={{this.togglePreview}}
|
||||
@processPreview={{this.processPreview}}
|
||||
@validation={{this.validation}}
|
||||
@loading={{this.composer.loading}}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import Component from "@ember/component";
|
||||
import EmberObject, { computed } from "@ember/object";
|
||||
import EmberObject, { action, computed } from "@ember/object";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import { getOwner } from "@ember/owner";
|
||||
import { next, schedule, throttle } from "@ember/runloop";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { BasePlugin } from "@uppy/core";
|
||||
import $ from "jquery";
|
||||
import { resolveAllShortUrls } from "pretty-text/upload-short-url";
|
||||
|
@ -39,7 +41,6 @@ import { findRawTemplate } from "discourse-common/lib/raw-templates";
|
|||
import discourseComputed, {
|
||||
bind,
|
||||
debounce,
|
||||
observes,
|
||||
on,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
@ -109,32 +110,32 @@ export function addApiImageWrapperButtonClickEvent(fn) {
|
|||
const DEBOUNCE_FETCH_MS = 450;
|
||||
const DEBOUNCE_JIT_MS = 2000;
|
||||
|
||||
export default Component.extend(ComposerUploadUppy, {
|
||||
classNameBindings: ["showToolbar:toolbar-visible", ":wmd-controls"],
|
||||
@classNameBindings("showToolbar:toolbar-visible", ":wmd-controls")
|
||||
export default class ComposerEditor extends Component.extend(
|
||||
ComposerUploadUppy
|
||||
) {
|
||||
editorClass = ".d-editor";
|
||||
fileUploadElementId = "file-uploader";
|
||||
mobileFileUploaderId = "mobile-file-upload";
|
||||
composerEventPrefix = "composer";
|
||||
uploadType = "composer";
|
||||
uppyId = "composer-editor-uppy";
|
||||
composerModelContentKey = "reply";
|
||||
editorInputClass = ".d-editor-input";
|
||||
shouldBuildScrollMap = true;
|
||||
scrollMap = null;
|
||||
processPreview = true;
|
||||
uploadMarkdownResolvers = uploadMarkdownResolvers;
|
||||
uploadPreProcessors = uploadPreProcessors;
|
||||
uploadHandlers = uploadHandlers;
|
||||
|
||||
editorClass: ".d-editor",
|
||||
fileUploadElementId: "file-uploader",
|
||||
mobileFileUploaderId: "mobile-file-upload",
|
||||
|
||||
composerEventPrefix: "composer",
|
||||
uploadType: "composer",
|
||||
uppyId: "composer-editor-uppy",
|
||||
composerModel: alias("composer"),
|
||||
composerModelContentKey: "reply",
|
||||
editorInputClass: ".d-editor-input",
|
||||
shouldBuildScrollMap: true,
|
||||
scrollMap: null,
|
||||
processPreview: true,
|
||||
|
||||
uploadMarkdownResolvers,
|
||||
uploadPreProcessors,
|
||||
uploadHandlers,
|
||||
@alias("composer") composerModel;
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
super.init(...arguments);
|
||||
this.warnedCannotSeeMentions = [];
|
||||
this.warnedGroupMentions = [];
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("composer.requiredCategoryMissing")
|
||||
replyPlaceholder(requiredCategoryMissing) {
|
||||
|
@ -149,19 +150,19 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
: "reply_placeholder_no_images";
|
||||
return `composer.${key}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
showLink() {
|
||||
return this.currentUser && this.currentUser.link_posting_access !== "none";
|
||||
},
|
||||
}
|
||||
|
||||
@observes("focusTarget")
|
||||
setFocus() {
|
||||
if (this.focusTarget === "editor") {
|
||||
putCursorAtEnd(this.element.querySelector("textarea"));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
markdownOptions() {
|
||||
|
@ -204,7 +205,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
this.site.hashtag_configurations["topic-composer"],
|
||||
hashtagIcons: this.site.hashtag_icons,
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_afterMentionComplete(value) {
|
||||
|
@ -216,7 +217,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
input?.blur();
|
||||
input?.focus();
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@on("didInsertElement")
|
||||
_composerEditorInit() {
|
||||
|
@ -266,7 +267,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
}
|
||||
|
||||
this.appEvents.trigger(`${this.composerEventPrefix}:will-open`);
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed(
|
||||
"composer.reply",
|
||||
|
@ -313,7 +314,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
lastShownAt: lastValidatedAt,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@computed("composer.{creatingTopic,editingFirstPost,creatingSharedDraft}")
|
||||
get _isNewTopic() {
|
||||
|
@ -322,11 +323,11 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
this.composer.editingFirstPost ||
|
||||
this.composer.creatingSharedDraft
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_resetShouldBuildScrollMap() {
|
||||
this.set("shouldBuildScrollMap", true);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleInputInteraction(event) {
|
||||
|
@ -338,7 +339,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
|
||||
preview.removeEventListener("scroll", this._handleInputOrPreviewScroll);
|
||||
event.target.addEventListener("scroll", this._handleInputOrPreviewScroll);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleInputOrPreviewScroll(event) {
|
||||
|
@ -347,7 +348,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
$(event.target),
|
||||
$(this.element.querySelector(".d-editor-preview-wrapper"))
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handlePreviewInteraction(event) {
|
||||
|
@ -356,7 +357,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
?.removeEventListener("scroll", this._handleInputOrPreviewScroll);
|
||||
|
||||
event.target?.addEventListener("scroll", this._handleInputOrPreviewScroll);
|
||||
},
|
||||
}
|
||||
|
||||
_syncScroll($callback, $input, $preview) {
|
||||
if (!this.scrollMap || this.shouldBuildScrollMap) {
|
||||
|
@ -365,7 +366,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
}
|
||||
|
||||
throttle(this, $callback, $input, $preview, this.scrollMap, 20);
|
||||
},
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/markdown-it/markdown-it.github.io
|
||||
_buildScrollMap($input, $preview) {
|
||||
|
@ -452,7 +453,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
}
|
||||
|
||||
return scrollMap;
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_throttledSyncEditorAndPreviewScroll(event) {
|
||||
|
@ -465,7 +466,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
$preview,
|
||||
20
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_syncEditorAndPreviewScroll($input, $preview) {
|
||||
if (!$input) {
|
||||
|
@ -490,7 +491,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
const factor = previewHeight / inputHeight;
|
||||
const desired = scrollPosition * factor;
|
||||
$preview.scrollTop(desired + 50);
|
||||
},
|
||||
}
|
||||
|
||||
_renderMentions(preview, unseen) {
|
||||
unseen ||= linkSeenMentions(preview, this.siteSettings);
|
||||
|
@ -500,7 +501,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
this._warnMentionedGroups(preview);
|
||||
this._warnCannotSeeMention(preview);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@debounce(DEBOUNCE_FETCH_MS)
|
||||
_renderUnseenMentions(preview, unseen) {
|
||||
|
@ -514,7 +515,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
this._warnCannotSeeMention(preview);
|
||||
this._warnHereMention(response.here_count);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_renderHashtags(preview, unseen) {
|
||||
const context = this.site.hashtag_configurations["topic-composer"];
|
||||
|
@ -522,14 +523,14 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
if (unseen.length > 0) {
|
||||
this._renderUnseenHashtags(preview, unseen, context);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@debounce(DEBOUNCE_FETCH_MS)
|
||||
_renderUnseenHashtags(preview, unseen, context) {
|
||||
fetchUnseenHashtagsInContext(context, unseen).then(() =>
|
||||
linkSeenHashtagsInContext(context, preview)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@debounce(DEBOUNCE_FETCH_MS)
|
||||
_refreshOneboxes(preview) {
|
||||
|
@ -549,15 +550,15 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
if (refresh && loaded > 0) {
|
||||
post.set("refreshedPost", true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_expandShortUrls(preview) {
|
||||
resolveAllShortUrls(ajax, this.siteSettings, preview);
|
||||
},
|
||||
}
|
||||
|
||||
_decorateCookedElement(preview) {
|
||||
this.appEvents.trigger("decorate-non-stream-cooked-element", preview);
|
||||
},
|
||||
}
|
||||
|
||||
@debounce(DEBOUNCE_JIT_MS)
|
||||
_warnMentionedGroups(preview) {
|
||||
|
@ -581,7 +582,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
// add a delay to allow for typing, so you don't open the warning right away
|
||||
// previously we would warn after @bob even if you were about to mention @bob2
|
||||
|
@ -620,7 +621,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
isGroup: true,
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
_warnHereMention(hereCount) {
|
||||
if (!hereCount || hereCount === 0) {
|
||||
|
@ -628,7 +629,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
}
|
||||
|
||||
this.hereMention(hereCount);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleImageScaleButtonClick(event) {
|
||||
|
@ -665,7 +666,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
|
||||
event.preventDefault();
|
||||
return;
|
||||
},
|
||||
}
|
||||
|
||||
resetImageControls(buttonWrapper) {
|
||||
const imageResize = buttonWrapper.querySelector(".scale-btn-container");
|
||||
|
@ -684,7 +685,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
readonlyContainer.removeAttribute("hidden");
|
||||
buttonWrapper.removeAttribute("editing");
|
||||
editContainer.setAttribute("hidden", "true");
|
||||
},
|
||||
}
|
||||
|
||||
commitAltText(buttonWrapper) {
|
||||
const index = parseInt(buttonWrapper.getAttribute("data-image-index"), 10);
|
||||
|
@ -704,7 +705,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
);
|
||||
|
||||
this.resetImageControls(buttonWrapper);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleAltTextInputKeypress(event) {
|
||||
|
@ -720,7 +721,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
const buttonWrapper = event.target.closest(".button-wrapper");
|
||||
this.commitAltText(buttonWrapper);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleAltTextEditButtonClick(event) {
|
||||
|
@ -750,7 +751,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
editContainer.removeAttribute("hidden");
|
||||
editContainerInput.focus();
|
||||
event.preventDefault();
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleAltTextOkButtonClick(event) {
|
||||
|
@ -760,7 +761,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
|
||||
const buttonWrapper = event.target.closest(".button-wrapper");
|
||||
this.commitAltText(buttonWrapper);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleAltTextCancelButtonClick(event) {
|
||||
|
@ -770,7 +771,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
|
||||
const buttonWrapper = event.target.closest(".button-wrapper");
|
||||
this.resetImageControls(buttonWrapper);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleImageDeleteButtonClick(event) {
|
||||
|
@ -789,7 +790,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
"",
|
||||
{ regex: IMAGE_MARKDOWN_REGEX, index }
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@bind
|
||||
_handleImageGridButtonClick(event) {
|
||||
|
@ -818,7 +819,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
"grid_surround",
|
||||
{ useBlockMode: true }
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_registerImageAltTextButtonClick(preview) {
|
||||
preview.addEventListener("click", this._handleAltTextCancelButtonClick);
|
||||
|
@ -832,7 +833,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
apiImageWrapperBtnEvents.forEach((fn) =>
|
||||
preview.addEventListener("click", fn)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@on("willDestroyElement")
|
||||
_composerClosed() {
|
||||
|
@ -870,17 +871,18 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
apiImageWrapperBtnEvents.forEach((fn) =>
|
||||
preview?.removeEventListener("click", fn)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onExpandPopupMenuOptions(toolbarEvent) {
|
||||
const selected = toolbarEvent.selected;
|
||||
toolbarEvent.selectText(selected.start, selected.end - selected.start);
|
||||
this.storeToolbarState(toolbarEvent);
|
||||
},
|
||||
}
|
||||
|
||||
showPreview() {
|
||||
this.send("togglePreview");
|
||||
},
|
||||
}
|
||||
|
||||
_isInQuote(element) {
|
||||
let parent = element.parentElement;
|
||||
|
@ -893,18 +895,18 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
_isPreviewRoot(element) {
|
||||
return (
|
||||
element.tagName === "DIV" &&
|
||||
element.classList.contains("d-editor-preview")
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_isQuote(element) {
|
||||
return element.tagName === "ASIDE" && element.classList.contains("quote");
|
||||
},
|
||||
}
|
||||
|
||||
_cursorIsOnEmptyLine() {
|
||||
const textArea = this.element.querySelector(".d-editor-input");
|
||||
|
@ -916,7 +918,7 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_findMatchingUploadHandler(fileName) {
|
||||
return this.uploadHandlers.find((handler) => {
|
||||
|
@ -924,62 +926,50 @@ export default Component.extend(ComposerUploadUppy, {
|
|||
const regex = new RegExp(`\\.(${ext})$`, "i");
|
||||
return regex.test(fileName);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
importQuote(toolbarEvent) {
|
||||
this.importQuote(toolbarEvent);
|
||||
},
|
||||
@action
|
||||
extraButtons(toolbar) {
|
||||
toolbar.addButton({
|
||||
id: "quote",
|
||||
group: "fontStyles",
|
||||
icon: "far-comment",
|
||||
sendAction: this.importQuote,
|
||||
title: "composer.quote_post_title",
|
||||
unshift: true,
|
||||
});
|
||||
|
||||
onExpandPopupMenuOptions(toolbarEvent) {
|
||||
this.onExpandPopupMenuOptions(toolbarEvent);
|
||||
},
|
||||
|
||||
togglePreview() {
|
||||
this.togglePreview();
|
||||
},
|
||||
|
||||
extraButtons(toolbar) {
|
||||
if (this.allowUpload && this.uploadIcon && this.site.desktopView) {
|
||||
toolbar.addButton({
|
||||
id: "quote",
|
||||
group: "fontStyles",
|
||||
icon: "far-comment",
|
||||
sendAction: this.importQuote,
|
||||
title: "composer.quote_post_title",
|
||||
unshift: true,
|
||||
id: "upload",
|
||||
group: "insertions",
|
||||
icon: this.uploadIcon,
|
||||
title: "upload",
|
||||
sendAction: this.showUploadModal,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.allowUpload && this.uploadIcon && this.site.desktopView) {
|
||||
toolbar.addButton({
|
||||
id: "upload",
|
||||
group: "insertions",
|
||||
icon: this.uploadIcon,
|
||||
title: "upload",
|
||||
sendAction: this.showUploadModal,
|
||||
});
|
||||
}
|
||||
toolbar.addButton({
|
||||
id: "options",
|
||||
group: "extras",
|
||||
icon: "cog",
|
||||
title: "composer.options",
|
||||
sendAction: this.onExpandPopupMenuOptions.bind(this),
|
||||
popupMenu: true,
|
||||
});
|
||||
}
|
||||
|
||||
toolbar.addButton({
|
||||
id: "options",
|
||||
group: "extras",
|
||||
icon: "cog",
|
||||
title: "composer.options",
|
||||
sendAction: this.onExpandPopupMenuOptions.bind(this),
|
||||
popupMenu: true,
|
||||
});
|
||||
},
|
||||
@action
|
||||
previewUpdated(preview, unseenMentions, unseenHashtags) {
|
||||
this._renderMentions(preview, unseenMentions);
|
||||
this._renderHashtags(preview, unseenHashtags);
|
||||
this._refreshOneboxes(preview);
|
||||
this._expandShortUrls(preview);
|
||||
|
||||
previewUpdated(preview, unseenMentions, unseenHashtags) {
|
||||
this._renderMentions(preview, unseenMentions);
|
||||
this._renderHashtags(preview, unseenHashtags);
|
||||
this._refreshOneboxes(preview);
|
||||
this._expandShortUrls(preview);
|
||||
if (!this.siteSettings.enable_diffhtml_preview) {
|
||||
this._decorateCookedElement(preview);
|
||||
}
|
||||
|
||||
if (!this.siteSettings.enable_diffhtml_preview) {
|
||||
this._decorateCookedElement(preview);
|
||||
}
|
||||
|
||||
this.afterRefresh(preview);
|
||||
},
|
||||
},
|
||||
});
|
||||
this.afterRefresh(preview);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,12 @@
|
|||
import Component from "@ember/component";
|
||||
import { getOwner } from "@ember/owner";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":composer-popup", "message.extraClass"],
|
||||
|
||||
@classNameBindings(":composer-popup", "message.extraClass")
|
||||
export default class ComposerMessage extends Component {
|
||||
@discourseComputed("message.templateName")
|
||||
layout(templateName) {
|
||||
return getOwner(this).lookup(`template:composer/${templateName}`);
|
||||
},
|
||||
|
||||
actions: {
|
||||
closeMessage() {
|
||||
deprecated(
|
||||
'You should use `action=(closeMessage message)` instead of `action=(action "closeMessage")`',
|
||||
{ id: "discourse.composer-message.closeMessage" }
|
||||
);
|
||||
this.closeMessage(this.message);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,26 @@ import Component from "@ember/component";
|
|||
import EmberObject from "@ember/object";
|
||||
import { alias, or } from "@ember/object/computed";
|
||||
import { next, schedule } from "@ember/runloop";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { load } from "pretty-text/oneboxer";
|
||||
import { lookupCache } from "pretty-text/oneboxer-cache";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import putCursorAtEnd from "discourse/lib/put-cursor-at-end";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["title-input"],
|
||||
watchForLink: alias("composer.canEditTopicFeaturedLink"),
|
||||
disabled: or("composer.loading", "composer.disableTitleInput"),
|
||||
isTitleFocused: false,
|
||||
@classNames("title-input")
|
||||
export default class ComposerTitle extends Component {
|
||||
@alias("composer.canEditTopicFeaturedLink") watchForLink;
|
||||
@or("composer.loading", "composer.disableTitleInput") disabled;
|
||||
|
||||
isTitleFocused = false;
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
const titleInput = this.element.querySelector("input");
|
||||
|
||||
this._focusHandler = () => this.set("isTitleFocused", true);
|
||||
|
@ -34,17 +37,17 @@ export default Component.extend({
|
|||
if (this.get("composer.titleLength") > 0) {
|
||||
discourseDebounce(this, this._titleChanged, 10);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
super.willDestroyElement(...arguments);
|
||||
const titleInput = this.element.querySelector("input");
|
||||
|
||||
if (titleInput) {
|
||||
titleInput.removeEventListener("focus", this._focusHandler);
|
||||
titleInput.removeEventListener("blur", this._blurHandler);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed(
|
||||
"composer.titleLength",
|
||||
|
@ -83,14 +86,14 @@ export default Component.extend({
|
|||
lastShownAt: lastValidatedAt,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("watchForLink")
|
||||
titleMaxLength(watchForLink) {
|
||||
// maxLength gets in the way of pasting long links, so don't use it if featured links are allowed.
|
||||
// Validation will display a message if titles are too long.
|
||||
return watchForLink ? null : this.siteSettings.max_topic_title_length;
|
||||
},
|
||||
}
|
||||
|
||||
@observes("composer.titleLength", "watchForLink")
|
||||
_titleChanged() {
|
||||
|
@ -110,14 +113,14 @@ export default Component.extend({
|
|||
} else {
|
||||
discourseDebounce(this, this._checkForUrl, 500);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@observes("composer.replyLength")
|
||||
_clearFeaturedLink() {
|
||||
if (this.watchForLink && this.bodyIsDefault()) {
|
||||
this.set("composer.featuredLink", null);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_checkForUrl() {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
|
@ -169,7 +172,7 @@ export default Component.extend({
|
|||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_updatePost(html) {
|
||||
if (html) {
|
||||
|
@ -207,13 +210,13 @@ export default Component.extend({
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
changeTitle(val) {
|
||||
if (val && val.length > 0) {
|
||||
this.set("composer.title", val.trim());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("composer.title", "composer.titleLength")
|
||||
isAbsoluteUrl(title, titleLength) {
|
||||
|
@ -222,7 +225,7 @@ export default Component.extend({
|
|||
/^(https?:)?\/\/[\w\.\-]+/i.test(title) &&
|
||||
!/\s/.test(title)
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
bodyIsDefault() {
|
||||
const reply = this.get("composer.reply") || "";
|
||||
|
@ -230,5 +233,5 @@ export default Component.extend({
|
|||
reply.length === 0 ||
|
||||
reply === (this.get("composer.category.topic_template") || "")
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import Component from "@ember/component";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
||||
@tagName("")
|
||||
export default class ComposerToggles extends Component {
|
||||
@discourseComputed("composeState")
|
||||
toggleTitle(composeState) {
|
||||
return composeState === "draft" || composeState === "saving"
|
||||
? "composer.abandon"
|
||||
: "composer.collapse";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("showToolbar")
|
||||
toggleToolbarTitle(showToolbar) {
|
||||
return showToolbar ? "composer.hide_toolbar" : "composer.show_toolbar";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("composeState")
|
||||
fullscreenTitle(composeState) {
|
||||
|
@ -23,14 +23,14 @@ export default Component.extend({
|
|||
: composeState === "fullscreen"
|
||||
? "composer.exit_fullscreen"
|
||||
: "composer.enter_fullscreen";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("composeState")
|
||||
toggleIcon(composeState) {
|
||||
return composeState === "draft" || composeState === "saving"
|
||||
? "times"
|
||||
: "chevron-down";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("composeState")
|
||||
fullscreenIcon(composeState) {
|
||||
|
@ -39,7 +39,7 @@ export default Component.extend({
|
|||
: composeState === "fullscreen"
|
||||
? "discourse-compress"
|
||||
: "discourse-expand";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("disableTextarea")
|
||||
showFullScreenButton(disableTextarea) {
|
||||
|
@ -47,5 +47,5 @@ export default Component.extend({
|
|||
return false;
|
||||
}
|
||||
return !disableTextarea;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set("_groups", []);
|
||||
},
|
||||
export default class ComposerUserSelector extends Component {
|
||||
_groups = [];
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
if (this.focusTarget === "usernames") {
|
||||
this.element.querySelector(".select-kit .select-kit-header").focus();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("recipients")
|
||||
splitRecipients(recipients) {
|
||||
|
@ -21,7 +19,7 @@ export default Component.extend({
|
|||
return recipients;
|
||||
}
|
||||
return recipients ? recipients.split(",").filter(Boolean) : [];
|
||||
},
|
||||
}
|
||||
|
||||
_updateGroups(selected, newGroups) {
|
||||
const groups = [];
|
||||
|
@ -39,13 +37,12 @@ export default Component.extend({
|
|||
_groups: groups,
|
||||
hasGroups: groups.length > 0,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
actions: {
|
||||
updateRecipients(selected, content) {
|
||||
const newGroups = content.filterBy("isGroup").mapBy("id");
|
||||
this._updateGroups(selected, newGroups);
|
||||
this.set("recipients", selected.join(","));
|
||||
},
|
||||
},
|
||||
});
|
||||
@action
|
||||
updateRecipients(selected, content) {
|
||||
const newGroups = content.filterBy("isGroup").mapBy("id");
|
||||
this._updateGroups(selected, newGroups);
|
||||
this.set("recipients", selected.join(","));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import Component from "@ember/component";
|
||||
import { classNameBindings, classNames } from "@ember-decorators/component";
|
||||
import I18n from "discourse-i18n";
|
||||
export default Component.extend({
|
||||
classNames: ["conditional-loading-section"],
|
||||
|
||||
classNameBindings: ["isLoading"],
|
||||
|
||||
isLoading: false,
|
||||
|
||||
title: I18n.t("conditional_loading_section.loading"),
|
||||
});
|
||||
@classNames("conditional-loading-section")
|
||||
@classNameBindings("isLoading")
|
||||
export default class ConditionalLoadingSection extends Component {
|
||||
isLoading = false;
|
||||
title = I18n.t("conditional_loading_section.loading");
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
import Component from "@ember/component";
|
||||
export default Component.extend();
|
||||
|
||||
export default class ConnectorContainer extends Component {}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
copyIcon: "copy",
|
||||
copyClass: "btn-primary",
|
||||
@tagName("")
|
||||
export default class CopyButton extends Component {
|
||||
copyIcon = "copy";
|
||||
copyClass = "btn-primary";
|
||||
|
||||
@bind
|
||||
_restoreButton() {
|
||||
|
@ -16,7 +17,7 @@ export default Component.extend({
|
|||
|
||||
this.set("copyIcon", "copy");
|
||||
this.set("copyClass", "btn-primary");
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
copy() {
|
||||
|
@ -36,5 +37,5 @@ export default Component.extend({
|
|||
|
||||
discourseDebounce(this._restoreButton, 3000);
|
||||
} catch (err) {}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,41 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import UppyUploadMixin from "discourse/mixins/uppy-upload";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend(UppyUploadMixin, {
|
||||
id: "create-invite-uploader",
|
||||
tagName: "div",
|
||||
type: "csv",
|
||||
autoStartUploads: false,
|
||||
uploadUrl: "/invites/upload_csv",
|
||||
preventDirectS3Uploads: true,
|
||||
fileInputSelector: "#csv-file",
|
||||
@tagName("div")
|
||||
export default class CreateInviteUploader extends Component.extend(
|
||||
UppyUploadMixin
|
||||
) {
|
||||
id = "create-invite-uploader";
|
||||
type = "csv";
|
||||
autoStartUploads = false;
|
||||
uploadUrl = "/invites/upload_csv";
|
||||
preventDirectS3Uploads = true;
|
||||
fileInputSelector = "#csv-file";
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return { bypassNewUserRestriction: true, csvOnly: true };
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("filesAwaitingUpload", "uploading")
|
||||
submitDisabled(filesAwaitingUpload, uploading) {
|
||||
return !filesAwaitingUpload || uploading;
|
||||
},
|
||||
}
|
||||
|
||||
uploadDone() {
|
||||
this.set("uploaded", true);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
startUpload() {
|
||||
this._startUpload();
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
setElement(element) {
|
||||
this.set("fileInputEl", element);
|
||||
this._initialize();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
label: "topic.create",
|
||||
btnClass: "btn-default",
|
||||
});
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
|
||||
@tagName("")
|
||||
export default class CreateTopicButton extends Component {
|
||||
label = "topic.create";
|
||||
btnClass = "btn-default";
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ import { hbs } from "ember-cli-htmlbars";
|
|||
import { getCustomHTML } from "discourse/helpers/custom-html";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
export default Component.extend({
|
||||
triggerAppEvent: null,
|
||||
export default class CustomHtml extends Component {
|
||||
triggerAppEvent = null;
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
super.init(...arguments);
|
||||
const name = this.name;
|
||||
const html = getCustomHTML(name);
|
||||
|
||||
|
@ -25,19 +25,19 @@ export default Component.extend({
|
|||
this.set("layout", template);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
super.didInsertElement(...arguments);
|
||||
if (this.triggerAppEvent === "true") {
|
||||
this.appEvents.trigger(`inserted-custom-html:${this.name}`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
super.willDestroyElement(...arguments);
|
||||
if (this.triggerAppEvent === "true") {
|
||||
this.appEvents.trigger(`destroyed-custom-html:${this.name}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user