DEV: Move gjs `<template>` to bottom of class definitions
To satisfy updated eslint configuration
This commit is contained in:
parent
31e4191a9b
commit
ee0fef489f
|
@ -14,6 +14,39 @@ export default class AdminPostMenu extends Component {
|
||||||
@service store;
|
@service store;
|
||||||
@service adminPostMenuButtons;
|
@service adminPostMenuButtons;
|
||||||
|
|
||||||
|
get reviewUrl() {
|
||||||
|
return `/review?topic_id=${this.args.data.transformedPost.id}&status=all`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get extraButtons() {
|
||||||
|
return this.adminPostMenuButtons.callbacks
|
||||||
|
.map((callback) => {
|
||||||
|
return callback(this.args.data.transformedPost);
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async topicAction(actionName) {
|
||||||
|
await this.args.close();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.args.data[actionName]?.();
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(`Unknown error while attempting \`${actionName}\`:`, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.args.data.scheduleRerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async extraAction(button) {
|
||||||
|
await this.args.close();
|
||||||
|
await button.action(this.args.data.post);
|
||||||
|
await this.args.data.scheduleRerender();
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ul>
|
<ul>
|
||||||
{{#if this.currentUser.staff}}
|
{{#if this.currentUser.staff}}
|
||||||
|
@ -205,37 +238,4 @@ export default class AdminPostMenu extends Component {
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
get reviewUrl() {
|
|
||||||
return `/review?topic_id=${this.args.data.transformedPost.id}&status=all`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get extraButtons() {
|
|
||||||
return this.adminPostMenuButtons.callbacks
|
|
||||||
.map((callback) => {
|
|
||||||
return callback(this.args.data.transformedPost);
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
async topicAction(actionName) {
|
|
||||||
await this.args.close();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.args.data[actionName]?.();
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(`Unknown error while attempting \`${actionName}\`:`, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.args.data.scheduleRerender();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
async extraAction(button) {
|
|
||||||
await this.args.close();
|
|
||||||
await button.action(this.args.data.post);
|
|
||||||
await this.args.data.scheduleRerender();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,6 @@ import { resolveAllShortUrls } from "pretty-text/upload-short-url";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
export default class CookText extends Component {
|
export default class CookText extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<div
|
|
||||||
...attributes
|
|
||||||
{{didUpdate this.buildOneboxes this.cooked}}
|
|
||||||
{{didUpdate this.resolveShortUrls this.cooked}}
|
|
||||||
{{didUpdate this.calculateOffsetHeight this.cooked}}
|
|
||||||
{{didUpdate this.loadCookedText @rawText}}
|
|
||||||
>
|
|
||||||
{{this.cooked}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
@tracked cooked = null;
|
@tracked cooked = null;
|
||||||
|
|
||||||
|
@ -63,4 +50,17 @@ export default class CookText extends Component {
|
||||||
resolveShortUrls(element) {
|
resolveShortUrls(element) {
|
||||||
resolveAllShortUrls(ajax, this.siteSettings, element, this.args.opts);
|
resolveAllShortUrls(ajax, this.siteSettings, element, this.args.opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<div
|
||||||
|
...attributes
|
||||||
|
{{didUpdate this.buildOneboxes this.cooked}}
|
||||||
|
{{didUpdate this.resolveShortUrls this.cooked}}
|
||||||
|
{{didUpdate this.calculateOffsetHeight this.cooked}}
|
||||||
|
{{didUpdate this.loadCookedText @rawText}}
|
||||||
|
>
|
||||||
|
{{this.cooked}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,62 +17,6 @@ const ACTION_AS_STRING_DEPRECATION_ARGS = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable no-pointer-down-event-binding }}
|
|
||||||
<button
|
|
||||||
{{! For legacy compatibility. Prefer passing class as attributes. }}
|
|
||||||
class={{concatClass
|
|
||||||
@class
|
|
||||||
(if @isLoading "is-loading")
|
|
||||||
(if this.btnLink "btn-link" "btn")
|
|
||||||
(if this.noText "no-text")
|
|
||||||
this.btnType
|
|
||||||
}}
|
|
||||||
{{! For legacy compatibility. Prefer passing these as html attributes. }}
|
|
||||||
id={{@id}}
|
|
||||||
form={{@form}}
|
|
||||||
aria-controls={{@ariaControls}}
|
|
||||||
aria-expanded={{this.computedAriaExpanded}}
|
|
||||||
tabindex={{@tabindex}}
|
|
||||||
type={{or @type "button"}}
|
|
||||||
...attributes
|
|
||||||
disabled={{this.isDisabled}}
|
|
||||||
title={{this.computedTitle}}
|
|
||||||
aria-label={{this.computedAriaLabel}}
|
|
||||||
{{on "keydown" this.keyDown}}
|
|
||||||
{{on "click" this.click}}
|
|
||||||
{{on "mousedown" this.mouseDown}}
|
|
||||||
>
|
|
||||||
{{#if @isLoading}}
|
|
||||||
{{~icon "spinner" class="loading-icon"~}}
|
|
||||||
{{else}}
|
|
||||||
{{#if @icon}}
|
|
||||||
{{#if @ariaHidden}}
|
|
||||||
<span aria-hidden="true">
|
|
||||||
{{~icon @icon~}}
|
|
||||||
</span>
|
|
||||||
{{else}}
|
|
||||||
{{~icon @icon~}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{~#if this.computedLabel~}}
|
|
||||||
<span class="d-button-label">
|
|
||||||
{{~htmlSafe this.computedLabel~}}
|
|
||||||
{{~#if @ellipsis~}}
|
|
||||||
…
|
|
||||||
{{~/if~}}
|
|
||||||
</span>
|
|
||||||
{{~else~}}
|
|
||||||
​
|
|
||||||
{{! Zero-width space character, so icon-only button height = regular button height }}
|
|
||||||
{{~/if~}}
|
|
||||||
|
|
||||||
{{yield}}
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service router;
|
@service router;
|
||||||
|
|
||||||
@notEmpty("args.icon") btnIcon;
|
@notEmpty("args.icon") btnIcon;
|
||||||
|
@ -199,4 +143,60 @@ export default class DButton extends GlimmerComponentWithDeprecatedParentView {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable no-pointer-down-event-binding }}
|
||||||
|
<button
|
||||||
|
{{! For legacy compatibility. Prefer passing class as attributes. }}
|
||||||
|
class={{concatClass
|
||||||
|
@class
|
||||||
|
(if @isLoading "is-loading")
|
||||||
|
(if this.btnLink "btn-link" "btn")
|
||||||
|
(if this.noText "no-text")
|
||||||
|
this.btnType
|
||||||
|
}}
|
||||||
|
{{! For legacy compatibility. Prefer passing these as html attributes. }}
|
||||||
|
id={{@id}}
|
||||||
|
form={{@form}}
|
||||||
|
aria-controls={{@ariaControls}}
|
||||||
|
aria-expanded={{this.computedAriaExpanded}}
|
||||||
|
tabindex={{@tabindex}}
|
||||||
|
type={{or @type "button"}}
|
||||||
|
...attributes
|
||||||
|
disabled={{this.isDisabled}}
|
||||||
|
title={{this.computedTitle}}
|
||||||
|
aria-label={{this.computedAriaLabel}}
|
||||||
|
{{on "keydown" this.keyDown}}
|
||||||
|
{{on "click" this.click}}
|
||||||
|
{{on "mousedown" this.mouseDown}}
|
||||||
|
>
|
||||||
|
{{#if @isLoading}}
|
||||||
|
{{~icon "spinner" class="loading-icon"~}}
|
||||||
|
{{else}}
|
||||||
|
{{#if @icon}}
|
||||||
|
{{#if @ariaHidden}}
|
||||||
|
<span aria-hidden="true">
|
||||||
|
{{~icon @icon~}}
|
||||||
|
</span>
|
||||||
|
{{else}}
|
||||||
|
{{~icon @icon~}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{~#if this.computedLabel~}}
|
||||||
|
<span class="d-button-label">
|
||||||
|
{{~htmlSafe this.computedLabel~}}
|
||||||
|
{{~#if @ellipsis~}}
|
||||||
|
…
|
||||||
|
{{~/if~}}
|
||||||
|
</span>
|
||||||
|
{{~else~}}
|
||||||
|
​
|
||||||
|
{{! Zero-width space character, so icon-only button height = regular button height }}
|
||||||
|
{{~/if~}}
|
||||||
|
|
||||||
|
{{yield}}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,18 @@ import deprecated from "discourse-common/lib/deprecated";
|
||||||
|
|
||||||
// Can add a body class from within a component
|
// Can add a body class from within a component
|
||||||
export default class DSection extends Component {
|
export default class DSection extends Component {
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
deprecated(
|
||||||
|
`<DSection> is deprecated. Use {{body-class "foo-page" "bar"}} and/or <section></section> instead.`,
|
||||||
|
{
|
||||||
|
since: "3.2.0.beta1",
|
||||||
|
dropFrom: "3.3.0.beta1",
|
||||||
|
id: "discourse.d-section",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#if @pageClass}}
|
{{#if @pageClass}}
|
||||||
{{bodyClass (concat @pageClass "-page")}}
|
{{bodyClass (concat @pageClass "-page")}}
|
||||||
|
@ -21,16 +33,4 @@ export default class DSection extends Component {
|
||||||
{{yield}}
|
{{yield}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super(...arguments);
|
|
||||||
deprecated(
|
|
||||||
`<DSection> is deprecated. Use {{body-class "foo-page" "bar"}} and/or <section></section> instead.`,
|
|
||||||
{
|
|
||||||
since: "3.2.0.beta1",
|
|
||||||
dropFrom: "3.3.0.beta1",
|
|
||||||
id: "discourse.d-section",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,29 +11,6 @@ import { on } from "@ember/modifier";
|
||||||
import autoFocus from "discourse/modifiers/auto-focus";
|
import autoFocus from "discourse/modifiers/auto-focus";
|
||||||
|
|
||||||
export default class FastEdit extends Component {
|
export default class FastEdit extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
{{! template-lint-disable no-pointer-down-event-binding }}
|
|
||||||
{{! template-lint-disable no-invalid-interactive }}
|
|
||||||
<div class="fast-edit-container" {{on "keydown" this.onKeydown}}>
|
|
||||||
<textarea
|
|
||||||
{{on "input" this.updateValue}}
|
|
||||||
id="fast-edit-input"
|
|
||||||
{{autoFocus}}
|
|
||||||
>{{@initialValue}}</textarea>
|
|
||||||
|
|
||||||
<DButton
|
|
||||||
class="btn-small btn-primary save-fast-edit"
|
|
||||||
@action={{this.save}}
|
|
||||||
@icon="pencil-alt"
|
|
||||||
@label="composer.save_edit"
|
|
||||||
@translatedTitle={{this.buttonTitle}}
|
|
||||||
@isLoading={{this.isSaving}}
|
|
||||||
@disabled={{this.disabled}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@tracked value = this.args.initialValue;
|
@tracked value = this.args.initialValue;
|
||||||
@tracked isSaving = false;
|
@tracked isSaving = false;
|
||||||
|
|
||||||
|
@ -81,4 +58,27 @@ export default class FastEdit extends Component {
|
||||||
this.args.close();
|
this.args.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
{{! template-lint-disable no-pointer-down-event-binding }}
|
||||||
|
{{! template-lint-disable no-invalid-interactive }}
|
||||||
|
<div class="fast-edit-container" {{on "keydown" this.onKeydown}}>
|
||||||
|
<textarea
|
||||||
|
{{on "input" this.updateValue}}
|
||||||
|
id="fast-edit-input"
|
||||||
|
{{autoFocus}}
|
||||||
|
>{{@initialValue}}</textarea>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
class="btn-small btn-primary save-fast-edit"
|
||||||
|
@action={{this.save}}
|
||||||
|
@icon="pencil-alt"
|
||||||
|
@label="composer.save_edit"
|
||||||
|
@translatedTitle={{this.buttonTitle}}
|
||||||
|
@isLoading={{this.isSaving}}
|
||||||
|
@disabled={{this.disabled}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,28 +22,6 @@ const FormTemplateField = <template>
|
||||||
</template>;
|
</template>;
|
||||||
|
|
||||||
export default class FormTemplateFieldWrapper extends Component {
|
export default class FormTemplateFieldWrapper extends Component {
|
||||||
<template>
|
|
||||||
{{#if this.parsedTemplate}}
|
|
||||||
<div
|
|
||||||
class="form-template-form__wrapper"
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
{{didUpdate this.refreshTemplate @id}}
|
|
||||||
>
|
|
||||||
{{#each this.parsedTemplate as |content|}}
|
|
||||||
<FormTemplateField
|
|
||||||
@component={{get this.fieldTypes content.type}}
|
|
||||||
@content={{content}}
|
|
||||||
@initialValue={{get this.initialValues content.id}}
|
|
||||||
/>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-error">
|
|
||||||
{{this.error}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@tracked error = null;
|
@tracked error = null;
|
||||||
@tracked parsedTemplate = null;
|
@tracked parsedTemplate = null;
|
||||||
|
|
||||||
|
@ -94,4 +72,26 @@ export default class FormTemplateFieldWrapper extends Component {
|
||||||
const templateContent = await response.form_template.template;
|
const templateContent = await response.form_template.template;
|
||||||
return this._loadTemplate(templateContent);
|
return this._loadTemplate(templateContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.parsedTemplate}}
|
||||||
|
<div
|
||||||
|
class="form-template-form__wrapper"
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
{{didUpdate this.refreshTemplate @id}}
|
||||||
|
>
|
||||||
|
{{#each this.parsedTemplate as |content|}}
|
||||||
|
<FormTemplateField
|
||||||
|
@component={{get this.fieldTypes content.type}}
|
||||||
|
@content={{content}}
|
||||||
|
@initialValue={{get this.initialValues content.id}}
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="alert alert-error">
|
||||||
|
{{this.error}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,49 +10,6 @@ const REPLIES_SUBSET = "replies";
|
||||||
const TOPICS_SUBSET = "topics";
|
const TOPICS_SUBSET = "topics";
|
||||||
|
|
||||||
export default class DismissNew extends Component {
|
export default class DismissNew extends Component {
|
||||||
<template>
|
|
||||||
<DModal
|
|
||||||
@closeModal={{@closeModal}}
|
|
||||||
@title={{this.modalTitle}}
|
|
||||||
@inline={{@inline}}
|
|
||||||
>
|
|
||||||
<:body>
|
|
||||||
<p>
|
|
||||||
{{#if this.showDismissNewTopics}}
|
|
||||||
<PreferenceCheckbox
|
|
||||||
@labelKey={{this.dismissNewTopicsLabel}}
|
|
||||||
@labelCount={{this.countNewTopics}}
|
|
||||||
@checked={{this.dismissTopics}}
|
|
||||||
@class="dismiss-topics"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
{{#if this.showDismissNewReplies}}
|
|
||||||
<PreferenceCheckbox
|
|
||||||
@labelKey={{this.dismissNewRepliesLabel}}
|
|
||||||
@labelCount={{this.countNewReplies}}
|
|
||||||
@checked={{this.dismissPosts}}
|
|
||||||
@class="dismiss-posts"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
<PreferenceCheckbox
|
|
||||||
@labelKey="topics.bulk.dismiss_new_modal.untrack"
|
|
||||||
@checked={{this.untrack}}
|
|
||||||
@class="untrack"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</:body>
|
|
||||||
<:footer>
|
|
||||||
<DButton
|
|
||||||
@action={{this.dismissed}}
|
|
||||||
@icon="check"
|
|
||||||
@label="topics.bulk.dismiss"
|
|
||||||
id="dismiss-read-confirm"
|
|
||||||
class="btn-primary"
|
|
||||||
/>
|
|
||||||
</:footer>
|
|
||||||
</DModal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@tracked untrack = false;
|
@tracked untrack = false;
|
||||||
@tracked dismissTopics = true;
|
@tracked dismissTopics = true;
|
||||||
@tracked dismissPosts = true;
|
@tracked dismissPosts = true;
|
||||||
|
@ -141,4 +98,47 @@ export default class DismissNew extends Component {
|
||||||
|
|
||||||
this.args.closeModal();
|
this.args.closeModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DModal
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@title={{this.modalTitle}}
|
||||||
|
@inline={{@inline}}
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<p>
|
||||||
|
{{#if this.showDismissNewTopics}}
|
||||||
|
<PreferenceCheckbox
|
||||||
|
@labelKey={{this.dismissNewTopicsLabel}}
|
||||||
|
@labelCount={{this.countNewTopics}}
|
||||||
|
@checked={{this.dismissTopics}}
|
||||||
|
@class="dismiss-topics"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
{{#if this.showDismissNewReplies}}
|
||||||
|
<PreferenceCheckbox
|
||||||
|
@labelKey={{this.dismissNewRepliesLabel}}
|
||||||
|
@labelCount={{this.countNewReplies}}
|
||||||
|
@checked={{this.dismissPosts}}
|
||||||
|
@class="dismiss-posts"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
<PreferenceCheckbox
|
||||||
|
@labelKey="topics.bulk.dismiss_new_modal.untrack"
|
||||||
|
@checked={{this.untrack}}
|
||||||
|
@class="untrack"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</:body>
|
||||||
|
<:footer>
|
||||||
|
<DButton
|
||||||
|
@action={{this.dismissed}}
|
||||||
|
@icon="check"
|
||||||
|
@label="topics.bulk.dismiss"
|
||||||
|
id="dismiss-read-confirm"
|
||||||
|
class="btn-primary"
|
||||||
|
/>
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,86 +22,6 @@ export function fixQuotes(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PostTextSelectionToolbar extends Component {
|
export default class PostTextSelectionToolbar extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
{{! template-lint-disable no-invalid-interactive }}
|
|
||||||
{{! template-lint-disable no-pointer-down-event-binding }}
|
|
||||||
<div
|
|
||||||
{{on "mousedown" this.trapEvents}}
|
|
||||||
{{on "mouseup" this.trapEvents}}
|
|
||||||
class={{concatClass "quote-button" "visible"}}
|
|
||||||
{{this.appEventsListeners}}
|
|
||||||
>
|
|
||||||
<div class="buttons">
|
|
||||||
<PluginOutlet
|
|
||||||
@name="post-text-buttons"
|
|
||||||
@defaultGlimmer={{true}}
|
|
||||||
@outletArgs={{hash data=@data}}
|
|
||||||
>
|
|
||||||
{{#if this.embedQuoteButton}}
|
|
||||||
<DButton
|
|
||||||
@icon="quote-left"
|
|
||||||
@label="post.quote_reply"
|
|
||||||
@title="post.quote_reply_shortcut"
|
|
||||||
class="btn-flat insert-quote"
|
|
||||||
@action={{@data.insertQuote}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if @data.canEditPost}}
|
|
||||||
<DButton
|
|
||||||
@icon="pencil-alt"
|
|
||||||
@label="post.quote_edit"
|
|
||||||
@title="post.quote_edit_shortcut"
|
|
||||||
class="btn-flat quote-edit-label"
|
|
||||||
{{on "click" this.toggleFastEdit}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.quoteSharingEnabled}}
|
|
||||||
<span class="quote-sharing">
|
|
||||||
{{#if this.quoteSharingShowLabel}}
|
|
||||||
<DButton
|
|
||||||
@icon="share"
|
|
||||||
@label="post.quote_share"
|
|
||||||
class="btn-flat quote-share-label"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<span class="quote-share-buttons">
|
|
||||||
{{#each this.quoteSharingSources as |source|}}
|
|
||||||
<DButton
|
|
||||||
@action={{fn this.share source}}
|
|
||||||
@translatedTitle={{source.title}}
|
|
||||||
@icon={{source.icon}}
|
|
||||||
class="btn-flat"
|
|
||||||
/>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
<PluginOutlet
|
|
||||||
@name="quote-share-buttons-after"
|
|
||||||
@connectorTagName="span"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
</PluginOutlet>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="extra">
|
|
||||||
{{#if this.isFastEditing}}
|
|
||||||
<FastEdit
|
|
||||||
@initialValue={{@data.quoteState.buffer}}
|
|
||||||
@post={{this.post}}
|
|
||||||
@close={{this.closeFastEdit}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<PluginOutlet @name="quote-button-after" @connectorTagName="div" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service modal;
|
@service modal;
|
||||||
@service site;
|
@service site;
|
||||||
|
@ -256,4 +176,84 @@ export default class PostTextSelectionToolbar extends Component {
|
||||||
quote: window.getSelection().toString(),
|
quote: window.getSelection().toString(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
{{! template-lint-disable no-invalid-interactive }}
|
||||||
|
{{! template-lint-disable no-pointer-down-event-binding }}
|
||||||
|
<div
|
||||||
|
{{on "mousedown" this.trapEvents}}
|
||||||
|
{{on "mouseup" this.trapEvents}}
|
||||||
|
class={{concatClass "quote-button" "visible"}}
|
||||||
|
{{this.appEventsListeners}}
|
||||||
|
>
|
||||||
|
<div class="buttons">
|
||||||
|
<PluginOutlet
|
||||||
|
@name="post-text-buttons"
|
||||||
|
@defaultGlimmer={{true}}
|
||||||
|
@outletArgs={{hash data=@data}}
|
||||||
|
>
|
||||||
|
{{#if this.embedQuoteButton}}
|
||||||
|
<DButton
|
||||||
|
@icon="quote-left"
|
||||||
|
@label="post.quote_reply"
|
||||||
|
@title="post.quote_reply_shortcut"
|
||||||
|
class="btn-flat insert-quote"
|
||||||
|
@action={{@data.insertQuote}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if @data.canEditPost}}
|
||||||
|
<DButton
|
||||||
|
@icon="pencil-alt"
|
||||||
|
@label="post.quote_edit"
|
||||||
|
@title="post.quote_edit_shortcut"
|
||||||
|
class="btn-flat quote-edit-label"
|
||||||
|
{{on "click" this.toggleFastEdit}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.quoteSharingEnabled}}
|
||||||
|
<span class="quote-sharing">
|
||||||
|
{{#if this.quoteSharingShowLabel}}
|
||||||
|
<DButton
|
||||||
|
@icon="share"
|
||||||
|
@label="post.quote_share"
|
||||||
|
class="btn-flat quote-share-label"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<span class="quote-share-buttons">
|
||||||
|
{{#each this.quoteSharingSources as |source|}}
|
||||||
|
<DButton
|
||||||
|
@action={{fn this.share source}}
|
||||||
|
@translatedTitle={{source.title}}
|
||||||
|
@icon={{source.icon}}
|
||||||
|
class="btn-flat"
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
<PluginOutlet
|
||||||
|
@name="quote-share-buttons-after"
|
||||||
|
@connectorTagName="span"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</PluginOutlet>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="extra">
|
||||||
|
{{#if this.isFastEditing}}
|
||||||
|
<FastEdit
|
||||||
|
@initialValue={{@data.quoteState.buffer}}
|
||||||
|
@post={{this.post}}
|
||||||
|
@close={{this.closeFastEdit}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<PluginOutlet @name="quote-button-after" @connectorTagName="div" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,15 +38,6 @@ export function fixQuotes(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PostTextSelection extends Component {
|
export default class PostTextSelection extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<div
|
|
||||||
{{this.documentListeners}}
|
|
||||||
{{this.appEventsListeners}}
|
|
||||||
{{this.runLoopHandlers}}
|
|
||||||
></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service appEvents;
|
@service appEvents;
|
||||||
@service capabilities;
|
@service capabilities;
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
|
@ -284,4 +275,13 @@ export default class PostTextSelection extends Component {
|
||||||
await this.args.selectText();
|
await this.args.selectText();
|
||||||
await this.hideToolbar();
|
await this.hideToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<div
|
||||||
|
{{this.documentListeners}}
|
||||||
|
{{this.appEventsListeners}}
|
||||||
|
{{this.runLoopHandlers}}
|
||||||
|
></div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ import Component from "@glimmer/component";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
export default class RenderGlimmerContainer extends Component {
|
export default class RenderGlimmerContainer extends Component {
|
||||||
|
@service renderGlimmer;
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#each this.renderGlimmer._registrations as |info|}}
|
{{#each this.renderGlimmer._registrations as |info|}}
|
||||||
{{#in-element info.element insertBefore=null}}
|
{{#in-element info.element insertBefore=null}}
|
||||||
|
@ -12,6 +14,4 @@ export default class RenderGlimmerContainer extends Component {
|
||||||
{{/in-element}}
|
{{/in-element}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service renderGlimmer;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,33 @@ import { action } from "@ember/object";
|
||||||
import { isRTL } from "discourse/lib/text-direction";
|
import { isRTL } from "discourse/lib/text-direction";
|
||||||
|
|
||||||
export default class ReviewableBundledAction extends Component {
|
export default class ReviewableBundledAction extends Component {
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
get multiple() {
|
||||||
|
return this.args.bundle.actions.length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
get first() {
|
||||||
|
return this.args.bundle.actions[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
get placement() {
|
||||||
|
const vertical = this.site.mobileView ? "top" : "bottom";
|
||||||
|
const horizontal = isRTL() ? "end" : "start";
|
||||||
|
|
||||||
|
return `${vertical}-${horizontal}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
perform(id) {
|
||||||
|
if (id) {
|
||||||
|
const _action = this.args.bundle.actions.find((a) => a.id === id);
|
||||||
|
this.args.performAction(_action);
|
||||||
|
} else {
|
||||||
|
this.args.performAction(this.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#if this.multiple}}
|
{{#if this.multiple}}
|
||||||
<DropdownSelectBox
|
<DropdownSelectBox
|
||||||
|
@ -41,31 +68,4 @@ export default class ReviewableBundledAction extends Component {
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service site;
|
|
||||||
|
|
||||||
get multiple() {
|
|
||||||
return this.args.bundle.actions.length > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
get first() {
|
|
||||||
return this.args.bundle.actions[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
get placement() {
|
|
||||||
const vertical = this.site.mobileView ? "top" : "bottom";
|
|
||||||
const horizontal = isRTL() ? "end" : "start";
|
|
||||||
|
|
||||||
return `${vertical}-${horizontal}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
perform(id) {
|
|
||||||
if (id) {
|
|
||||||
const _action = this.args.bundle.actions.find((a) => a.id === id);
|
|
||||||
this.args.performAction(_action);
|
|
||||||
} else {
|
|
||||||
this.args.performAction(this.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,6 @@ import Component from "@glimmer/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default class ScoreValue extends Component {
|
export default class ScoreValue extends Component {
|
||||||
<template>
|
|
||||||
{{#if @value}}
|
|
||||||
<span class="op">{{if this.isNegative "-" "+"}}</span>
|
|
||||||
<span class="score-value">
|
|
||||||
<span class="score-number">{{this.numericValue}}</span>
|
|
||||||
{{#if @label}}
|
|
||||||
<span title={{this.explanationTitle}} class="score-value-type">
|
|
||||||
{{this.explanationContent}}
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
get numericValue() {
|
get numericValue() {
|
||||||
return parseFloat(Math.abs(this.args.value)).toFixed(1);
|
return parseFloat(Math.abs(this.args.value)).toFixed(1);
|
||||||
}
|
}
|
||||||
|
@ -31,4 +17,18 @@ export default class ScoreValue extends Component {
|
||||||
get explanationContent() {
|
get explanationContent() {
|
||||||
return I18n.t(`review.explain.${this.args.label}.name`);
|
return I18n.t(`review.explain.${this.args.label}.name`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if @value}}
|
||||||
|
<span class="op">{{if this.isNegative "-" "+"}}</span>
|
||||||
|
<span class="score-value">
|
||||||
|
<span class="score-number">{{this.numericValue}}</span>
|
||||||
|
{{#if @label}}
|
||||||
|
<span title={{this.explanationTitle}} class="score-value-type">
|
||||||
|
{{this.explanationContent}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,19 @@ import { action } from "@ember/object";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
export default class UserTipContainer extends Component {
|
export default class UserTipContainer extends Component {
|
||||||
|
@service userTips;
|
||||||
|
|
||||||
|
get safeHtmlContent() {
|
||||||
|
return htmlSafe(this.args.data.contentHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
handleDismiss(_, event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.args.close();
|
||||||
|
this.userTips.hideUserTipForever(this.args.data.id);
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="user-tip__container">
|
<div class="user-tip__container">
|
||||||
<div class="user-tip__title">{{@data.titleText}}</div>
|
<div class="user-tip__title">{{@data.titleText}}</div>
|
||||||
|
@ -27,17 +40,4 @@ export default class UserTipContainer extends Component {
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service userTips;
|
|
||||||
|
|
||||||
get safeHtmlContent() {
|
|
||||||
return htmlSafe(this.args.data.contentHtml);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
handleDismiss(_, event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.args.close();
|
|
||||||
this.userTips.hideUserTipForever(this.args.data.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,6 @@ import I18n from "I18n";
|
||||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||||
|
|
||||||
export default class UserTip extends Component {
|
export default class UserTip extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<div {{this.registerTip}}>
|
|
||||||
{{#if this.shouldRenderTip}}
|
|
||||||
<span {{this.tip}}></span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service userTips;
|
@service userTips;
|
||||||
@service tooltip;
|
@service tooltip;
|
||||||
|
@ -80,4 +71,13 @@ export default class UserTip extends Component {
|
||||||
get shouldRenderTip() {
|
get shouldRenderTip() {
|
||||||
return this.userTips.renderedId === this.args.id;
|
return this.userTips.renderedId === this.args.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<div {{this.registerTip}}>
|
||||||
|
{{#if this.shouldRenderTip}}
|
||||||
|
<span {{this.tip}}></span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,40 @@ import TrapTab from "discourse/modifiers/trap-tab";
|
||||||
import DFloatPortal from "float-kit/components/d-float-portal";
|
import DFloatPortal from "float-kit/components/d-float-portal";
|
||||||
|
|
||||||
export default class DFloatBody extends Component {
|
export default class DFloatBody extends Component {
|
||||||
|
closeOnScroll = modifier(() => {
|
||||||
|
const firstScrollParent = getScrollParent(this.trigger);
|
||||||
|
|
||||||
|
const handler = () => {
|
||||||
|
this.args.instance.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
firstScrollParent.addEventListener("scroll", handler, { passive: true });
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
firstScrollParent.removeEventListener("scroll", handler);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
get supportsCloseOnClickOutside() {
|
||||||
|
return this.args.instance.expanded && this.options.closeOnClickOutside;
|
||||||
|
}
|
||||||
|
|
||||||
|
get supportsCloseOnEscape() {
|
||||||
|
return this.args.instance.expanded && this.options.closeOnEscape;
|
||||||
|
}
|
||||||
|
|
||||||
|
get supportsCloseOnScroll() {
|
||||||
|
return this.args.instance.expanded && this.options.closeOnScroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
get trigger() {
|
||||||
|
return this.args.instance.trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
get options() {
|
||||||
|
return this.args.instance.options;
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
<DFloatPortal
|
<DFloatPortal
|
||||||
|
@ -48,38 +82,4 @@ export default class DFloatBody extends Component {
|
||||||
</div>
|
</div>
|
||||||
</DFloatPortal>
|
</DFloatPortal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
closeOnScroll = modifier(() => {
|
|
||||||
const firstScrollParent = getScrollParent(this.trigger);
|
|
||||||
|
|
||||||
const handler = () => {
|
|
||||||
this.args.instance.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
firstScrollParent.addEventListener("scroll", handler, { passive: true });
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
firstScrollParent.removeEventListener("scroll", handler);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
get supportsCloseOnClickOutside() {
|
|
||||||
return this.args.instance.expanded && this.options.closeOnClickOutside;
|
|
||||||
}
|
|
||||||
|
|
||||||
get supportsCloseOnEscape() {
|
|
||||||
return this.args.instance.expanded && this.options.closeOnEscape;
|
|
||||||
}
|
|
||||||
|
|
||||||
get supportsCloseOnScroll() {
|
|
||||||
return this.args.instance.expanded && this.options.closeOnScroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
get trigger() {
|
|
||||||
return this.args.instance.trigger;
|
|
||||||
}
|
|
||||||
|
|
||||||
get options() {
|
|
||||||
return this.args.instance.options;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@ import Component from "@glimmer/component";
|
||||||
import { isTesting } from "discourse-common/config/environment";
|
import { isTesting } from "discourse-common/config/environment";
|
||||||
|
|
||||||
export default class DFloatPortal extends Component {
|
export default class DFloatPortal extends Component {
|
||||||
|
get inline() {
|
||||||
|
return this.args.inline ?? isTesting();
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{#if this.inline}}
|
{{#if this.inline}}
|
||||||
{{yield}}
|
{{yield}}
|
||||||
|
@ -11,8 +15,4 @@ export default class DFloatPortal extends Component {
|
||||||
{{/in-element}}
|
{{/in-element}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
get inline() {
|
|
||||||
return this.args.inline ?? isTesting();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { MENU } from "float-kit/lib/constants";
|
||||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
|
||||||
export default class DInlineMenu extends Component {
|
export default class DInlineMenu extends Component {
|
||||||
|
@service menu;
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
<div
|
<div
|
||||||
|
@ -22,6 +24,4 @@ export default class DInlineMenu extends Component {
|
||||||
@inline={{@inline}}
|
@inline={{@inline}}
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service menu;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
import and from "truth-helpers/helpers/and";
|
import and from "truth-helpers/helpers/and";
|
||||||
|
|
||||||
export default class DInlineTooltip extends Component {
|
export default class DInlineTooltip extends Component {
|
||||||
|
@service tooltip;
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
<div
|
<div
|
||||||
|
@ -26,6 +28,4 @@ export default class DInlineTooltip extends Component {
|
||||||
@inline={{@inline}}
|
@inline={{@inline}}
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service tooltip;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,49 @@ import { getOwner } from "@ember/application";
|
||||||
import DMenuInstance from "float-kit/lib/d-menu-instance";
|
import DMenuInstance from "float-kit/lib/d-menu-instance";
|
||||||
|
|
||||||
export default class DMenu extends Component {
|
export default class DMenu extends Component {
|
||||||
|
@service menu;
|
||||||
|
|
||||||
|
@tracked menuInstance = null;
|
||||||
|
|
||||||
|
registerTrigger = modifier((element) => {
|
||||||
|
const options = {
|
||||||
|
...this.args,
|
||||||
|
...{
|
||||||
|
autoUpdate: true,
|
||||||
|
listeners: true,
|
||||||
|
beforeTrigger: () => {
|
||||||
|
this.menu.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const instance = new DMenuInstance(getOwner(this), element, options);
|
||||||
|
|
||||||
|
this.menuInstance = instance;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
instance.destroy();
|
||||||
|
|
||||||
|
if (this.isDestroying) {
|
||||||
|
this.menuInstance = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
get menuId() {
|
||||||
|
return `d-menu-${this.menuInstance.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get options() {
|
||||||
|
return this.menuInstance?.options ?? {};
|
||||||
|
}
|
||||||
|
|
||||||
|
get componentArgs() {
|
||||||
|
return {
|
||||||
|
close: this.menuInstance.close,
|
||||||
|
data: this.options.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
<DButton
|
<DButton
|
||||||
|
@ -58,47 +101,4 @@ export default class DMenu extends Component {
|
||||||
</DFloatBody>
|
</DFloatBody>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service menu;
|
|
||||||
|
|
||||||
@tracked menuInstance = null;
|
|
||||||
|
|
||||||
registerTrigger = modifier((element) => {
|
|
||||||
const options = {
|
|
||||||
...this.args,
|
|
||||||
...{
|
|
||||||
autoUpdate: true,
|
|
||||||
listeners: true,
|
|
||||||
beforeTrigger: () => {
|
|
||||||
this.menu.close();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const instance = new DMenuInstance(getOwner(this), element, options);
|
|
||||||
|
|
||||||
this.menuInstance = instance;
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
instance.destroy();
|
|
||||||
|
|
||||||
if (this.isDestroying) {
|
|
||||||
this.menuInstance = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
get menuId() {
|
|
||||||
return `d-menu-${this.menuInstance.id}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get options() {
|
|
||||||
return this.menuInstance?.options ?? {};
|
|
||||||
}
|
|
||||||
|
|
||||||
get componentArgs() {
|
|
||||||
return {
|
|
||||||
close: this.menuInstance.close,
|
|
||||||
data: this.options.data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,6 @@ import { modifier } from "ember-modifier";
|
||||||
import deprecated from "discourse-common/lib/deprecated";
|
import deprecated from "discourse-common/lib/deprecated";
|
||||||
|
|
||||||
export default class DPopover extends Component {
|
export default class DPopover extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<div style="display:inline-flex;" {{this.registerDTooltip}}>
|
|
||||||
{{yield}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service tooltip;
|
@service tooltip;
|
||||||
|
|
||||||
registerDTooltip = modifier((element) => {
|
registerDTooltip = modifier((element) => {
|
||||||
|
@ -37,4 +30,11 @@ export default class DPopover extends Component {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<div style="display:inline-flex;" {{this.registerDTooltip}}>
|
||||||
|
{{yield}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import concatClass from "discourse/helpers/concat-class";
|
||||||
import { on } from "@ember/modifier";
|
import { on } from "@ember/modifier";
|
||||||
|
|
||||||
export default class DToasts extends Component {
|
export default class DToasts extends Component {
|
||||||
|
@service toasts;
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fk-d-toasts">
|
<div class="fk-d-toasts">
|
||||||
{{#each this.toasts.activeToasts as |toast|}}
|
{{#each this.toasts.activeToasts as |toast|}}
|
||||||
|
@ -22,6 +24,4 @@ export default class DToasts extends Component {
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service toasts;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,44 @@ import { getOwner } from "@ember/application";
|
||||||
import and from "truth-helpers/helpers/and";
|
import and from "truth-helpers/helpers/and";
|
||||||
|
|
||||||
export default class DTooltip extends Component {
|
export default class DTooltip extends Component {
|
||||||
|
@service tooltip;
|
||||||
|
|
||||||
|
@tracked tooltipInstance = null;
|
||||||
|
|
||||||
|
registerTrigger = modifier((element) => {
|
||||||
|
const options = {
|
||||||
|
...this.args,
|
||||||
|
...{
|
||||||
|
listeners: true,
|
||||||
|
beforeTrigger: () => {
|
||||||
|
this.tooltip.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const instance = new DTooltipInstance(getOwner(this), element, options);
|
||||||
|
|
||||||
|
this.tooltipInstance = instance;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
instance.destroy();
|
||||||
|
|
||||||
|
if (this.isDestroying) {
|
||||||
|
this.tooltipInstance = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
get options() {
|
||||||
|
return this.tooltipInstance?.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
get componentArgs() {
|
||||||
|
return {
|
||||||
|
close: this.tooltip.close,
|
||||||
|
data: this.options.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
<span
|
<span
|
||||||
|
@ -68,42 +106,4 @@ export default class DTooltip extends Component {
|
||||||
</DFloatBody>
|
</DFloatBody>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service tooltip;
|
|
||||||
|
|
||||||
@tracked tooltipInstance = null;
|
|
||||||
|
|
||||||
registerTrigger = modifier((element) => {
|
|
||||||
const options = {
|
|
||||||
...this.args,
|
|
||||||
...{
|
|
||||||
listeners: true,
|
|
||||||
beforeTrigger: () => {
|
|
||||||
this.tooltip.close();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const instance = new DTooltipInstance(getOwner(this), element, options);
|
|
||||||
|
|
||||||
this.tooltipInstance = instance;
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
instance.destroy();
|
|
||||||
|
|
||||||
if (this.isDestroying) {
|
|
||||||
this.tooltipInstance = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
get options() {
|
|
||||||
return this.tooltipInstance?.options;
|
|
||||||
}
|
|
||||||
|
|
||||||
get componentArgs() {
|
|
||||||
return {
|
|
||||||
close: this.tooltip.close,
|
|
||||||
data: this.options.data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,22 @@ import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default class ChatChannelMessageEmojiPicker extends Component {
|
export default class ChatChannelMessageEmojiPicker extends Component {
|
||||||
|
@service chatChannelInfoRouteOriginManager;
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
membersLabel = I18n.t("chat.channel_info.tabs.members");
|
||||||
|
settingsLabel = I18n.t("chat.channel_info.tabs.settings");
|
||||||
|
backToChannelLabel = I18n.t("chat.channel_info.back_to_all_channel");
|
||||||
|
backToAllChannelsLabel = I18n.t("chat.channel_info.back_to_channel");
|
||||||
|
|
||||||
|
get showTabs() {
|
||||||
|
return (
|
||||||
|
this.site.desktopView &&
|
||||||
|
this.args.channel.membershipsCount > 1 &&
|
||||||
|
this.args.channel.isOpen
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-full-page-header">
|
<div class="chat-full-page-header">
|
||||||
<div class="chat-channel-header-details">
|
<div class="chat-channel-header-details">
|
||||||
|
@ -66,20 +82,4 @@ export default class ChatChannelMessageEmojiPicker extends Component {
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service chatChannelInfoRouteOriginManager;
|
|
||||||
@service site;
|
|
||||||
|
|
||||||
membersLabel = I18n.t("chat.channel_info.tabs.members");
|
|
||||||
settingsLabel = I18n.t("chat.channel_info.tabs.settings");
|
|
||||||
backToChannelLabel = I18n.t("chat.channel_info.back_to_all_channel");
|
|
||||||
backToAllChannelsLabel = I18n.t("chat.channel_info.back_to_channel");
|
|
||||||
|
|
||||||
get showTabs() {
|
|
||||||
return (
|
|
||||||
this.site.desktopView &&
|
|
||||||
this.args.channel.membershipsCount > 1 &&
|
|
||||||
this.args.channel.isOpen
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,45 +14,6 @@ import { hash } from "@ember/helper";
|
||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
|
|
||||||
export default class ChatChannelMembers extends Component {
|
export default class ChatChannelMembers extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<div class="chat-channel-members">
|
|
||||||
<DcFilterInput
|
|
||||||
@class="chat-channel-members__filter"
|
|
||||||
@filterAction={{this.mutFilter}}
|
|
||||||
@icons={{hash right="search"}}
|
|
||||||
placeholder={{this.filterPlaceholder}}
|
|
||||||
{{this.focusInput}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{{#if (gt @channel.membershipsCount 0)}}
|
|
||||||
<ul class="chat-channel-members__list" {{this.fill}}>
|
|
||||||
{{#each this.members as |membership|}}
|
|
||||||
<li class="chat-channel-members__list-item">
|
|
||||||
<ChatUserInfo @user={{membership.user}} @avatarSize="tiny" />
|
|
||||||
</li>
|
|
||||||
{{else}}
|
|
||||||
{{#if this.noResults}}
|
|
||||||
<li
|
|
||||||
class="chat-channel-members__list-item -no-results alert alert-info"
|
|
||||||
>
|
|
||||||
{{this.noMembershipsFoundLabel}}
|
|
||||||
</li>
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div {{this.loadMore}}>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<p class="alert alert-info">
|
|
||||||
{{this.noMembershipsLabel}}
|
|
||||||
</p>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service chatApi;
|
@service chatApi;
|
||||||
@service modal;
|
@service modal;
|
||||||
@service loadingSlider;
|
@service loadingSlider;
|
||||||
|
@ -122,4 +83,43 @@ export default class ChatChannelMembers extends Component {
|
||||||
await this.members.load({ limit: 20 });
|
await this.members.load({ limit: 20 });
|
||||||
this.loadingSlider.transitionEnded();
|
this.loadingSlider.transitionEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<div class="chat-channel-members">
|
||||||
|
<DcFilterInput
|
||||||
|
@class="chat-channel-members__filter"
|
||||||
|
@filterAction={{this.mutFilter}}
|
||||||
|
@icons={{hash right="search"}}
|
||||||
|
placeholder={{this.filterPlaceholder}}
|
||||||
|
{{this.focusInput}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{#if (gt @channel.membershipsCount 0)}}
|
||||||
|
<ul class="chat-channel-members__list" {{this.fill}}>
|
||||||
|
{{#each this.members as |membership|}}
|
||||||
|
<li class="chat-channel-members__list-item">
|
||||||
|
<ChatUserInfo @user={{membership.user}} @avatarSize="tiny" />
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
{{#if this.noResults}}
|
||||||
|
<li
|
||||||
|
class="chat-channel-members__list-item -no-results alert alert-info"
|
||||||
|
>
|
||||||
|
{{this.noMembershipsFoundLabel}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div {{this.loadMore}}>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<p class="alert alert-info">
|
||||||
|
{{this.noMembershipsLabel}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,6 @@ import ChatEmojiPicker from "discourse/plugins/chat/discourse/components/chat-em
|
||||||
import { modifier } from "ember-modifier";
|
import { modifier } from "ember-modifier";
|
||||||
|
|
||||||
export default class ChatChannelMessageEmojiPicker extends Component {
|
export default class ChatChannelMessageEmojiPicker extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<ChatEmojiPicker
|
|
||||||
@context="chat-channel-message"
|
|
||||||
@didInsert={{this.didInsert}}
|
|
||||||
@willDestroy={{this.willDestroy}}
|
|
||||||
@didSelectEmoji={{this.didSelectEmoji}}
|
|
||||||
@class="hidden"
|
|
||||||
{{this.listenToBodyScroll}}
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service site;
|
@service site;
|
||||||
@service chatEmojiPickerManager;
|
@service chatEmojiPickerManager;
|
||||||
|
|
||||||
|
@ -74,4 +62,16 @@ export default class ChatChannelMessageEmojiPicker extends Component {
|
||||||
willDestroy() {
|
willDestroy() {
|
||||||
this._popper?.destroy();
|
this._popper?.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<ChatEmojiPicker
|
||||||
|
@context="chat-channel-message"
|
||||||
|
@didInsert={{this.didInsert}}
|
||||||
|
@willDestroy={{this.willDestroy}}
|
||||||
|
@didSelectEmoji={{this.didSelectEmoji}}
|
||||||
|
@class="hidden"
|
||||||
|
{{this.listenToBodyScroll}}
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,70 +22,6 @@ import { htmlSafe } from "@ember/template";
|
||||||
const FADEOUT_CLASS = "-fade-out";
|
const FADEOUT_CLASS = "-fade-out";
|
||||||
|
|
||||||
export default class ChatChannelRow extends Component {
|
export default class ChatChannelRow extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel"
|
|
||||||
@models={{@channel.routeModels}}
|
|
||||||
class={{concatClass
|
|
||||||
"chat-channel-row"
|
|
||||||
(if @channel.focused "focused")
|
|
||||||
(if @channel.currentUserMembership.muted "muted")
|
|
||||||
(if @options.leaveButton "can-leave")
|
|
||||||
(if (eq this.chat.activeChannel.id @channel.id) "active")
|
|
||||||
(if this.channelHasUnread "has-unread")
|
|
||||||
}}
|
|
||||||
tabindex="0"
|
|
||||||
data-chat-channel-id={{@channel.id}}
|
|
||||||
{{didInsert this.startTrackingStatus}}
|
|
||||||
{{willDestroy this.stopTrackingStatus}}
|
|
||||||
{{(if this.shouldRemoveChannel (modifier this.onRemoveChannel))}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class={{concatClass
|
|
||||||
"chat-channel-row__content"
|
|
||||||
(if this.shouldReset "-animate-reset")
|
|
||||||
}}
|
|
||||||
{{(if this.shouldHandleSwipe (modifier this.registerSwipableRow))}}
|
|
||||||
{{(if this.shouldHandleSwipe (modifier this.handleSwipe))}}
|
|
||||||
{{(if this.shouldReset (modifier this.onReset))}}
|
|
||||||
style={{this.rowStyle}}
|
|
||||||
>
|
|
||||||
<ChatChannelTitle @channel={{@channel}} />
|
|
||||||
<ChatChannelMetadata @channel={{@channel}} @unreadIndicator={{true}} />
|
|
||||||
|
|
||||||
{{#if
|
|
||||||
(and @options.leaveButton @channel.isFollowing this.site.desktopView)
|
|
||||||
}}
|
|
||||||
<ToggleChannelMembershipButton
|
|
||||||
@channel={{@channel}}
|
|
||||||
@options={{hash
|
|
||||||
leaveClass="btn-flat chat-channel-leave-btn"
|
|
||||||
labelType="none"
|
|
||||||
leaveIcon="times"
|
|
||||||
leaveTitle=(if
|
|
||||||
@channel.isDirectMessageChannel
|
|
||||||
this.leaveDirectMessageLabel
|
|
||||||
this.leaveChannelLabel
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if this.showRemoveButton}}
|
|
||||||
<div
|
|
||||||
class={{concatClass
|
|
||||||
"chat-channel-row__action-btn"
|
|
||||||
(if this.isAtThreshold "-at-threshold" "-not-at-threshold")
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{{icon "times-circle"}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</LinkTo>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service api;
|
@service api;
|
||||||
@service capabilities;
|
@service capabilities;
|
||||||
@service chat;
|
@service chat;
|
||||||
|
@ -219,4 +155,68 @@ export default class ChatChannelRow extends Component {
|
||||||
stopTrackingStatus() {
|
stopTrackingStatus() {
|
||||||
this.#firstDirectMessageUser?.stopTrackingStatus();
|
this.#firstDirectMessageUser?.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
<LinkTo
|
||||||
|
@route="chat.channel"
|
||||||
|
@models={{@channel.routeModels}}
|
||||||
|
class={{concatClass
|
||||||
|
"chat-channel-row"
|
||||||
|
(if @channel.focused "focused")
|
||||||
|
(if @channel.currentUserMembership.muted "muted")
|
||||||
|
(if @options.leaveButton "can-leave")
|
||||||
|
(if (eq this.chat.activeChannel.id @channel.id) "active")
|
||||||
|
(if this.channelHasUnread "has-unread")
|
||||||
|
}}
|
||||||
|
tabindex="0"
|
||||||
|
data-chat-channel-id={{@channel.id}}
|
||||||
|
{{didInsert this.startTrackingStatus}}
|
||||||
|
{{willDestroy this.stopTrackingStatus}}
|
||||||
|
{{(if this.shouldRemoveChannel (modifier this.onRemoveChannel))}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={{concatClass
|
||||||
|
"chat-channel-row__content"
|
||||||
|
(if this.shouldReset "-animate-reset")
|
||||||
|
}}
|
||||||
|
{{(if this.shouldHandleSwipe (modifier this.registerSwipableRow))}}
|
||||||
|
{{(if this.shouldHandleSwipe (modifier this.handleSwipe))}}
|
||||||
|
{{(if this.shouldReset (modifier this.onReset))}}
|
||||||
|
style={{this.rowStyle}}
|
||||||
|
>
|
||||||
|
<ChatChannelTitle @channel={{@channel}} />
|
||||||
|
<ChatChannelMetadata @channel={{@channel}} @unreadIndicator={{true}} />
|
||||||
|
|
||||||
|
{{#if
|
||||||
|
(and @options.leaveButton @channel.isFollowing this.site.desktopView)
|
||||||
|
}}
|
||||||
|
<ToggleChannelMembershipButton
|
||||||
|
@channel={{@channel}}
|
||||||
|
@options={{hash
|
||||||
|
leaveClass="btn-flat chat-channel-leave-btn"
|
||||||
|
labelType="none"
|
||||||
|
leaveIcon="times"
|
||||||
|
leaveTitle=(if
|
||||||
|
@channel.isDirectMessageChannel
|
||||||
|
this.leaveDirectMessageLabel
|
||||||
|
this.leaveChannelLabel
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if this.showRemoveButton}}
|
||||||
|
<div
|
||||||
|
class={{concatClass
|
||||||
|
"chat-channel-row__action-btn"
|
||||||
|
(if this.isAtThreshold "-at-threshold" "-not-at-threshold")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{{icon "times-circle"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</LinkTo>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,279 +27,6 @@ const NOTIFICATION_LEVELS = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export default class ChatAboutScreen extends Component {
|
export default class ChatAboutScreen extends Component {
|
||||||
<template>
|
|
||||||
<div class="chat-channel-settings">
|
|
||||||
<ChatForm as |form|>
|
|
||||||
{{#if this.shouldRenderTitleSection}}
|
|
||||||
<form.section @title={{this.titleSectionTitle}} as |section|>
|
|
||||||
<section.row>
|
|
||||||
<:default>
|
|
||||||
<div class="chat-channel-settings__name">
|
|
||||||
{{replaceEmoji @channel.title}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if @channel.isCategoryChannel}}
|
|
||||||
<div class="chat-channel-settings__slug">
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel"
|
|
||||||
@models={{@channel.routeModels}}
|
|
||||||
>
|
|
||||||
/chat/c/{{@channel.slug}}/{{@channel.id}}
|
|
||||||
</LinkTo>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</:default>
|
|
||||||
|
|
||||||
<:action>
|
|
||||||
{{#if this.canEditChannel}}
|
|
||||||
<DButton
|
|
||||||
@label="chat.channel_settings.edit"
|
|
||||||
@action={{this.onEditChannelName}}
|
|
||||||
class="edit-name-slug-btn btn-flat"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</:action>
|
|
||||||
|
|
||||||
</section.row>
|
|
||||||
</form.section>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.shouldRenderDescriptionSection}}
|
|
||||||
<form.section @title={{this.descriptionSectionTitle}} as |section|>
|
|
||||||
<section.row>
|
|
||||||
<:default>
|
|
||||||
{{#if @channel.description.length}}
|
|
||||||
{{@channel.description}}
|
|
||||||
{{else}}
|
|
||||||
{{this.descriptionPlaceholder}}
|
|
||||||
{{/if}}
|
|
||||||
</:default>
|
|
||||||
|
|
||||||
<:action>
|
|
||||||
{{#if this.canEditChannel}}
|
|
||||||
<DButton
|
|
||||||
@label={{if
|
|
||||||
@channel.description.length
|
|
||||||
"chat.channel_settings.edit"
|
|
||||||
"chat.channel_settings.add"
|
|
||||||
}}
|
|
||||||
@action={{this.onEditChannelDescription}}
|
|
||||||
class="edit-description-btn btn-flat"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
</form.section>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.site.mobileView}}
|
|
||||||
<form.section as |section|>
|
|
||||||
<section.row
|
|
||||||
@label={{this.membersLabel}}
|
|
||||||
@route="chat.channel.info.members"
|
|
||||||
@routeModels={{@channel.routeModels}}
|
|
||||||
/>
|
|
||||||
</form.section>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if @channel.isOpen}}
|
|
||||||
<form.section @title={{this.settingsSectionTitle}} as |section|>
|
|
||||||
<section.row @label={{this.muteSectionLabel}}>
|
|
||||||
<:action>
|
|
||||||
<DToggleSwitch
|
|
||||||
@state={{@channel.currentUserMembership.muted}}
|
|
||||||
class="chat-channel-settings__mute-switch"
|
|
||||||
{{on "click" this.onToggleMuted}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
|
|
||||||
{{#if this.shouldRenderDesktopNotificationsLevelSection}}
|
|
||||||
<section.row @label={{this.desktopNotificationsLevelLabel}}>
|
|
||||||
<:action>
|
|
||||||
<ComboBox
|
|
||||||
@content={{this.notificationLevels}}
|
|
||||||
@value={{@channel.currentUserMembership.desktopNotificationLevel}}
|
|
||||||
@valueProperty="value"
|
|
||||||
@class="chat-channel-settings__selector chat-channel-settings__desktop-notifications-selector"
|
|
||||||
@onChange={{fn
|
|
||||||
this.saveNotificationSettings
|
|
||||||
"desktopNotificationLevel"
|
|
||||||
"desktop_notification_level"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.shouldRenderMobileNotificationsLevelSection}}
|
|
||||||
<section.row @label={{this.mobileNotificationsLevelLabel}}>
|
|
||||||
<:action>
|
|
||||||
<ComboBox
|
|
||||||
@content={{this.notificationLevels}}
|
|
||||||
@value={{@channel.currentUserMembership.mobileNotificationLevel}}
|
|
||||||
@valueProperty="value"
|
|
||||||
@class="chat-channel-settings__selector chat-channel-settings__mobile-notifications-selector"
|
|
||||||
@onChange={{fn
|
|
||||||
this.saveNotificationSettings
|
|
||||||
"mobileNotificationLevel"
|
|
||||||
"mobile_notification_level"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
</form.section>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<form.section @title={{this.channelInfoSectionTitle}} as |section|>
|
|
||||||
{{#if @channel.isCategoryChannel}}
|
|
||||||
<section.row @label={{this.categoryLabel}}>
|
|
||||||
{{categoryBadge
|
|
||||||
@channel.chatable
|
|
||||||
link=true
|
|
||||||
allowUncategorized=true
|
|
||||||
}}
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<section.row @label={{this.historyLabel}}>
|
|
||||||
<ChatRetentionReminderText @channel={{@channel}} />
|
|
||||||
</section.row>
|
|
||||||
</form.section>
|
|
||||||
|
|
||||||
{{#if this.shouldRenderAdminSection}}
|
|
||||||
<form.section
|
|
||||||
@title={{this.adminSectionTitle}}
|
|
||||||
data-section="admin"
|
|
||||||
as |section|
|
|
||||||
>
|
|
||||||
{{#if this.autoJoinAvailable}}
|
|
||||||
<section.row @label={{this.autoJoinLabel}}>
|
|
||||||
<:action>
|
|
||||||
<DToggleSwitch
|
|
||||||
@state={{@channel.autoJoinUsers}}
|
|
||||||
class="chat-channel-settings__auto-join-switch"
|
|
||||||
{{on
|
|
||||||
"click"
|
|
||||||
(fn this.onToggleAutoJoinUsers @channel.autoJoinUsers)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.toggleChannelWideMentionsAvailable}}
|
|
||||||
<section.row @label={{this.channelWideMentionsLabel}}>
|
|
||||||
<:action>
|
|
||||||
<DToggleSwitch
|
|
||||||
class="chat-channel-settings__channel-wide-mentions"
|
|
||||||
@state={{@channel.allowChannelWideMentions}}
|
|
||||||
{{on
|
|
||||||
"click"
|
|
||||||
(fn
|
|
||||||
this.onToggleChannelWideMentions
|
|
||||||
@channel.allowChannelWideMentions
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
|
|
||||||
<:description>
|
|
||||||
{{this.channelWideMentionsDescription}}
|
|
||||||
</:description>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.toggleThreadingAvailable}}
|
|
||||||
<section.row @label={{this.toggleThreadingLabel}}>
|
|
||||||
<:action>
|
|
||||||
<DToggleSwitch
|
|
||||||
@state={{@channel.threadingEnabled}}
|
|
||||||
class="chat-channel-settings__threading-switch"
|
|
||||||
{{on
|
|
||||||
"click"
|
|
||||||
(fn
|
|
||||||
this.onToggleThreadingEnabled @channel.threadingEnabled
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
|
|
||||||
<:description>
|
|
||||||
{{this.toggleThreadingDescription}}
|
|
||||||
</:description>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.shouldRenderStatusSection}}
|
|
||||||
{{#if this.shouldRenderArchiveRow}}
|
|
||||||
<section.row>
|
|
||||||
<:action>
|
|
||||||
<DButton
|
|
||||||
@action={{this.onArchiveChannel}}
|
|
||||||
@label="chat.channel_settings.archive_channel"
|
|
||||||
@icon="archive"
|
|
||||||
class="archive-btn chat-form__btn btn-flat"
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<section.row>
|
|
||||||
<:action>
|
|
||||||
{{#if @channel.isOpen}}
|
|
||||||
<DButton
|
|
||||||
@action={{this.onToggleChannelState}}
|
|
||||||
@label="chat.channel_settings.close_channel"
|
|
||||||
@icon="lock"
|
|
||||||
class="close-btn chat-form__btn btn-flat"
|
|
||||||
/>
|
|
||||||
{{else}}
|
|
||||||
<DButton
|
|
||||||
@action={{this.onToggleChannelState}}
|
|
||||||
@label="chat.channel_settings.open_channel"
|
|
||||||
@icon="unlock"
|
|
||||||
class="open-btn chat-form__btn btn-flat"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
|
|
||||||
<section.row>
|
|
||||||
<:action>
|
|
||||||
<DButton
|
|
||||||
@action={{this.onDeleteChannel}}
|
|
||||||
@label="chat.channel_settings.delete_channel"
|
|
||||||
@icon="trash-alt"
|
|
||||||
class="delete-btn chat-form__btn btn-flat"
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
</form.section>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<form.section as |section|>
|
|
||||||
<section.row>
|
|
||||||
<:action>
|
|
||||||
<ToggleChannelMembershipButton
|
|
||||||
@channel={{@channel}}
|
|
||||||
@options={{hash
|
|
||||||
joinClass="btn-primary"
|
|
||||||
leaveClass="btn-flat"
|
|
||||||
joinIcon="sign-in-alt"
|
|
||||||
leaveIcon="sign-out-alt"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</:action>
|
|
||||||
</section.row>
|
|
||||||
</form.section>
|
|
||||||
</ChatForm>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service chatApi;
|
@service chatApi;
|
||||||
@service chatGuardian;
|
@service chatGuardian;
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
|
@ -578,4 +305,277 @@ export default class ChatAboutScreen extends Component {
|
||||||
model: this.args.channel,
|
model: this.args.channel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="chat-channel-settings">
|
||||||
|
<ChatForm as |form|>
|
||||||
|
{{#if this.shouldRenderTitleSection}}
|
||||||
|
<form.section @title={{this.titleSectionTitle}} as |section|>
|
||||||
|
<section.row>
|
||||||
|
<:default>
|
||||||
|
<div class="chat-channel-settings__name">
|
||||||
|
{{replaceEmoji @channel.title}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if @channel.isCategoryChannel}}
|
||||||
|
<div class="chat-channel-settings__slug">
|
||||||
|
<LinkTo
|
||||||
|
@route="chat.channel"
|
||||||
|
@models={{@channel.routeModels}}
|
||||||
|
>
|
||||||
|
/chat/c/{{@channel.slug}}/{{@channel.id}}
|
||||||
|
</LinkTo>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</:default>
|
||||||
|
|
||||||
|
<:action>
|
||||||
|
{{#if this.canEditChannel}}
|
||||||
|
<DButton
|
||||||
|
@label="chat.channel_settings.edit"
|
||||||
|
@action={{this.onEditChannelName}}
|
||||||
|
class="edit-name-slug-btn btn-flat"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</:action>
|
||||||
|
|
||||||
|
</section.row>
|
||||||
|
</form.section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.shouldRenderDescriptionSection}}
|
||||||
|
<form.section @title={{this.descriptionSectionTitle}} as |section|>
|
||||||
|
<section.row>
|
||||||
|
<:default>
|
||||||
|
{{#if @channel.description.length}}
|
||||||
|
{{@channel.description}}
|
||||||
|
{{else}}
|
||||||
|
{{this.descriptionPlaceholder}}
|
||||||
|
{{/if}}
|
||||||
|
</:default>
|
||||||
|
|
||||||
|
<:action>
|
||||||
|
{{#if this.canEditChannel}}
|
||||||
|
<DButton
|
||||||
|
@label={{if
|
||||||
|
@channel.description.length
|
||||||
|
"chat.channel_settings.edit"
|
||||||
|
"chat.channel_settings.add"
|
||||||
|
}}
|
||||||
|
@action={{this.onEditChannelDescription}}
|
||||||
|
class="edit-description-btn btn-flat"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
</form.section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.site.mobileView}}
|
||||||
|
<form.section as |section|>
|
||||||
|
<section.row
|
||||||
|
@label={{this.membersLabel}}
|
||||||
|
@route="chat.channel.info.members"
|
||||||
|
@routeModels={{@channel.routeModels}}
|
||||||
|
/>
|
||||||
|
</form.section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if @channel.isOpen}}
|
||||||
|
<form.section @title={{this.settingsSectionTitle}} as |section|>
|
||||||
|
<section.row @label={{this.muteSectionLabel}}>
|
||||||
|
<:action>
|
||||||
|
<DToggleSwitch
|
||||||
|
@state={{@channel.currentUserMembership.muted}}
|
||||||
|
class="chat-channel-settings__mute-switch"
|
||||||
|
{{on "click" this.onToggleMuted}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
|
||||||
|
{{#if this.shouldRenderDesktopNotificationsLevelSection}}
|
||||||
|
<section.row @label={{this.desktopNotificationsLevelLabel}}>
|
||||||
|
<:action>
|
||||||
|
<ComboBox
|
||||||
|
@content={{this.notificationLevels}}
|
||||||
|
@value={{@channel.currentUserMembership.desktopNotificationLevel}}
|
||||||
|
@valueProperty="value"
|
||||||
|
@class="chat-channel-settings__selector chat-channel-settings__desktop-notifications-selector"
|
||||||
|
@onChange={{fn
|
||||||
|
this.saveNotificationSettings
|
||||||
|
"desktopNotificationLevel"
|
||||||
|
"desktop_notification_level"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.shouldRenderMobileNotificationsLevelSection}}
|
||||||
|
<section.row @label={{this.mobileNotificationsLevelLabel}}>
|
||||||
|
<:action>
|
||||||
|
<ComboBox
|
||||||
|
@content={{this.notificationLevels}}
|
||||||
|
@value={{@channel.currentUserMembership.mobileNotificationLevel}}
|
||||||
|
@valueProperty="value"
|
||||||
|
@class="chat-channel-settings__selector chat-channel-settings__mobile-notifications-selector"
|
||||||
|
@onChange={{fn
|
||||||
|
this.saveNotificationSettings
|
||||||
|
"mobileNotificationLevel"
|
||||||
|
"mobile_notification_level"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
</form.section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<form.section @title={{this.channelInfoSectionTitle}} as |section|>
|
||||||
|
{{#if @channel.isCategoryChannel}}
|
||||||
|
<section.row @label={{this.categoryLabel}}>
|
||||||
|
{{categoryBadge
|
||||||
|
@channel.chatable
|
||||||
|
link=true
|
||||||
|
allowUncategorized=true
|
||||||
|
}}
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<section.row @label={{this.historyLabel}}>
|
||||||
|
<ChatRetentionReminderText @channel={{@channel}} />
|
||||||
|
</section.row>
|
||||||
|
</form.section>
|
||||||
|
|
||||||
|
{{#if this.shouldRenderAdminSection}}
|
||||||
|
<form.section
|
||||||
|
@title={{this.adminSectionTitle}}
|
||||||
|
data-section="admin"
|
||||||
|
as |section|
|
||||||
|
>
|
||||||
|
{{#if this.autoJoinAvailable}}
|
||||||
|
<section.row @label={{this.autoJoinLabel}}>
|
||||||
|
<:action>
|
||||||
|
<DToggleSwitch
|
||||||
|
@state={{@channel.autoJoinUsers}}
|
||||||
|
class="chat-channel-settings__auto-join-switch"
|
||||||
|
{{on
|
||||||
|
"click"
|
||||||
|
(fn this.onToggleAutoJoinUsers @channel.autoJoinUsers)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.toggleChannelWideMentionsAvailable}}
|
||||||
|
<section.row @label={{this.channelWideMentionsLabel}}>
|
||||||
|
<:action>
|
||||||
|
<DToggleSwitch
|
||||||
|
class="chat-channel-settings__channel-wide-mentions"
|
||||||
|
@state={{@channel.allowChannelWideMentions}}
|
||||||
|
{{on
|
||||||
|
"click"
|
||||||
|
(fn
|
||||||
|
this.onToggleChannelWideMentions
|
||||||
|
@channel.allowChannelWideMentions
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
|
||||||
|
<:description>
|
||||||
|
{{this.channelWideMentionsDescription}}
|
||||||
|
</:description>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.toggleThreadingAvailable}}
|
||||||
|
<section.row @label={{this.toggleThreadingLabel}}>
|
||||||
|
<:action>
|
||||||
|
<DToggleSwitch
|
||||||
|
@state={{@channel.threadingEnabled}}
|
||||||
|
class="chat-channel-settings__threading-switch"
|
||||||
|
{{on
|
||||||
|
"click"
|
||||||
|
(fn
|
||||||
|
this.onToggleThreadingEnabled @channel.threadingEnabled
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
|
||||||
|
<:description>
|
||||||
|
{{this.toggleThreadingDescription}}
|
||||||
|
</:description>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.shouldRenderStatusSection}}
|
||||||
|
{{#if this.shouldRenderArchiveRow}}
|
||||||
|
<section.row>
|
||||||
|
<:action>
|
||||||
|
<DButton
|
||||||
|
@action={{this.onArchiveChannel}}
|
||||||
|
@label="chat.channel_settings.archive_channel"
|
||||||
|
@icon="archive"
|
||||||
|
class="archive-btn chat-form__btn btn-flat"
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<section.row>
|
||||||
|
<:action>
|
||||||
|
{{#if @channel.isOpen}}
|
||||||
|
<DButton
|
||||||
|
@action={{this.onToggleChannelState}}
|
||||||
|
@label="chat.channel_settings.close_channel"
|
||||||
|
@icon="lock"
|
||||||
|
class="close-btn chat-form__btn btn-flat"
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<DButton
|
||||||
|
@action={{this.onToggleChannelState}}
|
||||||
|
@label="chat.channel_settings.open_channel"
|
||||||
|
@icon="unlock"
|
||||||
|
class="open-btn chat-form__btn btn-flat"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
|
||||||
|
<section.row>
|
||||||
|
<:action>
|
||||||
|
<DButton
|
||||||
|
@action={{this.onDeleteChannel}}
|
||||||
|
@label="chat.channel_settings.delete_channel"
|
||||||
|
@icon="trash-alt"
|
||||||
|
class="delete-btn chat-form__btn btn-flat"
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</form.section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<form.section as |section|>
|
||||||
|
<section.row>
|
||||||
|
<:action>
|
||||||
|
<ToggleChannelMembershipButton
|
||||||
|
@channel={{@channel}}
|
||||||
|
@options={{hash
|
||||||
|
joinClass="btn-primary"
|
||||||
|
leaveClass="btn-flat"
|
||||||
|
joinIcon="sign-in-alt"
|
||||||
|
leaveIcon="sign-out-alt"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</:action>
|
||||||
|
</section.row>
|
||||||
|
</form.section>
|
||||||
|
</ChatForm>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,91 @@ const REDUCED = "reduced";
|
||||||
const REDUCED_WIDTH_THRESHOLD = 500;
|
const REDUCED_WIDTH_THRESHOLD = 500;
|
||||||
|
|
||||||
export default class ChatMessageActionsDesktop extends Component {
|
export default class ChatMessageActionsDesktop extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatEmojiPickerManager;
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
@tracked size = FULL;
|
||||||
|
|
||||||
|
popper = null;
|
||||||
|
|
||||||
|
get message() {
|
||||||
|
return this.chat.activeMessage.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
get context() {
|
||||||
|
return this.chat.activeMessage.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
get messageInteractor() {
|
||||||
|
return new ChatMessageInteractor(
|
||||||
|
getOwner(this),
|
||||||
|
this.message,
|
||||||
|
this.context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get shouldRenderFavoriteReactions() {
|
||||||
|
return this.size === FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onWheel() {
|
||||||
|
// prevents menu to stop scroll on the list of messages
|
||||||
|
this.chat.activeMessage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setup(element) {
|
||||||
|
this.popper?.destroy();
|
||||||
|
|
||||||
|
schedule("afterRender", () => {
|
||||||
|
const messageContainer = chatMessageContainer(
|
||||||
|
this.message.id,
|
||||||
|
this.context
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!messageContainer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewport = messageContainer.closest(".popper-viewport");
|
||||||
|
this.size =
|
||||||
|
viewport.clientWidth < REDUCED_WIDTH_THRESHOLD ? REDUCED : FULL;
|
||||||
|
|
||||||
|
if (!messageContainer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.popper = createPopper(messageContainer, element, {
|
||||||
|
placement: "top-end",
|
||||||
|
strategy: "fixed",
|
||||||
|
modifiers: [
|
||||||
|
{
|
||||||
|
name: "flip",
|
||||||
|
enabled: true,
|
||||||
|
options: {
|
||||||
|
boundary: viewport,
|
||||||
|
fallbackPlacements: ["bottom-end"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ name: "hide", enabled: true },
|
||||||
|
{ name: "eventListeners", options: { scroll: false } },
|
||||||
|
{
|
||||||
|
name: "offset",
|
||||||
|
options: { offset: [-2, MSG_ACTIONS_VERTICAL_PADDING] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
teardown() {
|
||||||
|
this.popper?.destroy();
|
||||||
|
this.popper = null;
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
{{#if (and this.site.desktopView this.chat.activeMessage.model.persisted)}}
|
{{#if (and this.site.desktopView this.chat.activeMessage.model.persisted)}}
|
||||||
|
@ -112,89 +197,4 @@ export default class ChatMessageActionsDesktop extends Component {
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service chat;
|
|
||||||
@service chatEmojiPickerManager;
|
|
||||||
@service site;
|
|
||||||
|
|
||||||
@tracked size = FULL;
|
|
||||||
|
|
||||||
popper = null;
|
|
||||||
|
|
||||||
get message() {
|
|
||||||
return this.chat.activeMessage.model;
|
|
||||||
}
|
|
||||||
|
|
||||||
get context() {
|
|
||||||
return this.chat.activeMessage.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
get messageInteractor() {
|
|
||||||
return new ChatMessageInteractor(
|
|
||||||
getOwner(this),
|
|
||||||
this.message,
|
|
||||||
this.context
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get shouldRenderFavoriteReactions() {
|
|
||||||
return this.size === FULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
onWheel() {
|
|
||||||
// prevents menu to stop scroll on the list of messages
|
|
||||||
this.chat.activeMessage = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
setup(element) {
|
|
||||||
this.popper?.destroy();
|
|
||||||
|
|
||||||
schedule("afterRender", () => {
|
|
||||||
const messageContainer = chatMessageContainer(
|
|
||||||
this.message.id,
|
|
||||||
this.context
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!messageContainer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewport = messageContainer.closest(".popper-viewport");
|
|
||||||
this.size =
|
|
||||||
viewport.clientWidth < REDUCED_WIDTH_THRESHOLD ? REDUCED : FULL;
|
|
||||||
|
|
||||||
if (!messageContainer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.popper = createPopper(messageContainer, element, {
|
|
||||||
placement: "top-end",
|
|
||||||
strategy: "fixed",
|
|
||||||
modifiers: [
|
|
||||||
{
|
|
||||||
name: "flip",
|
|
||||||
enabled: true,
|
|
||||||
options: {
|
|
||||||
boundary: viewport,
|
|
||||||
fallbackPlacements: ["bottom-end"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ name: "hide", enabled: true },
|
|
||||||
{ name: "eventListeners", options: { scroll: false } },
|
|
||||||
{
|
|
||||||
name: "offset",
|
|
||||||
options: { offset: [-2, MSG_ACTIONS_VERTICAL_PADDING] },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
teardown() {
|
|
||||||
this.popper?.destroy();
|
|
||||||
this.popper = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,86 @@ import or from "truth-helpers/helpers/or";
|
||||||
import BookmarkIcon from "discourse/components/bookmark-icon";
|
import BookmarkIcon from "discourse/components/bookmark-icon";
|
||||||
|
|
||||||
export default class ChatMessageActionsMobile extends Component {
|
export default class ChatMessageActionsMobile extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service site;
|
||||||
|
@service capabilities;
|
||||||
|
|
||||||
|
@tracked hasExpandedReply = false;
|
||||||
|
@tracked showFadeIn = false;
|
||||||
|
|
||||||
|
get message() {
|
||||||
|
return this.chat.activeMessage.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
get context() {
|
||||||
|
return this.chat.activeMessage.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
get messageInteractor() {
|
||||||
|
return new ChatMessageInteractor(
|
||||||
|
getOwner(this),
|
||||||
|
this.message,
|
||||||
|
this.context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
fadeAndVibrate() {
|
||||||
|
discourseLater(this.#addFadeIn.bind(this));
|
||||||
|
|
||||||
|
if (this.capabilities.userHasBeenActive && this.capabilities.canVibrate) {
|
||||||
|
navigator.vibrate(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
expandReply(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.hasExpandedReply = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
collapseMenu(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.#onCloseMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
actAndCloseMenu(fnId) {
|
||||||
|
this.messageInteractor[fnId]();
|
||||||
|
this.#onCloseMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
openEmojiPicker(_, event) {
|
||||||
|
this.messageInteractor.openEmojiPicker(_, event);
|
||||||
|
this.#onCloseMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
#onCloseMenu() {
|
||||||
|
this.#removeFadeIn();
|
||||||
|
|
||||||
|
// we don't want to remove the component right away as it's animating
|
||||||
|
// 200 is equal to the duration of the css animation
|
||||||
|
discourseLater(() => {
|
||||||
|
if (this.isDestroying || this.isDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// by ensuring we are not hovering any message anymore
|
||||||
|
// we also ensure the menu is fully removed
|
||||||
|
this.chat.activeMessage = null;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addFadeIn() {
|
||||||
|
this.showFadeIn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#removeFadeIn() {
|
||||||
|
this.showFadeIn = false;
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
{{#if (and this.site.mobileView this.chat.activeMessage.model.persisted)}}
|
{{#if (and this.site.mobileView this.chat.activeMessage.model.persisted)}}
|
||||||
|
@ -113,84 +193,4 @@ export default class ChatMessageActionsMobile extends Component {
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@service chat;
|
|
||||||
@service site;
|
|
||||||
@service capabilities;
|
|
||||||
|
|
||||||
@tracked hasExpandedReply = false;
|
|
||||||
@tracked showFadeIn = false;
|
|
||||||
|
|
||||||
get message() {
|
|
||||||
return this.chat.activeMessage.model;
|
|
||||||
}
|
|
||||||
|
|
||||||
get context() {
|
|
||||||
return this.chat.activeMessage.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
get messageInteractor() {
|
|
||||||
return new ChatMessageInteractor(
|
|
||||||
getOwner(this),
|
|
||||||
this.message,
|
|
||||||
this.context
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
fadeAndVibrate() {
|
|
||||||
discourseLater(this.#addFadeIn.bind(this));
|
|
||||||
|
|
||||||
if (this.capabilities.userHasBeenActive && this.capabilities.canVibrate) {
|
|
||||||
navigator.vibrate(5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
expandReply(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.hasExpandedReply = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
collapseMenu(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.#onCloseMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
actAndCloseMenu(fnId) {
|
|
||||||
this.messageInteractor[fnId]();
|
|
||||||
this.#onCloseMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
openEmojiPicker(_, event) {
|
|
||||||
this.messageInteractor.openEmojiPicker(_, event);
|
|
||||||
this.#onCloseMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
#onCloseMenu() {
|
|
||||||
this.#removeFadeIn();
|
|
||||||
|
|
||||||
// we don't want to remove the component right away as it's animating
|
|
||||||
// 200 is equal to the duration of the css animation
|
|
||||||
discourseLater(() => {
|
|
||||||
if (this.isDestroying || this.isDestroyed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// by ensuring we are not hovering any message anymore
|
|
||||||
// we also ensure the menu is fully removed
|
|
||||||
this.chat.activeMessage = null;
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
#addFadeIn() {
|
|
||||||
this.showFadeIn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#removeFadeIn() {
|
|
||||||
this.showFadeIn = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,38 +11,6 @@ import and from "truth-helpers/helpers/and";
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
|
||||||
export default class ChatMessageReaction extends Component {
|
export default class ChatMessageReaction extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
{{#if (and @reaction this.emojiUrl)}}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
tabindex="0"
|
|
||||||
class={{concatClass
|
|
||||||
"chat-message-reaction"
|
|
||||||
(if @reaction.reacted "reacted")
|
|
||||||
(if this.isActive "-active")
|
|
||||||
}}
|
|
||||||
data-emoji-name={{@reaction.emoji}}
|
|
||||||
title={{this.emojiString}}
|
|
||||||
{{on "click" this.handleClick passive=true}}
|
|
||||||
{{this.registerTooltip}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
loading="lazy"
|
|
||||||
class="emoji"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
alt={{this.emojiString}}
|
|
||||||
src={{this.emojiUrl}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{{#if (and this.showCount @reaction.count)}}
|
|
||||||
<span class="count">{{@reaction.count}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service capabilities;
|
@service capabilities;
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service tooltip;
|
@service tooltip;
|
||||||
|
@ -101,4 +69,36 @@ export default class ChatMessageReaction extends Component {
|
||||||
|
|
||||||
return emojiUnescape(getReactionText(this.args.reaction, this.currentUser));
|
return emojiUnescape(getReactionText(this.args.reaction, this.currentUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
{{#if (and @reaction this.emojiUrl)}}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
tabindex="0"
|
||||||
|
class={{concatClass
|
||||||
|
"chat-message-reaction"
|
||||||
|
(if @reaction.reacted "reacted")
|
||||||
|
(if this.isActive "-active")
|
||||||
|
}}
|
||||||
|
data-emoji-name={{@reaction.emoji}}
|
||||||
|
title={{this.emojiString}}
|
||||||
|
{{on "click" this.handleClick passive=true}}
|
||||||
|
{{this.registerTooltip}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
loading="lazy"
|
||||||
|
class="emoji"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
alt={{this.emojiString}}
|
||||||
|
src={{this.emojiUrl}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{#if (and this.showCount @reaction.count)}}
|
||||||
|
<span class="count">{{@reaction.count}}</span>
|
||||||
|
{{/if}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,140 +48,6 @@ export const MENTION_KEYWORDS = ["here", "all"];
|
||||||
export const MESSAGE_CONTEXT_THREAD = "thread";
|
export const MESSAGE_CONTEXT_THREAD = "thread";
|
||||||
|
|
||||||
export default class ChatMessage extends Component {
|
export default class ChatMessage extends Component {
|
||||||
<template>
|
|
||||||
{{! template-lint-disable no-invalid-interactive }}
|
|
||||||
{{! template-lint-disable modifier-name-case }}
|
|
||||||
{{#if this.shouldRender}}
|
|
||||||
{{#if (eq @context "channel")}}
|
|
||||||
<ChatMessageSeparatorDate
|
|
||||||
@fetchMessagesByDate={{@fetchMessagesByDate}}
|
|
||||||
@message={{@message}}
|
|
||||||
/>
|
|
||||||
<ChatMessageSeparatorNew @message={{@message}} />
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div
|
|
||||||
class={{concatClass
|
|
||||||
"chat-message-container"
|
|
||||||
(if this.pane.selectingMessages "-selectable")
|
|
||||||
(if @message.highlighted "-highlighted")
|
|
||||||
(if (eq @message.user.id this.currentUser.id) "is-by-current-user")
|
|
||||||
(if @message.staged "-staged" "-persisted")
|
|
||||||
(if this.hasActiveState "-active")
|
|
||||||
(if @message.bookmark "-bookmarked")
|
|
||||||
(if @message.deletedAt "-deleted")
|
|
||||||
(if @message.selected "-selected")
|
|
||||||
(if @message.error "-errored")
|
|
||||||
(if this.showThreadIndicator "has-thread-indicator")
|
|
||||||
(if this.hideUserInfo "-user-info-hidden")
|
|
||||||
(if this.hasReply "has-reply")
|
|
||||||
}}
|
|
||||||
data-id={{@message.id}}
|
|
||||||
data-thread-id={{@message.thread.id}}
|
|
||||||
{{didInsert this.didInsertMessage}}
|
|
||||||
{{didUpdate this.didUpdateMessageId @message.id}}
|
|
||||||
{{didUpdate this.didUpdateMessageVersion @message.version}}
|
|
||||||
{{willDestroy this.willDestroyMessage}}
|
|
||||||
{{on "mouseenter" this.onMouseEnter passive=true}}
|
|
||||||
{{on "mouseleave" this.onMouseLeave passive=true}}
|
|
||||||
{{on "mousemove" this.onMouseMove passive=true}}
|
|
||||||
{{this.toggleCheckIfPossible}}
|
|
||||||
{{ChatOnLongPress
|
|
||||||
this.onLongPressStart
|
|
||||||
this.onLongPressEnd
|
|
||||||
this.onLongPressCancel
|
|
||||||
}}
|
|
||||||
...attributes
|
|
||||||
>
|
|
||||||
{{#if this.show}}
|
|
||||||
{{#if this.pane.selectingMessages}}
|
|
||||||
<Input
|
|
||||||
@type="checkbox"
|
|
||||||
class="chat-message-selector"
|
|
||||||
@checked={{@message.selected}}
|
|
||||||
{{on "click" this.toggleChecked}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.deletedAndCollapsed}}
|
|
||||||
<div class="chat-message-text -deleted">
|
|
||||||
<DButton
|
|
||||||
@action={{this.expand}}
|
|
||||||
@translatedLabel={{this.deletedMessageLabel}}
|
|
||||||
class="btn-flat chat-message-expand"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{{else if this.hiddenAndCollapsed}}
|
|
||||||
<div class="chat-message-text -hidden">
|
|
||||||
<DButton
|
|
||||||
@action={{this.expand}}
|
|
||||||
@label="chat.hidden"
|
|
||||||
class="btn-flat chat-message-expand"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<div class="chat-message">
|
|
||||||
{{#unless this.hideReplyToInfo}}
|
|
||||||
<ChatMessageInReplyToIndicator @message={{@message}} />
|
|
||||||
{{/unless}}
|
|
||||||
|
|
||||||
{{#if this.hideUserInfo}}
|
|
||||||
<ChatMessageLeftGutter @message={{@message}} />
|
|
||||||
{{else}}
|
|
||||||
<ChatMessageAvatar @message={{@message}} />
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="chat-message-content">
|
|
||||||
<ChatMessageInfo
|
|
||||||
@message={{@message}}
|
|
||||||
@show={{not this.hideUserInfo}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ChatMessageText
|
|
||||||
@cooked={{@message.cooked}}
|
|
||||||
@uploads={{@message.uploads}}
|
|
||||||
@edited={{@message.edited}}
|
|
||||||
>
|
|
||||||
{{#if @message.reactions.length}}
|
|
||||||
<div class="chat-message-reaction-list">
|
|
||||||
{{#each @message.reactions as |reaction|}}
|
|
||||||
<ChatMessageReaction
|
|
||||||
@reaction={{reaction}}
|
|
||||||
@onReaction={{this.messageInteractor.react}}
|
|
||||||
@message={{@message}}
|
|
||||||
@showTooltip={{true}}
|
|
||||||
/>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
{{#if this.shouldRenderOpenEmojiPickerButton}}
|
|
||||||
<DButton
|
|
||||||
@action={{this.messageInteractor.openEmojiPicker}}
|
|
||||||
@icon="discourse-emojis"
|
|
||||||
@title="chat.react"
|
|
||||||
@forwardEvent={{true}}
|
|
||||||
class="chat-message-react-btn"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</ChatMessageText>
|
|
||||||
|
|
||||||
<ChatMessageError
|
|
||||||
@message={{@message}}
|
|
||||||
@onRetry={{@resendStagedMessage}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if this.showThreadIndicator}}
|
|
||||||
<ChatMessageThreadIndicator @message={{@message}} />
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service site;
|
@service site;
|
||||||
@service dialog;
|
@service dialog;
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
|
@ -624,4 +490,138 @@ export default class ChatMessage extends Component {
|
||||||
user.off("status-changed", this, "refreshStatusOnMentions");
|
user.off("status-changed", this, "refreshStatusOnMentions");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable no-invalid-interactive }}
|
||||||
|
{{! template-lint-disable modifier-name-case }}
|
||||||
|
{{#if this.shouldRender}}
|
||||||
|
{{#if (eq @context "channel")}}
|
||||||
|
<ChatMessageSeparatorDate
|
||||||
|
@fetchMessagesByDate={{@fetchMessagesByDate}}
|
||||||
|
@message={{@message}}
|
||||||
|
/>
|
||||||
|
<ChatMessageSeparatorNew @message={{@message}} />
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={{concatClass
|
||||||
|
"chat-message-container"
|
||||||
|
(if this.pane.selectingMessages "-selectable")
|
||||||
|
(if @message.highlighted "-highlighted")
|
||||||
|
(if (eq @message.user.id this.currentUser.id) "is-by-current-user")
|
||||||
|
(if @message.staged "-staged" "-persisted")
|
||||||
|
(if this.hasActiveState "-active")
|
||||||
|
(if @message.bookmark "-bookmarked")
|
||||||
|
(if @message.deletedAt "-deleted")
|
||||||
|
(if @message.selected "-selected")
|
||||||
|
(if @message.error "-errored")
|
||||||
|
(if this.showThreadIndicator "has-thread-indicator")
|
||||||
|
(if this.hideUserInfo "-user-info-hidden")
|
||||||
|
(if this.hasReply "has-reply")
|
||||||
|
}}
|
||||||
|
data-id={{@message.id}}
|
||||||
|
data-thread-id={{@message.thread.id}}
|
||||||
|
{{didInsert this.didInsertMessage}}
|
||||||
|
{{didUpdate this.didUpdateMessageId @message.id}}
|
||||||
|
{{didUpdate this.didUpdateMessageVersion @message.version}}
|
||||||
|
{{willDestroy this.willDestroyMessage}}
|
||||||
|
{{on "mouseenter" this.onMouseEnter passive=true}}
|
||||||
|
{{on "mouseleave" this.onMouseLeave passive=true}}
|
||||||
|
{{on "mousemove" this.onMouseMove passive=true}}
|
||||||
|
{{this.toggleCheckIfPossible}}
|
||||||
|
{{ChatOnLongPress
|
||||||
|
this.onLongPressStart
|
||||||
|
this.onLongPressEnd
|
||||||
|
this.onLongPressCancel
|
||||||
|
}}
|
||||||
|
...attributes
|
||||||
|
>
|
||||||
|
{{#if this.show}}
|
||||||
|
{{#if this.pane.selectingMessages}}
|
||||||
|
<Input
|
||||||
|
@type="checkbox"
|
||||||
|
class="chat-message-selector"
|
||||||
|
@checked={{@message.selected}}
|
||||||
|
{{on "click" this.toggleChecked}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.deletedAndCollapsed}}
|
||||||
|
<div class="chat-message-text -deleted">
|
||||||
|
<DButton
|
||||||
|
@action={{this.expand}}
|
||||||
|
@translatedLabel={{this.deletedMessageLabel}}
|
||||||
|
class="btn-flat chat-message-expand"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{{else if this.hiddenAndCollapsed}}
|
||||||
|
<div class="chat-message-text -hidden">
|
||||||
|
<DButton
|
||||||
|
@action={{this.expand}}
|
||||||
|
@label="chat.hidden"
|
||||||
|
class="btn-flat chat-message-expand"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="chat-message">
|
||||||
|
{{#unless this.hideReplyToInfo}}
|
||||||
|
<ChatMessageInReplyToIndicator @message={{@message}} />
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
|
{{#if this.hideUserInfo}}
|
||||||
|
<ChatMessageLeftGutter @message={{@message}} />
|
||||||
|
{{else}}
|
||||||
|
<ChatMessageAvatar @message={{@message}} />
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="chat-message-content">
|
||||||
|
<ChatMessageInfo
|
||||||
|
@message={{@message}}
|
||||||
|
@show={{not this.hideUserInfo}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ChatMessageText
|
||||||
|
@cooked={{@message.cooked}}
|
||||||
|
@uploads={{@message.uploads}}
|
||||||
|
@edited={{@message.edited}}
|
||||||
|
>
|
||||||
|
{{#if @message.reactions.length}}
|
||||||
|
<div class="chat-message-reaction-list">
|
||||||
|
{{#each @message.reactions as |reaction|}}
|
||||||
|
<ChatMessageReaction
|
||||||
|
@reaction={{reaction}}
|
||||||
|
@onReaction={{this.messageInteractor.react}}
|
||||||
|
@message={{@message}}
|
||||||
|
@showTooltip={{true}}
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if this.shouldRenderOpenEmojiPickerButton}}
|
||||||
|
<DButton
|
||||||
|
@action={{this.messageInteractor.openEmojiPicker}}
|
||||||
|
@icon="discourse-emojis"
|
||||||
|
@title="chat.react"
|
||||||
|
@forwardEvent={{true}}
|
||||||
|
class="chat-message-react-btn"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</ChatMessageText>
|
||||||
|
|
||||||
|
<ChatMessageError
|
||||||
|
@message={{@message}}
|
||||||
|
@onRetry={{@resendStagedMessage}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if this.showThreadIndicator}}
|
||||||
|
<ChatMessageThreadIndicator @message={{@message}} />
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,6 @@ import I18n from "I18n";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
export default class ChatRetentionReminderText extends Component {
|
export default class ChatRetentionReminderText extends Component {
|
||||||
<template>
|
|
||||||
<span class="chat-retention-reminder-text">
|
|
||||||
{{this.text}}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
|
|
||||||
get text() {
|
get text() {
|
||||||
|
@ -36,4 +30,10 @@ export default class ChatRetentionReminderText extends Component {
|
||||||
? this.siteSettings.chat_dm_retention_days
|
? this.siteSettings.chat_dm_retention_days
|
||||||
: this.siteSettings.chat_channel_retention_days;
|
: this.siteSettings.chat_channel_retention_days;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="chat-retention-reminder-text">
|
||||||
|
{{this.text}}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,25 +5,6 @@ import { htmlSafe } from "@ember/template";
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
|
||||||
export default class ChatUserAvatar extends Component {
|
export default class ChatUserAvatar extends Component {
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
class={{concatClass "chat-user-avatar" (if this.isOnline "is-online")}}
|
|
||||||
data-username={{@user.username}}
|
|
||||||
>
|
|
||||||
{{#if this.interactive}}
|
|
||||||
<div
|
|
||||||
role="button"
|
|
||||||
class="chat-user-avatar__container clickable"
|
|
||||||
data-user-card={{@user.username}}
|
|
||||||
>
|
|
||||||
{{this.avatar}}
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
{{this.avatar}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service chat;
|
@service chat;
|
||||||
|
|
||||||
get avatar() {
|
get avatar() {
|
||||||
|
@ -55,4 +36,23 @@ export default class ChatUserAvatar extends Component {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class={{concatClass "chat-user-avatar" (if this.isOnline "is-online")}}
|
||||||
|
data-username={{@user.username}}
|
||||||
|
>
|
||||||
|
{{#if this.interactive}}
|
||||||
|
<div
|
||||||
|
role="button"
|
||||||
|
class="chat-user-avatar__container clickable"
|
||||||
|
data-user-card={{@user.username}}
|
||||||
|
>
|
||||||
|
{{this.avatar}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{this.avatar}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@ import Component from "@glimmer/component";
|
||||||
import ChatFormRow from "discourse/plugins/chat/discourse/components/chat/form/row";
|
import ChatFormRow from "discourse/plugins/chat/discourse/components/chat/form/row";
|
||||||
|
|
||||||
export default class ChatFormSection extends Component {
|
export default class ChatFormSection extends Component {
|
||||||
|
get yieldableArgs() {
|
||||||
|
return { row: ChatFormRow };
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-form__section" ...attributes>
|
<div class="chat-form__section" ...attributes>
|
||||||
{{#if @title}}
|
{{#if @title}}
|
||||||
|
@ -15,8 +19,4 @@ export default class ChatFormSection extends Component {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
get yieldableArgs() {
|
|
||||||
return { row: ChatFormRow };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,24 +8,6 @@ import concatClass from "discourse/helpers/concat-class";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default class ChatHeaderIcon extends Component {
|
export default class ChatHeaderIcon extends Component {
|
||||||
<template>
|
|
||||||
<a
|
|
||||||
href={{this.href}}
|
|
||||||
tabindex="0"
|
|
||||||
class={{concatClass "icon" "btn-flat" (if this.isActive "active")}}
|
|
||||||
title={{this.title}}
|
|
||||||
>
|
|
||||||
{{~icon this.icon~}}
|
|
||||||
{{#if this.showUnreadIndicator}}
|
|
||||||
<ChatHeaderIconUnreadIndicator
|
|
||||||
@urgentCount={{@urgentCount}}
|
|
||||||
@unreadCount={{@unreadCount}}
|
|
||||||
@indicatorPreference={{@indicatorPreference}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service site;
|
@service site;
|
||||||
@service chatStateManager;
|
@service chatStateManager;
|
||||||
|
@ -96,4 +78,22 @@ export default class ChatHeaderIcon extends Component {
|
||||||
|
|
||||||
return getURL(this.chatStateManager.lastKnownChatURL || "/chat");
|
return getURL(this.chatStateManager.lastKnownChatURL || "/chat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
href={{this.href}}
|
||||||
|
tabindex="0"
|
||||||
|
class={{concatClass "icon" "btn-flat" (if this.isActive "active")}}
|
||||||
|
title={{this.title}}
|
||||||
|
>
|
||||||
|
{{~icon this.icon~}}
|
||||||
|
{{#if this.showUnreadIndicator}}
|
||||||
|
<ChatHeaderIconUnreadIndicator
|
||||||
|
@urgentCount={{@urgentCount}}
|
||||||
|
@unreadCount={{@unreadCount}}
|
||||||
|
@indicatorPreference={{@indicatorPreference}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,6 @@ import {
|
||||||
const MAX_UNREAD_COUNT = 99;
|
const MAX_UNREAD_COUNT = 99;
|
||||||
|
|
||||||
export default class ChatHeaderIconUnreadIndicator extends Component {
|
export default class ChatHeaderIconUnreadIndicator extends Component {
|
||||||
<template>
|
|
||||||
{{#if this.showUrgentIndicator}}
|
|
||||||
<div class="chat-channel-unread-indicator -urgent">
|
|
||||||
<div class="chat-channel-unread-indicator__number">
|
|
||||||
{{this.unreadCountLabel}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{else if this.showUnreadIndicator}}
|
|
||||||
<div class="chat-channel-unread-indicator"></div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service chatTrackingStateManager;
|
@service chatTrackingStateManager;
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
|
|
||||||
|
@ -78,4 +66,16 @@ export default class ChatHeaderIconUnreadIndicator extends Component {
|
||||||
|
|
||||||
return preferences.includes(this.indicatorPreference);
|
return preferences.includes(this.indicatorPreference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.showUrgentIndicator}}
|
||||||
|
<div class="chat-channel-unread-indicator -urgent">
|
||||||
|
<div class="chat-channel-unread-indicator__number">
|
||||||
|
{{this.unreadCountLabel}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else if this.showUnreadIndicator}}
|
||||||
|
<div class="chat-channel-unread-indicator"></div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,49 +12,6 @@ import not from "truth-helpers/helpers/not";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default class ChatSelectionManager extends Component {
|
export default class ChatSelectionManager extends Component {
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
class="chat-selection-management"
|
|
||||||
data-last-copy-successful={{this.lastCopySuccessful}}
|
|
||||||
>
|
|
||||||
<div class="chat-selection-management__buttons">
|
|
||||||
<DButton
|
|
||||||
@icon="quote-left"
|
|
||||||
@label="chat.selection.quote_selection"
|
|
||||||
@disabled={{not this.anyMessagesSelected}}
|
|
||||||
@action={{this.quoteMessages}}
|
|
||||||
id="chat-quote-btn"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DButton
|
|
||||||
@icon="copy"
|
|
||||||
@label="chat.selection.copy"
|
|
||||||
@disabled={{not this.anyMessagesSelected}}
|
|
||||||
@action={{this.copyMessages}}
|
|
||||||
id="chat-copy-btn"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{{#if this.enableMove}}
|
|
||||||
<DButton
|
|
||||||
@icon="sign-out-alt"
|
|
||||||
@label="chat.selection.move_selection_to_channel"
|
|
||||||
@disabled={{not this.anyMessagesSelected}}
|
|
||||||
@action={{this.openMoveMessageModal}}
|
|
||||||
id="chat-move-to-channel-btn"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<DButton
|
|
||||||
@icon="times"
|
|
||||||
@label="chat.selection.cancel"
|
|
||||||
@action={{@pane.cancelSelecting}}
|
|
||||||
id="chat-cancel-selection-btn"
|
|
||||||
class="btn-secondary cancel-btn"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@service("composer") topicComposer;
|
@service("composer") topicComposer;
|
||||||
@service router;
|
@service router;
|
||||||
@service modal;
|
@service modal;
|
||||||
|
@ -150,4 +107,47 @@ export default class ChatSelectionManager extends Component {
|
||||||
popupAjaxError(error);
|
popupAjaxError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="chat-selection-management"
|
||||||
|
data-last-copy-successful={{this.lastCopySuccessful}}
|
||||||
|
>
|
||||||
|
<div class="chat-selection-management__buttons">
|
||||||
|
<DButton
|
||||||
|
@icon="quote-left"
|
||||||
|
@label="chat.selection.quote_selection"
|
||||||
|
@disabled={{not this.anyMessagesSelected}}
|
||||||
|
@action={{this.quoteMessages}}
|
||||||
|
id="chat-quote-btn"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@icon="copy"
|
||||||
|
@label="chat.selection.copy"
|
||||||
|
@disabled={{not this.anyMessagesSelected}}
|
||||||
|
@action={{this.copyMessages}}
|
||||||
|
id="chat-copy-btn"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{#if this.enableMove}}
|
||||||
|
<DButton
|
||||||
|
@icon="sign-out-alt"
|
||||||
|
@label="chat.selection.move_selection_to_channel"
|
||||||
|
@disabled={{not this.anyMessagesSelected}}
|
||||||
|
@action={{this.openMoveMessageModal}}
|
||||||
|
id="chat-move-to-channel-btn"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@icon="times"
|
||||||
|
@label="chat.selection.cancel"
|
||||||
|
@action={{@pane.cancelSelecting}}
|
||||||
|
id="chat-cancel-selection-btn"
|
||||||
|
class="btn-secondary cancel-btn"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,25 @@ import { modifier } from "ember-modifier";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
|
||||||
export default class DcFilterInput extends Component {
|
export default class DcFilterInput extends Component {
|
||||||
|
@tracked isFocused = false;
|
||||||
|
|
||||||
|
focusState = modifier((element) => {
|
||||||
|
const focusInHandler = () => {
|
||||||
|
this.isFocused = true;
|
||||||
|
};
|
||||||
|
const focusOutHandler = () => {
|
||||||
|
this.isFocused = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
element.addEventListener("focusin", focusInHandler);
|
||||||
|
element.addEventListener("focusout", focusOutHandler);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
element.removeEventListener("focusin", focusInHandler);
|
||||||
|
element.removeEventListener("focusout", focusOutHandler);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
{{! template-lint-disable modifier-name-case }}
|
{{! template-lint-disable modifier-name-case }}
|
||||||
<div
|
<div
|
||||||
|
@ -36,23 +55,4 @@ export default class DcFilterInput extends Component {
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@tracked isFocused = false;
|
|
||||||
|
|
||||||
focusState = modifier((element) => {
|
|
||||||
const focusInHandler = () => {
|
|
||||||
this.isFocused = true;
|
|
||||||
};
|
|
||||||
const focusOutHandler = () => {
|
|
||||||
this.isFocused = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
element.addEventListener("focusin", focusInHandler);
|
|
||||||
element.addEventListener("focusout", focusOutHandler);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
element.removeEventListener("focusin", focusInHandler);
|
|
||||||
element.removeEventListener("focusout", focusOutHandler);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue