DEV: Update linting setup and fix issues (#17345)

Re-lands #16119 and #17298

* Update eslint-config-discourse
* Update linting workflow
* Prettier-ignore stuff
* Update template-lint config
* Auto-fix template issues
* Fix various template issues
  Mostly incorrect attributes and unused templates
* Prettier js files
* Fix template auto-fix regressions
* Small css tweak

Co-authored-by: Peter Wagenet <peter.wagenet@gmail.com>
This commit is contained in:
Jarek Radosz 2022-07-06 10:37:54 +02:00 committed by GitHub
parent f7c133ac74
commit c3fd91670e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
186 changed files with 3235 additions and 3127 deletions

View File

@ -86,8 +86,9 @@ jobs:
if: ${{ always() }} if: ${{ always() }}
run: | run: |
yarn ember-template-lint \ yarn ember-template-lint \
app/assets/javascripts \ --no-error-on-unmatched-pattern \
plugins/**/assets/javascripts "app/assets/javascripts/**/*.hbs" \
"plugins/**/assets/javascripts/**/*.hbs"
- name: English locale lint (core) - name: English locale lint (core)
if: ${{ always() }} if: ${{ always() }}

View File

@ -22,4 +22,10 @@ app/assets/javascripts/discourse/tests/fixtures
spec/ spec/
node_modules/ node_modules/
dist/ dist/
tmp/
**/*.rb **/*.rb
**/*.hbs
**/*.html
**/*.json
**/*.md

View File

@ -1,58 +1,9 @@
module.exports = { module.exports = {
extends: "recommended", plugins: ["ember-template-lint-plugin-discourse"],
ignore: ["**/*.raw"], extends: "discourse:recommended",
rules: { rules: {
"block-indentation": true, "no-capital-arguments": false, // TODO: we extensively use `args` argument name
"deprecated-render-helper": true,
"eol-last": "always",
"linebreak-style": true,
"link-rel-noopener": "strict",
"no-abstract-roles": true,
"no-args-paths": true,
"no-attrs-in-components": true,
"no-debugger": true,
"no-duplicate-attributes": true,
"no-extra-mut-helper-argument": true,
"no-html-comments": true,
"no-index-component-invocation": true,
"no-inline-styles": false,
"no-input-block": true,
"no-input-tagname": true,
"no-implicit-this": {
allow: [
'loading-spinner'
]
},
"no-invalid-interactive": true,
"no-invalid-link-text": true,
"no-invalid-meta": true,
"no-invalid-role": true,
"no-log": true,
"no-negated-condition": true,
"no-nested-interactive": true,
"no-multiple-empty-lines": true,
"no-obsolete-elements": true,
"no-outlet-outside-routes": true,
"no-partial": true,
"no-positive-tabindex": false,
"no-quoteless-attributes": true,
"no-shadowed-elements": true,
"no-trailing-spaces": true,
"no-triple-curlies": true,
"no-unbound": true,
"no-unnecessary-concat": true,
"no-unnecessary-component-helper": true,
"no-unused-block-params": true,
quotes: "double",
"require-button-type": true,
"require-iframe-title": true,
"require-valid-alt-text": false,
"self-closing-void-elements": true,
"simple-unless": true,
"style-concatenation": true,
"table-groups": true,
"link-href-attributes": false,
"no-curly-component-invocation": { "no-curly-component-invocation": {
allow: [ allow: [
// These are helpers, not components // These are helpers, not components
@ -64,5 +15,8 @@ module.exports = {
"mobile-directory-item-label", "mobile-directory-item-label",
], ],
}, },
"no-implicit-this": {
allow: ["loading-spinner"],
},
}, },
}; };

View File

@ -5,7 +5,8 @@ import I18n from "I18n";
import { bind, observes } from "discourse-common/utils/decorators"; import { bind, observes } from "discourse-common/utils/decorators";
import { on } from "@ember/object/evented"; import { on } from "@ember/object/evented";
const COLOR_VARS_REGEX = /\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g; const COLOR_VARS_REGEX =
/\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g;
export default Component.extend({ export default Component.extend({
mode: "css", mode: "css",

View File

@ -12,7 +12,7 @@ export default Controller.extend({
"filter", "filter",
"siteSettings.dashboard_hidden_reports" "siteSettings.dashboard_hidden_reports"
) )
filterReports(reports, filter) { filteredReports(reports, filter) {
if (filter) { if (filter) {
filter = filter.toLowerCase(); filter = filter.toLowerCase();
reports = reports.filter((report) => { reports = reports.filter((report) => {

View File

@ -32,8 +32,9 @@ export default Route.extend({
actions: { actions: {
installModal() { installModal() {
const currentTheme = this.controllerFor("adminCustomizeThemes.show") const currentTheme = this.controllerFor(
.model; "adminCustomizeThemes.show"
).model;
if (currentTheme && currentTheme.warnUnassignedComponent) { if (currentTheme && currentTheme.warnUnassignedComponent) {
showUnassignedComponentWarning(currentTheme, (result) => { showUnassignedComponentWarning(currentTheme, (result) => {
if (!result) { if (!result) {

View File

@ -12,8 +12,9 @@ export default DiscourseRoute.extend({
const routeName = "adminUsersList.show"; const routeName = "adminUsersList.show";
if (transition.targetName === routeName) { if (transition.targetName === routeName) {
const params = transition.routeInfos.find((a) => a.name === routeName) const params = transition.routeInfos.find(
.params; (a) => a.name === routeName
).params;
const controller = this.controllerFor(routeName); const controller = this.controllerFor(routeName);
if (controller) { if (controller) {
controller.setProperties({ controller.setProperties({

View File

@ -46,9 +46,10 @@ export default Service.extend({
}); });
controller.setProperties({ postId: opts.postId, postEdit: opts.postEdit }); controller.setProperties({ postId: opts.postId, postEdit: opts.postEdit });
return (user.adminUserView return (
? Promise.resolve(user) user.adminUserView
: AdminUser.find(user.get("id")) ? Promise.resolve(user)
: AdminUser.find(user.get("id"))
).then((loadedUser) => { ).then((loadedUser) => {
controller.setProperties({ controller.setProperties({
user: loadedUser, user: loadedUser,

View File

@ -16,7 +16,7 @@
</AdminFormRow> </AdminFormRow>
{{else}} {{else}}
<AdminFormRow @label="admin.api.description"> <AdminFormRow @label="admin.api.description">
<Input @value={{this.model.description}} @maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} /> <Input @value={{this.model.description}} maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} />
</AdminFormRow> </AdminFormRow>
<AdminFormRow @label="admin.api.user_mode"> <AdminFormRow @label="admin.api.user_mode">
@ -76,7 +76,7 @@
</td> </td>
<td> <td>
{{#each act.params as |p|}} {{#each act.params as |p|}}
<Input @maxlength="255" @value={{get act p}} placeholder={{p}} /> <Input maxlength="255" @value={{get act p}} placeholder={{p}} />
{{/each}} {{/each}}
</td> </td>
</tr> </tr>

View File

@ -11,7 +11,7 @@
<AdminFormRow @label="admin.api.description"> <AdminFormRow @label="admin.api.description">
{{#if this.editingDescription}} {{#if this.editingDescription}}
<Input @value={{this.buffered.description}} @maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} /> <Input @value={{this.buffered.description}} maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} />
{{else}} {{else}}
<span> <span>
{{if this.model.description this.model.description (i18n "admin.api.no_description")}} {{if this.model.description this.model.description (i18n "admin.api.no_description")}}

View File

@ -3,14 +3,14 @@
<div class="control-group"> <div class="control-group">
<label for="name">{{i18n "admin.badges.name"}}</label> <label for="name">{{i18n "admin.badges.name"}}</label>
{{#if this.readOnly}} {{#if this.readOnly}}
<Input @type="text" @name="name" @value={{this.buffered.name}} @disabled={{true}} /> <Input @type="text" name="name" @value={{this.buffered.name}} disabled={{true}} />
<p class="help"> <p class="help">
<LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "name")}}> <LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "name")}}>
{{i18n "admin.badges.read_only_setting_help"}} {{i18n "admin.badges.read_only_setting_help"}}
</LinkTo> </LinkTo>
</p> </p>
{{else}} {{else}}
<Input @type="text" @name="name" @value={{this.buffered.name}} /> <Input @type="text" name="name" @value={{this.buffered.name}} />
{{/if}} {{/if}}
</div> </div>
@ -56,28 +56,28 @@
<div class="control-group"> <div class="control-group">
<label for="description">{{i18n "admin.badges.description"}}</label> <label for="description">{{i18n "admin.badges.description"}}</label>
{{#if this.buffered.system}} {{#if this.buffered.system}}
<Textarea @name="description" @value={{this.buffered.description}} @disabled={{true}} /> <Textarea name="description" @value={{this.buffered.description}} disabled={{true}} />
<p class="help"> <p class="help">
<LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "description")}}> <LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "description")}}>
{{i18n "admin.badges.read_only_setting_help"}} {{i18n "admin.badges.read_only_setting_help"}}
</LinkTo> </LinkTo>
</p> </p>
{{else}} {{else}}
<Textarea @name="description" @value={{this.buffered.description}} /> <Textarea name="description" @value={{this.buffered.description}} />
{{/if}} {{/if}}
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="long_description">{{i18n "admin.badges.long_description"}}</label> <label for="long_description">{{i18n "admin.badges.long_description"}}</label>
{{#if this.buffered.system}} {{#if this.buffered.system}}
<Textarea @name="long_description" @value={{this.buffered.long_description}} @disabled={{true}} /> <Textarea name="long_description" @value={{this.buffered.long_description}} disabled={{true}} />
<p class="help"> <p class="help">
<LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "long_description")}}> <LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "long_description")}}>
{{i18n "admin.badges.read_only_setting_help"}} {{i18n "admin.badges.read_only_setting_help"}}
</LinkTo> </LinkTo>
</p> </p>
{{else}} {{else}}
<Textarea @name="long_description" @value={{this.buffered.long_description}} /> <Textarea name="long_description" @value={{this.buffered.long_description}} />
{{/if}} {{/if}}
</div> </div>
@ -97,14 +97,14 @@
<div class="control-group"> <div class="control-group">
<label> <label>
<Input @type="checkbox" @checked={{this.buffered.auto_revoke}} @disabled={{this.readOnly}} /> <Input @type="checkbox" @checked={{this.buffered.auto_revoke}} disabled={{this.readOnly}} />
{{i18n "admin.badges.auto_revoke"}} {{i18n "admin.badges.auto_revoke"}}
</label> </label>
</div> </div>
<div class="control-group"> <div class="control-group">
<label> <label>
<Input @type="checkbox" @checked={{this.buffered.target_posts}} @disabled={{this.readOnly}} /> <Input @type="checkbox" @checked={{this.buffered.target_posts}} disabled={{this.readOnly}} />
{{i18n "admin.badges.target_posts"}} {{i18n "admin.badges.target_posts"}}
</label> </label>
</div> </div>
@ -128,21 +128,21 @@
<div> <div>
<label> <label>
<Input @type="checkbox" @checked={{this.buffered.multiple_grant}} @disabled={{this.readOnly}} /> <Input @type="checkbox" @checked={{this.buffered.multiple_grant}} disabled={{this.readOnly}} />
{{i18n "admin.badges.multiple_grant"}} {{i18n "admin.badges.multiple_grant"}}
</label> </label>
</div> </div>
<div> <div>
<label> <label>
<Input @type="checkbox" @checked={{this.buffered.listable}} @disabled={{this.readOnly}} /> <Input @type="checkbox" @checked={{this.buffered.listable}} disabled={{this.readOnly}} />
{{i18n "admin.badges.listable"}} {{i18n "admin.badges.listable"}}
</label> </label>
</div> </div>
<div> <div>
<label> <label>
<Input @type="checkbox" @checked={{this.buffered.show_posts}} @disabled={{this.readOnly}} /> <Input @type="checkbox" @checked={{this.buffered.show_posts}} disabled={{this.readOnly}} />
{{i18n "admin.badges.show_posts"}} {{i18n "admin.badges.show_posts"}}
</label> </label>
</div> </div>

View File

@ -3,7 +3,7 @@
<ul class="nav nav-pills target"> <ul class="nav nav-pills target">
{{#each this.visibleTargets as |target|}} {{#each this.visibleTargets as |target|}}
<li> <li>
<LinkTo @route={{this.editRouteName}} @models={{array this.theme.id target.name this.fieldName}} @replace={{true}} @title={{this.field.title}} class={{if target.edited "edited" "blank"}}> <LinkTo @route={{this.editRouteName}} @models={{array this.theme.id target.name this.fieldName}} @replace={{true}} title={{this.field.title}} class={{if target.edited "edited" "blank"}}>
{{#if target.error}}{{d-icon "exclamation-triangle"}}{{/if}} {{#if target.error}}{{d-icon "exclamation-triangle"}}{{/if}}
{{#if target.icon}}{{d-icon target.icon}}{{/if}} {{#if target.icon}}{{d-icon target.icon}}{{/if}}
{{i18n (concat "admin.customize.theme." target.name)}} {{i18n (concat "admin.customize.theme." target.name)}}
@ -24,7 +24,7 @@
<li class="spacer"></li> <li class="spacer"></li>
<li> <li>
<label> <label>
<Input @type="checkbox" @checked={{this.onlyOverridden}} @click={{action "onlyOverriddenChanged" value="target.checked"}} /> <Input @type="checkbox" @checked={{this.onlyOverridden}} {{on "click" (action "onlyOverriddenChanged" value="target.checked")}} />
{{i18n "admin.customize.theme.hide_unused_fields"}} {{i18n "admin.customize.theme.hide_unused_fields"}}
</label> </label>
</li> </li>
@ -37,7 +37,7 @@
<ul class="nav nav-pills fields"> <ul class="nav nav-pills fields">
{{#each this.visibleFields as |field|}} {{#each this.visibleFields as |field|}}
<li> <li>
<LinkTo @route={{this.editRouteName}} @models={{array this.theme.id this.currentTargetName field.name}} @replace={{true}} @title={{field.title}} class={{if field.edited "edited" "blank"}}> <LinkTo @route={{this.editRouteName}} @models={{array this.theme.id this.currentTargetName field.name}} @replace={{true}} title={{field.title}} class={{if field.edited "edited" "blank"}}>
{{#if field.error}}{{d-icon "exclamation-triangle"}}{{/if}} {{#if field.error}}{{d-icon "exclamation-triangle"}}{{/if}}
{{#if field.icon}}{{d-icon field.icon}}{{/if}} {{#if field.icon}}{{d-icon field.icon}}{{/if}}
{{field.translatedName}} {{field.translatedName}}

View File

@ -5,11 +5,11 @@
</AdminFormRow> </AdminFormRow>
<AdminFormRow @label="admin.user_fields.name"> <AdminFormRow @label="admin.user_fields.name">
<Input @value={{this.buffered.name}} class="user-field-name" @maxlength="255" /> <Input @value={{this.buffered.name}} class="user-field-name" maxlength="255" />
</AdminFormRow> </AdminFormRow>
<AdminFormRow @label="admin.user_fields.description"> <AdminFormRow @label="admin.user_fields.description">
<Input @value={{this.buffered.description}} class="user-field-desc" @maxlength="255" /> <Input @value={{this.buffered.description}} class="user-field-desc" maxlength="255" />
</AdminFormRow> </AdminFormRow>
{{#if this.bufferedFieldType.hasOptions}} {{#if this.bufferedFieldType.hasOptions}}

View File

@ -1,3 +1,3 @@
<Input @id={{this.typeName}} @type="checkbox" @name="event-choice" @checked={{this.enabled}} /> <Input id={{this.typeName}} @type="checkbox" name="event-choice" @checked={{this.enabled}} />
<label for={{this.typeName}}>{{this.name}}</label> <label for={{this.typeName}}>{{this.name}}</label>
<p>{{this.details}}</p> <p>{{this.details}}</p>

View File

@ -1,7 +1,7 @@
{{#if this.editing}} {{#if this.editing}}
<td class="editing-input"> <td class="editing-input">
<div class="label">{{i18n "admin.embedding.host"}}</div> <div class="label">{{i18n "admin.embedding.host"}}</div>
<Input @value={{this.buffered.host}} placeholder="example.com" @enter={{action "save"}} class="host-name" @autofocus={{true}} /> <Input @value={{this.buffered.host}} placeholder="example.com" @enter={{action "save"}} class="host-name" autofocus={{true}} />
</td> </td>
<td class="editing-input"> <td class="editing-input">
<div class="label">{{i18n "admin.embedding.class_name"}}</div> <div class="label">{{i18n "admin.embedding.class_name"}}</div>

View File

@ -1,11 +1,11 @@
{{#if this.isCheckbox}} {{#if this.isCheckbox}}
<label for={{this.inputId}}> <label for={{this.inputId}}>
<Input @checked={{this.checked}} @id={{this.inputId}} @type="checkbox" /> <Input @checked={{this.checked}} id={{this.inputId}} @type="checkbox" />
{{i18n this.translationKey}} {{i18n this.translationKey}}
</label> </label>
{{else}} {{else}}
<label for={{this.inputId}}>{{i18n this.translationKey}}</label> <label for={{this.inputId}}>{{i18n this.translationKey}}</label>
<Input @value={{this.value}} @id={{this.inputId}} placeholder={{this.placeholder}} /> <Input @value={{this.value}} id={{this.inputId}} placeholder={{this.placeholder}} />
{{/if}} {{/if}}
<div class="clearfix"></div> <div class="clearfix"></div>

View File

@ -1,5 +1,5 @@
<label class="checkbox-label"> <label class="checkbox-label">
<Input @type="checkbox" @disabled={{this.disabled}} @checked={{this.buffer}} /> <Input @type="checkbox" disabled={{this.disabled}} @checked={{this.buffer}} />
{{i18n this.labelKey}} {{i18n this.labelKey}}
</label> </label>
{{#if this.changed}} {{#if this.changed}}

View File

@ -1 +1 @@
<Input @type="checkbox" @checked={{this.checked}} @click={{action "onChange"}} /> <Input @type="checkbox" @checked={{this.checked}} {{on "click" (action "onChange")}} />

View File

@ -3,8 +3,8 @@
{{#each this.collection as |value index|}} {{#each this.collection as |value index|}}
<div class="value" data-index={{index}}> <div class="value" data-index={{index}}>
<DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" /> <DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" />
<Input @value={{value.key}} class="value-input" @focus-out={{action "changeKey" index}} /> <Input @value={{value.key}} class="value-input" {{on "focusout" (action "changeKey" index)}} />
<Input @value={{value.secret}} class="value-input" @focus-out={{action "changeSecret" index}} @type={{if this.isSecret "password" "text"}} /> <Input @value={{value.secret}} class="value-input" @type={{if this.isSecret "password" "text"}} {{on "focusout" (action "changeSecret" index)}} />
</div> </div>
{{/each}} {{/each}}
</div> </div>

View File

@ -4,21 +4,19 @@
<div data-index={{index}} class="value"> <div data-index={{index}} class="value">
<DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" /> <DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" />
<Input @title={{value}} @value={{value}} class="value-input" @focus-out={{action "changeValue" index}} /> <Input title={{value}} @value={{value}} class="value-input" {{on "focusout" (action "changeValue" index)}} />
{{#if this.showUpDownButtons}} {{#if this.showUpDownButtons}}
<DButton @action={{action "shift" -1 index}} @icon="arrow-up" @class="shift-up-value-btn btn-small" /> <DButton @action={{action "shift" -1 index}} @icon="arrow-up" @class="shift-up-value-btn btn-small" />
<DButton @action={{action "shift" 1 index}} @icon="arrow-down" @class="shift-down-value-btn btn-small" /> <DButton @action={{action "shift" 1 index}} @icon="arrow-down" @class="shift-down-value-btn btn-small" />
{{/if}} {{/if}}
</div> </div>
{{/each}} {{/each}}
</div> </div>
{{/if}} {{/if}}
<div class="simple-list-input"> <div class="simple-list-input">
<Input @type="text" @value={{this.newValue}} @placeholderKey="admin.site_settings.simple_list.add_item" class="add-value-input" @autocomplete="off" @autocorrect="off" @autocapitalize="off" /> <Input @type="text" @value={{this.newValue}} placeholder={{i18n "admin.site_settings.simple_list.add_item"}} class="add-value-input" autocomplete="off" autocorrect="off" autocapitalize="off" />
<DButton @action={{action "addValue"}} @actionParam={{this.newValue}} @disabled={{this.inputEmpty}} @icon="plus" @class="add-value-btn btn-small" /> <DButton @action={{action "addValue"}} @actionParam={{this.newValue}} @disabled={{this.inputEmpty}} @icon="plus" @class="add-value-btn btn-small" />
</div> </div>

View File

@ -2,7 +2,7 @@
<h3> <h3>
{{#if this.staffLogFilter}} {{#if this.staffLogFilter}}
{{this.settingName}} {{this.settingName}}
<LinkTo @route="adminLogs.staffActionLogs" @query={{hash filters=this.staffLogFilter force_refresh=true}} @title={{i18n "admin.settings.history"}}> <LinkTo @route="adminLogs.staffActionLogs" @query={{hash filters=this.staffLogFilter force_refresh=true}} title={{i18n "admin.settings.history"}}>
<span class="history-icon"> <span class="history-icon">
{{d-icon "history"}} {{d-icon "history"}}
</span> </span>

View File

@ -1,9 +1,9 @@
{{#if this.setting.textarea}} {{#if this.setting.textarea}}
<Textarea @value={{this.value}} @classNames="input-setting-textarea" /> <Textarea @value={{this.value}} class="input-setting-textarea" />
{{else if this.setting.json_schema}} {{else if this.setting.json_schema}}
<DButton @action={{action "launchJsonEditorModal"}} @icon="pencil-alt" @label="admin.site_settings.json_schema.edit" /> <DButton @action={{action "launchJsonEditorModal"}} @icon="pencil-alt" @label="admin.site_settings.json_schema.edit" />
{{else if this.isSecret}} {{else if this.isSecret}}
<Input @type="password" @value={{this.value}} @classNames="input-setting-string" /> <Input @type="password" @value={{this.value}} class="input-setting-string" />
{{else}} {{else}}
<TextField @value={{this.value}} @classNames="input-setting-string" /> <TextField @value={{this.value}} @classNames="input-setting-string" />
{{/if}} {{/if}}

View File

@ -1,4 +1,4 @@
{{!-- template-lint-disable no-invalid-interactive --}} {{!-- template-lint-disable no-invalid-interactive --}}
<div class="table staff-actions" {{on "click" (fn this.openLinks)}}> <div class="table staff-actions" {{on "click" this.openLinks}}>
{{yield}} {{yield}}
</div> </div>

View File

@ -6,7 +6,7 @@
<div class="themes-list-container"> <div class="themes-list-container">
{{#if this.showFilter}} {{#if this.showFilter}}
<div class="themes-list-filter themes-list-item"> <div class="themes-list-filter themes-list-item">
<Input class="filter-input" placeholder={{i18n "admin.customize.theme.filter_placeholder"}} @autocomplete="off" @type="search" @value={{mut this.filterTerm}} /> <Input class="filter-input" placeholder={{i18n "admin.customize.theme.filter_placeholder"}} autocomplete="off" @type="search" @value={{mut this.filterTerm}} />
{{d-icon "search"}} {{d-icon "search"}}
</div> </div>
{{/if}} {{/if}}

View File

@ -4,7 +4,7 @@
<div data-index={{index}} class="value"> <div data-index={{index}} class="value">
<DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" /> <DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" />
<Input @title={{value}} @value={{value}} class="value-input" @focus-out={{action "changeValue" index}} /> <Input title={{value}} @value={{value}} class="value-input" {{on "focusout" (action "changeValue" index)}} />
{{#if this.showUpDownButtons}} {{#if this.showUpDownButtons}}
<DButton @action={{action "shift" -1 index}} @icon="arrow-up" @class="shift-up-value-btn btn-small" /> <DButton @action={{action "shift" -1 index}} @icon="arrow-up" @class="shift-up-value-btn btn-small" />

View File

@ -22,8 +22,8 @@
{{#if this.canLink}} {{#if this.canLink}}
<div class="watched-word-input"> <div class="watched-word-input">
<label for="watched-replacement">{{i18n "admin.watched_words.form.link_label"}}</label> <label for="watched-link">{{i18n "admin.watched_words.form.link_label"}}</label>
<TextField @id="watched-replacement" @value={{this.replacement}} @disabled={{this.formSubmitted}} @class="watched-word-input-field" @autocorrect="off" @autocapitalize="off" @placeholderKey="admin.watched_words.form.link_placeholder" /> <TextField @id="watched-link" @value={{this.replacement}} @disabled={{this.formSubmitted}} @class="watched-word-input-field" @autocorrect="off" @autocapitalize="off" @placeholderKey="admin.watched_words.form.link_placeholder" />
</div> </div>
{{/if}} {{/if}}

View File

@ -2,11 +2,11 @@
<div class="reports-index section"> <div class="reports-index section">
<div class="section-title"> <div class="section-title">
<h2>{{i18n "admin.reports.title"}}</h2> <h2>{{i18n "admin.reports.title"}}</h2>
<Input class="filter-reports-input" @input={{action "filterReports" value="target.value"}} placeholder={{i18n "admin.dashboard.filter_reports"}} @autofocus={{true}} /> <Input class="filter-reports-input" placeholder={{i18n "admin.dashboard.filter_reports"}} autofocus={{true}} {{on "input" (action "filterReports" value="target.value")}} />
</div> </div>
<ul class="reports-list"> <ul class="reports-list">
{{#each this.filterReports as |report|}} {{#each this.filteredReports as |report|}}
<li class="report"> <li class="report">
<LinkTo @route="adminReports.show" @model={{report.type}}> <LinkTo @route="adminReports.show" @model={{report.type}}>
<h3 class="report-title">{{report.title}}</h3> <h3 class="report-title">{{report.title}}</h3>

View File

@ -2,7 +2,7 @@
<div class="email-advanced-test"> <div class="email-advanced-test">
<label for="email">{{i18n "admin.email.advanced_test.email"}}</label> <label for="email">{{i18n "admin.email.advanced_test.email"}}</label>
<Textarea @name="email" @value={{this.email}} class="email-body" /> <DButton @action={{action "run"}} @label="admin.email.advanced_test.run" /> <Textarea name="email" @value={{this.email}} class="email-body" /> <DButton @action={{action "run"}} @label="admin.email.advanced_test.run" />
</div> </div>
<ConditionalLoadingSpinner @condition={{this.loading}}> <ConditionalLoadingSpinner @condition={{this.loading}}>

View File

@ -1,7 +1,7 @@
<p> <p>
{{i18n "admin.logs.screened_urls.description"}} {{i18n "admin.logs.screened_urls.description"}}
</p> </p>
<DButton @class="btn-default" @action={{action "exportScreenedUrlList"}} @title="admin.export_csv.button_title.screened_url" @icon="download" @label="admin.export_csv.button_text" /> <DButton @class="btn-default" @action={{action "exportScreenedUrlList"}} @title="admin.export_csv.button_title.screened_url" @icon="download" @label="admin.export_csv.button_text" />
<br> <br>
<ConditionalLoadingSpinner @condition={{this.loading}}> <ConditionalLoadingSpinner @condition={{this.loading}}>

View File

@ -6,7 +6,7 @@
</section> </section>
<section class="field"> <section class="field">
<label for="theme-variable-name">{{i18n "admin.customize.theme.variable_name"}}</label> <label for="theme-variable-name">{{i18n "admin.customize.theme.variable_name"}}</label>
<Input @id="theme-variable-name" @value={{this.name}} /> <Input id="theme-variable-name" @value={{this.name}} />
</section> </section>
{{#if this.fileSelected}} {{#if this.fileSelected}}
{{#if this.errorMessage}} {{#if this.errorMessage}}

View File

@ -14,7 +14,7 @@
<div class="control-group"> <div class="control-group">
<label>{{i18n "admin.email.incoming_emails.modal.headers"}}</label> <label>{{i18n "admin.email.incoming_emails.modal.headers"}}</label>
<div class="controls"> <div class="controls">
<Textarea @value={{this.model.headers}} @wrap="off" /> <Textarea @value={{this.model.headers}} wrap="off" />
</div> </div>
</div> </div>

View File

@ -72,7 +72,7 @@
<div class="public-key"> <div class="public-key">
<div class="label">{{i18n "admin.customize.theme.public_key"}}</div> <div class="label">{{i18n "admin.customize.theme.public_key"}}</div>
<div class="public-key-text-wrapper"> <div class="public-key-text-wrapper">
<Textarea class="public-key-value" @readonly={{true}} @value={{this.publicKey}} /> <CopyButton @selector="textarea.public-key-value" /> <Textarea class="public-key-value" readonly={{true}} @value={{this.publicKey}} /> <CopyButton @selector="textarea.public-key-value" />
</div> </div>
</div> </div>
{{else}} {{else}}

View File

@ -1,6 +1,6 @@
<DModalBody @rawTitle={{i18n "admin.watched_words.test.modal_title" action=this.model.name}} @class="watched-words-test-modal"> <DModalBody @rawTitle={{i18n "admin.watched_words.test.modal_title" action=this.model.name}} @class="watched-words-test-modal">
<p>{{i18n "admin.watched_words.test.description"}}</p> <p>{{i18n "admin.watched_words.test.description"}}</p>
<Textarea @name="test_value" @value={{this.value}} @autofocus="autofocus" /> <Textarea name="test_value" @value={{this.value}} autofocus="autofocus" />
{{#if this.matches}} {{#if this.matches}}
<p> <p>
{{i18n "admin.watched_words.test.found_matches"}} {{i18n "admin.watched_words.test.found_matches"}}

View File

@ -14,7 +14,7 @@
</div> </div>
<label> <label>
<Input @type="checkbox" @checked={{this.overridden}} @click={{action "toggleOverridden"}} /> <Input @type="checkbox" @checked={{this.overridden}} {{on "click" (action "toggleOverridden")}} />
{{i18n "admin.site_text.show_overriden"}} {{i18n "admin.site_text.show_overriden"}}
</label> </label>
</p> </p>

View File

@ -22,7 +22,7 @@
{{#if this.currentAction.words}} {{#if this.currentAction.words}}
<label class="show-words-checkbox"> <label class="show-words-checkbox">
<Input @type="checkbox" @checked={{this.adminWatchedWords.showWords}} @disabled={{this.adminWatchedWords.disableShowWords}} /> <Input @type="checkbox" @checked={{this.adminWatchedWords.showWords}} disabled={{this.adminWatchedWords.disableShowWords}} />
{{i18n "admin.watched_words.show_words" count=this.currentAction.words.length}} {{i18n "admin.watched_words.show_words" count=this.currentAction.words.length}}
</label> </label>
{{/if}} {{/if}}

View File

@ -1,9 +1,9 @@
<div class="web-hook-direction"> <div class="web-hook-direction">
<LinkTo @route="adminWebHooks" @tagName="button" @classNames="btn"> <LinkTo @route="adminWebHooks" class="btn">
{{d-icon "list"}} {{i18n "admin.web_hooks.events.go_list"}} {{d-icon "list"}} {{i18n "admin.web_hooks.events.go_list"}}
</LinkTo> </LinkTo>
<DButton @icon="paper-plane" @label="admin.web_hooks.events.ping" @action={{action "ping"}} @disabled={{this.pingDisabled}} /> <DButton @icon="paper-plane" @label="admin.web_hooks.events.ping" @action={{action "ping"}} @disabled={{this.pingDisabled}} />
<LinkTo @route="adminWebHooks.show" @model={{this.model.extras.web_hook_id}} @tagName="button" @classNames="btn"> <LinkTo @route="adminWebHooks.show" @model={{this.model.extras.web_hook_id}} class="btn">
{{d-icon "far-edit"}} {{i18n "admin.web_hooks.events.go_details"}} {{d-icon "far-edit"}} {{i18n "admin.web_hooks.events.go_details"}}
</LinkTo> </LinkTo>
</div> </div>

View File

@ -66,11 +66,11 @@
<PluginOutlet @name="web-hook-fields" @tagName="span" @connectorTagName="div" @args={{hash model=this.model}} /> <PluginOutlet @name="web-hook-fields" @tagName="span" @connectorTagName="div" @args={{hash model=this.model}} />
<div> <div>
<Input @type="checkbox" @name="verify_certificate" @checked={{this.model.verify_certificate}} /> {{i18n "admin.web_hooks.verify_certificate"}} <Input @type="checkbox" name="verify_certificate" @checked={{this.model.verify_certificate}} /> {{i18n "admin.web_hooks.verify_certificate"}}
</div> </div>
<div> <div>
<div> <div>
<Input @type="checkbox" @name="active" @checked={{this.model.active}} /> {{i18n "admin.web_hooks.active"}} <Input @type="checkbox" name="active" @checked={{this.model.active}} /> {{i18n "admin.web_hooks.active"}}
</div> </div>
{{#if this.model.active}} {{#if this.model.active}}
<div class="instructions">{{i18n "admin.web_hooks.active_notice"}}</div> <div class="instructions">{{i18n "admin.web_hooks.active_notice"}}</div>

View File

@ -1,7 +1,7 @@
<div class="web-hooks-listing"> <div class="web-hooks-listing">
<p>{{i18n "admin.web_hooks.instruction"}}</p> <p>{{i18n "admin.web_hooks.instruction"}}</p>
<div class="new-webhook"> <div class="new-webhook">
<LinkTo @route="adminWebHooks.show" @model="new" @tagName="button" @classNames="btn btn-default"> <LinkTo @route="adminWebHooks.show" @model="new" class="btn btn-default">
{{d-icon "plus"}} {{i18n "admin.web_hooks.new"}} {{d-icon "plus"}} {{i18n "admin.web_hooks.new"}}
</LinkTo> </LinkTo>
</div> </div>
@ -23,7 +23,7 @@
<td class="payload-url"><LinkTo @route="adminWebHooks.show" @model={{webHook}}>{{webHook.payload_url}}</LinkTo></td> <td class="payload-url"><LinkTo @route="adminWebHooks.show" @model={{webHook}}>{{webHook.payload_url}}</LinkTo></td>
<td class="description">{{webHook.description}}</td> <td class="description">{{webHook.description}}</td>
<td class="controls"> <td class="controls">
<LinkTo @route="adminWebHooks.show" @model={{webHook}} @tagName="button" @classNames="btn btn-default no-text">{{d-icon "far-edit"}}</LinkTo> <LinkTo @route="adminWebHooks.show" @model={{webHook}} class="btn btn-default no-text">{{d-icon "far-edit"}}</LinkTo>
<DButton @class="destroy btn-danger" @action={{action "destroy"}} @actionParam={{webHook}} @icon="times" /> <DButton @class="destroy btn-danger" @action={{action "destroy"}} @actionParam={{webHook}} @icon="times" />
</td> </td>
</tr> </tr>

View File

@ -10,9 +10,8 @@ if (security) {
.getElementById("security-key-allowed-credential-ids") .getElementById("security-key-allowed-credential-ids")
.value.split(","), .value.split(","),
(credentialData) => { (credentialData) => {
document.getElementById( document.getElementById("security-key-credential").value =
"security-key-credential" JSON.stringify(credentialData);
).value = JSON.stringify(credentialData);
$(e.target).parents("form").submit(); $(e.target).parents("form").submit();
}, },

View File

@ -130,7 +130,8 @@ TemplateCompiler.prototype.targetExtension = "js";
TemplateCompiler.prototype.registerPlugins = function registerPlugins() {}; TemplateCompiler.prototype.registerPlugins = function registerPlugins() {};
TemplateCompiler.prototype.initializeFeatures = function initializeFeatures() {}; TemplateCompiler.prototype.initializeFeatures =
function initializeFeatures() {};
TemplateCompiler.prototype.processString = function (string, relativePath) { TemplateCompiler.prototype.processString = function (string, relativePath) {
let filename = relativePath.replace(/^templates\//, "").replace(/\.hbr$/, ""); let filename = relativePath.replace(/^templates\//, "").replace(/\.hbr$/, "");

View File

@ -1,7 +1,7 @@
"use strict"; "use strict";
const WidgetHbsCompiler = require("../../../../lib/javascripts/widget-hbs-compiler") const WidgetHbsCompiler =
.WidgetHbsCompiler; require("../../../../lib/javascripts/widget-hbs-compiler").WidgetHbsCompiler;
const glimmer = require("@glimmer/syntax"); const glimmer = require("@glimmer/syntax");

View File

@ -48,7 +48,8 @@ import userSearch from "discourse/lib/user-search";
// Group 3 is optional. group 4 can match images with or without a markdown title. // Group 3 is optional. group 4 can match images with or without a markdown title.
// All matches are whitespace tolerant as long it's still valid markdown. // All matches are whitespace tolerant as long it's still valid markdown.
// If the image is inside a code block, we'll ignore it `(?!(.*`))`. // If the image is inside a code block, we'll ignore it `(?!(.*`))`.
const IMAGE_MARKDOWN_REGEX = /!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g; const IMAGE_MARKDOWN_REGEX =
/!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g;
let uploadHandlers = []; let uploadHandlers = [];
export function addComposerUploadHandler(extensions, method) { export function addComposerUploadHandler(extensions, method) {
@ -565,9 +566,8 @@ export default Component.extend(ComposerUploadUppy, {
); );
const scale = event.target.dataset.scale; const scale = event.target.dataset.scale;
const matchingPlaceholder = this.get("composer.reply").match( const matchingPlaceholder =
IMAGE_MARKDOWN_REGEX this.get("composer.reply").match(IMAGE_MARKDOWN_REGEX);
);
if (matchingPlaceholder) { if (matchingPlaceholder) {
const match = matchingPlaceholder[index]; const match = matchingPlaceholder[index];
@ -608,9 +608,8 @@ export default Component.extend(ComposerUploadUppy, {
commitAltText(buttonWrapper) { commitAltText(buttonWrapper) {
const index = parseInt(buttonWrapper.getAttribute("data-image-index"), 10); const index = parseInt(buttonWrapper.getAttribute("data-image-index"), 10);
const matchingPlaceholder = this.get("composer.reply").match( const matchingPlaceholder =
IMAGE_MARKDOWN_REGEX this.get("composer.reply").match(IMAGE_MARKDOWN_REGEX);
);
const match = matchingPlaceholder[index]; const match = matchingPlaceholder[index];
const input = buttonWrapper.querySelector("input.alt-text-input"); const input = buttonWrapper.querySelector("input.alt-text-input");
const replacement = match.replace( const replacement = match.replace(

View File

@ -51,9 +51,8 @@ export default Component.extend({
let userTextFields = document.getElementsByClassName("user-fields")[0]; let userTextFields = document.getElementsByClassName("user-fields")[0];
if (userTextFields) { if (userTextFields) {
userTextFields = userTextFields.getElementsByClassName( userTextFields =
"ember-text-field" userTextFields.getElementsByClassName("ember-text-field");
);
} }
if (userTextFields) { if (userTextFields) {
@ -76,9 +75,8 @@ export default Component.extend({
let userTextFields = document.getElementsByClassName("user-fields")[0]; let userTextFields = document.getElementsByClassName("user-fields")[0];
if (userTextFields) { if (userTextFields) {
userTextFields = userTextFields.getElementsByClassName( userTextFields =
"ember-text-field" userTextFields.getElementsByClassName("ember-text-field");
);
} }
if (userTextFields) { if (userTextFields) {

View File

@ -499,9 +499,10 @@ export default Component.extend(TextareaTextManipulation, {
return false; return false;
} }
const matches = /(?:^|[\s.\?,@\/#!%&*;:\[\]{}=\-_()])(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gi.exec( const matches =
text.substring(0, cp) /(?:^|[\s.\?,@\/#!%&*;:\[\]{}=\-_()])(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gi.exec(
); text.substring(0, cp)
);
if (matches && matches[1]) { if (matches && matches[1]) {
return [matches[1]]; return [matches[1]];

View File

@ -200,9 +200,8 @@ export default Component.extend({
} }
focusableElements = focusableElements + ", button:enabled"; focusableElements = focusableElements + ", button:enabled";
const firstFocusableElement = innerContainer.querySelectorAll( const firstFocusableElement =
focusableElements innerContainer.querySelectorAll(focusableElements)?.[0];
)?.[0];
const focusableContent = innerContainer.querySelectorAll(focusableElements); const focusableContent = innerContainer.querySelectorAll(focusableElements);
const lastFocusableElement = focusableContent[focusableContent.length - 1]; const lastFocusableElement = focusableContent[focusableContent.length - 1];

View File

@ -17,12 +17,9 @@ export default Component.extend({
"form.imap_port" "form.imap_port"
) )
missingSettings(email_username, email_password, imap_server, imap_port) { missingSettings(email_username, email_password, imap_server, imap_port) {
return [ return [email_username, email_password, imap_server, imap_port].some(
email_username, (value) => isEmpty(value)
email_password, );
imap_server,
imap_port,
].some((value) => isEmpty(value));
}, },
@discourseComputed("group.imap_mailboxes") @discourseComputed("group.imap_mailboxes")

View File

@ -17,12 +17,9 @@ export default Component.extend({
"form.smtp_port" "form.smtp_port"
) )
missingSettings(email_username, email_password, smtp_server, smtp_port) { missingSettings(email_username, email_password, smtp_server, smtp_port) {
return [ return [email_username, email_password, smtp_server, smtp_port].some(
email_username, (value) => isEmpty(value)
email_password, );
smtp_server,
smtp_port,
].some((value) => isEmpty(value));
}, },
@action @action

View File

@ -206,9 +206,8 @@ export default Controller.extend(ModalFunctionality, {
} else { } else {
this.set("loggedIn", true); this.set("loggedIn", true);
// Trigger the browser's password manager using the hidden static login form: // Trigger the browser's password manager using the hidden static login form:
const hiddenLoginForm = document.getElementById( const hiddenLoginForm =
"hidden-login-form" document.getElementById("hidden-login-form");
);
const applyHiddenFormInputValue = (value, key) => { const applyHiddenFormInputValue = (value, key) => {
if (!hiddenLoginForm) { if (!hiddenLoginForm) {
return; return;

View File

@ -74,9 +74,10 @@ export default Controller.extend({
saveEmail() { saveEmail() {
this.set("saving", true); this.set("saving", true);
return (this.new return (
? this.model.addEmail(this.newEmail) this.new
: this.model.changeEmail(this.newEmail) ? this.model.addEmail(this.newEmail)
: this.model.changeEmail(this.newEmail)
).then( ).then(
() => { () => {
this.set("success", true); this.set("success", true);

View File

@ -781,8 +781,8 @@ export default Controller.extend(bufferedProperty("model"), {
Bookmark.create({ Bookmark.create({
bookmarkable_id: post.id, bookmarkable_id: post.id,
bookmarkable_type: "Post", bookmarkable_type: "Post",
auto_delete_preference: this.currentUser auto_delete_preference:
.bookmark_auto_delete_preference, this.currentUser.bookmark_auto_delete_preference,
}), }),
post post
); );
@ -1335,8 +1335,8 @@ export default Controller.extend(bufferedProperty("model"), {
Bookmark.create({ Bookmark.create({
bookmarkable_id: this.model.id, bookmarkable_id: this.model.id,
bookmarkable_type: "Topic", bookmarkable_type: "Topic",
auto_delete_preference: this.currentUser auto_delete_preference:
.bookmark_auto_delete_preference, this.currentUser.bookmark_auto_delete_preference,
}) })
); );
} }

View File

@ -31,11 +31,9 @@ export default Controller.extend({
discourseDebounce( discourseDebounce(
this, this,
function () { function () {
Invite.findInvitedBy( Invite.findInvitedBy(this.user, this.filter, this.searchTerm).then(
this.user, (invites) => this.set("model", invites)
this.filter, );
this.searchTerm
).then((invites) => this.set("model", invites));
}, },
INPUT_DELAY INPUT_DELAY
); );

View File

@ -46,8 +46,8 @@ export default function offsetCalculator() {
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
const documentHeight = document.body.clientHeight; const documentHeight = document.body.clientHeight;
const topicBottomOffsetTop = document.getElementById("topic-bottom") const topicBottomOffsetTop =
.offsetTop; document.getElementById("topic-bottom").offsetTop;
// the footer is bigger than the window, we can scroll down past the last post // the footer is bigger than the window, we can scroll down past the last post
if (documentHeight - windowHeight > topicBottomOffsetTop) { if (documentHeight - windowHeight > topicBottomOffsetTop) {

View File

@ -1,7 +1,8 @@
import { prioritizeNameFallback } from "discourse/lib/settings"; import { prioritizeNameFallback } from "discourse/lib/settings";
import { helperContext } from "discourse-common/lib/helpers"; import { helperContext } from "discourse-common/lib/helpers";
export const QUOTE_REGEXP = /\[quote=([^\]]*)\]((?:[\s\S](?!\[quote=[^\]]*\]))*?)\[\/quote\]/im; export const QUOTE_REGEXP =
/\[quote=([^\]]*)\]((?:[\s\S](?!\[quote=[^\]]*\]))*?)\[\/quote\]/im;
// Build the BBCode quote around the selected text // Build the BBCode quote around the selected text
export function buildQuote(post, contents, opts = {}) { export function buildQuote(post, contents, opts = {}) {

View File

@ -90,8 +90,8 @@ export default class StickyAvatars {
return; return;
} }
const postContentHeight = entry.target.querySelector(".contents") const postContentHeight =
?.clientHeight; entry.target.querySelector(".contents")?.clientHeight;
if ( if (
this.direction === "⬆️" || this.direction === "⬆️" ||
postContentHeight > window.innerHeight - headerOffset() postContentHeight > window.innerHeight - headerOffset()

View File

@ -127,7 +127,8 @@ export function validateUploadedFile(file, opts) {
return true; return true;
} }
export const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|svg|ico|heic|heif|webp)/i; export const IMAGES_EXTENSIONS_REGEX =
/(png|jpe?g|gif|svg|ico|heic|heif|webp)/i;
function extensionsToArray(exts) { function extensionsToArray(exts) {
return exts return exts

View File

@ -51,8 +51,8 @@ export default class UppyMediaOptimization extends UploadPreProcessorPlugin {
@bind @bind
async _optimizeSerial(fileIds) { async _optimizeSerial(fileIds) {
let optimizeTasks = fileIds.map((fileId) => () => let optimizeTasks = fileIds.map(
this._optimizeFile(fileId) (fileId) => () => this._optimizeFile(fileId)
); );
for (const task of optimizeTasks) { for (const task of optimizeTasks) {

View File

@ -199,7 +199,8 @@ function organizeResults(r, options) {
// will not find me, which is a reasonable compromise // will not find me, which is a reasonable compromise
// //
// we also ignore if we notice a double space or a string that is only a space // we also ignore if we notice a double space or a string that is only a space
const ignoreRegex = /([\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*,\/:;<=>?\[\]^`{|}~])|\s\s|^\s$|^[^+]*\+[^@]*$/; const ignoreRegex =
/([\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*,\/:;<=>?\[\]^`{|}~])|\s\s|^\s$|^[^+]*\+[^@]*$/;
export function skipSearch(term, allowEmails, lastSeenUsers = false) { export function skipSearch(term, allowEmails, lastSeenUsers = false) {
if (lastSeenUsers) { if (lastSeenUsers) {

View File

@ -139,13 +139,15 @@ export function highlightPost(postNumber) {
export function emailValid(email) { export function emailValid(email) {
// see: http://stackoverflow.com/questions/46155/validate-email-address-in-javascript // see: http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
const re = /^[a-zA-Z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/; const re =
/^[a-zA-Z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/;
return re.test(email); return re.test(email);
} }
export function hostnameValid(hostname) { export function hostnameValid(hostname) {
// see: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address // see: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
const re = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)+([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/; const re =
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)+([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
return hostname && re.test(hostname); return hostname && re.test(hostname);
} }
@ -457,7 +459,8 @@ export function postRNWebviewMessage(prop, value) {
} }
} }
const CODE_BLOCKS_REGEX = /^( |\t).*|`[^`]+`|^```[^]*?^```|\[code\][^]*?\[\/code\]/gm; const CODE_BLOCKS_REGEX =
/^( |\t).*|`[^`]+`|^```[^]*?^```|\[code\][^]*?\[\/code\]/gm;
// | ^ | ^ | ^ | ^ | // | ^ | ^ | ^ | ^ |
// | | | | // | | | |
// | | | code blocks between [code] // | | | code blocks between [code]

View File

@ -125,8 +125,8 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
user: this.currentUser, user: this.currentUser,
siteSettings: this.siteSettings, siteSettings: this.siteSettings,
isPrivateMessage, isPrivateMessage,
allowStaffToUploadAnyFileInPm: this.siteSettings allowStaffToUploadAnyFileInPm:
.allow_staff_to_upload_any_file_in_pm, this.siteSettings.allow_staff_to_upload_any_file_in_pm,
}; };
const isUploading = validateUploadedFile(currentFile, validationOpts); const isUploading = validateUploadedFile(currentFile, validationOpts);

View File

@ -95,9 +95,10 @@ export default Mixin.create({
const post = value.slice(end); const post = value.slice(end);
if (opts && opts.lineVal) { if (opts && opts.lineVal) {
const lineVal = value.split("\n")[ const lineVal =
value.slice(0, this._textarea.selectionStart).split("\n").length - 1 value.split("\n")[
]; value.slice(0, this._textarea.selectionStart).split("\n").length - 1
];
return { start, end, value: selVal, pre, post, lineVal }; return { start, end, value: selVal, pre, post, lineVal };
} else { } else {
return { start, end, value: selVal, pre, post }; return { start, end, value: selVal, pre, post };

View File

@ -81,9 +81,8 @@ Badge.reopenClass({
if ("badge_groupings" in json) { if ("badge_groupings" in json) {
json.badge_groupings.forEach( json.badge_groupings.forEach(
(badgeGroupingJson) => (badgeGroupingJson) =>
(badgeGroupings[badgeGroupingJson.id] = BadgeGrouping.create( (badgeGroupings[badgeGroupingJson.id] =
badgeGroupingJson BadgeGrouping.create(badgeGroupingJson))
))
); );
} }

View File

@ -221,8 +221,8 @@ const Category = RestModel.extend({
custom_fields: this.custom_fields, custom_fields: this.custom_fields,
topic_template: this.topic_template, topic_template: this.topic_template,
all_topics_wiki: this.all_topics_wiki, all_topics_wiki: this.all_topics_wiki,
allow_unlimited_owner_edits_on_first_post: this allow_unlimited_owner_edits_on_first_post:
.allow_unlimited_owner_edits_on_first_post, this.allow_unlimited_owner_edits_on_first_post,
allowed_tags: this.allowed_tags, allowed_tags: this.allowed_tags,
allowed_tag_groups: this.allowed_tag_groups, allowed_tag_groups: this.allowed_tag_groups,
allow_global_tags: this.allow_global_tags, allow_global_tags: this.allow_global_tags,

View File

@ -258,8 +258,8 @@ const Group = RestModel.extend({
default_notification_level: this.default_notification_level, default_notification_level: this.default_notification_level,
membership_request_template: this.membership_request_template, membership_request_template: this.membership_request_template,
publish_read_state: this.publish_read_state, publish_read_state: this.publish_read_state,
allow_unknown_sender_topic_replies: this allow_unknown_sender_topic_replies:
.allow_unknown_sender_topic_replies, this.allow_unknown_sender_topic_replies,
}; };
["muted", "regular", "watching", "tracking", "watching_first_post"].forEach( ["muted", "regular", "watching", "tracking", "watching_first_post"].forEach(

View File

@ -26,15 +26,12 @@ export default {
const site = Site.current(); const site = Site.current();
site.get("filters").forEach((filter) => { site.get("filters").forEach((filter) => {
const filterCapitalized = capitalize(filter); const filterCapitalized = capitalize(filter);
app[ app[`Discovery${filterCapitalized}Controller`] =
`Discovery${filterCapitalized}Controller` DiscoverySortableController.extend();
] = DiscoverySortableController.extend(); app[`Discovery${filterCapitalized}CategoryController`] =
app[ DiscoverySortableController.extend();
`Discovery${filterCapitalized}CategoryController` app[`Discovery${filterCapitalized}CategoryNoneController`] =
] = DiscoverySortableController.extend(); DiscoverySortableController.extend();
app[
`Discovery${filterCapitalized}CategoryNoneController`
] = DiscoverySortableController.extend();
if (filter === "top") { if (filter === "top") {
app.DiscoveryTopRoute = buildTopicRoute("top", { app.DiscoveryTopRoute = buildTopicRoute("top", {
@ -50,12 +47,10 @@ export default {
app[`Discovery${filterCapitalized}Route`] = buildTopicRoute(filter); app[`Discovery${filterCapitalized}Route`] = buildTopicRoute(filter);
} }
app[`Discovery${filterCapitalized}CategoryRoute`] = buildCategoryRoute( app[`Discovery${filterCapitalized}CategoryRoute`] =
filter buildCategoryRoute(filter);
); app[`Discovery${filterCapitalized}CategoryNoneRoute`] =
app[ buildCategoryRoute(filter, { no_subcategories: true });
`Discovery${filterCapitalized}CategoryNoneRoute`
] = buildCategoryRoute(filter, { no_subcategories: true });
}); });
app["TagsShowCategoryRoute"] = TagShowRoute.extend(); app["TagsShowCategoryRoute"] = TagShowRoute.extend();
@ -70,15 +65,12 @@ export default {
app["TagShow" + capitalize(filter) + "Route"] = TagShowRoute.extend({ app["TagShow" + capitalize(filter) + "Route"] = TagShowRoute.extend({
navMode: filter, navMode: filter,
}); });
app[ app["TagsShowCategory" + capitalize(filter) + "Route"] =
"TagsShowCategory" + capitalize(filter) + "Route" TagShowRoute.extend({ navMode: filter });
] = TagShowRoute.extend({ navMode: filter }); app["TagsShowCategoryNone" + capitalize(filter) + "Route"] =
app[ TagShowRoute.extend({ navMode: filter, noSubcategories: true });
"TagsShowCategoryNone" + capitalize(filter) + "Route" app["TagsShowCategoryAll" + capitalize(filter) + "Route"] =
] = TagShowRoute.extend({ navMode: filter, noSubcategories: true }); TagShowRoute.extend({ navMode: filter, noSubcategories: false });
app[
"TagsShowCategoryAll" + capitalize(filter) + "Route"
] = TagShowRoute.extend({ navMode: filter, noSubcategories: false });
}); });
}, },
}; };

View File

@ -48,9 +48,8 @@ export default {
caps.isiOSPWA = caps.isPwa && caps.isIOS; caps.isiOSPWA = caps.isPwa && caps.isIOS;
caps.wasLaunchedFromDiscourseHub = window.location.search.includes( caps.wasLaunchedFromDiscourseHub =
"discourse_app=1" window.location.search.includes("discourse_app=1");
);
caps.isAppWebview = window.ReactNativeWebView !== undefined; caps.isAppWebview = window.ReactNativeWebView !== undefined;
// Inject it // Inject it

View File

@ -1,9 +1,8 @@
import Route from "@ember/routing/route"; import Route from "@ember/routing/route";
export default Route.extend({ export default Route.extend({
setupController(controller) { setupController(controller) {
const accountCreated = this.controllerFor("account-created").get( const accountCreated =
"accountCreated" this.controllerFor("account-created").get("accountCreated");
);
controller.set("accountCreated", accountCreated); controller.set("accountCreated", accountCreated);
controller.set("newEmail", accountCreated.email); controller.set("newEmail", accountCreated.email);
}, },

View File

@ -6,9 +6,8 @@ const ForgotPasswordRoute = buildStaticRoute("password-reset");
ForgotPasswordRoute.reopen({ ForgotPasswordRoute.reopen({
beforeModel() { beforeModel() {
const loginRequired = this.controllerFor("application").get( const loginRequired =
"loginRequired" this.controllerFor("application").get("loginRequired");
);
this.replaceWith( this.replaceWith(
loginRequired ? "login" : `discovery.${defaultHomepage()}` loginRequired ? "login" : `discovery.${defaultHomepage()}`
).then((e) => { ).then((e) => {

View File

@ -73,18 +73,23 @@ export default class MediaOptimizationWorkerService extends Service {
width: imageData.width, width: imageData.width,
height: imageData.height, height: imageData.height,
settings: { settings: {
resize_threshold: this.siteSettings resize_threshold:
.composer_media_optimization_image_resize_dimensions_threshold, this.siteSettings
resize_target: this.siteSettings .composer_media_optimization_image_resize_dimensions_threshold,
.composer_media_optimization_image_resize_width_target, resize_target:
resize_pre_multiply: this.siteSettings this.siteSettings
.composer_media_optimization_image_resize_pre_multiply, .composer_media_optimization_image_resize_width_target,
resize_linear_rgb: this.siteSettings resize_pre_multiply:
.composer_media_optimization_image_resize_linear_rgb, this.siteSettings
encode_quality: this.siteSettings .composer_media_optimization_image_resize_pre_multiply,
.composer_media_optimization_image_encode_quality, resize_linear_rgb:
debug_mode: this.siteSettings this.siteSettings
.composer_media_optimization_debug_mode, .composer_media_optimization_image_resize_linear_rgb,
encode_quality:
this.siteSettings
.composer_media_optimization_image_encode_quality,
debug_mode:
this.siteSettings.composer_media_optimization_debug_mode,
}, },
}, },
[imageData.data.buffer] [imageData.data.buffer]

View File

@ -293,9 +293,8 @@ export default class PresenceService extends Service {
_getInitialData(channelName) { _getInitialData(channelName) {
let promiseProxy = this._initialDataRequests[channelName]; let promiseProxy = this._initialDataRequests[channelName];
if (!promiseProxy) { if (!promiseProxy) {
promiseProxy = this._initialDataRequests[ promiseProxy = this._initialDataRequests[channelName] =
channelName createPromiseProxy();
] = createPromiseProxy();
} }
once(this, this._makeInitialDataRequest); once(this, this._makeInitialDataRequest);

View File

@ -13,7 +13,7 @@
<tbody class="topic-list-body"> <tbody class="topic-list-body">
{{#each this.content as |bookmark|}} {{#each this.content as |bookmark|}}
<tr class="topic-list-item bookmark-list-item"> <tr class="topic-list-item bookmark-list-item">
<td class="main-link topic-list-data" role="rowheader"> <th scope="row" class="main-link topic-list-data">
<span class="link-top-line"> <span class="link-top-line">
<div class="bookmark-metadata"> <div class="bookmark-metadata">
{{#if bookmark.reminder_at}} {{#if bookmark.reminder_at}}
@ -58,7 +58,7 @@
{{/if}} {{/if}}
{{!-- template-lint-disable --}} {{!-- template-lint-disable --}}
<p class="post-excerpt" {{on "click" this.screenExcerptForExternalLink}}>{{html-safe bookmark.excerpt}}</p> <p class="post-excerpt" {{on "click" this.screenExcerptForExternalLink}}>{{html-safe bookmark.excerpt}}</p>
</td> </th>
{{#unless this.site.mobileView}} {{#unless this.site.mobileView}}
<td class="topic-list-data"> <td class="topic-list-data">
{{#if bookmark.user.avatar_template}} {{#if bookmark.user.avatar_template}}

View File

@ -8,7 +8,7 @@
{{/if}} {{/if}}
<div class="control-group bookmark-name-wrap"> <div class="control-group bookmark-name-wrap">
<Input @id="bookmark-name" @value={{this.model.name}} @name="bookmark-name" class="bookmark-name" @enter={{action "saveAndClose"}} placeholder={{i18n "post.bookmarks.name_placeholder"}} @maxlength="100" /> <Input id="bookmark-name" @value={{this.model.name}} name="bookmark-name" class="bookmark-name" @enter={{action "saveAndClose"}} placeholder={{i18n "post.bookmarks.name_placeholder"}} maxlength="100" />
<DButton @icon="cog" @action={{action "toggleShowOptions"}} @class="bookmark-options-button" @ariaLabel="post.bookmarks.options" /> <DButton @icon="cog" @action={{action "toggleShowOptions"}} @class="bookmark-options-button" @ariaLabel="post.bookmarks.options" />
</div> </div>

View File

@ -17,7 +17,7 @@
{{#each this.topics as |t|}} {{#each this.topics as |t|}}
<div class="controls existing-topic"> <div class="controls existing-topic">
<label class="radio"> <label class="radio">
<Input @id={{concat "choose-topic-" t.id}} @checked={{eq t.id this.selectedTopicId}} @click={{action "chooseTopic" t}} @type="radio" @name="choose_topic_id" /> <Input id={{concat "choose-topic-" t.id}} @checked={{eq t.id this.selectedTopicId}} @type="radio" name="choose_topic_id" {{on "click" (action "chooseTopic" t)}} />
<TopicStatus @topic={{t}} @disableActions={{true}} /> <TopicStatus @topic={{t}} @disableActions={{true}} />
<span class="topic-title"> <span class="topic-title">
{{replace-emoji t.fancy_title}} {{replace-emoji t.fancy_title}}

View File

@ -1,4 +1,4 @@
<Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{readonly this.value}} @input={{action "onChangeDate"}} @id={{this.inputId}} /> <Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{readonly this.value}} id={{this.inputId}} {{on "input" (action "onChangeDate")}} />
{{#unless this.useGlobalPickerContainer}} {{#unless this.useGlobalPickerContainer}}
<div class="picker-container"></div> <div class="picker-container"></div>

View File

@ -1 +1 @@
<Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{this.value}} @autocomplete="off" /> <Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{this.value}} autocomplete="off" />

View File

@ -13,7 +13,7 @@
<section class="field allow-global-tags"> <section class="field allow-global-tags">
<label> <label>
<Input @type="checkbox" @checked={{this.category.allow_global_tags}} @id="allow_global_tags" @disabled={{this.disableAllowGlobalTags}} /> <Input @type="checkbox" @checked={{this.category.allow_global_tags}} id="allow_global_tags" disabled={{this.disableAllowGlobalTags}} />
{{i18n "category.allow_global_tags_label"}} {{i18n "category.allow_global_tags_label"}}
</label> </label>
</section> </section>

View File

@ -1,7 +1,7 @@
{{#if this.isActive}} {{#if this.isActive}}
{{!-- template-lint-disable no-invalid-interactive --}} {{!-- template-lint-disable no-invalid-interactive no-down-event-binding --}}
<div {{on "keydown" (action "keydown")}} class="emoji-picker {{if this.isActive "opened"}}"> <div {{on "keydown" (action "keydown")}} class="emoji-picker {{if this.isActive "opened"}}">
{{!-- template-lint-enable no-invalid-interactive --}} {{!-- template-lint-enable no-invalid-interactive no-down-event-binding --}}
<div class="emoji-picker-category-buttons"> <div class="emoji-picker-category-buttons">
{{#if this.recentEmojis.length}} {{#if this.recentEmojis.length}}
<button type="button" data-section="recent" {{action "onCategorySelection" "recent"}} class="btn btn-default category-button emoji"> <button type="button" data-section="recent" {{action "onCategorySelection" "recent"}} class="btn btn-default category-button emoji">
@ -20,7 +20,7 @@
<div class="emoji-picker-content"> <div class="emoji-picker-content">
<div class="emoji-picker-search-container"> <div class="emoji-picker-search-container">
<Input class="filter" @name="filter" @value={{@initialFilter}} placeholder={{i18n "emoji_picker.filter_placeholder"}} @autocomplete="off" @type="search" @autocorrect="off" @autocapitalize="off" @input={{action "onFilterChange"}} /> <Input class="filter" name="filter" @value={{@initialFilter}} placeholder={{i18n "emoji_picker.filter_placeholder"}} autocomplete="off" @type="search" autocorrect="off" autocapitalize="off" {{on "input" (action "onFilterChange")}} />
{{d-icon "search"}} {{d-icon "search"}}
</div> </div>

View File

@ -4,7 +4,7 @@
{{i18n "admin.emoji.name"}} {{i18n "admin.emoji.name"}}
</span> </span>
<div class="input"> <div class="input">
<Input @id="emoji-name" @name="name" @placeholderKey="admin.emoji.name" @value={{readonly this.name}} @input={{action (mut this.name) value="target.value"}} /> <Input id="emoji-name" name="name" placeholder={{i18n "admin.emoji.name"}} @value={{readonly this.name}} {{on "input" (action (mut this.name) value="target.value")}} />
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">

View File

@ -7,7 +7,7 @@
<div class="flag-action-type-details"> <div class="flag-action-type-details">
<span class="description">{{html-safe this.flag.description}}</span> <span class="description">{{html-safe this.flag.description}}</span>
{{#if this.showMessageInput}} {{#if this.showMessageInput}}
<Textarea @name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div> <Textarea name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div>
{{/if}} {{/if}}
</div> </div>
</label> </label>
@ -26,7 +26,7 @@
<div class="description">{{html-safe this.description}}</div> <div class="description">{{html-safe this.description}}</div>
{{/if}} {{/if}}
{{#if this.showMessageInput}} {{#if this.showMessageInput}}
<Textarea @name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div> <Textarea name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div>
{{/if}} {{/if}}
</div> </div>
</label> </label>

View File

@ -16,7 +16,7 @@
<div class="control-group future-date-input-time-picker"> <div class="control-group future-date-input-time-picker">
{{d-icon "far-clock"}} {{d-icon "far-clock"}}
<Input placeholder="--:--" @type="time" class="time-input" @value={{this._time}} @disabled={{this.timeInputDisabled}} @input={{action "onChangeTime" value="target.value"}} /> <Input placeholder="--:--" @type="time" class="time-input" @value={{this._time}} disabled={{this.timeInputDisabled}} {{on "input" (action "onChangeTime" value="target.value")}} />
</div> </div>
{{/if}} {{/if}}
</div> </div>

View File

@ -3,11 +3,11 @@
<div> <div>
<div class="control-group"> <div class="control-group">
<label for="imap_server">{{i18n "groups.manage.email.credentials.imap_server"}}</label> <label for="imap_server">{{i18n "groups.manage.email.credentials.imap_server"}}</label>
<Input @type="text" @name="imap_server" @value={{this.form.imap_server}} @tabindex="8" @onChange={{action "resetSettingsValid"}} /> <Input @type="text" name="imap_server" @value={{this.form.imap_server}} tabindex="8" {{on "change" (action "resetSettingsValid")}} />
</div> </div>
<label for="enable_ssl_imap"> <label for="enable_ssl_imap">
<Input @type="checkbox" @checked={{this.form.imap_ssl}} @id="enable_ssl_imap" @tabindex="11" @onChange={{action "resetSettingsValid"}} /> <Input @type="checkbox" @checked={{this.form.imap_ssl}} id="enable_ssl_imap" tabindex="11" {{on "change" (action "resetSettingsValid")}} />
{{i18n "groups.manage.email.credentials.imap_ssl"}} {{i18n "groups.manage.email.credentials.imap_ssl"}}
</label> </label>
</div> </div>
@ -15,7 +15,7 @@
<div> <div>
<div class="control-group"> <div class="control-group">
<label for="imap_port">{{i18n "groups.manage.email.credentials.imap_port"}}</label> <label for="imap_port">{{i18n "groups.manage.email.credentials.imap_port"}}</label>
<Input @type="text" @name="imap_port" @value={{this.form.imap_port}} @tabindex="9" @onChange={{action "resetSettingsValid" this.form.imap_port}} /> <Input @type="text" name="imap_port" @value={{this.form.imap_port}} tabindex="9" {{on "change" (action "resetSettingsValid" this.form.imap_port)}} />
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
<p>{{i18n "groups.manage.email.smtp_instructions"}}</p> <p>{{i18n "groups.manage.email.smtp_instructions"}}</p>
<label for="enable_smtp"> <label for="enable_smtp">
<Input @type="checkbox" @checked={{this.group.smtp_enabled}} @id="enable_smtp" @change={{action "smtpEnabledChange"}} @tabindex="1" /> <Input @type="checkbox" @checked={{this.group.smtp_enabled}} id="enable_smtp" tabindex="1" {{on "change" (action "smtpEnabledChange")}} />
{{i18n "groups.manage.email.enable_smtp"}} {{i18n "groups.manage.email.enable_smtp"}}
</label> </label>
@ -23,7 +23,7 @@
<div class="alert alert-warning">{{i18n "groups.manage.email.imap_alpha_warning"}}</div> <div class="alert alert-warning">{{i18n "groups.manage.email.imap_alpha_warning"}}</div>
<label for="enable_imap"> <label for="enable_imap">
<Input @type="checkbox" @disabled={{not this.enableImapSettings}} @checked={{this.group.imap_enabled}} @id="enable_imap" @change={{action "imapEnabledChange"}} @tabindex="8" /> <Input @type="checkbox" disabled={{not this.enableImapSettings}} @checked={{this.group.imap_enabled}} id="enable_imap" tabindex="8" {{on "change" (action "imapEnabledChange")}} />
{{i18n "groups.manage.email.enable_imap"}} {{i18n "groups.manage.email.enable_imap"}}
</label> </label>
@ -37,7 +37,7 @@
<div class="control-group"> <div class="control-group">
<h3>{{i18n "groups.manage.email.imap_additional_settings"}}</h3> <h3>{{i18n "groups.manage.email.imap_additional_settings"}}</h3>
<label class="control-group-inline" for="allow_unknown_sender_topic_replies"> <label class="control-group-inline" for="allow_unknown_sender_topic_replies">
<Input @type="checkbox" @name="allow_unknown_sender_topic_replies" @id="allow_unknown_sender_topic_replies" @checked={{this.group.allow_unknown_sender_topic_replies}} @tabindex="13" /> <Input @type="checkbox" name="allow_unknown_sender_topic_replies" id="allow_unknown_sender_topic_replies" @checked={{this.group.allow_unknown_sender_topic_replies}} tabindex="13" />
<span>{{i18n "groups.manage.email.settings.allow_unknown_sender_topic_replies"}}</span> <span>{{i18n "groups.manage.email.settings.allow_unknown_sender_topic_replies"}}</span>
</label> </label>
<p>{{i18n "groups.manage.email.settings.allow_unknown_sender_topic_replies_hint"}}</p> <p>{{i18n "groups.manage.email.settings.allow_unknown_sender_topic_replies_hint"}}</p>

View File

@ -13,7 +13,7 @@
{{#each this.tabs as |tab|}} {{#each this.tabs as |tab|}}
<li> <li>
<LinkTo @route={{tab.route}} @model={{this.group}} @title={{tab.message}} class={{tab.name}}> <LinkTo @route={{tab.route}} @model={{this.group}} title={{tab.message}} class={{tab.name}}>
{{#if tab.icon}}{{d-icon tab.icon}}{{/if}} {{#if tab.icon}}{{d-icon tab.icon}}{{/if}}
{{tab.message}} {{tab.message}}
{{#if tab.count}}<span class="count">({{tab.count}})</span>{{/if}} {{#if tab.count}}<span class="count">({{tab.count}})</span>{{/if}}

View File

@ -3,16 +3,16 @@
<div> <div>
<div class="control-group"> <div class="control-group">
<label for="username">{{i18n "groups.manage.email.credentials.username"}}</label> <label for="username">{{i18n "groups.manage.email.credentials.username"}}</label>
<Input @type="text" @name="username" @value={{this.form.email_username}} @tabindex="1" @onChange={{action "resetSettingsValid"}} /> <Input @type="text" name="username" @value={{this.form.email_username}} tabindex="1" {{on "change" (action "resetSettingsValid")}} />
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="smtp_server">{{i18n "groups.manage.email.credentials.smtp_server"}}</label> <label for="smtp_server">{{i18n "groups.manage.email.credentials.smtp_server"}}</label>
<Input @type="text" @name="smtp_server" @value={{this.form.smtp_server}} @tabindex="4" @onChange={{action "resetSettingsValid"}} /> <Input @type="text" name="smtp_server" @value={{this.form.smtp_server}} tabindex="4" {{on "change" (action "resetSettingsValid")}} />
</div> </div>
<label for="enable_ssl"> <label for="enable_ssl">
<Input @type="checkbox" @checked={{this.form.smtp_ssl}} @id="enable_ssl" @tabindex="6" @onChange={{action "resetSettingsValid"}} /> <Input @type="checkbox" @checked={{this.form.smtp_ssl}} id="enable_ssl" tabindex="6" {{on "change" (action "resetSettingsValid")}} />
{{i18n "groups.manage.email.credentials.smtp_ssl"}} {{i18n "groups.manage.email.credentials.smtp_ssl"}}
</label> </label>
</div> </div>
@ -20,19 +20,19 @@
<div> <div>
<div class="control-group"> <div class="control-group">
<label for="password">{{i18n "groups.manage.email.credentials.password"}}</label> <label for="password">{{i18n "groups.manage.email.credentials.password"}}</label>
<Input @type="password" @name="password" @value={{this.form.email_password}} @tabindex="2" @onChange={{action "resetSettingsValid"}} /> <Input @type="password" name="password" @value={{this.form.email_password}} tabindex="2" {{on "change" (action "resetSettingsValid")}} />
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="smtp_port">{{i18n "groups.manage.email.credentials.smtp_port"}}</label> <label for="smtp_port">{{i18n "groups.manage.email.credentials.smtp_port"}}</label>
<Input @type="text" @name="smtp_port" @value={{this.form.smtp_port}} @tabindex="5" @onChange={{action "resetSettingsValid" this.form.smtp_port}} /> <Input @type="text" name="smtp_port" @value={{this.form.smtp_port}} tabindex="5" {{on "change" (action "resetSettingsValid" this.form.smtp_port)}} />
</div> </div>
</div> </div>
<div> <div>
<div class="control-group"> <div class="control-group">
<label for="from_alias">{{i18n "groups.manage.email.settings.from_alias"}}</label> <label for="from_alias">{{i18n "groups.manage.email.settings.from_alias"}}</label>
<Input @type="text" @name="from_alias" @id="from_alias" @value={{this.form.email_from_alias}} @onChange={{action "resetSettingsValid"}} @tabindex="3" /> <Input @type="text" name="from_alias" id="from_alias" @value={{this.form.email_from_alias}} {{on "change" (action "resetSettingsValid")}} tabindex="3" />
<p>{{i18n "groups.manage.email.settings.from_alias_hint"}}</p> <p>{{i18n "groups.manage.email.settings.from_alias_hint"}}</p>
</div> </div>
</div> </div>

View File

@ -2,7 +2,7 @@
<label class="control-label">{{i18n "groups.manage.membership.access"}}</label> <label class="control-label">{{i18n "groups.manage.membership.access"}}</label>
<label> <label>
<Input @type="checkbox" class="group-form-public-admission" @checked={{this.model.public_admission}} @disabled={{this.disablePublicSetting}} /> <Input @type="checkbox" class="group-form-public-admission" @checked={{this.model.public_admission}} disabled={{this.disablePublicSetting}} />
{{i18n "groups.public_admission"}} {{i18n "groups.public_admission"}}
</label> </label>
@ -14,7 +14,7 @@
</label> </label>
<label> <label>
<Input @type="checkbox" class="group-form-allow-membership-requests" @checked={{this.model.allow_membership_requests}} @disabled={{this.disableMembershipRequestSetting}} /> <Input @type="checkbox" class="group-form-allow-membership-requests" @checked={{this.model.allow_membership_requests}} disabled={{this.disableMembershipRequestSetting}} />
{{i18n "groups.allow_membership_requests"}} {{i18n "groups.allow_membership_requests"}}
</label> </label>
@ -68,7 +68,7 @@
{{i18n "admin.groups.default_title"}} {{i18n "admin.groups.default_title"}}
</label> </label>
<Input @value={{this.model.title}} @name="title" class="input-xxlarge" /> <Input @value={{this.model.title}} name="title" class="input-xxlarge" />
<div class="control-instructions"> <div class="control-instructions">
{{i18n "admin.groups.default_title_description"}} {{i18n "admin.groups.default_title_description"}}

View File

@ -1,4 +1,4 @@
<label class="checkbox-label"> <label class="checkbox-label">
<Input @type="checkbox" @disabled={{this.disabled}} @checked={{this.checked}} /> <Input @type="checkbox" disabled={{this.disabled}} @checked={{this.checked}} />
{{this.label}} {{this.label}}
</label> </label>

View File

@ -29,7 +29,7 @@
{{#if this.siteSettings.enable_fast_edit}} {{#if this.siteSettings.enable_fast_edit}}
{{#if this._displayFastEditInput}} {{#if this._displayFastEditInput}}
<div class="fast-edit-container"> <div class="fast-edit-container">
<Textarea @id="fast-edit-input" @value={{this._fastEditNewSelection}} /> <DButton @action={{action "_saveFastEdit"}} @class="btn-small btn-primary save-fast-edit" @icon="pencil-alt" @label="composer.save_edit" @translatedTitle={{this._saveEditButtonTitle}} @disabled={{this._saveFastEditDisabled}} @isLoading={{this._isSavingFastEdit}} /> <Textarea id="fast-edit-input" @value={{this._fastEditNewSelection}} /> <DButton @action={{action "_saveFastEdit"}} @class="btn-small btn-primary save-fast-edit" @icon="pencil-alt" @label="composer.save_edit" @translatedTitle={{this._saveEditButtonTitle}} @disabled={{this._saveFastEditDisabled}} @isLoading={{this._isSavingFastEdit}} />
</div> </div>
{{/if}} {{/if}}
{{/if}} {{/if}}

View File

@ -1,4 +1,4 @@
<div class="relative-time-picker"> <div class="relative-time-picker">
<Input class="relative-time-duration" @min={{this.durationMin}} @step={{this.durationStep}} @type="number" @value={{this.duration}} @onChange={{action "onChangeDuration"}} @id={{this.id}} /> <Input class="relative-time-duration" min={{this.durationMin}} step={{this.durationStep}} @type="number" @value={{this.duration}} {{on "change" (action "onChangeDuration")}} id={{this.id}} />
<ComboBox @content={{this.intervals}} @value={{this.selectedInterval}} @class="relative-time-intervals" @onChange={{action "onChangeInterval"}} /> <ComboBox @content={{this.intervals}} @value={{this.selectedInterval}} @class="relative-time-intervals" @onChange={{action "onChangeInterval"}} />
</div> </div>

View File

@ -1 +1 @@
<Input @value={{this.value}} @change={{this.valueChanged}} class="reviewable-input-text" /> <Input @value={{this.value}} class="reviewable-input-text" {{on "change" this.valueChanged}} />

View File

@ -1 +1 @@
<Textarea @value={{this.value}} @change={{this.valueChanged}} class="reviewable-input-textarea" /> <Textarea @value={{this.value}} {{on "change" this.valueChanged}} class="reviewable-input-textarea" />

View File

@ -23,7 +23,7 @@
{{#if this.showAllTagsCheckbox}} {{#if this.showAllTagsCheckbox}}
<section class="field"> <section class="field">
<label> <label>
<Input @type="checkbox" class="all-tags" @checked={{this.searchedTerms.special.all_tags}} @click={{action "onChangeSearchTermForAllTags" value="target.checked"}} /> <Input @type="checkbox" class="all-tags" @checked={{this.searchedTerms.special.all_tags}} {{on "click" (action "onChangeSearchTermForAllTags" value="target.checked")}} />
{{i18n "search.advanced.filters.all_tags"}} {{i18n "search.advanced.filters.all_tags"}}
</label> </label>
</section> </section>
@ -39,24 +39,24 @@
{{#if this.currentUser}} {{#if this.currentUser}}
<div class="grouped-control-field"> <div class="grouped-control-field">
<Input @id="matching-title-only" @type="checkbox" class="in-title" @checked={{this.searchedTerms.special.in.title}} @click={{action "onChangeSearchTermForSpecialInTitle" value="target.checked"}} /> <Input id="matching-title-only" @type="checkbox" class="in-title" @checked={{this.searchedTerms.special.in.title}} {{on "click" (action "onChangeSearchTermForSpecialInTitle" value="target.checked")}} />
<label for="matching-title-only"> <label for="matching-title-only">
{{i18n "search.advanced.filters.title"}} {{i18n "search.advanced.filters.title"}}
</label> </label>
</div> </div>
<div class="grouped-control-field"> <div class="grouped-control-field">
<Input @id="matching-liked" @type="checkbox" class="in-likes" @checked={{this.searchedTerms.special.in.likes}} @click={{action "onChangeSearchTermForSpecialInLikes" value="target.checked"}} /> <Input id="matching-liked" @type="checkbox" class="in-likes" @checked={{this.searchedTerms.special.in.likes}} {{on "click" (action "onChangeSearchTermForSpecialInLikes" value="target.checked")}} />
<label for="matching-liked">{{i18n "search.advanced.filters.likes"}}</label> <label for="matching-liked">{{i18n "search.advanced.filters.likes"}}</label>
</div> </div>
<div class="grouped-control-field"> <div class="grouped-control-field">
<Input @id="matching-in-messages" @type="checkbox" class="in-private" @checked={{this.searchedTerms.special.in.messages}} @click={{action "onChangeSearchTermForSpecialInMessages" value="target.checked"}} /> <Input id="matching-in-messages" @type="checkbox" class="in-private" @checked={{this.searchedTerms.special.in.messages}} {{on "click" (action "onChangeSearchTermForSpecialInMessages" value="target.checked")}} />
<label for="matching-in-messages">{{i18n "search.advanced.filters.private"}}</label> <label for="matching-in-messages">{{i18n "search.advanced.filters.private"}}</label>
</div> </div>
<div class="grouped-control-field"> <div class="grouped-control-field">
<Input @id="matching-seen" @type="checkbox" class="in-seen" @checked={{this.searchedTerms.special.in.seen}} @click={{action "onChangeSearchTermForSpecialInSeen" value="target.checked"}} /> <Input id="matching-seen" @type="checkbox" class="in-seen" @checked={{this.searchedTerms.special.in.seen}} {{on "click" (action "onChangeSearchTermForSpecialInSeen" value="target.checked")}} />
<label for="matching-seen">{{i18n "search.advanced.filters.seen"}}</label> <label for="matching-seen">{{i18n "search.advanced.filters.seen"}}</label>
</div> </div>
{{/if}} {{/if}}
@ -114,9 +114,9 @@
{{!-- TODO: Using a label here fails no-nested-interactive lint rule --}} {{!-- TODO: Using a label here fails no-nested-interactive lint rule --}}
<span class="control-label">{{i18n "search.advanced.post.count.label"}}</span> <span class="control-label">{{i18n "search.advanced.post.count.label"}}</span>
<div class="controls"> <div class="controls">
<Input @type="number" @value={{readonly this.searchedTerms.min_posts}} class="input-small" @id="search-min-post-count" @input={{action "onChangeSearchTermMinPostCount" value="target.value"}} placeholder={{i18n "search.advanced.post.min.placeholder"}} @aria-label={{i18n "search.advanced.post.min.aria_label"}} /> <Input @type="number" @value={{readonly this.searchedTerms.min_posts}} class="input-small" id="search-min-post-count" placeholder={{i18n "search.advanced.post.min.placeholder"}} aria-label={{i18n "search.advanced.post.min.aria_label"}} {{on "input" (action "onChangeSearchTermMinPostCount" value="target.value")}} />
{{d-icon "arrows-alt-h"}} {{d-icon "arrows-alt-h"}}
<Input @type="number" @value={{readonly this.searchedTerms.max_posts}} class="input-small" @id="search-max-post-count" @input={{action "onChangeSearchTermMaxPostCount" value="target.value"}} placeholder={{i18n "search.advanced.post.max.placeholder"}} @aria-label={{i18n "search.advanced.post.max.aria_label"}} /> <Input @type="number" @value={{readonly this.searchedTerms.max_posts}} class="input-small" id="search-max-post-count" placeholder={{i18n "search.advanced.post.max.placeholder"}} aria-label={{i18n "search.advanced.post.max.aria_label"}} {{on "input" (action "onChangeSearchTermMaxPostCount" value="target.value")}} />
</div> </div>
</div> </div>
@ -124,9 +124,9 @@
{{!-- TODO: Using a label here fails no-nested-interactive lint rule --}} {{!-- TODO: Using a label here fails no-nested-interactive lint rule --}}
<span class="control-label">{{i18n "search.advanced.views.label"}}</span> <span class="control-label">{{i18n "search.advanced.views.label"}}</span>
<div class="controls"> <div class="controls">
<Input @type="number" @value={{readonly this.searchedTerms.min_views}} class="input-small" @id="search-min-views" @input={{action "onChangeSearchTermMinViews" value="target.value"}} placeholder={{i18n "search.advanced.min_views.placeholder"}} @aria-label={{i18n "search.advanced.min_views.aria_label"}} /> <Input @type="number" @value={{readonly this.searchedTerms.min_views}} class="input-small" id="search-min-views" placeholder={{i18n "search.advanced.min_views.placeholder"}} aria-label={{i18n "search.advanced.min_views.aria_label"}} {{on "input" (action "onChangeSearchTermMinViews" value="target.value")}} />
{{d-icon "arrows-alt-h"}} {{d-icon "arrows-alt-h"}}
<Input @type="number" @value={{readonly this.searchedTerms.max_views}} class="input-small" @id="search-max-views" @input={{action "onChangeSearchTermMaxViews" value="target.value"}} placeholder={{i18n "search.advanced.max_views.placeholder"}} @aria-label={{i18n "search.advanced.max_views.aria_label"}} /> <Input @type="number" @value={{readonly this.searchedTerms.max_views}} class="input-small" id="search-max-views" placeholder={{i18n "search.advanced.max_views.placeholder"}} aria-label={{i18n "search.advanced.max_views.aria_label"}} {{on "input" (action "onChangeSearchTermMaxViews" value="target.value")}} />
</div> </div>
</div> </div>
</details> </details>

View File

@ -8,7 +8,7 @@
@route={{@headerRoute}} @route={{@headerRoute}}
@query={{@headerQuery}} @query={{@headerQuery}}
@models={{if @headerModel (array @headerModel) (if @headerModels @headerModels (array))}} @models={{if @headerModel (array @headerModel) (if @headerModels @headerModels (array))}}
@class="sidebar-section-header-link" class="sidebar-section-header-link"
title={{@headerLinkTitle}}> title={{@headerLinkTitle}}>
{{@headerLinkText}} {{@headerLinkText}}

View File

@ -25,7 +25,7 @@
<section class="group-one-per-topic"> <section class="group-one-per-topic">
<label> <label>
<Input @type="checkbox" @checked={{this.buffered.one_per_topic}} @name="onepertopic" /> <Input @type="checkbox" @checked={{this.buffered.one_per_topic}} name="onepertopic" />
{{i18n "tagging.groups.one_per_topic_label"}} {{i18n "tagging.groups.one_per_topic_label"}}
</label> </label>
</section> </section>

View File

@ -16,7 +16,7 @@
</div> </div>
<div class="tap-tile-time-input"> <div class="tap-tile-time-input">
{{d-icon "far-clock"}} {{d-icon "far-clock"}}
<Input placeholder="--:--" @id="custom-time" @type="time" class="time-input" @value={{this.customTime}} /> <Input placeholder="--:--" id="custom-time" @type="time" class="time-input" @value={{this.customTime}} />
</div> </div>
</div> </div>
<div class="control-group custom-date-time-wrap custom-relative-wrap"> <div class="control-group custom-date-time-wrap custom-relative-wrap">

View File

@ -6,7 +6,7 @@
<div class="controls"> <div class="controls">
<label class="control-label checkbox-label"> <label class="control-label checkbox-label">
<Input @id={{concat "user-" this.elementId}} @checked={{this.value}} @type="checkbox" /> <Input id={{concat "user-" this.elementId}} @checked={{this.value}} @type="checkbox" />
<span> <span>
{{html-safe this.field.description}} {{#unless this.field.name}}{{#if this.field.required}}<span class="required">*</span>{{/if}}{{/unless}} {{html-safe this.field.description}} {{#unless this.field.name}}{{#if this.field.required}}<span class="required">*</span>{{/if}}{{/unless}}
</span> </span>

View File

@ -3,6 +3,6 @@
{{#if this.field.required}}<span class="required">*</span>{{/if}} {{#if this.field.required}}<span class="required">*</span>{{/if}}
</label> </label>
<div class="controls"> <div class="controls">
<Input @id={{concat "user-" this.elementId}} @value={{this.value}} @maxlength={{this.site.user_field_max_length}} /> <Input id={{concat "user-" this.elementId}} @value={{this.value}} maxlength={{this.site.user_field_max_length}} />
<div class="instructions">{{html-safe this.field.description}}</div> <div class="instructions">{{html-safe this.field.description}}</div>
</div> </div>

View File

@ -23,7 +23,7 @@
{{#if this.context}} {{#if this.context}}
<div class="search-context"> <div class="search-context">
<label> <label>
<Input @type="checkbox" @name="searchContext" @checked={{this.searchContextEnabled}} /> {{this.searchContextDescription}} <Input @type="checkbox" name="searchContext" @checked={{this.searchContextEnabled}} /> {{this.searchContextDescription}}
</label> </label>
</div> </div>
{{/if}} {{/if}}

View File

@ -50,7 +50,7 @@
<tr> <tr>
{{#if this.isBulk}} {{#if this.isBulk}}
<td class="bulk-select"> <td class="bulk-select">
<Input @type="checkbox" class="bulk-select" @click={{action "selectMember" m}} /> <Input @type="checkbox" class="bulk-select" {{on "click" (action "selectMember" m)}} />
</td> </td>
{{/if}} {{/if}}

View File

@ -7,7 +7,7 @@
{{/if}} {{/if}}
<div class="groups-header-filters"> <div class="groups-header-filters">
<Input @value={{readonly this.filter}} @placeholderKey="groups.index.all" class="groups-header-filters-name no-blur" @input={{action "onFilterChanged" value="target.value"}} /> <Input @value={{readonly this.filter}} placeholder={{i18n "groups.index.all"}} class="groups-header-filters-name no-blur" {{on "input" (action "onFilterChanged" value="target.value")}} />
<ComboBox @value={{this.type}} @content={{this.types}} @class="groups-header-filters-type" @onChange={{action (mut this.type)}} @options={{hash <ComboBox @value={{this.type}} @content={{this.types}} @class="groups-header-filters-type" @onChange={{action (mut this.type)}} @options={{hash
clearable=true clearable=true
@ -22,7 +22,7 @@
<div class="container"> <div class="container">
<div class="groups-boxes"> <div class="groups-boxes">
{{#each this.groups as |group|}} {{#each this.groups as |group|}}
<LinkTo @route="group.members" @model={{group.name}} @classNames={{concat "group-box " group.name}}> <LinkTo @route="group.members" @model={{group.name}} class={{concat "group-box " group.name}}>
<div class="group-box-inner"> <div class="group-box-inner">
<div class="group-info-wrapper"> <div class="group-info-wrapper">
{{#if group.flair_url}} {{#if group.flair_url}}

Some files were not shown because too many files have changed in this diff Show More