diff --git a/client/@types/global.d.ts b/client/@types/global.d.ts index d76c493e..c5a0f177 100644 --- a/client/@types/global.d.ts +++ b/client/@types/global.d.ts @@ -61,6 +61,8 @@ declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_LABEL: s declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_DESC: string declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_LABEL: string declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_DESC: string +declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL_LABEL: string +declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL_DESC: string declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_COMMENTS_LABEL: string declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_COMMENTS_DESC: string declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_COMMAND_LABEL: string diff --git a/client/common/configuration/register.ts b/client/common/configuration/register.ts index f408a07c..d3b09cf5 100644 --- a/client/common/configuration/register.ts +++ b/client/common/configuration/register.ts @@ -4,8 +4,8 @@ import type { RegisterClientOptions } from '@peertube/peertube-types/client' import { renderConfigurationHome } from './templates/home' -import { renderConfigurationChannel } from './templates/channel' -import { render } from 'lit' +import './templates/ChannelConfigurationElement' +import { html, render } from 'lit' /** * Registers stuff related to the user's configuration pages. @@ -29,7 +29,7 @@ async function registerConfiguration (clientOptions: RegisterClientOptions): Pro onMount: async ({ rootEl }) => { const urlParams = new URLSearchParams(window.location.search) const channelId = urlParams.get('channelId') ?? '' - render(await renderConfigurationChannel(clientOptions, channelId, rootEl), rootEl) + render(html``, rootEl) } }) diff --git a/client/common/configuration/templates/ChannelConfigurationElement.ts b/client/common/configuration/templates/ChannelConfigurationElement.ts index 9343ef6d..1cc5ea95 100644 --- a/client/common/configuration/templates/ChannelConfigurationElement.ts +++ b/client/common/configuration/templates/ChannelConfigurationElement.ts @@ -1,42 +1,146 @@ +import { RegisterClientOptions } from '@peertube/peertube-types/client' import { html, LitElement } from 'lit' import { repeat } from 'lit-html/directives/repeat.js' import { customElement, property } from 'lit/decorators.js' +import { ptTr } from './TranslationDirective' +import { localizedHelpUrl } from '../../../utils/help' +import './DynamicTableFormElement' +import './PluginConfigurationRow' +import { until } from 'async' +import { Task } from '@lit/task'; @customElement('channel-configuration') export class ChannelConfigurationElement extends LitElement { - @property() - public list: string[] = ["foo", "bar", "baz"] - - @property() - public newEl: string = 'change_me' + @property({ attribute: false }) + public registerClientOptions: RegisterClientOptions | undefined createRenderRoot = () => { return this } - render() { - return html` - - ` - } + private _asyncTaskRender = new Task(this, { - private _addToList(newEl: string) { - return () => { - this.list.push(newEl) - this.requestUpdate('list') - } - } + task: async ([registerClientOptions], {signal}) => { + let link = registerClientOptions ? await localizedHelpUrl(registerClientOptions, { page: 'documentation/user/streamers/bot/forbidden_words' }) : ''; - private _removeFromList(index: number) { - return () => { - this.list.splice(index, 1) - this.requestUpdate('list') + return { + url : new URL(link), + title: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC) + } + }, + + args: () => [this.registerClientOptions] + + }); + + render = () => { + let tableHeader = { + words: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC2) + }, + regex: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_DESC) + }, + applyToModerators: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_DESC) + }, + label: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL_DESC) + }, + reason: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_DESC) + }, + comments: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_COMMENTS_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_COMMENTS_DESC) + } } + let tableSchema = { + words: { + inputType: 'text', + default: 'helloqwesad' + }, + regex: { + inputType: 'text', + default: 'helloaxzca' + }, + applyToModerators: { + inputType: 'checkbox', + default: true + }, + label: { + inputType: 'text', + default: 'helloasx' + }, + reason: { + inputType: 'select', + default: 'transphobia', + label: 'choose your poison', + options: {'racism': 'Racism', 'sexism': 'Sexism', 'transphobia': 'Transphobia', 'bigotry': 'Bigotry'} + }, + comments: { + inputType: 'textarea', + default: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in + culpa qui officia deserunt mollit anim id est laborum.` + }, + } + let tableRows = [ + { + words: 'teweqwst', + regex: 'tesdgst', + applyToModerators: false, + label: 'teswet', + reason: 'sexism', + comments: 'tsdaswest', + }, + { + words: 'tedsadst', + regex: 'tezxccst', + applyToModerators: true, + label: 'tewest', + reason: 'racism', + comments: 'tesxzct', + }, + { + words: 'tesadsdxst', + regex: 'dsfsdf', + applyToModerators: false, + label: 'tesdadst', + reason: 'bigotry', + comments: 'tsadest', + }, + ] + + return this._asyncTaskRender.render({ + complete: (helpLink) => html` +
+ + + + + +
` + }) } } diff --git a/client/common/configuration/templates/DynamicTableFormElement.ts b/client/common/configuration/templates/DynamicTableFormElement.ts index 80c32cff..4b7bed0b 100644 --- a/client/common/configuration/templates/DynamicTableFormElement.ts +++ b/client/common/configuration/templates/DynamicTableFormElement.ts @@ -1,6 +1,9 @@ import { html, LitElement, TemplateResult } from 'lit' import { repeat } from 'lit/directives/repeat.js' import { customElement, property, state } from 'lit/decorators.js' +import { unsafeHTML } from 'lit/directives/unsafe-html.js' +import { ifDefined } from 'lit/directives/if-defined.js' +import { StaticValue, unsafeStatic } from 'lit/static-html.js' type DynamicTableAcceptedTypes = number | string | boolean | Date @@ -41,7 +44,7 @@ interface CellDataSchema { export class DynamicTableFormElement extends LitElement { @property({ attribute: false }) - public header: { [key : string]: TemplateResult<1> } = {} + public header: { [key : string]: { colName: TemplateResult, description: TemplateResult } } = {} @property({ attribute: false }) @@ -87,55 +90,51 @@ export class DynamicTableFormElement extends LitElement { render = () => { const inputId = `peertube-livechat-${this.formName.replaceAll('_','-')}-table` + for(let row of this.rows) { + if (!row._id) { + row._id = this._lastRowId++ + } + } return html` -
-
-

Bot command #1

-

You can configure the bot to respond to commands. A command is a message starting with a "!", like for example "!help" that calls the "help" command. For more information about how to configure this feature, please refer to the documentation by clicking on the help button.

- - - - - - -
-
- - ${this._renderHeader()} - - ${repeat(this.rows, this._renderDataRow)} - - - - -
-
-
- ${JSON.stringify(this.rows)} + + ${this._renderHeader()} + + ${repeat(this.rows,(row) => row._id, this._renderDataRow)} + + + + +
` } private _renderHeader = () => { - return html`#${Object.values(this.header).map(this._renderHeaderCell)}Remove Row` + return html` + + + ${Object.values(this.header).map(this._renderHeaderCell)} + Remove Row + + ` } - private _renderHeaderCell = (headerCellData: TemplateResult<1> | any) => { - return html`${headerCellData}` - + private _renderHeaderCell = (headerCellData: { colName: TemplateResult, description: TemplateResult }) => { + return html` +
${headerCellData.colName}
+ ` } private _renderDataRow = (rowData: { _id: number; [key : string]: DynamicTableAcceptedTypes }) => { - if (!rowData._id) { - rowData._id = this._lastRowId++ - - } - const inputId = `peertube-livechat-${this.formName.replaceAll('_','-')}-row-${rowData._id}` - return html`${rowData._id}${repeat(Object.entries(rowData).filter(([k,v]) => k != '_id'), (data) => this.renderDataCell(data, rowData._id))}` + return html` + + ${Object.entries(rowData).filter(([k,v]) => k != '_id').map((data) => this.renderDataCell(data, rowData._id))} + + ` } @@ -175,12 +174,12 @@ export class DynamicTableFormElement extends LitElement { name=${inputName} class="form-control" id=${inputId} - min=${propertySchema?.min} - max=${propertySchema?.max} - minlength=${propertySchema?.minlength} - maxlength=${propertySchema?.maxlength} - @oninput=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} - .value=${propertyValue} + min=${ifDefined(propertySchema?.min)} + max=${ifDefined(propertySchema?.max)} + minlength=${ifDefined(propertySchema?.minlength)} + maxlength=${ifDefined(propertySchema?.maxlength)} + @input=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} + .value=${propertyValue as string} />` break @@ -189,19 +188,26 @@ export class DynamicTableFormElement extends LitElement { name=${inputName} class="form-control" id=${inputId} - min=${propertySchema?.min} - max=${propertySchema?.max} - minlength=${propertySchema?.minlength} - maxlength=${propertySchema?.maxlength} - @oninput=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} - .value=${propertyValue} + min=${ifDefined(propertySchema?.min)} + max=${ifDefined(propertySchema?.max)} + minlength=${ifDefined(propertySchema?.minlength)} + maxlength=${ifDefined(propertySchema?.maxlength)} + @input=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} + .value=${propertyValue as string} >` break case 'select': - formElement = html` this._updatePropertyFromValue(event, propertyName, rowId)} + > - ${Object.entries(propertySchema?.options ?? {})?.map(([value,name]) => html``)} + ${Object.entries(propertySchema?.options ?? {}) + ?.map(([value,name]) => + html`` + )} ` break @@ -222,12 +228,12 @@ export class DynamicTableFormElement extends LitElement { name=${inputName} class="form-control" id=${inputId} - min=${propertySchema?.min} - max=${propertySchema?.max} - minlength=${propertySchema?.minlength} - maxlength=${propertySchema?.maxlength} - @oninput=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} - .value=${propertyValue} + min=${ifDefined(propertySchema?.min)} + max=${ifDefined(propertySchema?.max)} + minlength=${ifDefined(propertySchema?.minlength)} + maxlength=${ifDefined(propertySchema?.maxlength)} + @input=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} + .value=${(propertyValue as Date).toISOString()} />` break @@ -246,12 +252,12 @@ export class DynamicTableFormElement extends LitElement { name=${inputName} class="form-control" id=${inputId} - min=${propertySchema?.min} - max=${propertySchema?.max} - minlength=${propertySchema?.minlength} - maxlength=${propertySchema?.maxlength} - @oninput=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} - .value=${propertyValue} + min=${ifDefined(propertySchema?.min)} + max=${ifDefined(propertySchema?.max)} + minlength=${ifDefined(propertySchema?.minlength)} + maxlength=${ifDefined(propertySchema?.maxlength)} + @input=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} + .value=${propertyValue as String} />` break @@ -269,9 +275,9 @@ export class DynamicTableFormElement extends LitElement { name=${inputName} class="form-check-input" id=${inputId} - @oninput=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} - value="" - ?checked=${propertyValue} + @input=${(event: InputEvent) => this._updatePropertyFromValue(event, propertyName, rowId)} + .value=${propertyValue as String} + ?checked=${propertyValue as Boolean} />` break @@ -281,24 +287,26 @@ export class DynamicTableFormElement extends LitElement { } if (!formElement) { - console.warn(`value type '${propertyValue.constructor}' is incompatible with field type '${propertySchema.inputType}' for form entry '${propertyName.toString()}'.`) + console.warn(`value type '${propertyValue.constructor}' is incompatible` + + `with field type '${propertySchema.inputType}' for form entry '${propertyName.toString()}'.`) } - console.log - return html`${formElement}` } - _updatePropertyFromValue(event: InputEvent, propertyName: string, rowId : number) { + _updatePropertyFromValue(event: Event, propertyName: string, rowId : number) { let target = event?.target as (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) + let value = (target && target instanceof HTMLInputElement && target.type == "checkbox") ? !!(target?.checked) : target?.value - if(target?.value) { + if(value !== undefined) { for(let row of this.rows) { if(row._id === rowId) { - row[propertyName] = target?.value + row[propertyName] = value + + this.requestUpdate('rows') return } diff --git a/client/common/configuration/templates/PluginConfigurationRow.ts b/client/common/configuration/templates/PluginConfigurationRow.ts new file mode 100644 index 00000000..b275d21b --- /dev/null +++ b/client/common/configuration/templates/PluginConfigurationRow.ts @@ -0,0 +1,41 @@ +import { html, LitElement } from 'lit' +import { customElement, property } from 'lit/decorators.js' +import { unsafeSVG } from 'lit/directives/unsafe-svg.js' +import { StaticValue } from 'lit/static-html.js' +import { helpButtonSVG } from '../../../videowatch/buttons' + +@customElement('plugin-configuration-row') +export class PLuginConfigurationRow extends LitElement { + + @property({ attribute: false }) + public title: string = `title` + + @property({ attribute: false }) + public description: string = `Here's a description` + + @property({ attribute: false }) + public helpLink: { url: URL, title: string } = { url : new URL('https://lmddgtfy.net/'), title: 'Online Help'} + + createRenderRoot = () => { + return this + } + + render() { + return html` +
+
+

${this.title}

+

${this.description}

+ ${unsafeSVG(helpButtonSVG())} +
+
+

Nothing in this row.

+
+
` + } +} diff --git a/client/common/configuration/templates/TranslationDirective.ts b/client/common/configuration/templates/TranslationDirective.ts new file mode 100644 index 00000000..94644a03 --- /dev/null +++ b/client/common/configuration/templates/TranslationDirective.ts @@ -0,0 +1,41 @@ +import { PartInfo, directive } from 'lit/directive.js' +import { AsyncDirective } from 'lit/async-directive.js' +import { RegisterClientHelpers } from '@peertube/peertube-types/client'; + +export class TranslationDirective extends AsyncDirective { + + private _peertubeHelpers?: RegisterClientHelpers + + private _translatedValue : string = '' + private _localizationId : string = '' + + constructor(partInfo: PartInfo) { + super(partInfo); + + //_peertubeOptionsPromise.then((options) => this._peertubeHelpers = options.peertubeHelpers) + } + + override render = (locId: string) => { + this._localizationId = locId // TODO Check current component for context (to infer the prefix) + + if (this._translatedValue === '') { + this._translatedValue = locId + } + + this._asyncUpdateTranslation() + + return this._translatedValue + } + + _asyncUpdateTranslation = async () => { + let newValue = await this._peertubeHelpers?.translate(this._localizationId) ?? '' + + if (newValue !== '' && newValue !== this._translatedValue) { + this._translatedValue = newValue + this.setValue(newValue) + } + } +} + +export const ptTr = directive(TranslationDirective) + diff --git a/client/common/configuration/templates/channel.ts b/client/common/configuration/templates/channel.ts index 744d0b1f..dc1ca49a 100644 --- a/client/common/configuration/templates/channel.ts +++ b/client/common/configuration/templates/channel.ts @@ -2,16 +2,20 @@ // // SPDX-License-Identifier: AGPL-3.0-only -import type { RegisterClientOptions } from '@peertube/peertube-types/client' +import type { RegisterClientHelpers, RegisterClientOptions } from '@peertube/peertube-types/client' import { localizedHelpUrl } from '../../../utils/help' import { helpButtonSVG } from '../../../videowatch/buttons' import { getConfigurationChannelViewData } from './logic/channel' import { TemplateResult, html } from 'lit' import { unsafeHTML } from 'lit/directives/unsafe-html.js' +import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; // Must use require for mustache, import seems buggy. const Mustache = require('mustache') + import './DynamicTableFormElement' import './ChannelConfigurationElement' +import './PluginConfigurationRow' +import { ptTr } from './TranslationDirective' /** * Renders the configuration settings page for a given channel, @@ -26,6 +30,8 @@ async function renderConfigurationChannel ( channelId: string, rootEl: HTMLElement ): Promise { + const peertubeHelpers = registerClientOptions.peertubeHelpers + try { const view : {[key: string] : any} = await getConfigurationChannelViewData(registerClientOptions, channelId) await fillViewHelpButtons(registerClientOptions, view) @@ -34,12 +40,30 @@ async function renderConfigurationChannel ( //await vivifyConfigurationChannel(registerClientOptions, rootEl, channelId) let tableHeader = { - words: html`${view.forbiddenWords}
`, - regex: html`${view.forbiddenWordsRegexp}
`, - applyToModerators: html`${view.forbiddenWordsApplyToModerators}
`, - label: html`${view.forbiddenWordsLabel}
`, - reason: html`${view.forbiddenWordsReason}
`, - comments: html`${view.forbiddenWordsComments}
`, + words: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC2) + }, + regex: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REGEXP_DESC) + }, + applyToModerators: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_APPLYTOMODERATORS_DESC) + }, + label: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_LABEL_DESC) + }, + reason: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_REASON_DESC) + }, + comments: { + colName: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_COMMENTS_LABEL), + description: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_COMMENTS_DESC) + } } let tableSchema = { words: { @@ -102,19 +126,30 @@ async function renderConfigurationChannel ( }, ] - return html`${unsafeHTML(Mustache.render(MUSTACHE_CONFIGURATION_CHANNEL, view))} + let helpLink = { + url : new URL(await localizedHelpUrl(registerClientOptions, { page: 'documentation/user/streamers/bot/forbidden_words' })), + title: ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_FORBIDDEN_WORDS_DESC) + } + + return html`
- - -
${JSON.stringify(tableRows)}` + + + + ` } catch (err: any) { - registerClientOptions.peertubeHelpers.notifier.error(err.toString()) + peertubeHelpers.notifier.error(err.toString()) return html`` } } @@ -150,7 +185,8 @@ async function fillLabels ( registerClientOptions: RegisterClientOptions, view: {[key: string] : string} ): Promise { - const { peertubeHelpers } = registerClientOptions + const peertubeHelpers = registerClientOptions.peertubeHelpers + view.title = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_TITLE) view.description = await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_DESC) diff --git a/client/common/configuration/templates/home.ts b/client/common/configuration/templates/home.ts index f343e7cd..342e24ce 100644 --- a/client/common/configuration/templates/home.ts +++ b/client/common/configuration/templates/home.ts @@ -5,7 +5,10 @@ import type { RegisterClientOptions } from '@peertube/peertube-types/client' import { localizedHelpUrl } from '../../../utils/help' import { helpButtonSVG } from '../../../videowatch/buttons' -import { TemplateResult, html } from 'lit'; +import { TemplateResult, html } from 'lit' +import { unsafeHTML } from 'lit/directives/unsafe-html.js' +import { ptTr } from './TranslationDirective' +import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; interface HomeViewData { title: string @@ -86,9 +89,9 @@ async function _fillViewHelpButtons ( // TODO: refactor with the similar functio return html`${helpIcon}` + >${unsafeHTML(helpIcon)}` } return button('documentation/user/streamers/channel') diff --git a/languages/en.yml b/languages/en.yml index bc6e2c55..d200d801 100644 --- a/languages/en.yml +++ b/languages/en.yml @@ -398,6 +398,8 @@ livechat_configuration_channel_forbidden_words_reason_label: "Reason" livechat_configuration_channel_forbidden_words_reason_desc: "Reason to display besides deleted messages" livechat_configuration_channel_forbidden_words_regexp_label: "Consider as regular expressions" livechat_configuration_channel_forbidden_words_regexp_desc: "By checking this option, you can use regular expressions." +livechat_configuration_channel_forbidden_words_label_label: "Label" +livechat_configuration_channel_forbidden_words_label_desc: "Label for this forbidden words rule" livechat_configuration_channel_forbidden_words_applytomoderators_label: "Also moderate messages from moderators" livechat_configuration_channel_forbidden_words_applytomoderators_desc: | By default, moderator messages will not be deleted when containing forbidden words. diff --git a/package-lock.json b/package-lock.json index 6855f716..ba13ba0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "10.0.2", "license": "AGPL-3.0", "dependencies": { + "@lit/context": "^1.1.1", + "@lit/task": "^1.0.0", "@xmpp/jid": "^0.13.1", "async": "^3.2.2", "decache": "^4.6.0", @@ -18,6 +20,7 @@ "lit": "^3.1.3", "log-rotate": "^0.2.8", "openid-client": "^5.6.5", + "rxjs": "^7.8.1", "validate-color": "^2.2.1", "xmppjs-chat-bot": "^0.3.0" }, @@ -2670,6 +2673,14 @@ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==" }, + "node_modules/@lit/context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.1.tgz", + "integrity": "sha512-q/Rw7oWSJidUP43f/RUPwqZ6f5VlY8HzinTWxL/gW1Hvm2S5q2hZvV+qM8WFcC+oLNNknc3JKsd5TwxLk1hbdg==", + "dependencies": { + "@lit/reactive-element": "^1.6.2 || ^2.0.0" + } + }, "node_modules/@lit/reactive-element": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz", @@ -2678,6 +2689,14 @@ "@lit-labs/ssr-dom-shim": "^1.2.0" } }, + "node_modules/@lit/task": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lit/task/-/task-1.0.0.tgz", + "integrity": "sha512-7jocGBh3yGlo3kKxQggZph2txK4X5GYNWp2FAsmV9u2spzUypwrzRzXe8I72icAb02B00+k2nlvxVcrQB6vyrw==", + "dependencies": { + "@lit/reactive-element": "^1.0.0 || ^2.0.0" + } + }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", @@ -10516,6 +10535,19 @@ "integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==", "dev": true }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/safe-array-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", @@ -14289,6 +14321,14 @@ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==" }, + "@lit/context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@lit/context/-/context-1.1.1.tgz", + "integrity": "sha512-q/Rw7oWSJidUP43f/RUPwqZ6f5VlY8HzinTWxL/gW1Hvm2S5q2hZvV+qM8WFcC+oLNNknc3JKsd5TwxLk1hbdg==", + "requires": { + "@lit/reactive-element": "^1.6.2 || ^2.0.0" + } + }, "@lit/reactive-element": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz", @@ -14297,6 +14337,14 @@ "@lit-labs/ssr-dom-shim": "^1.2.0" } }, + "@lit/task": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lit/task/-/task-1.0.0.tgz", + "integrity": "sha512-7jocGBh3yGlo3kKxQggZph2txK4X5GYNWp2FAsmV9u2spzUypwrzRzXe8I72icAb02B00+k2nlvxVcrQB6vyrw==", + "requires": { + "@lit/reactive-element": "^1.0.0 || ^2.0.0" + } + }, "@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", @@ -20289,6 +20337,21 @@ "integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==", "dev": true }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + } + } + }, "safe-array-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", diff --git a/package.json b/package.json index 3447335c..b738cbcb 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "dist/assets/styles/configuration.css" ], "dependencies": { + "@lit/context": "^1.1.1", + "@lit/task": "^1.0.0", "@xmpp/jid": "^0.13.1", "async": "^3.2.2", "decache": "^4.6.0", @@ -42,6 +44,7 @@ "lit": "^3.1.3", "log-rotate": "^0.2.8", "openid-client": "^5.6.5", + "rxjs": "^7.8.1", "validate-color": "^2.2.1", "xmppjs-chat-bot": "^0.3.0" },