mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Introduce {{body-class}}
, soft-deprecate <DSection />
(#23479)
`<DSection />` is now deprecated. Please use `{{body-class "foo-page" "bar"}}` and/or `<section></section>` instead.
This commit is contained in:
parent
055d29d898
commit
87d0336f05
@ -1,4 +1,4 @@
|
||||
<DSection @class="award-badge">
|
||||
<section class="award-badge">
|
||||
<h1>{{i18n "admin.badges.mass_award.title"}}</h1>
|
||||
<p>{{i18n "admin.badges.mass_award.description"}}</p>
|
||||
|
||||
@ -93,4 +93,4 @@
|
||||
"admin.badges.mass_award.no_badge_selected"
|
||||
}}</span>
|
||||
{{/if}}
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,4 @@
|
||||
<DSection @class="current-badges">
|
||||
<section class="current-badges">
|
||||
<div class="badge-intro admin-intro">
|
||||
<img
|
||||
src={{this.badgeIntroEmoji}}
|
||||
@ -22,4 +22,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,4 @@
|
||||
<DSection @class="current-badge content-body">
|
||||
<section class="current-badge content-body">
|
||||
<div class="control-group current-badge__toggle-badge">
|
||||
<DToggleSwitch
|
||||
@state={{this.buffered.enabled}}
|
||||
@ -287,7 +287,7 @@
|
||||
{{/unless}}
|
||||
</div>
|
||||
</form>
|
||||
</DSection>
|
||||
</section>
|
||||
|
||||
{{#if this.grant_count}}
|
||||
<div class="content-body current-badge-actions">
|
||||
|
@ -269,8 +269,8 @@
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.model.component}}
|
||||
<DSection
|
||||
@class="form-horizontal theme settings control-unit theme-settings__color-scheme"
|
||||
<section
|
||||
class="form-horizontal theme settings control-unit theme-settings__color-scheme"
|
||||
>
|
||||
<div class="row setting">
|
||||
<div class="setting-label">
|
||||
@ -305,11 +305,11 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
||||
{{/unless}}
|
||||
|
||||
{{#if this.model.component}}
|
||||
<DSection @class="form-horizontal theme settings control-unit">
|
||||
<section class="form-horizontal theme settings control-unit">
|
||||
<div class="row setting">
|
||||
<ThemeSettingRelativesSelector
|
||||
@setting={{this.relativesSelectorSettingsForComponent}}
|
||||
@ -317,9 +317,9 @@
|
||||
@class="theme-setting"
|
||||
/>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
||||
{{else}}
|
||||
<DSection @class="form-horizontal theme settings control-unit">
|
||||
<section class="form-horizontal theme settings control-unit">
|
||||
<div class="row setting">
|
||||
<ThemeSettingRelativesSelector
|
||||
@setting={{this.relativesSelectorSettingsForTheme}}
|
||||
@ -327,7 +327,7 @@
|
||||
@class="theme-setting"
|
||||
/>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.model.remote_theme.is_git}}
|
||||
@ -421,7 +421,7 @@
|
||||
<p><i>{{i18n
|
||||
"admin.customize.theme.overriden_settings_explanation"
|
||||
}}</i></p>
|
||||
<DSection @class="form-horizontal theme settings control-unit">
|
||||
<section class="form-horizontal theme settings control-unit">
|
||||
{{#each this.settings as |setting|}}
|
||||
<ThemeSettingEditor
|
||||
@setting={{setting}}
|
||||
@ -429,7 +429,7 @@
|
||||
@class="theme-setting control-unit"
|
||||
/>
|
||||
{{/each}}
|
||||
</DSection>
|
||||
</section>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -438,8 +438,8 @@
|
||||
<div class="mini-title">{{i18n
|
||||
"admin.customize.theme.theme_translations"
|
||||
}}</div>
|
||||
<DSection
|
||||
@class="form-horizontal theme settings translations control-unit"
|
||||
<section
|
||||
class="form-horizontal theme settings translations control-unit"
|
||||
>
|
||||
{{#each this.translations as |translation|}}
|
||||
<ThemeTranslation
|
||||
@ -448,7 +448,7 @@
|
||||
@class="theme-translation"
|
||||
/>
|
||||
{{/each}}
|
||||
</DSection>
|
||||
</section>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{{#if this.filteredContent}}
|
||||
<DSection @class="form-horizontal settings">
|
||||
<section class="form-horizontal settings">
|
||||
{{#each this.filteredContent as |setting|}}
|
||||
<SiteSetting
|
||||
@setting={{setting}}
|
||||
@ -12,7 +12,7 @@
|
||||
count=this.category.maxResults
|
||||
}}</p>
|
||||
{{/if}}
|
||||
</DSection>
|
||||
</section>
|
||||
{{else}}
|
||||
<br />
|
||||
{{i18n "admin.site_settings.no_results"}}
|
||||
|
@ -1,3 +1 @@
|
||||
<DSection>
|
||||
{{outlet}}
|
||||
</DSection>
|
||||
<section>{{outlet}}</section>
|
@ -1,9 +1,8 @@
|
||||
<DSection
|
||||
tabIndex="-1"
|
||||
<section
|
||||
tabindex="-1"
|
||||
id={{this.elementId}}
|
||||
aria-hidden={{not this.isVisible}}
|
||||
class={{this.HTMLClassList}}
|
||||
@scrollTop={{false}}
|
||||
{{did-insert this.registerAppEventListeners}}
|
||||
{{will-destroy this.deregisterAppEventListeners}}
|
||||
>
|
||||
@ -81,4 +80,4 @@
|
||||
<div class="d-lightbox__focus-trap" tabindex="0"></div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</DSection>
|
||||
</section>
|
@ -0,0 +1,36 @@
|
||||
import Component from "@glimmer/component";
|
||||
import bodyClass from "discourse/helpers/body-class";
|
||||
import { concat } from "@ember/helper";
|
||||
import notEq from "truth-helpers/helpers/not-eq";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
// Can add a body class from within a component
|
||||
export default class DSection extends Component {
|
||||
<template>
|
||||
{{#if @pageClass}}
|
||||
{{bodyClass (concat @pageClass "-page")}}
|
||||
{{/if}}
|
||||
|
||||
{{#if @bodyClass}}
|
||||
{{bodyClass @bodyClass}}
|
||||
{{/if}}
|
||||
|
||||
{{#if (notEq @tagName "")}}
|
||||
<section id={{@id}} class={{@class}} ...attributes>{{yield}}</section>
|
||||
{{else}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
deprecated(
|
||||
`<DSection> is deprecated. Use {{body-class "foo-page" "bar"}} and/or <section></section> instead.`,
|
||||
{
|
||||
since: "3.2.0.beta1",
|
||||
dropFrom: "3.3.0.beta1",
|
||||
id: "discourse.d-section",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import Component from "@ember/component";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
|
||||
// Can add a body class from within a component
|
||||
export default class extends Component {
|
||||
tagName = null;
|
||||
pageClass = null;
|
||||
bodyClass = null;
|
||||
currentClasses = new Set();
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
scheduleOnce("afterRender", this, this._updateClasses);
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
scheduleOnce("afterRender", this, this._removeClasses);
|
||||
}
|
||||
|
||||
_updateClasses() {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const desiredClasses = new Set();
|
||||
if (this.pageClass) {
|
||||
desiredClasses.add(`${this.pageClass}-page`);
|
||||
}
|
||||
if (this.bodyClass) {
|
||||
for (const bodyClass of this.bodyClass.split(" ")) {
|
||||
desiredClasses.add(bodyClass);
|
||||
}
|
||||
}
|
||||
|
||||
document.body.classList.add(...desiredClasses);
|
||||
const removeClasses = [...this.currentClasses].filter(
|
||||
(c) => !desiredClasses.has(c)
|
||||
);
|
||||
document.body.classList.remove(...removeClasses);
|
||||
this.currentClasses = desiredClasses;
|
||||
}
|
||||
|
||||
_removeClasses() {
|
||||
document.body.classList.remove(...this.currentClasses);
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
<DSection @pageClass="has-sidebar" @id="d-sidebar" @class="sidebar-container">
|
||||
{{body-class "has-sidebar-page"}}
|
||||
|
||||
<section id="d-sidebar" class="sidebar-container">
|
||||
{{#if this.showSwitchPanelButtonsOnTop}}
|
||||
<Sidebar::SwitchPanelButtons @buttons={{this.switchPanelButtons}} />
|
||||
{{/if}}
|
||||
@ -21,4 +23,4 @@
|
||||
{{/unless}}
|
||||
|
||||
<Sidebar::Footer />
|
||||
</DSection>
|
||||
</section>
|
13
app/assets/javascripts/discourse/app/helpers/body-class.js
Normal file
13
app/assets/javascripts/discourse/app/helpers/body-class.js
Normal file
@ -0,0 +1,13 @@
|
||||
import Helper from "@ember/component/helper";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class BodyClass extends Helper {
|
||||
@service bodyClasses;
|
||||
|
||||
compute([...classes]) {
|
||||
this.bodyClasses.registerClasses(
|
||||
this,
|
||||
classes.flatMap((c) => c?.split(" ")).filter(Boolean)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import Service from "@ember/service";
|
||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||
import { registerDestructor } from "@ember/destroyable";
|
||||
|
||||
@disableImplicitInjections
|
||||
export default class BodyClassesService extends Service {
|
||||
#helpers = new Map();
|
||||
|
||||
registerClasses(helper, classes) {
|
||||
if (this.#helpers.has(helper)) {
|
||||
const previousClasses = this.#helpers.get(helper);
|
||||
|
||||
this.#helpers.set(helper, classes);
|
||||
this.removeUnusedClasses(previousClasses);
|
||||
} else {
|
||||
this.#helpers.set(helper, classes);
|
||||
|
||||
registerDestructor(helper, () => {
|
||||
const previousClasses = this.#helpers.get(helper);
|
||||
this.#helpers.delete(helper);
|
||||
this.removeUnusedClasses(previousClasses);
|
||||
});
|
||||
}
|
||||
|
||||
for (const bodyClass of classes) {
|
||||
document.body.classList.add(bodyClass);
|
||||
}
|
||||
}
|
||||
|
||||
removeUnusedClasses(classes) {
|
||||
const remainingClasses = new Set([...this.#helpers.values()].flat());
|
||||
|
||||
for (const bodyClass of classes) {
|
||||
if (!remainingClasses.has(bodyClass)) {
|
||||
document.body.classList.remove(bodyClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
<DSection @pageClass="about">
|
||||
{{body-class "about-page"}}
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="contents clearfix body-page">
|
||||
|
||||
@ -172,4 +174,4 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @pageClass="badges">
|
||||
{{body-class "badges-page"}}
|
||||
|
||||
<section>
|
||||
<div class="container badges">
|
||||
<h1>{{i18n "badges.title"}}</h1>
|
||||
|
||||
@ -21,4 +23,4 @@
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1 +0,0 @@
|
||||
<section>{{yield}}</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @bodyClass="static-{{this.model.path}}" @class="container">
|
||||
{{body-class (concat "static-" this.model.path)}}
|
||||
|
||||
<section class="container">
|
||||
<WatchRead>
|
||||
<div class="contents clearfix body-page">
|
||||
<PluginOutlet @name="above-static" />
|
||||
@ -6,4 +8,4 @@
|
||||
<PluginOutlet @name="below-static" />
|
||||
</div>
|
||||
</WatchRead>
|
||||
</DSection>
|
||||
</section>
|
@ -2,7 +2,9 @@
|
||||
{{hide-application-footer}}
|
||||
{{/if}}
|
||||
|
||||
<DSection @pageClass="search" @class="search-container">
|
||||
{{body-class "search-page"}}
|
||||
|
||||
<section class="search-container">
|
||||
<ScrollTracker
|
||||
@name="full-page-search"
|
||||
@tag={{this.searchTerm}}
|
||||
@ -280,4 +282,4 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -2,9 +2,11 @@
|
||||
{{hide-application-footer}}
|
||||
{{/if}}
|
||||
|
||||
{{body-class "groups-page"}}
|
||||
|
||||
<PluginOutlet @name="before-groups-index-container" @connectorTagName="div" />
|
||||
|
||||
<DSection @pageClass="groups" @class="container groups-index">
|
||||
<section class="container groups-index">
|
||||
<div class="groups-header">
|
||||
{{#if this.currentUser.can_create_group}}
|
||||
<DButton
|
||||
@ -126,7 +128,6 @@
|
||||
<p role="status">{{i18n "groups.index.empty"}}</p>
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
||||
|
||||
</DSection>
|
||||
</section>
|
||||
|
||||
<PluginOutlet @name="after-groups-index-container" @connectorTagName="div" />
|
@ -1,4 +1,6 @@
|
||||
<DSection @pageClass="groups-new">
|
||||
{{body-class "groups-new-page"}}
|
||||
|
||||
<section>
|
||||
<h1>{{i18n "admin.groups.new.title"}}</h1>
|
||||
|
||||
<hr />
|
||||
@ -51,4 +53,4 @@
|
||||
</LinkTo>
|
||||
</div>
|
||||
</form>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @pageClass="invite">
|
||||
{{body-class "invite-page"}}
|
||||
|
||||
<section>
|
||||
<div class="container invites-show clearfix">
|
||||
<div class="login-welcome-header">
|
||||
<h1 class="login-title">{{this.welcomeTitle}}</h1>
|
||||
@ -231,4 +233,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @bodyClass="static-login" @class="container">
|
||||
{{body-class "static-login"}}
|
||||
|
||||
<section class="container">
|
||||
<div class="contents clearfix body-page">
|
||||
<div class="login-welcome">
|
||||
<PluginOutlet @name="above-login" @outletArgs={{hash model=this.model}} />
|
||||
@ -29,4 +31,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @bodyClass="navigation-categories" @class="navigation-container">
|
||||
{{body-class "navigation-categories"}}
|
||||
|
||||
<section class="navigation-container">
|
||||
<DNavigation
|
||||
@filterMode="categories"
|
||||
@showCategoryAdmin={{this.showCategoryAdmin}}
|
||||
@ -8,4 +10,4 @@
|
||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||
@createTopic={{fn this.composer.openNewTopic (hash preferDraft=true)}}
|
||||
/>
|
||||
</DSection>
|
||||
</section>
|
@ -17,7 +17,7 @@
|
||||
</span>
|
||||
</section>
|
||||
|
||||
<DSection @class="navigation-container category-navigation">
|
||||
<section class="navigation-container category-navigation">
|
||||
<DNavigation
|
||||
@category={{this.category}}
|
||||
@filterMode={{this.filterMode}}
|
||||
@ -37,4 +37,4 @@
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash category=this.category}}
|
||||
/>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @bodyClass="navigation-topics" @class="navigation-container">
|
||||
{{body-class "navigation-topics"}}
|
||||
|
||||
<section class="navigation-container">
|
||||
<DNavigation
|
||||
@filterMode={{this.filterMode}}
|
||||
@canCreateTopic={{this.canCreateTopic}}
|
||||
@ -6,4 +8,4 @@
|
||||
@createTopic={{fn this.composer.openNewTopic (hash preferDraft=true)}}
|
||||
@skipCategoriesNavItem={{this.skipCategoriesNavItem}}
|
||||
/>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,6 @@
|
||||
<DSection @bodyClass="navigation-filter" @class="navigation-container">
|
||||
{{body-class "navigation-filter"}}
|
||||
|
||||
<section class="navigation-container">
|
||||
<div class="topic-query-filter">
|
||||
<div class="topic-query-filter__input">
|
||||
{{d-icon "filter" class="topic-query-filter__icon"}}
|
||||
@ -41,4 +43,4 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,54 +1,53 @@
|
||||
<DSection @pageClass="user-preferences" @tagName="">
|
||||
<section class="user-content user-preferences solo-preference">
|
||||
<form class="form-vertical">
|
||||
{{#if this.success}}
|
||||
<div class="alert alert-success">{{this.successMessage}}</div>
|
||||
<LinkTo @route="preferences.account" class="success-back">
|
||||
{{d-icon "arrow-left"}}
|
||||
{{i18n "user.change_email.back_to_preferences"}}
|
||||
</LinkTo>
|
||||
{{body-class "user-preferences-page"}}
|
||||
|
||||
{{else}}
|
||||
{{#if this.error}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
{{i18n
|
||||
(if this.new "user.add_email.title" "user.change_email.title")
|
||||
}}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<TextField
|
||||
@value={{this.newEmail}}
|
||||
@id="change-email"
|
||||
@classNames="input-xxlarge"
|
||||
@autofocus="autofocus"
|
||||
/>
|
||||
<div class="instructions">
|
||||
{{#if this.taken}}
|
||||
{{i18n "user.change_email.taken"}}
|
||||
{{else}}
|
||||
{{i18n "user.email.instructions"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<InputTip @validation={{this.emailValidation}} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="controls save-button">
|
||||
<DButton
|
||||
@action={{action "saveEmail"}}
|
||||
@disabled={{this.saveDisabled}}
|
||||
@translatedLabel={{this.saveButtonText}}
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
<CancelLink
|
||||
@route="preferences.account"
|
||||
@args={{this.model.username}}
|
||||
/>
|
||||
</div>
|
||||
<section class="user-content user-preferences solo-preference">
|
||||
<form class="form-vertical">
|
||||
{{#if this.success}}
|
||||
<div class="alert alert-success">{{this.successMessage}}</div>
|
||||
<LinkTo @route="preferences.account" class="success-back">
|
||||
{{d-icon "arrow-left"}}
|
||||
{{i18n "user.change_email.back_to_preferences"}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
{{#if this.error}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
</section>
|
||||
</DSection>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
{{i18n
|
||||
(if this.new "user.add_email.title" "user.change_email.title")
|
||||
}}
|
||||
</label>
|
||||
<div class="controls">
|
||||
<TextField
|
||||
@value={{this.newEmail}}
|
||||
@id="change-email"
|
||||
@classNames="input-xxlarge"
|
||||
@autofocus="autofocus"
|
||||
/>
|
||||
<div class="instructions">
|
||||
{{#if this.taken}}
|
||||
{{i18n "user.change_email.taken"}}
|
||||
{{else}}
|
||||
{{i18n "user.email.instructions"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<InputTip @validation={{this.emailValidation}} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="controls save-button">
|
||||
<DButton
|
||||
@action={{action "saveEmail"}}
|
||||
@disabled={{this.saveDisabled}}
|
||||
@translatedLabel={{this.saveButtonText}}
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
<CancelLink
|
||||
@route="preferences.account"
|
||||
@args={{this.model.username}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
</section>
|
@ -1,213 +1,213 @@
|
||||
<DSection @pageClass="user-preferences" @tagName="">
|
||||
<section class="user-content user-preferences solo-preference second-factor">
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
<form class="form-vertical">
|
||||
{{#if this.showEnforcedNotice}}
|
||||
<div class="alert alert-error">{{i18n
|
||||
"user.second_factor.enforced_notice"
|
||||
}}</div>
|
||||
{{/if}}
|
||||
{{body-class "user-preferences-page"}}
|
||||
|
||||
{{#if this.displayOAuthWarning}}
|
||||
<div class="alert alert-warning">{{i18n
|
||||
"user.second_factor.oauth_enabled_warning"
|
||||
}}</div>
|
||||
{{/if}}
|
||||
<section class="user-content user-preferences solo-preference second-factor">
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
<form class="form-vertical">
|
||||
{{#if this.showEnforcedNotice}}
|
||||
<div class="alert alert-error">{{i18n
|
||||
"user.second_factor.enforced_notice"
|
||||
}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
{{#if this.displayOAuthWarning}}
|
||||
<div class="alert alert-warning">{{i18n
|
||||
"user.second_factor.oauth_enabled_warning"
|
||||
}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.loaded}}
|
||||
<div class="control-group totp">
|
||||
<div class="controls">
|
||||
<h2>{{i18n "user.second_factor.totp.title"}}</h2>
|
||||
{{#each this.totps as |totp|}}
|
||||
<div class="second-factor-item row">
|
||||
<div class="details">
|
||||
{{#if totp.name}}
|
||||
{{totp.name}}
|
||||
{{else}}
|
||||
{{i18n "user.second_factor.totp.default_name"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if this.isCurrentUser}}
|
||||
<div class="actions">
|
||||
<TokenBasedAuthDropdown
|
||||
@totp={{totp}}
|
||||
@editSecondFactor={{action "editSecondFactor"}}
|
||||
@disableSingleSecondFactor={{action
|
||||
"disableSingleSecondFactor"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
<DButton
|
||||
@action={{action "createTotp"}}
|
||||
@icon="plus"
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor.totp.add"
|
||||
class="btn-default new-totp"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="control-group security-key">
|
||||
<div class="controls">
|
||||
<h2>{{i18n "user.second_factor.security_key.title"}}</h2>
|
||||
{{#each this.security_keys as |security_key|}}
|
||||
<div class="second-factor-item row">
|
||||
<div class="details">
|
||||
{{#if security_key.name}}
|
||||
{{security_key.name}}
|
||||
{{else}}
|
||||
{{i18n "user.second_factor.security_key.default_name"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.isCurrentUser}}
|
||||
<div class="actions">
|
||||
<SecurityKeyDropdown
|
||||
@securityKey={{security_key}}
|
||||
@editSecurityKey={{action "editSecurityKey"}}
|
||||
@disableSingleSecondFactor={{action
|
||||
"disableSingleSecondFactor"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
<DButton
|
||||
@action={{action "createSecurityKey"}}
|
||||
@icon="plus"
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor.security_key.add"
|
||||
class="btn-default new-security-key"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group pref-second-factor-backup">
|
||||
<div class="controls pref-second-factor-backup">
|
||||
<h2>{{i18n "user.second_factor_backup.title"}}</h2>
|
||||
{{#if this.loaded}}
|
||||
<div class="control-group totp">
|
||||
<div class="controls">
|
||||
<h2>{{i18n "user.second_factor.totp.title"}}</h2>
|
||||
{{#each this.totps as |totp|}}
|
||||
<div class="second-factor-item row">
|
||||
{{#if this.model.second_factor_enabled}}
|
||||
<div class="details">
|
||||
{{#if this.model.second_factor_backup_enabled}}
|
||||
{{html-safe
|
||||
(i18n
|
||||
"user.second_factor_backup.manage"
|
||||
count=this.model.second_factor_remaining_backup_codes
|
||||
)
|
||||
}}
|
||||
{{else}}
|
||||
<DButton
|
||||
@action={{action "editSecondFactorBackup"}}
|
||||
@icon="plus"
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor_backup.enable_long"
|
||||
class="btn-default new-second-factor-backup"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.model.second_factor_backup_enabled this.isCurrentUser
|
||||
)
|
||||
}}
|
||||
<div class="actions">
|
||||
<TwoFactorBackupDropdown
|
||||
@secondFactorBackupEnabled={{this.model.second_factor_backup_enabled}}
|
||||
@editSecondFactorBackup={{action
|
||||
"editSecondFactorBackup"
|
||||
}}
|
||||
@disableSecondFactorBackup={{action
|
||||
"disableSecondFactorBackup"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="details">
|
||||
{{#if totp.name}}
|
||||
{{totp.name}}
|
||||
{{else}}
|
||||
{{i18n "user.second_factor.totp.default_name"}}
|
||||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
{{i18n "user.second_factor_backup.enable_prerequisites"}}
|
||||
</div>
|
||||
{{#if this.isCurrentUser}}
|
||||
<div class="actions">
|
||||
<TokenBasedAuthDropdown
|
||||
@totp={{totp}}
|
||||
@editSecondFactor={{action "editSecondFactor"}}
|
||||
@disableSingleSecondFactor={{action
|
||||
"disableSingleSecondFactor"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
<DButton
|
||||
@action={{action "createTotp"}}
|
||||
@icon="plus"
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor.totp.add"
|
||||
class="btn-default new-totp"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.model.second_factor_enabled}}
|
||||
{{#unless this.showEnforcedNotice}}
|
||||
<div class="control-group pref-second-factor-disable-all">
|
||||
<div class="controls -actions">
|
||||
<DButton
|
||||
@icon="ban"
|
||||
@action={{action "disableAllSecondFactors"}}
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor.disable_all"
|
||||
class="btn-danger"
|
||||
/>
|
||||
<CancelLink
|
||||
@route="preferences.security"
|
||||
@args={{this.model.username}}
|
||||
/>
|
||||
<div class="control-group security-key">
|
||||
<div class="controls">
|
||||
<h2>{{i18n "user.second_factor.security_key.title"}}</h2>
|
||||
{{#each this.security_keys as |security_key|}}
|
||||
<div class="second-factor-item row">
|
||||
<div class="details">
|
||||
{{#if security_key.name}}
|
||||
{{security_key.name}}
|
||||
{{else}}
|
||||
{{i18n "user.second_factor.security_key.default_name"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{i18n "user.password.title"}}</label>
|
||||
|
||||
<div class="controls">
|
||||
<div>
|
||||
<TextField
|
||||
@value={{this.password}}
|
||||
@id="password"
|
||||
@type="password"
|
||||
@classNames="input-large"
|
||||
@autofocus="autofocus"
|
||||
/>
|
||||
</div>
|
||||
<div class="instructions">
|
||||
{{i18n "user.second_factor.confirm_password_description"}}
|
||||
{{#if this.isCurrentUser}}
|
||||
<div class="actions">
|
||||
<SecurityKeyDropdown
|
||||
@securityKey={{security_key}}
|
||||
@editSecurityKey={{action "editSecurityKey"}}
|
||||
@disableSingleSecondFactor={{action
|
||||
"disableSingleSecondFactor"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
<DButton
|
||||
@action={{action "createSecurityKey"}}
|
||||
@icon="plus"
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor.security_key.add"
|
||||
class="btn-default new-security-key"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group pref-second-factor-backup">
|
||||
<div class="controls pref-second-factor-backup">
|
||||
<h2>{{i18n "user.second_factor_backup.title"}}</h2>
|
||||
<div class="second-factor-item row">
|
||||
{{#if this.model.second_factor_enabled}}
|
||||
<div class="details">
|
||||
{{#if this.model.second_factor_backup_enabled}}
|
||||
{{html-safe
|
||||
(i18n
|
||||
"user.second_factor_backup.manage"
|
||||
count=this.model.second_factor_remaining_backup_codes
|
||||
)
|
||||
}}
|
||||
{{else}}
|
||||
<DButton
|
||||
@action={{action "editSecondFactorBackup"}}
|
||||
@icon="plus"
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor_backup.enable_long"
|
||||
class="btn-default new-second-factor-backup"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.model.second_factor_backup_enabled this.isCurrentUser
|
||||
)
|
||||
}}
|
||||
<div class="actions">
|
||||
<TwoFactorBackupDropdown
|
||||
@secondFactorBackupEnabled={{this.model.second_factor_backup_enabled}}
|
||||
@editSecondFactorBackup={{action
|
||||
"editSecondFactorBackup"
|
||||
}}
|
||||
@disableSecondFactorBackup={{action
|
||||
"disableSecondFactorBackup"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
{{i18n "user.second_factor_backup.enable_prerequisites"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls -actions">
|
||||
<DButton
|
||||
@action={{action "confirmPassword"}}
|
||||
@disabled={{this.loading}}
|
||||
@label="continue"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
|
||||
{{#unless this.showEnforcedNotice}}
|
||||
{{#if this.model.second_factor_enabled}}
|
||||
{{#unless this.showEnforcedNotice}}
|
||||
<div class="control-group pref-second-factor-disable-all">
|
||||
<div class="controls -actions">
|
||||
<DButton
|
||||
@icon="ban"
|
||||
@action={{action "disableAllSecondFactors"}}
|
||||
@disabled={{this.loading}}
|
||||
@label="user.second_factor.disable_all"
|
||||
class="btn-danger"
|
||||
/>
|
||||
<CancelLink
|
||||
@route="preferences.security"
|
||||
@args={{this.model.username}}
|
||||
/>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="controls" style="margin-top: 5px">
|
||||
{{this.resetPasswordProgress}}
|
||||
{{#unless this.resetPasswordLoading}}
|
||||
<a
|
||||
href
|
||||
class="instructions"
|
||||
{{on "click" this.resetPassword}}
|
||||
>{{i18n "user.second_factor.forgot_password"}}</a>
|
||||
{{/unless}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{i18n "user.password.title"}}</label>
|
||||
|
||||
<div class="controls">
|
||||
<div>
|
||||
<TextField
|
||||
@value={{this.password}}
|
||||
@id="password"
|
||||
@type="password"
|
||||
@classNames="input-large"
|
||||
@autofocus="autofocus"
|
||||
/>
|
||||
</div>
|
||||
<div class="instructions">
|
||||
{{i18n "user.second_factor.confirm_password_description"}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
</ConditionalLoadingSpinner>
|
||||
</section>
|
||||
</DSection>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls -actions">
|
||||
<DButton
|
||||
@action={{action "confirmPassword"}}
|
||||
@disabled={{this.loading}}
|
||||
@label="continue"
|
||||
type="submit"
|
||||
class="btn-primary"
|
||||
/>
|
||||
|
||||
{{#unless this.showEnforcedNotice}}
|
||||
<CancelLink
|
||||
@route="preferences.security"
|
||||
@args={{this.model.username}}
|
||||
/>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<div class="controls" style="margin-top: 5px">
|
||||
{{this.resetPasswordProgress}}
|
||||
{{#unless this.resetPasswordLoading}}
|
||||
<a
|
||||
href
|
||||
class="instructions"
|
||||
{{on "click" this.resetPassword}}
|
||||
>{{i18n "user.second_factor.forgot_password"}}</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</form>
|
||||
</ConditionalLoadingSpinner>
|
||||
</section>
|
@ -1,4 +1,4 @@
|
||||
<DSection @pageClass="user-preferences" />
|
||||
{{body-class "user-preferences-page"}}
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - preferences">
|
||||
|
@ -1,7 +1,9 @@
|
||||
<DSection @bodyClass="static-privacy" @class="container">
|
||||
{{body-class "static-privacy"}}
|
||||
|
||||
<section class="container">
|
||||
<div class="contents clearfix body-page">
|
||||
<PluginOutlet @name="above-static" />
|
||||
{{html-safe this.model.html}}
|
||||
<PluginOutlet @name="below-static" />
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -2,200 +2,188 @@
|
||||
{{hide-application-footer}}
|
||||
{{/if}}
|
||||
|
||||
<DSection
|
||||
@tagName=""
|
||||
@pageClass="tags"
|
||||
@bodyClass={{concat
|
||||
"tag-"
|
||||
this.tag.id
|
||||
(if this.category.slug (concat " category-" this.category.slug))
|
||||
""
|
||||
(if this.additionalTags " tags-intersection")
|
||||
}}
|
||||
>
|
||||
<div class="container">
|
||||
<DiscourseBanner @user={{this.currentUser}} @banner={{this.site.banner}} />
|
||||
</div>
|
||||
{{body-class
|
||||
"tags-page"
|
||||
(concat "tag-" this.tag.id)
|
||||
(if this.category.slug (concat "category-" this.category.slug))
|
||||
(if this.additionalTags "tags-intersection")
|
||||
}}
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="discovery-list-controls-above"
|
||||
@connectorTagName="div"
|
||||
/>
|
||||
</span>
|
||||
<div class="container">
|
||||
<DiscourseBanner @user={{this.currentUser}} @banner={{this.site.banner}} />
|
||||
</div>
|
||||
|
||||
<div class="list-controls">
|
||||
<PluginOutlet
|
||||
@name="discovery-navigation-bar-above"
|
||||
@connectorTagName="div"
|
||||
/>
|
||||
<div class="container">
|
||||
<section class="navigation-container tag-navigation">
|
||||
<DNavigation
|
||||
@filterMode={{this.filterMode}}
|
||||
@canCreateTopic={{this.canCreateTopic}}
|
||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||
@createTopic={{route-action "createTopic"}}
|
||||
@category={{this.category}}
|
||||
@editCategory={{route-action "editCategory" this.category}}
|
||||
@tag={{this.tag}}
|
||||
@noSubcategories={{this.noSubcategories}}
|
||||
@tagNotification={{this.tagNotification}}
|
||||
@additionalTags={{this.additionalTags}}
|
||||
@showInfo={{this.showInfo}}
|
||||
@canCreateTopicOnTag={{this.canCreateTopicOnTag}}
|
||||
@createTopicDisabled={{this.createTopicDisabled}}
|
||||
@changeTagNotificationLevel={{action "changeTagNotificationLevel"}}
|
||||
@toggleInfo={{action "toggleInfo"}}
|
||||
/>
|
||||
<span>
|
||||
<PluginOutlet @name="discovery-list-controls-above" @connectorTagName="div" />
|
||||
</span>
|
||||
|
||||
<PluginOutlet
|
||||
@name="tag-navigation"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash category=this.category tag=this.tag}}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.showInfo}}
|
||||
<TagInfo
|
||||
@tag={{this.tag}}
|
||||
@list={{this.list}}
|
||||
@deleteAction={{action "deleteTag"}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="discovery-list-container-top"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash category=this.category}}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<TopicDismissButtons
|
||||
@position="top"
|
||||
@selectedTopics={{this.selected}}
|
||||
@model={{this.model}}
|
||||
@showResetNew={{this.showResetNew}}
|
||||
@showDismissRead={{this.showDismissRead}}
|
||||
@resetNew={{action "resetNew"}}
|
||||
<div class="list-controls">
|
||||
<PluginOutlet
|
||||
@name="discovery-navigation-bar-above"
|
||||
@connectorTagName="div"
|
||||
/>
|
||||
<div class="container">
|
||||
<section class="navigation-container tag-navigation">
|
||||
<DNavigation
|
||||
@filterMode={{this.filterMode}}
|
||||
@canCreateTopic={{this.canCreateTopic}}
|
||||
@hasDraft={{this.currentUser.has_topic_draft}}
|
||||
@createTopic={{route-action "createTopic"}}
|
||||
@category={{this.category}}
|
||||
@editCategory={{route-action "editCategory" this.category}}
|
||||
@tag={{this.tag}}
|
||||
@noSubcategories={{this.noSubcategories}}
|
||||
@tagNotification={{this.tagNotification}}
|
||||
@additionalTags={{this.additionalTags}}
|
||||
@showInfo={{this.showInfo}}
|
||||
@canCreateTopicOnTag={{this.canCreateTopicOnTag}}
|
||||
@createTopicDisabled={{this.createTopicDisabled}}
|
||||
@changeTagNotificationLevel={{action "changeTagNotificationLevel"}}
|
||||
@toggleInfo={{action "toggleInfo"}}
|
||||
/>
|
||||
|
||||
<span>
|
||||
<PluginOutlet @name="discovery-above" @connectorTagName="div" />
|
||||
</span>
|
||||
<PluginOutlet
|
||||
@name="tag-navigation"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash category=this.category tag=this.tag}}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container list-container">
|
||||
<div class="row">
|
||||
<div class="full-width">
|
||||
<PluginOutlet @name="before-list-area" />
|
||||
<div id="list-area">
|
||||
{{#unless this.loading}}
|
||||
<DiscoveryTopicsList
|
||||
@model={{this.list}}
|
||||
@refresh={{action "refresh"}}
|
||||
@autoAddTopicsToBulkSelect={{this.autoAddTopicsToBulkSelect}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@addTopicsToBulkSelect={{action "addTopicsToBulkSelect"}}
|
||||
>
|
||||
{{#if this.top}}
|
||||
<div class="top-lists">
|
||||
<PeriodChooser
|
||||
@period={{this.period}}
|
||||
@action={{action "changePeriod"}}
|
||||
@fullDay={{false}}
|
||||
/>
|
||||
{{#if this.showInfo}}
|
||||
<TagInfo
|
||||
@tag={{this.tag}}
|
||||
@list={{this.list}}
|
||||
@deleteAction={{action "deleteTag"}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="discovery-list-container-top"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash category=this.category}}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<TopicDismissButtons
|
||||
@position="top"
|
||||
@selectedTopics={{this.selected}}
|
||||
@model={{this.model}}
|
||||
@showResetNew={{this.showResetNew}}
|
||||
@showDismissRead={{this.showDismissRead}}
|
||||
@resetNew={{action "resetNew"}}
|
||||
/>
|
||||
|
||||
<span>
|
||||
<PluginOutlet @name="discovery-above" @connectorTagName="div" />
|
||||
</span>
|
||||
|
||||
<div class="container list-container">
|
||||
<div class="row">
|
||||
<div class="full-width">
|
||||
<PluginOutlet @name="before-list-area" />
|
||||
<div id="list-area">
|
||||
{{#unless this.loading}}
|
||||
<DiscoveryTopicsList
|
||||
@model={{this.list}}
|
||||
@refresh={{action "refresh"}}
|
||||
@autoAddTopicsToBulkSelect={{this.autoAddTopicsToBulkSelect}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@addTopicsToBulkSelect={{action "addTopicsToBulkSelect"}}
|
||||
>
|
||||
{{#if this.top}}
|
||||
<div class="top-lists">
|
||||
<PeriodChooser
|
||||
@period={{this.period}}
|
||||
@action={{action "changePeriod"}}
|
||||
@fullDay={{false}}
|
||||
/>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if this.topicTrackingState.hasIncoming}}
|
||||
<div class="show-more {{if this.hasTopics 'has-topics'}}">
|
||||
<a
|
||||
tabindex="0"
|
||||
href
|
||||
{{on "click" this.showInserted}}
|
||||
class="alert alert-info clickable"
|
||||
>
|
||||
<CountI18n
|
||||
@key="topic_count_"
|
||||
@suffix={{this.topicTrackingState.filter}}
|
||||
@count={{this.topicTrackingState.incomingCount}}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if this.topicTrackingState.hasIncoming}}
|
||||
<div class="show-more {{if this.hasTopics 'has-topics'}}">
|
||||
<a
|
||||
tabindex="0"
|
||||
href
|
||||
{{on "click" this.showInserted}}
|
||||
class="alert alert-info clickable"
|
||||
>
|
||||
<CountI18n
|
||||
@key="topic_count_"
|
||||
@suffix={{this.topicTrackingState.filter}}
|
||||
@count={{this.topicTrackingState.incomingCount}}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#unless this.bulkSelectEnabled}}
|
||||
{{#if
|
||||
(and this.showTopicsAndRepliesToggle this.site.mobileView)
|
||||
}}
|
||||
<NewListHeaderControlsWrapper
|
||||
@current={{this.subset}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
@changeNewListSubset={{action "changeNewListSubset"}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{#if this.list.topics}}
|
||||
<TopicList
|
||||
@topics={{this.list.topics}}
|
||||
@canBulkSelect={{this.canBulkSelect}}
|
||||
@toggleBulkSelect={{action "toggleBulkSelect"}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@bulkSelectAction={{action "refresh"}}
|
||||
@updateAutoAddTopicsToBulkSelect={{action
|
||||
"updateAutoAddTopicsToBulkSelect"
|
||||
}}
|
||||
@selected={{this.selected}}
|
||||
@category={{this.category}}
|
||||
@showPosters={{true}}
|
||||
@order={{this.order}}
|
||||
@ascending={{this.ascending}}
|
||||
@changeSort={{action "changeSort"}}
|
||||
@focusLastVisitedTopic={{true}}
|
||||
@showTopicsAndRepliesToggle={{this.showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{this.subset}}
|
||||
@changeNewListSubset={{action "changeNewListSubset"}}
|
||||
{{/if}}
|
||||
{{#unless this.bulkSelectEnabled}}
|
||||
{{#if (and this.showTopicsAndRepliesToggle this.site.mobileView)}}
|
||||
<NewListHeaderControlsWrapper
|
||||
@current={{this.subset}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
@changeNewListSubset={{action "changeNewListSubset"}}
|
||||
/>
|
||||
{{/if}}
|
||||
</DiscoveryTopicsList>
|
||||
|
||||
<footer class="topic-list-bottom">
|
||||
<TopicDismissButtons
|
||||
@position="bottom"
|
||||
@selectedTopics={{this.selected}}
|
||||
@model={{this.model}}
|
||||
@showResetNew={{this.showResetNew}}
|
||||
@showDismissRead={{this.showDismissRead}}
|
||||
@resetNew={{action "resetNew"}}
|
||||
{{/unless}}
|
||||
{{#if this.list.topics}}
|
||||
<TopicList
|
||||
@topics={{this.list.topics}}
|
||||
@canBulkSelect={{this.canBulkSelect}}
|
||||
@toggleBulkSelect={{action "toggleBulkSelect"}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@bulkSelectAction={{action "refresh"}}
|
||||
@updateAutoAddTopicsToBulkSelect={{action
|
||||
"updateAutoAddTopicsToBulkSelect"
|
||||
}}
|
||||
@selected={{this.selected}}
|
||||
@category={{this.category}}
|
||||
@showPosters={{true}}
|
||||
@order={{this.order}}
|
||||
@ascending={{this.ascending}}
|
||||
@changeSort={{action "changeSort"}}
|
||||
@focusLastVisitedTopic={{true}}
|
||||
@showTopicsAndRepliesToggle={{this.showTopicsAndRepliesToggle}}
|
||||
@newListSubset={{this.subset}}
|
||||
@changeNewListSubset={{action "changeNewListSubset"}}
|
||||
@newRepliesCount={{this.newRepliesCount}}
|
||||
@newTopicsCount={{this.newTopicsCount}}
|
||||
/>
|
||||
{{/if}}
|
||||
</DiscoveryTopicsList>
|
||||
|
||||
{{#unless this.list.canLoadMore}}
|
||||
<FooterMessage
|
||||
@education={{this.footerEducation}}
|
||||
@message={{this.footerMessage}}
|
||||
>
|
||||
{{html-safe
|
||||
(i18n
|
||||
"topic.browse_all_tags_or_latest" basePath=(base-path)
|
||||
)
|
||||
}}
|
||||
</FooterMessage>
|
||||
{{/unless}}
|
||||
</footer>
|
||||
{{/unless}}
|
||||
<footer class="topic-list-bottom">
|
||||
<TopicDismissButtons
|
||||
@position="bottom"
|
||||
@selectedTopics={{this.selected}}
|
||||
@model={{this.model}}
|
||||
@showResetNew={{this.showResetNew}}
|
||||
@showDismissRead={{this.showDismissRead}}
|
||||
@resetNew={{action "resetNew"}}
|
||||
/>
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{this.list.loadingMore}} />
|
||||
</div>
|
||||
{{#unless this.list.canLoadMore}}
|
||||
<FooterMessage
|
||||
@education={{this.footerEducation}}
|
||||
@message={{this.footerMessage}}
|
||||
>
|
||||
{{html-safe
|
||||
(i18n "topic.browse_all_tags_or_latest" basePath=(base-path))
|
||||
}}
|
||||
</FooterMessage>
|
||||
{{/unless}}
|
||||
</footer>
|
||||
{{/unless}}
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{this.list.loadingMore}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
<PluginOutlet @name="discovery-below" @connectorTagName="div" />
|
||||
</span>
|
||||
</DSection>
|
||||
<span>
|
||||
<PluginOutlet @name="discovery-below" @connectorTagName="div" />
|
||||
</span>
|
@ -1,3 +1,2 @@
|
||||
<DSection @pageClass="tags" @tagName="">
|
||||
{{outlet}}
|
||||
</DSection>
|
||||
{{body-class "tags-page"}}
|
||||
{{outlet}}
|
@ -1,7 +1,9 @@
|
||||
<DSection @bodyClass="static-tos" @class="container">
|
||||
{{body-class "static-tos"}}
|
||||
|
||||
<section class="container">
|
||||
<div class="contents clearfix body-page">
|
||||
<PluginOutlet @name="above-static" />
|
||||
{{html-safe this.model.html}}
|
||||
<PluginOutlet @name="below-static" />
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,230 +1,226 @@
|
||||
<DSection @pageClass="user-invites" @tagName="">
|
||||
{{#if this.canInviteToForum}}
|
||||
<LoadMore
|
||||
@class="user-content"
|
||||
@id="user-content"
|
||||
@selector=".user-invite-list tr"
|
||||
@action={{action "loadMore"}}
|
||||
>
|
||||
<DSection @class="user-additional-controls">
|
||||
{{#if this.showSearch}}
|
||||
<div class="user-invite-search">
|
||||
<form><TextField
|
||||
@value={{this.searchTerm}}
|
||||
@placeholderKey="user.invited.search"
|
||||
/></form>
|
||||
</div>
|
||||
{{body-class "user-invites-page"}}
|
||||
|
||||
{{#if this.canInviteToForum}}
|
||||
<LoadMore
|
||||
@class="user-content"
|
||||
@id="user-content"
|
||||
@selector=".user-invite-list tr"
|
||||
@action={{action "loadMore"}}
|
||||
>
|
||||
<section class="user-additional-controls">
|
||||
{{#if this.showSearch}}
|
||||
<div class="user-invite-search">
|
||||
<form><TextField
|
||||
@value={{this.searchTerm}}
|
||||
@placeholderKey="user.invited.search"
|
||||
/></form>
|
||||
</div>
|
||||
{{/if}}
|
||||
<section class="user-invite-buttons">
|
||||
<DButton
|
||||
@icon="plus"
|
||||
@action={{this.createInvite}}
|
||||
@label="user.invited.create"
|
||||
class="btn-default"
|
||||
/>
|
||||
{{#if this.canBulkInvite}}
|
||||
{{#if this.siteSettings.allow_bulk_invite}}
|
||||
{{#unless this.site.mobileView}}
|
||||
<DButton
|
||||
@icon="upload"
|
||||
@action={{this.createInviteCsv}}
|
||||
@label="user.invited.bulk_invite.text"
|
||||
class="btn-flat"
|
||||
/>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<DSection @class="user-invite-buttons">
|
||||
<DButton
|
||||
@icon="plus"
|
||||
@action={{this.createInvite}}
|
||||
@label="user.invited.create"
|
||||
class="btn-default"
|
||||
/>
|
||||
{{#if this.canBulkInvite}}
|
||||
{{#if this.siteSettings.allow_bulk_invite}}
|
||||
{{#unless this.site.mobileView}}
|
||||
<DButton
|
||||
@icon="upload"
|
||||
@action={{this.createInviteCsv}}
|
||||
@label="user.invited.bulk_invite.text"
|
||||
class="btn-flat"
|
||||
/>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if this.showBulkActionButtons}}
|
||||
{{#if this.inviteExpired}}
|
||||
{{#if this.removedAll}}
|
||||
<span class="removed-all">
|
||||
{{i18n "user.invited.removed_all"}}
|
||||
</span>
|
||||
{{else}}
|
||||
<DButton
|
||||
@icon="times"
|
||||
@action={{this.destroyAllExpired}}
|
||||
@label="user.invited.remove_all"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.invitePending}}
|
||||
{{#if this.reinvitedAll}}
|
||||
<span class="reinvited-all">
|
||||
<DButton
|
||||
@icon="check"
|
||||
@disabled={{true}}
|
||||
@label="user.invited.reinvited_all"
|
||||
/>
|
||||
</span>
|
||||
{{else if this.hasEmailInvites}}
|
||||
<DButton
|
||||
@icon="sync"
|
||||
@action={{this.reinviteAll}}
|
||||
@label="user.invited.reinvite_all"
|
||||
class="btn-default"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</DSection>
|
||||
</DSection>
|
||||
<section>
|
||||
{{#if this.model.invites}}
|
||||
{{#if this.inviteRedeemed}}
|
||||
<table class="table user-invite-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "user.invited.user"}}</th>
|
||||
<th>{{i18n "user.invited.redeemed_at"}}</th>
|
||||
{{#if this.model.can_see_invite_details}}
|
||||
<th>{{i18n "user.last_seen"}}</th>
|
||||
<th>{{i18n "user.invited.topics_entered"}}</th>
|
||||
<th>{{i18n "user.invited.posts_read_count"}}</th>
|
||||
<th>{{i18n "user.invited.time_read"}}</th>
|
||||
<th>{{i18n "user.invited.days_visited"}}</th>
|
||||
<th>{{i18n "user.invited.invited_via"}}</th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.model.invites as |invite|}}
|
||||
<tr>
|
||||
<td>
|
||||
<LinkTo @route="user" @model={{invite.user}}>{{avatar
|
||||
invite.user
|
||||
imageSize="tiny"
|
||||
}}</LinkTo>
|
||||
<LinkTo
|
||||
@route="user"
|
||||
@model={{invite.user}}
|
||||
>{{invite.user.username}}</LinkTo>
|
||||
</td>
|
||||
<td>{{format-date invite.redeemed_at}}</td>
|
||||
{{#if this.model.can_see_invite_details}}
|
||||
<td>{{format-date invite.user.last_seen_at}}</td>
|
||||
<td>{{number invite.user.topics_entered}}</td>
|
||||
<td>{{number invite.user.posts_read_count}}</td>
|
||||
<td>{{format-duration invite.user.time_read}}</td>
|
||||
<td>
|
||||
<span
|
||||
title={{i18n "user.invited.days_visited"}}
|
||||
>{{html-safe invite.user.days_visited}}</span>
|
||||
/
|
||||
<span
|
||||
title={{i18n "user.invited.account_age_days"}}
|
||||
>{{html-safe invite.user.days_since_created}}</span>
|
||||
</td>
|
||||
<td>{{html-safe invite.invite_source}}</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<table class="table user-invite-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "user.invited.invited_via"}}</th>
|
||||
<th>{{i18n "user.invited.sent"}}</th>
|
||||
<th>{{i18n "user.invited.expires_at"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.model.invites as |invite|}}
|
||||
<tr>
|
||||
<td class="invite-type">
|
||||
<div class="label">{{i18n
|
||||
"user.invited.invited_via"
|
||||
}}</div>
|
||||
{{#if invite.email}}
|
||||
{{d-icon "envelope"}}
|
||||
{{invite.email}}
|
||||
{{else}}
|
||||
{{d-icon "link"}}
|
||||
{{i18n
|
||||
"user.invited.invited_via_link"
|
||||
key=invite.shortKey
|
||||
count=invite.redemption_count
|
||||
max=invite.max_redemptions_allowed
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{#each invite.groups as |g|}}
|
||||
<p class="invite-extra"><a href="/g/{{g.name}}">{{d-icon
|
||||
"users"
|
||||
}}
|
||||
{{g.name}}</a></p>
|
||||
{{/each}}
|
||||
|
||||
{{#if invite.topic}}
|
||||
<p class="invite-extra"><a
|
||||
href={{invite.topic.url}}
|
||||
>{{d-icon "file"}} {{invite.topic.title}}</a></p>
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
<td class="invite-updated-at">
|
||||
<div class="label">{{i18n "user.invited.sent"}}</div>
|
||||
{{format-date invite.updated_at}}
|
||||
</td>
|
||||
|
||||
<td class="invite-expires-at">
|
||||
<div class="label">{{i18n
|
||||
"user.invited.expires_at"
|
||||
}}</div>
|
||||
{{#if this.inviteExpired}}
|
||||
{{raw-date invite.expires_at}}
|
||||
{{else if invite.expired}}
|
||||
{{i18n "user.invited.expired"}}
|
||||
{{else}}
|
||||
{{raw-date invite.expires_at}}
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if invite.can_delete_invite}}
|
||||
<td class="invite-actions">
|
||||
<DButton
|
||||
@icon="pencil-alt"
|
||||
@action={{fn this.editInvite invite}}
|
||||
@title="user.invited.edit"
|
||||
class="btn-default"
|
||||
/>
|
||||
<DButton
|
||||
@icon="trash-alt"
|
||||
@action={{fn this.destroyInvite invite}}
|
||||
@title={{if
|
||||
invite.destroyed
|
||||
"user.invited.removed"
|
||||
"user.invited.remove"
|
||||
}}
|
||||
class="cancel"
|
||||
/>
|
||||
</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{this.invitesLoading}} />
|
||||
{{else}}
|
||||
<div class="user-invite-none">
|
||||
{{#if this.canBulkInvite}}
|
||||
{{html-safe (i18n "user.invited.bulk_invite.none")}}
|
||||
{{#if this.showBulkActionButtons}}
|
||||
{{#if this.inviteExpired}}
|
||||
{{#if this.removedAll}}
|
||||
<span class="removed-all">
|
||||
{{i18n "user.invited.removed_all"}}
|
||||
</span>
|
||||
{{else}}
|
||||
{{i18n "user.invited.none"}}
|
||||
<DButton
|
||||
@icon="times"
|
||||
@action={{this.destroyAllExpired}}
|
||||
@label="user.invited.remove_all"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.invitePending}}
|
||||
{{#if this.reinvitedAll}}
|
||||
<span class="reinvited-all">
|
||||
<DButton
|
||||
@icon="check"
|
||||
@disabled={{true}}
|
||||
@label="user.invited.reinvited_all"
|
||||
/>
|
||||
</span>
|
||||
{{else if this.hasEmailInvites}}
|
||||
<DButton
|
||||
@icon="sync"
|
||||
@action={{this.reinviteAll}}
|
||||
@label="user.invited.reinvite_all"
|
||||
class="btn-default"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</section>
|
||||
</LoadMore>
|
||||
{{else}}
|
||||
<div class="alert alert-error invite-error">
|
||||
{{this.model.error}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</DSection>
|
||||
</section>
|
||||
<section>
|
||||
{{#if this.model.invites}}
|
||||
{{#if this.inviteRedeemed}}
|
||||
<table class="table user-invite-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "user.invited.user"}}</th>
|
||||
<th>{{i18n "user.invited.redeemed_at"}}</th>
|
||||
{{#if this.model.can_see_invite_details}}
|
||||
<th>{{i18n "user.last_seen"}}</th>
|
||||
<th>{{i18n "user.invited.topics_entered"}}</th>
|
||||
<th>{{i18n "user.invited.posts_read_count"}}</th>
|
||||
<th>{{i18n "user.invited.time_read"}}</th>
|
||||
<th>{{i18n "user.invited.days_visited"}}</th>
|
||||
<th>{{i18n "user.invited.invited_via"}}</th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.model.invites as |invite|}}
|
||||
<tr>
|
||||
<td>
|
||||
<LinkTo @route="user" @model={{invite.user}}>{{avatar
|
||||
invite.user
|
||||
imageSize="tiny"
|
||||
}}</LinkTo>
|
||||
<LinkTo
|
||||
@route="user"
|
||||
@model={{invite.user}}
|
||||
>{{invite.user.username}}</LinkTo>
|
||||
</td>
|
||||
<td>{{format-date invite.redeemed_at}}</td>
|
||||
{{#if this.model.can_see_invite_details}}
|
||||
<td>{{format-date invite.user.last_seen_at}}</td>
|
||||
<td>{{number invite.user.topics_entered}}</td>
|
||||
<td>{{number invite.user.posts_read_count}}</td>
|
||||
<td>{{format-duration invite.user.time_read}}</td>
|
||||
<td>
|
||||
<span
|
||||
title={{i18n "user.invited.days_visited"}}
|
||||
>{{html-safe invite.user.days_visited}}</span>
|
||||
/
|
||||
<span
|
||||
title={{i18n "user.invited.account_age_days"}}
|
||||
>{{html-safe invite.user.days_since_created}}</span>
|
||||
</td>
|
||||
<td>{{html-safe invite.invite_source}}</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<table class="table user-invite-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "user.invited.invited_via"}}</th>
|
||||
<th>{{i18n "user.invited.sent"}}</th>
|
||||
<th>{{i18n "user.invited.expires_at"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.model.invites as |invite|}}
|
||||
<tr>
|
||||
<td class="invite-type">
|
||||
<div class="label">{{i18n "user.invited.invited_via"}}</div>
|
||||
{{#if invite.email}}
|
||||
{{d-icon "envelope"}}
|
||||
{{invite.email}}
|
||||
{{else}}
|
||||
{{d-icon "link"}}
|
||||
{{i18n
|
||||
"user.invited.invited_via_link"
|
||||
key=invite.shortKey
|
||||
count=invite.redemption_count
|
||||
max=invite.max_redemptions_allowed
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{#each invite.groups as |g|}}
|
||||
<p class="invite-extra"><a href="/g/{{g.name}}">{{d-icon
|
||||
"users"
|
||||
}}
|
||||
{{g.name}}</a></p>
|
||||
{{/each}}
|
||||
|
||||
{{#if invite.topic}}
|
||||
<p class="invite-extra"><a
|
||||
href={{invite.topic.url}}
|
||||
>{{d-icon "file"}} {{invite.topic.title}}</a></p>
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
<td class="invite-updated-at">
|
||||
<div class="label">{{i18n "user.invited.sent"}}</div>
|
||||
{{format-date invite.updated_at}}
|
||||
</td>
|
||||
|
||||
<td class="invite-expires-at">
|
||||
<div class="label">{{i18n "user.invited.expires_at"}}</div>
|
||||
{{#if this.inviteExpired}}
|
||||
{{raw-date invite.expires_at}}
|
||||
{{else if invite.expired}}
|
||||
{{i18n "user.invited.expired"}}
|
||||
{{else}}
|
||||
{{raw-date invite.expires_at}}
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if invite.can_delete_invite}}
|
||||
<td class="invite-actions">
|
||||
<DButton
|
||||
@icon="pencil-alt"
|
||||
@action={{fn this.editInvite invite}}
|
||||
@title="user.invited.edit"
|
||||
class="btn-default"
|
||||
/>
|
||||
<DButton
|
||||
@icon="trash-alt"
|
||||
@action={{fn this.destroyInvite invite}}
|
||||
@title={{if
|
||||
invite.destroyed
|
||||
"user.invited.removed"
|
||||
"user.invited.remove"
|
||||
}}
|
||||
class="cancel"
|
||||
/>
|
||||
</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{this.invitesLoading}} />
|
||||
{{else}}
|
||||
<div class="user-invite-none">
|
||||
{{#if this.canBulkInvite}}
|
||||
{{html-safe (i18n "user.invited.bulk_invite.none")}}
|
||||
{{else}}
|
||||
{{i18n "user.invited.none"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</LoadMore>
|
||||
{{else}}
|
||||
<div class="alert alert-error invite-error">
|
||||
{{this.model.error}}
|
||||
</div>
|
||||
{{/if}}
|
@ -1,5 +1,5 @@
|
||||
{{#if this.can_see_invite_details}}
|
||||
<DSection @pageClass="user-invites" />
|
||||
{{body-class "user-invites-page"}}
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - invites">
|
||||
|
@ -9,7 +9,7 @@
|
||||
{{if this.model.profile_hidden 'profile-hidden'}}
|
||||
{{this.primaryGroup}}"
|
||||
>
|
||||
<DSection @class="user-main">
|
||||
<section class="user-main">
|
||||
<a href="#user-content" id="skip-link" class="skip-link__user-nav">
|
||||
{{i18n "skip_user_nav"}}
|
||||
</a>
|
||||
@ -474,5 +474,5 @@
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
||||
</div>
|
@ -1,4 +1,4 @@
|
||||
<DSection @pageClass="user-activity" />
|
||||
{{body-class "user-activity-page"}}
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - activity">
|
||||
|
@ -1,4 +1,6 @@
|
||||
<DSection @pageClass="user-badges" @class="user-content" id="user-content">
|
||||
{{body-class "user-badges-page"}}
|
||||
|
||||
<section class="user-content" id="user-content">
|
||||
<p class="favorite-count">
|
||||
{{i18n
|
||||
"badges.favorite_count"
|
||||
@ -25,4 +27,4 @@
|
||||
@outletArgs={{hash user=this.user.model}}
|
||||
/>
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
@ -1,4 +1,4 @@
|
||||
<DSection @pageClass="user-messages" />
|
||||
{{body-class "user-messages-page"}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="user-messages-above-navigation"
|
||||
|
@ -2,7 +2,7 @@
|
||||
{{hide-application-footer}}
|
||||
{{/if}}
|
||||
|
||||
<DSection @pageClass="user-notifications" />
|
||||
{{body-class "user-notifications-page"}}
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - notifications">
|
||||
|
@ -1,306 +1,300 @@
|
||||
<DSection @pageClass="user-summary" @tagName="">
|
||||
<div class="user-content" id="user-content">
|
||||
<PluginOutlet
|
||||
@name="above-user-summary-stats"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
{{#if this.model.can_see_summary_stats}}
|
||||
<div class="top-section stats-section">
|
||||
<h3 class="stats-title">{{i18n "user.summary.stats"}}</h3>
|
||||
<ul>
|
||||
<li class="stats-days-visited">
|
||||
{{body-class "user-summary-page"}}
|
||||
|
||||
<div class="user-content" id="user-content">
|
||||
<PluginOutlet
|
||||
@name="above-user-summary-stats"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
{{#if this.model.can_see_summary_stats}}
|
||||
<div class="top-section stats-section">
|
||||
<h3 class="stats-title">{{i18n "user.summary.stats"}}</h3>
|
||||
<ul>
|
||||
<li class="stats-days-visited">
|
||||
<UserStat
|
||||
@value={{this.model.days_visited}}
|
||||
@label="user.summary.days_visited"
|
||||
/>
|
||||
</li>
|
||||
<li class="stats-time-read">
|
||||
<UserStat
|
||||
@value={{this.timeRead}}
|
||||
@label="user.summary.time_read"
|
||||
@rawTitle={{i18n
|
||||
"user.summary.time_read_title"
|
||||
duration=this.timeReadMedium
|
||||
}}
|
||||
@type="string"
|
||||
/>
|
||||
</li>
|
||||
{{#if this.showRecentTimeRead}}
|
||||
<li class="stats-recent-read">
|
||||
<UserStat
|
||||
@value={{this.model.days_visited}}
|
||||
@label="user.summary.days_visited"
|
||||
/>
|
||||
</li>
|
||||
<li class="stats-time-read">
|
||||
<UserStat
|
||||
@value={{this.timeRead}}
|
||||
@label="user.summary.time_read"
|
||||
@value={{this.recentTimeRead}}
|
||||
@label="user.summary.recent_time_read"
|
||||
@rawTitle={{i18n
|
||||
"user.summary.time_read_title"
|
||||
duration=this.timeReadMedium
|
||||
"user.summary.recent_time_read_title"
|
||||
duration=this.recentTimeReadMedium
|
||||
}}
|
||||
@type="string"
|
||||
/>
|
||||
</li>
|
||||
{{#if this.showRecentTimeRead}}
|
||||
<li class="stats-recent-read">
|
||||
<UserStat
|
||||
@value={{this.recentTimeRead}}
|
||||
@label="user.summary.recent_time_read"
|
||||
@rawTitle={{i18n
|
||||
"user.summary.recent_time_read_title"
|
||||
duration=this.recentTimeReadMedium
|
||||
}}
|
||||
@type="string"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li class="stats-topics-entered">
|
||||
{{/if}}
|
||||
<li class="stats-topics-entered">
|
||||
<UserStat
|
||||
@value={{this.model.topics_entered}}
|
||||
@label="user.summary.topics_entered"
|
||||
/>
|
||||
</li>
|
||||
<li class="stats-posts-read">
|
||||
<UserStat
|
||||
@value={{this.model.posts_read_count}}
|
||||
@label="user.summary.posts_read"
|
||||
/>
|
||||
</li>
|
||||
<li class="stats-likes-given linked-stat">
|
||||
<LinkTo @route="userActivity.likesGiven">
|
||||
<UserStat
|
||||
@value={{this.model.topics_entered}}
|
||||
@label="user.summary.topics_entered"
|
||||
/>
|
||||
</li>
|
||||
<li class="stats-posts-read">
|
||||
<UserStat
|
||||
@value={{this.model.posts_read_count}}
|
||||
@label="user.summary.posts_read"
|
||||
/>
|
||||
</li>
|
||||
<li class="stats-likes-given linked-stat">
|
||||
<LinkTo @route="userActivity.likesGiven">
|
||||
<UserStat
|
||||
@value={{this.model.likes_given}}
|
||||
@icon="heart"
|
||||
@label="user.summary.likes_given"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="stats-likes-received">
|
||||
<UserStat
|
||||
@value={{this.model.likes_received}}
|
||||
@value={{this.model.likes_given}}
|
||||
@icon="heart"
|
||||
@label="user.summary.likes_received"
|
||||
@label="user.summary.likes_given"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="stats-likes-received">
|
||||
<UserStat
|
||||
@value={{this.model.likes_received}}
|
||||
@icon="heart"
|
||||
@label="user.summary.likes_received"
|
||||
/>
|
||||
</li>
|
||||
{{#if this.model.bookmark_count}}
|
||||
<li class="stats-bookmark-count linked-stat">
|
||||
<LinkTo @route="userActivity.bookmarks">
|
||||
<UserStat
|
||||
@value={{this.model.bookmark_count}}
|
||||
@label="user.summary.bookmark_count"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{#if this.model.bookmark_count}}
|
||||
<li class="stats-bookmark-count linked-stat">
|
||||
<LinkTo @route="userActivity.bookmarks">
|
||||
<UserStat
|
||||
@value={{this.model.bookmark_count}}
|
||||
@label="user.summary.bookmark_count"
|
||||
/>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
<li class="stats-topic-count linked-stat">
|
||||
<LinkTo @route="userActivity.topics">
|
||||
<UserStat
|
||||
@value={{this.model.topic_count}}
|
||||
@label="user.summary.topic_count"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="stats-post-count linked-stat">
|
||||
<LinkTo @route="userActivity.replies">
|
||||
<UserStat
|
||||
@value={{this.model.post_count}}
|
||||
@label="user.summary.post_count"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<PluginOutlet
|
||||
@name="user-summary-stat"
|
||||
@connectorTagName="li"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="below-user-summary-stats"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
|
||||
<div class="top-section">
|
||||
<UserSummarySection @title="top_replies" @class="replies-section pull-left">
|
||||
<UserSummaryTopicsList
|
||||
@type="replies"
|
||||
@items={{this.model.replies}}
|
||||
@user={{this.user}}
|
||||
as |reply|
|
||||
>
|
||||
<UserSummaryTopic
|
||||
@createdAt={{reply.createdAt}}
|
||||
@topic={{reply.topic}}
|
||||
@likes={{reply.like_count}}
|
||||
@url={{reply.url}}
|
||||
/>
|
||||
</UserSummaryTopicsList>
|
||||
</UserSummarySection>
|
||||
|
||||
<UserSummarySection @title="top_topics" @class="topics-section pull-right">
|
||||
<UserSummaryTopicsList
|
||||
@type="topics"
|
||||
@items={{this.model.topics}}
|
||||
@user={{this.user}}
|
||||
as |topic|
|
||||
>
|
||||
<UserSummaryTopic
|
||||
@createdAt={{topic.created_at}}
|
||||
@topic={{topic}}
|
||||
@likes={{topic.like_count}}
|
||||
@url={{topic.url}}
|
||||
/>
|
||||
</UserSummaryTopicsList>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
|
||||
<div class="top-section">
|
||||
<UserSummarySection @title="top_links" @class="links-section pull-left">
|
||||
{{#if this.model.links.length}}
|
||||
<ul>
|
||||
{{#each this.model.links as |link|}}
|
||||
<li>
|
||||
{{! template-lint-disable link-rel-noopener }}
|
||||
<a
|
||||
class="domain"
|
||||
href={{link.url}}
|
||||
title={{link.title}}
|
||||
rel="noopener {{unless
|
||||
this.user.removeNoFollow
|
||||
'nofollow ugc'
|
||||
}}"
|
||||
target="_blank"
|
||||
>
|
||||
{{shorten-url link.url}}
|
||||
</a>
|
||||
{{! template-lint-enable link-rel-noopener }}
|
||||
|
||||
<span
|
||||
class="badge badge-notification clicks"
|
||||
title={{i18n "topic_map.clicks" count=link.clicks}}
|
||||
>
|
||||
{{number link.clicks}}
|
||||
</span>
|
||||
|
||||
<br />
|
||||
|
||||
<a href={{link.post_url}}>
|
||||
{{html-safe link.topic.fancyTitle}}
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li class="stats-topic-count linked-stat">
|
||||
<LinkTo @route="userActivity.topics">
|
||||
<UserStat
|
||||
@value={{this.model.topic_count}}
|
||||
@label="user.summary.topic_count"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="stats-post-count linked-stat">
|
||||
<LinkTo @route="userActivity.replies">
|
||||
<UserStat
|
||||
@value={{this.model.post_count}}
|
||||
@label="user.summary.post_count"
|
||||
/>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_links"}}</p>
|
||||
{{/if}}
|
||||
</UserSummarySection>
|
||||
|
||||
<UserSummarySection
|
||||
@title="most_replied_to_users"
|
||||
@class="summary-user-list replied-section pull-right"
|
||||
>
|
||||
<UserSummaryUsersList
|
||||
@none="no_replies"
|
||||
@users={{this.model.most_replied_to_users}}
|
||||
as |user|
|
||||
>
|
||||
<UserSummaryUser @user={{user}} @icon="reply" @countClass="replies" />
|
||||
</UserSummaryUsersList>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
|
||||
<div class="top-section most-liked-section">
|
||||
<UserSummarySection
|
||||
@title="most_liked_by"
|
||||
@class="summary-user-list liked-by-section pull-left"
|
||||
>
|
||||
<UserSummaryUsersList
|
||||
@none="no_likes"
|
||||
@users={{this.model.most_liked_by_users}}
|
||||
as |user|
|
||||
>
|
||||
<UserSummaryUser @user={{user}} @icon="heart" @countClass="likes" />
|
||||
</UserSummaryUsersList>
|
||||
</UserSummarySection>
|
||||
|
||||
<UserSummarySection
|
||||
@title="most_liked_users"
|
||||
@class="summary-user-list liked-section pull-right"
|
||||
>
|
||||
<UserSummaryUsersList
|
||||
@none="no_likes"
|
||||
@users={{this.model.most_liked_users}}
|
||||
as |user|
|
||||
>
|
||||
<UserSummaryUser @user={{user}} @icon="heart" @countClass="likes" />
|
||||
</UserSummaryUsersList>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
|
||||
{{#if this.model.top_categories.length}}
|
||||
<div class="top-section top-categories-section">
|
||||
<UserSummarySection
|
||||
@title="top_categories"
|
||||
@class="summary-category-list pull-left"
|
||||
>
|
||||
<table>
|
||||
<thead>
|
||||
<th class="category-link"></th>
|
||||
<th class="topic-count">{{i18n "user.summary.topics"}}</th>
|
||||
<th class="reply-count">{{i18n "user.summary.replies"}}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.model.top_categories as |category|}}
|
||||
<tr>
|
||||
<td class="category-link">
|
||||
{{category-link
|
||||
category
|
||||
allowUncategorized="true"
|
||||
hideParent=false
|
||||
}}
|
||||
</td>
|
||||
<td class="topic-count">
|
||||
<UserSummaryCategorySearch
|
||||
@user={{this.user}}
|
||||
@category={{category}}
|
||||
@count={{category.topic_count}}
|
||||
/>
|
||||
</td>
|
||||
<td class="reply-count">
|
||||
<UserSummaryCategorySearch
|
||||
@user={{this.user}}
|
||||
@category={{category}}
|
||||
@count={{category.post_count}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.siteSettings.enable_badges}}
|
||||
<div class="top-section badges-section">
|
||||
<h3 class="stats-title">{{i18n "user.summary.top_badges"}}</h3>
|
||||
|
||||
{{#if this.model.badges}}
|
||||
<div class="badge-group-list">
|
||||
{{#each this.model.badges as |badge|}}
|
||||
<BadgeCard
|
||||
@badge={{badge}}
|
||||
@count={{badge.count}}
|
||||
@username={{this.user.username_lower}}
|
||||
/>
|
||||
{{/each}}
|
||||
<PluginOutlet
|
||||
@name="user-summary-stat"
|
||||
@connectorTagName="li"
|
||||
@name="after-user-summary-badges"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_badges"}}</p>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="below-user-summary-stats"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
|
||||
<div class="top-section">
|
||||
<UserSummarySection
|
||||
@title="top_replies"
|
||||
@class="replies-section pull-left"
|
||||
>
|
||||
<UserSummaryTopicsList
|
||||
@type="replies"
|
||||
@items={{this.model.replies}}
|
||||
@user={{this.user}}
|
||||
as |reply|
|
||||
>
|
||||
<UserSummaryTopic
|
||||
@createdAt={{reply.createdAt}}
|
||||
@topic={{reply.topic}}
|
||||
@likes={{reply.like_count}}
|
||||
@url={{reply.url}}
|
||||
/>
|
||||
</UserSummaryTopicsList>
|
||||
</UserSummarySection>
|
||||
|
||||
<UserSummarySection
|
||||
@title="top_topics"
|
||||
@class="topics-section pull-right"
|
||||
>
|
||||
<UserSummaryTopicsList
|
||||
@type="topics"
|
||||
@items={{this.model.topics}}
|
||||
@user={{this.user}}
|
||||
as |topic|
|
||||
>
|
||||
<UserSummaryTopic
|
||||
@createdAt={{topic.created_at}}
|
||||
@topic={{topic}}
|
||||
@likes={{topic.like_count}}
|
||||
@url={{topic.url}}
|
||||
/>
|
||||
</UserSummaryTopicsList>
|
||||
</UserSummarySection>
|
||||
{{#if this.moreBadges}}
|
||||
<LinkTo @route="user.badges" @model={{this.user}} class="more">
|
||||
{{i18n "user.summary.more_badges"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="top-section">
|
||||
<UserSummarySection @title="top_links" @class="links-section pull-left">
|
||||
{{#if this.model.links.length}}
|
||||
<ul>
|
||||
{{#each this.model.links as |link|}}
|
||||
<li>
|
||||
{{! template-lint-disable link-rel-noopener }}
|
||||
<a
|
||||
class="domain"
|
||||
href={{link.url}}
|
||||
title={{link.title}}
|
||||
rel="noopener {{unless
|
||||
this.user.removeNoFollow
|
||||
'nofollow ugc'
|
||||
}}"
|
||||
target="_blank"
|
||||
>
|
||||
{{shorten-url link.url}}
|
||||
</a>
|
||||
{{! template-lint-enable link-rel-noopener }}
|
||||
|
||||
<span
|
||||
class="badge badge-notification clicks"
|
||||
title={{i18n "topic_map.clicks" count=link.clicks}}
|
||||
>
|
||||
{{number link.clicks}}
|
||||
</span>
|
||||
|
||||
<br />
|
||||
|
||||
<a href={{link.post_url}}>
|
||||
{{html-safe link.topic.fancyTitle}}
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_links"}}</p>
|
||||
{{/if}}
|
||||
</UserSummarySection>
|
||||
|
||||
<UserSummarySection
|
||||
@title="most_replied_to_users"
|
||||
@class="summary-user-list replied-section pull-right"
|
||||
>
|
||||
<UserSummaryUsersList
|
||||
@none="no_replies"
|
||||
@users={{this.model.most_replied_to_users}}
|
||||
as |user|
|
||||
>
|
||||
<UserSummaryUser @user={{user}} @icon="reply" @countClass="replies" />
|
||||
</UserSummaryUsersList>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
|
||||
<div class="top-section most-liked-section">
|
||||
<UserSummarySection
|
||||
@title="most_liked_by"
|
||||
@class="summary-user-list liked-by-section pull-left"
|
||||
>
|
||||
<UserSummaryUsersList
|
||||
@none="no_likes"
|
||||
@users={{this.model.most_liked_by_users}}
|
||||
as |user|
|
||||
>
|
||||
<UserSummaryUser @user={{user}} @icon="heart" @countClass="likes" />
|
||||
</UserSummaryUsersList>
|
||||
</UserSummarySection>
|
||||
|
||||
<UserSummarySection
|
||||
@title="most_liked_users"
|
||||
@class="summary-user-list liked-section pull-right"
|
||||
>
|
||||
<UserSummaryUsersList
|
||||
@none="no_likes"
|
||||
@users={{this.model.most_liked_users}}
|
||||
as |user|
|
||||
>
|
||||
<UserSummaryUser @user={{user}} @icon="heart" @countClass="likes" />
|
||||
</UserSummaryUsersList>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
|
||||
{{#if this.model.top_categories.length}}
|
||||
<div class="top-section top-categories-section">
|
||||
<UserSummarySection
|
||||
@title="top_categories"
|
||||
@class="summary-category-list pull-left"
|
||||
>
|
||||
<table>
|
||||
<thead>
|
||||
<th class="category-link"></th>
|
||||
<th class="topic-count">{{i18n "user.summary.topics"}}</th>
|
||||
<th class="reply-count">{{i18n "user.summary.replies"}}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.model.top_categories as |category|}}
|
||||
<tr>
|
||||
<td class="category-link">
|
||||
{{category-link
|
||||
category
|
||||
allowUncategorized="true"
|
||||
hideParent=false
|
||||
}}
|
||||
</td>
|
||||
<td class="topic-count">
|
||||
<UserSummaryCategorySearch
|
||||
@user={{this.user}}
|
||||
@category={{category}}
|
||||
@count={{category.topic_count}}
|
||||
/>
|
||||
</td>
|
||||
<td class="reply-count">
|
||||
<UserSummaryCategorySearch
|
||||
@user={{this.user}}
|
||||
@category={{category}}
|
||||
@count={{category.post_count}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</UserSummarySection>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.siteSettings.enable_badges}}
|
||||
<div class="top-section badges-section">
|
||||
<h3 class="stats-title">{{i18n "user.summary.top_badges"}}</h3>
|
||||
|
||||
{{#if this.model.badges}}
|
||||
<div class="badge-group-list">
|
||||
{{#each this.model.badges as |badge|}}
|
||||
<BadgeCard
|
||||
@badge={{badge}}
|
||||
@count={{badge.count}}
|
||||
@username={{this.user.username_lower}}
|
||||
/>
|
||||
{{/each}}
|
||||
<PluginOutlet
|
||||
@name="after-user-summary-badges"
|
||||
@outletArgs={{hash model=this.model user=this.user}}
|
||||
/>
|
||||
</div>
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_badges"}}</p>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.moreBadges}}
|
||||
<LinkTo @route="user.badges" @model={{this.user}} class="more">
|
||||
{{i18n "user.summary.more_badges"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</DSection>
|
||||
{{/if}}
|
||||
</div>
|
@ -2,7 +2,8 @@
|
||||
{{hide-application-footer}}
|
||||
{{/if}}
|
||||
|
||||
<DSection @pageClass="users">
|
||||
{{body-class "users-page"}}
|
||||
<section>
|
||||
<LoadMore
|
||||
@selector=".directory-table .directory-table__cell"
|
||||
@action={{action "loadMore"}}
|
||||
@ -86,4 +87,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</LoadMore>
|
||||
</DSection>
|
||||
</section>
|
@ -10,5 +10,6 @@ globalThis.deprecationWorkflow.config = {
|
||||
matchId: "ember-this-fallback.this-property-fallback",
|
||||
},
|
||||
{ handler: "silence", matchId: "discourse.select-kit" },
|
||||
{ handler: "silence", matchId: "discourse.d-section" },
|
||||
],
|
||||
};
|
||||
|
@ -1,28 +1,35 @@
|
||||
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "ember-qunit";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import { test } from "qunit";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import { withSilencedDeprecationsAsync } from "discourse-common/lib/deprecated";
|
||||
import Component from "@ember/component";
|
||||
import { registerTemporaryModule } from "discourse/tests/helpers/temporary-module-helper";
|
||||
|
||||
acceptance("Plugin Outlet - Deprecated parentView", function (needs) {
|
||||
needs.hooks.beforeEach(function () {
|
||||
registerTemporaryModule(
|
||||
"discourse/templates/connectors/user-profile-primary/hello",
|
||||
hbs`<span class='hello-username'>{{this.parentView.parentView.class}}</span>`
|
||||
);
|
||||
});
|
||||
module("Plugin Outlet - Deprecated parentView", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("Can access parentView", async function (assert) {
|
||||
this.component = class AComponent extends Component {
|
||||
layout = hbs`<PluginOutlet @name="an-outlet" @connectorTagName="div" />`;
|
||||
};
|
||||
|
||||
registerTemporaryModule(
|
||||
"discourse/templates/connectors/an-outlet/hello",
|
||||
hbs`<span class="hello-username">{{this.parentView.parentView.constructor.name}}</span>`
|
||||
);
|
||||
|
||||
test("Can access parentview", async function (assert) {
|
||||
await withSilencedDeprecationsAsync(
|
||||
"discourse.plugin-outlet-parent-view",
|
||||
async () => {
|
||||
await visit("/u/eviltrout");
|
||||
assert.strictEqual(
|
||||
query(".hello-username").innerText,
|
||||
"user-main",
|
||||
"it renders a value from parentView.parentView"
|
||||
);
|
||||
await render(hbs`<this.component />`);
|
||||
|
||||
assert
|
||||
.dom(".hello-username")
|
||||
.hasText(
|
||||
"AComponent",
|
||||
"it renders a value from parentView.parentView"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import DSection from "discourse/components/d-section";
|
||||
|
||||
module("Integration | Component | d-section", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("can set classes on the body element", async function (assert) {
|
||||
await render(<template>
|
||||
<DSection @pageClass="test" @bodyClass="foo bar" class="special">
|
||||
testing!
|
||||
</DSection>
|
||||
</template>);
|
||||
|
||||
assert.dom(".special").hasText("testing!");
|
||||
assert.strictEqual(document.body.className, "test-page foo bar");
|
||||
});
|
||||
});
|
@ -0,0 +1,42 @@
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { render, settled } from "@ember/test-helpers";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
|
||||
module("Integration | Helper | body-class", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("A single class", async function (assert) {
|
||||
await render(hbs`{{body-class "foo"}}`);
|
||||
|
||||
assert.true(document.body.classList.contains("foo"));
|
||||
});
|
||||
|
||||
test("Multiple classes", async function (assert) {
|
||||
this.set("bar", "bar");
|
||||
await render(hbs`{{body-class "baz" this.bar}}`);
|
||||
|
||||
assert.true(document.body.classList.contains("baz"));
|
||||
assert.true(document.body.classList.contains("bar"));
|
||||
});
|
||||
|
||||
test("Empty classes", async function (assert) {
|
||||
const classesBefore = document.body.className;
|
||||
await render(hbs`{{body-class (if false "not-really")}}`);
|
||||
assert.strictEqual(document.body.className, classesBefore);
|
||||
});
|
||||
|
||||
test("Dynamic classes", async function (assert) {
|
||||
this.set("dynamic", "bar");
|
||||
await render(hbs`{{body-class this.dynamic}}`);
|
||||
assert.true(document.body.classList.contains("bar"), "has .bar");
|
||||
|
||||
this.set("dynamic", "baz");
|
||||
await settled();
|
||||
assert.true(document.body.classList.contains("baz"), "has .baz");
|
||||
assert.false(
|
||||
document.body.classList.contains("bar"),
|
||||
"does not have .bar anymore"
|
||||
);
|
||||
});
|
||||
});
|
@ -14,7 +14,7 @@
|
||||
</StyleguideExample>
|
||||
|
||||
<StyleguideExample @title=".user-navigation .nav-stacked" class="half-size">
|
||||
<DSection @class="user-navigation">
|
||||
<section class="user-navigation">
|
||||
<MobileNav
|
||||
@class="preferences-nav"
|
||||
@desktopClass="preferences-list action-list nav-stacked"
|
||||
@ -27,5 +27,5 @@
|
||||
</li>
|
||||
{{/each}}
|
||||
</MobileNav>
|
||||
</DSection>
|
||||
</section>
|
||||
</StyleguideExample>
|
@ -1,7 +1,7 @@
|
||||
<StyleguideExample @title="navigation">
|
||||
<div class="list-controls">
|
||||
<div class="container">
|
||||
<DSection @class="navigation-container">
|
||||
<section class="navigation-container">
|
||||
<BreadCrumbs @categories={{@dummy.categories}} />
|
||||
<NavigationBar @navItems={{@dummy.navItems}} @filterMode="latest" />
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<CategoriesAdminDropdown />
|
||||
<CreateTopicButton @canCreateTopic={{true}} />
|
||||
</div>
|
||||
</DSection>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</StyleguideExample>
|
@ -1,5 +1,5 @@
|
||||
<StyleguideExample @title=".user-main .about.collapsed-info.no-background">
|
||||
<DSection @class="user-main">
|
||||
<section class="user-main">
|
||||
<section class="collapsed-info about no-background">
|
||||
<div class="profile-image"></div>
|
||||
|
||||
@ -41,11 +41,11 @@
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</section>
|
||||
</DSection>
|
||||
</section>
|
||||
</StyleguideExample>
|
||||
|
||||
<StyleguideExample @title=".user-main .about.collapsed-info.has-background">
|
||||
<DSection @class="user-main">
|
||||
<section class="user-main">
|
||||
<section
|
||||
class="collapsed-info about has-background"
|
||||
style={{@dummy.user.profileBackground}}
|
||||
@ -89,11 +89,11 @@
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</section>
|
||||
</DSection>
|
||||
</section>
|
||||
</StyleguideExample>
|
||||
|
||||
<StyleguideExample @title=".user-main .about.no-background">
|
||||
<DSection @class="user-main">
|
||||
<section class="user-main">
|
||||
<section class="about no-background">
|
||||
|
||||
<div class="staff-counters">
|
||||
@ -244,11 +244,11 @@
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
</DSection>
|
||||
</section>
|
||||
</StyleguideExample>
|
||||
|
||||
<StyleguideExample @title=".user-main .about.has-background">
|
||||
<DSection @class="user-main">
|
||||
<section class="user-main">
|
||||
<section
|
||||
class="about has-background"
|
||||
style={{@dummy.user.profileBackground}}
|
||||
@ -399,5 +399,5 @@
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
</DSection>
|
||||
</section>
|
||||
</StyleguideExample>
|
Loading…
Reference in New Issue
Block a user