mirror of
https://github.com/flarum/core.git
synced 2025-08-13 11:54:32 +02:00
Compare commits
11 Commits
sm/itemlis
...
as/better-
Author | SHA1 | Date | |
---|---|---|---|
|
b475049269 | ||
|
392b90710c | ||
|
5b43e3cfd7 | ||
|
b9ed71700a | ||
|
6712fef3cf | ||
|
5fa968df2f | ||
|
b88db06a74 | ||
|
d34cf1d925 | ||
|
c6287e1520 | ||
|
222d9ccff7 | ||
|
c9fdd0753f |
@@ -13,6 +13,9 @@ export default class FlagList extends Component {
|
||||
this.state = this.attrs.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const flags = this.state.cache || [];
|
||||
|
||||
|
@@ -24,6 +24,9 @@ export default class FlagPostModal extends Modal {
|
||||
return app.translator.trans('flarum-flags.forum.flag_post.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
if (this.success) {
|
||||
return (
|
||||
|
@@ -11,6 +11,9 @@ export default class FlagsDropdown extends NotificationsDropdown {
|
||||
super.initAttrs(attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getMenu() {
|
||||
return (
|
||||
<div className={'Dropdown-menu ' + this.attrs.menuClassName} onclick={this.menuClick.bind(this)}>
|
||||
|
@@ -18,6 +18,9 @@ export default class FlagsPage extends Page {
|
||||
this.bodyClass = 'App--flags';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<div className="FlagsPage">
|
||||
|
@@ -64,7 +64,7 @@ export default class Updater<Attrs> extends Component<Attrs> {
|
||||
super.oninit(vnode);
|
||||
}
|
||||
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
const extensions = this.getExtensionUpdates();
|
||||
let coreUpdate: UpdatedPackage | undefined = this.getCoreUpdate();
|
||||
let core: any;
|
||||
|
@@ -26,7 +26,7 @@ export default class WhyNotModal<Attrs extends WhyNotModalAttrs = WhyNotModalAtt
|
||||
this.requestWhyNot();
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
return <div className="Modal-body">{this.loading ? <LoadingIndicator /> : <pre className="WhyNotModal-contents">{this.whyNot}</pre>}</div>;
|
||||
}
|
||||
|
||||
|
@@ -46,6 +46,9 @@ export default class StatisticsWidget extends DashboardWidget {
|
||||
return 'StatisticsWidget';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
const thisPeriod = this.periods[this.selectedPeriod];
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import { slug } from 'flarum/common/utils/string';
|
||||
import Stream from 'flarum/common/utils/Stream';
|
||||
|
||||
import tagLabel from '../../common/helpers/tagLabel';
|
||||
import type Mithril from 'mithril';
|
||||
import Mithril from 'mithril';
|
||||
import type Tag from '../../common/models/Tag';
|
||||
import extractText from 'flarum/common/utils/extractText';
|
||||
import { ModelIdentifier } from 'flarum/common/Model';
|
||||
@@ -50,13 +50,13 @@ export default class EditTagModal extends Modal<EditTagModalAttrs> {
|
||||
return 'EditTagModal Modal--small';
|
||||
}
|
||||
|
||||
title() {
|
||||
title(): Mithril.Children {
|
||||
return this.name()
|
||||
? tagLabel(app.store.createRecord('tags', { attributes: this.submitData() }))
|
||||
? tagLabel(app.store.createRecord<Tag>('tags', { attributes: this.submitData() }))
|
||||
: app.translator.trans('flarum-tags.admin.edit_tag.title');
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
<div className="Form">
|
||||
@@ -67,7 +67,7 @@ export default class EditTagModal extends Modal<EditTagModalAttrs> {
|
||||
}
|
||||
|
||||
fields() {
|
||||
const items = new ItemList();
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add('name', <div className="Form-group">
|
||||
<label>{app.translator.trans('flarum-tags.admin.edit_tag.name_label')}</label>
|
||||
|
@@ -51,6 +51,9 @@ export default class TagsPage extends ExtensionPage {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
if (this.loading) {
|
||||
return <LoadingIndicator />;
|
||||
@@ -63,7 +66,7 @@ export default class TagsPage extends ExtensionPage {
|
||||
const maxSecondaryTags = this.setting('flarum-tags.max_secondary_tags', 0);
|
||||
|
||||
const tags = sortTags(app.store.all('tags').filter(tag => !tag.parent()));
|
||||
|
||||
|
||||
return (
|
||||
<div className="TagsContent">
|
||||
<div className="TagsContent-list">
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import { ComponentAttrs } from 'flarum/common/Component';
|
||||
import classList from 'flarum/common/utils/classList';
|
||||
import type Tag from '../models/Tag';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
export default function tagIcon(tag, attrs = {}, settings = {}) {
|
||||
export default function tagIcon(tag: Tag, attrs: ComponentAttrs = {}, settings: {useColor?: boolean} = {}): Mithril.Children {
|
||||
const hasIcon = tag && tag.icon();
|
||||
const { useColor = true } = settings;
|
||||
|
@@ -1,8 +1,13 @@
|
||||
import app from 'flarum/common/app';
|
||||
|
||||
import extract from 'flarum/common/utils/extract';
|
||||
import Link from 'flarum/common/components/Link';
|
||||
import tagIcon from './tagIcon';
|
||||
import type Tag from '../models/Tag';
|
||||
import type { ComponentAttrs } from 'flarum/common/Component';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
export default function tagLabel(tag, attrs = {}) {
|
||||
export default function tagLabel(tag?: Tag, attrs: ComponentAttrs = {}): Mithril.Children {
|
||||
attrs.style = attrs.style || {};
|
||||
attrs.className = 'TagLabel ' + (attrs.className || '');
|
||||
|
||||
@@ -28,11 +33,15 @@ export default function tagLabel(tag, attrs = {}) {
|
||||
attrs.className += ' untagged';
|
||||
}
|
||||
|
||||
return (
|
||||
m((link ? Link : 'span'), attrs,
|
||||
<span className="TagLabel-text">
|
||||
const children = (
|
||||
<span className="TagLabel-text">
|
||||
{tag && tag.icon() && tagIcon(tag, {}, {useColor: false})} {tagText}
|
||||
</span>
|
||||
)
|
||||
);
|
||||
|
||||
if (link) {
|
||||
return <Link {...attrs}>{children}</Link>
|
||||
}
|
||||
|
||||
return <span {...attrs}>{children}</span>;
|
||||
}
|
@@ -1,15 +1,18 @@
|
||||
import extract from 'flarum/common/utils/extract';
|
||||
import tagLabel from './tagLabel';
|
||||
import sortTags from '../utils/sortTags';
|
||||
import type Tag from '../models/Tag';
|
||||
import type { ComponentAttrs } from 'flarum/common/Component';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
export default function tagsLabel(tags, attrs = {}) {
|
||||
export default function tagsLabel(tags: Tag[], attrs: ComponentAttrs = {}): Mithril.Children {
|
||||
const children = [];
|
||||
const link = extract(attrs, 'link');
|
||||
|
||||
attrs.className = 'TagsLabel ' + (attrs.className || '');
|
||||
|
||||
if (tags) {
|
||||
sortTags(tags).forEach(tag => {
|
||||
sortTags(tags).forEach((tag: Tag) => {
|
||||
if (tag || tags.length === 1) {
|
||||
children.push(tagLabel(tag, {link}));
|
||||
}
|
@@ -139,6 +139,9 @@ export default class TagDiscussionModal extends Modal<TagDiscussionModalAttrs> {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
if (this.tagsLoading || !this.tags) {
|
||||
return <LoadingIndicator />;
|
||||
|
@@ -2,6 +2,9 @@ import Component from 'flarum/common/Component';
|
||||
import tagIcon from '../../common/helpers/tagIcon';
|
||||
|
||||
export default class TagHero extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const tag = this.attrs.model;
|
||||
const color = tag.color();
|
||||
|
@@ -4,6 +4,9 @@ import classList from 'flarum/common/utils/classList';
|
||||
import tagIcon from '../../common/helpers/tagIcon';
|
||||
|
||||
export default class TagLinkButton extends LinkButton {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
const tag = this.attrs.model;
|
||||
const active = this.constructor.isActive(this.attrs);
|
||||
|
@@ -35,6 +35,9 @@ export default class TagsPage extends Page {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
if (this.loading) {
|
||||
return <LoadingIndicator />;
|
||||
|
@@ -6,6 +6,9 @@ import classList from 'flarum/common/utils/classList';
|
||||
* @TODO move to core
|
||||
*/
|
||||
export default class ToggleButton extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
const { className, isToggled, ...attrs } = this.attrs;
|
||||
const icon = isToggled ? 'far fa-check-circle' : 'far fa-circle';
|
||||
|
@@ -1,4 +1,6 @@
|
||||
declare module '@askvortsov/rich-icu-message-formatter' {
|
||||
import Mithril from 'mithril';
|
||||
|
||||
type IValues = Record<string, any>;
|
||||
|
||||
type ITypeHandler = (
|
||||
@@ -10,16 +12,13 @@ declare module '@askvortsov/rich-icu-message-formatter' {
|
||||
) => string;
|
||||
type IRichHandler = (tag: any, values: IValues, contents: string) => any;
|
||||
|
||||
type ValueOrArray<T> = T | ValueOrArray<T>[];
|
||||
type NestedStringArray = ValueOrArray<string>;
|
||||
|
||||
export class RichMessageFormatter {
|
||||
locale: string | null;
|
||||
constructor(locale: string | null, typeHandlers: Record<string, ITypeHandler>, richHandler: IRichHandler);
|
||||
|
||||
format(message: string, values: IValues): string;
|
||||
process(message: string, values: IValues): NestedStringArray;
|
||||
rich(message: string, values: IValues): NestedStringArray;
|
||||
process(message: string, values: IValues): Mithril.Children;
|
||||
rich(message: string, values: IValues): Mithril.Children;
|
||||
}
|
||||
|
||||
export function mithrilRichHandler(tag: any, values: IValues, contents: string): any;
|
||||
|
@@ -1,9 +1,15 @@
|
||||
import Component from '../../common/Component';
|
||||
import Component, { ComponentAttrs } from '../../common/Component';
|
||||
import classList from '../../common/utils/classList';
|
||||
import icon from '../../common/helpers/icon';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
export default class AdminHeader extends Component {
|
||||
view(vnode) {
|
||||
export interface IAdminHeaderAttrs extends ComponentAttrs {
|
||||
icon: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export default class AdminHeader<CustomAttrs extends IAdminHeaderAttrs = IAdminHeaderAttrs> extends Component<CustomAttrs> {
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children {
|
||||
return [
|
||||
<div className={classList(['AdminHeader', this.attrs.className])}>
|
||||
<div className="container">
|
@@ -14,6 +14,9 @@ export default class AdminNav extends Component {
|
||||
this.query = Stream('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<SelectDropdown className="AdminNav App-titleControl AdminNav-Main" buttonClassName="Button">
|
||||
|
@@ -17,6 +17,9 @@ export default class AppearancePage extends AdminPage {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return [
|
||||
<div className="Form">
|
||||
|
@@ -38,6 +38,9 @@ export default class BasicsPage extends AdminPage {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return [
|
||||
<div className="Form">
|
||||
|
@@ -10,6 +10,9 @@ export default class EditCustomCssModal extends SettingsModal {
|
||||
return app.translator.trans('core.admin.edit_css.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
form() {
|
||||
return [
|
||||
<p>
|
||||
|
@@ -10,6 +10,9 @@ export default class EditCustomFooterModal extends SettingsModal {
|
||||
return app.translator.trans('core.admin.edit_footer.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
form() {
|
||||
return [
|
||||
<p>{app.translator.trans('core.admin.edit_footer.customize_text')}</p>,
|
||||
|
@@ -10,6 +10,9 @@ export default class EditCustomHeaderModal extends SettingsModal {
|
||||
return app.translator.trans('core.admin.edit_header.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
form() {
|
||||
return [
|
||||
<p>{app.translator.trans('core.admin.edit_header.customize_text')}</p>,
|
||||
|
@@ -41,6 +41,9 @@ export default class EditGroupModal extends Modal {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
|
@@ -54,7 +54,7 @@ export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionP
|
||||
return this.extension.id + '-Page';
|
||||
}
|
||||
|
||||
view(vnode: Mithril.VnodeDOM<Attrs, this>) {
|
||||
view(vnode: Mithril.VnodeDOM<Attrs, this>): Mithril.Children {
|
||||
if (!this.extension) return null;
|
||||
|
||||
return (
|
||||
@@ -71,7 +71,7 @@ export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionP
|
||||
);
|
||||
}
|
||||
|
||||
header() {
|
||||
header(): Mithril.Children {
|
||||
const isEnabled = this.isEnabled();
|
||||
|
||||
return [
|
||||
@@ -106,8 +106,8 @@ export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionP
|
||||
];
|
||||
}
|
||||
|
||||
sections(vnode: Mithril.VnodeDOM<Attrs, this>) {
|
||||
const items = new ItemList();
|
||||
sections(vnode: Mithril.VnodeDOM<Attrs, this>): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add('content', this.content(vnode));
|
||||
|
||||
@@ -131,7 +131,7 @@ export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionP
|
||||
return items;
|
||||
}
|
||||
|
||||
content(vnode: Mithril.VnodeDOM<Attrs, this>) {
|
||||
content(vnode: Mithril.VnodeDOM<Attrs, this>): Mithril.Children {
|
||||
const settings = app.extensionData.getSettings(this.extension.id);
|
||||
|
||||
return (
|
||||
@@ -150,7 +150,7 @@ export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionP
|
||||
);
|
||||
}
|
||||
|
||||
topItems() {
|
||||
topItems(): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
items.add('version', <span className="ExtensionVersion">{this.extension.version}</span>);
|
||||
|
@@ -16,6 +16,9 @@ export default class ExtensionsWidget extends DashboardWidget {
|
||||
return 'ExtensionsWidget';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
const categories = app.extensionCategories;
|
||||
|
||||
@@ -26,6 +29,9 @@ export default class ExtensionsWidget extends DashboardWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
extensionCategory(category) {
|
||||
return (
|
||||
<div className="ExtensionList-Category">
|
||||
@@ -35,6 +41,9 @@ export default class ExtensionsWidget extends DashboardWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
extensionWidget(extension) {
|
||||
return (
|
||||
<li className={'ExtensionListItem ' + (!isExtensionEnabled(extension.id) ? 'disabled' : '')}>
|
||||
|
@@ -7,6 +7,9 @@ import listItems from '../../common/helpers/listItems';
|
||||
* default skin, these are shown just to the right of the forum title.
|
||||
*/
|
||||
export default class HeaderPrimary extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return <ul className="Header-controls">{listItems(this.items().toArray())}</ul>;
|
||||
}
|
||||
|
@@ -9,6 +9,9 @@ import listItems from '../../common/helpers/listItems';
|
||||
* The `HeaderSecondary` component displays secondary header controls.
|
||||
*/
|
||||
export default class HeaderSecondary extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return <ul className="Header-controls">{listItems(this.items().toArray())}</ul>;
|
||||
}
|
||||
|
@@ -42,6 +42,9 @@ export default class MailPage extends AdminPage {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
if (this.loading) {
|
||||
return <LoadingIndicator />;
|
||||
|
@@ -33,7 +33,7 @@ export interface ScopeItem {
|
||||
export interface IPermissionGridAttrs extends ComponentAttrs {}
|
||||
|
||||
export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = IPermissionGridAttrs> extends Component<CustomAttrs> {
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children {
|
||||
const scopes = this.scopeItems().toArray();
|
||||
|
||||
const permissionCells = (permission: PermissionGridEntry | { children: PermissionGridEntry[] }) => {
|
||||
|
@@ -16,6 +16,9 @@ export default class PermissionsPage extends AdminPage {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return [
|
||||
<div className="PermissionsPage-groups">
|
||||
|
@@ -38,7 +38,7 @@ export default class ReadmeModal<CustomAttrs extends IReadmeModalAttrs = IReadme
|
||||
});
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
const text = app.translator.trans('core.admin.extension.readme.no_readme');
|
||||
|
||||
return (
|
||||
|
@@ -18,10 +18,16 @@ export default class SessionDropdown extends Dropdown {
|
||||
attrs.menuClassName = 'Dropdown-menu--right';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
return super.view({ ...vnode, children: this.items().toArray() });
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
getButtonContent() {
|
||||
const user = app.session.user;
|
||||
|
||||
|
@@ -16,6 +16,9 @@ export default class SettingsModal extends Modal {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
@@ -28,6 +31,9 @@ export default class SettingsModal extends Modal {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
submitButton() {
|
||||
return (
|
||||
<Button type="submit" className="Button Button--primary" loading={this.loading} disabled={!this.changed()}>
|
||||
|
@@ -11,6 +11,9 @@ export default class StatusWidget extends DashboardWidget {
|
||||
return 'StatusWidget';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return <ul>{listItems(this.items().toArray())}</ul>;
|
||||
}
|
||||
|
@@ -4,6 +4,9 @@ import Button from '../../common/components/Button';
|
||||
export default class UploadImageButton extends Button {
|
||||
loading = false;
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
this.attrs.loading = this.loading;
|
||||
this.attrs.className = (this.attrs.className || '') + ' Button';
|
||||
|
@@ -77,7 +77,7 @@ export default class UserListPage extends AdminPage {
|
||||
/**
|
||||
* Component to render.
|
||||
*/
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
if (typeof this.pageData === 'undefined') {
|
||||
this.loadPage(0);
|
||||
|
||||
|
@@ -22,7 +22,7 @@ export interface AlertAttrs extends ComponentAttrs {
|
||||
* some controls, and may be dismissible.
|
||||
*/
|
||||
export default class Alert<T extends AlertAttrs = AlertAttrs> extends Component<T> {
|
||||
view(vnode: Mithril.VnodeDOM<T, this>) {
|
||||
view(vnode: Mithril.VnodeDOM<T, this>): Mithril.Children {
|
||||
const attrs = Object.assign({}, this.attrs);
|
||||
|
||||
const type = extract(attrs, 'type');
|
||||
|
@@ -1,31 +0,0 @@
|
||||
import Component from '../Component';
|
||||
|
||||
/**
|
||||
* The `AlertManager` component provides an area in which `Alert` components can
|
||||
* be shown and dismissed.
|
||||
*/
|
||||
export default class AlertManager extends Component {
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
|
||||
this.state = this.attrs.state;
|
||||
}
|
||||
|
||||
view() {
|
||||
return (
|
||||
<div class="AlertManager">
|
||||
{Object.entries(this.state.getActiveAlerts()).map(([key, alert]) => {
|
||||
const urgent = alert.attrs.type === 'error';
|
||||
|
||||
return (
|
||||
<div class="AlertManager-alert" role="alert" aria-live={urgent ? 'assertive' : 'polite'}>
|
||||
<alert.componentClass {...alert.attrs} ondismiss={this.state.dismiss.bind(this.state, key)}>
|
||||
{alert.children}
|
||||
</alert.componentClass>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
39
framework/core/js/src/common/components/AlertManager.tsx
Normal file
39
framework/core/js/src/common/components/AlertManager.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import type Mithril from 'mithril';
|
||||
import Component, { ComponentAttrs } from '../Component';
|
||||
import type AlertManagerState from '../states/AlertManagerState';
|
||||
|
||||
export interface IAlertManagerAttrs extends ComponentAttrs {
|
||||
state: AlertManagerState;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `AlertManager` component provides an area in which `Alert` components can
|
||||
* be shown and dismissed.
|
||||
*/
|
||||
export default class AlertManager<CustomAttrs extends IAlertManagerAttrs = IAlertManagerAttrs> extends Component<CustomAttrs> {
|
||||
alertsState!: AlertManagerState;
|
||||
|
||||
oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||
super.oninit(vnode);
|
||||
|
||||
this.alertsState = this.attrs.state;
|
||||
}
|
||||
|
||||
view(): Mithril.Children {
|
||||
return (
|
||||
<div class="AlertManager">
|
||||
{Object.entries(this.alertsState.getActiveAlerts()).map(([key, alert]) => {
|
||||
const urgent = alert.attrs.type === 'error';
|
||||
|
||||
return (
|
||||
<div class="AlertManager-alert" role="alert" aria-live={urgent ? 'assertive' : 'polite'}>
|
||||
<alert.componentClass {...alert.attrs} ondismiss={this.alertsState.dismiss.bind(this.alertsState, parseInt(key))}>
|
||||
{alert.children}
|
||||
</alert.componentClass>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@@ -17,6 +17,9 @@ import classList from '../utils/classList';
|
||||
* All other attrs will be assigned as attributes on the badge element.
|
||||
*/
|
||||
export default class Badge extends Component {
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const { type, icon: iconName, label, color, style = {}, ...attrs } = this.attrs;
|
||||
|
||||
|
@@ -67,7 +67,7 @@ export interface IButtonAttrs extends ComponentAttrs {
|
||||
* styles can be applied by providing `className="Button"` to the Button component.
|
||||
*/
|
||||
export default class Button<CustomAttrs extends IButtonAttrs = IButtonAttrs> extends Component<CustomAttrs> {
|
||||
view(vnode: Mithril.VnodeDOM<CustomAttrs, this>) {
|
||||
view(vnode: Mithril.VnodeDOM<CustomAttrs, this>): Mithril.Children {
|
||||
let { type, title, 'aria-label': ariaLabel, icon: iconName, disabled, loading, className, class: _class, ...attrs } = this.attrs;
|
||||
|
||||
// If no `type` attr provided, set to "button"
|
||||
|
@@ -17,6 +17,9 @@ import withAttr from '../utils/withAttr';
|
||||
* - `children` A text label to display next to the checkbox.
|
||||
*/
|
||||
export default class Checkbox extends Component {
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
// Sometimes, false is stored in the DB as '0'. This is a temporary
|
||||
// conversion layer until a more robust settings encoding is introduced
|
||||
|
@@ -5,7 +5,7 @@ import classList from '../utils/classList';
|
||||
import icon from '../helpers/icon';
|
||||
|
||||
export default class ColorPreviewInput extends Component {
|
||||
view(vnode: Mithril.Vnode<ComponentAttrs, this>) {
|
||||
view(vnode: Mithril.Vnode<ComponentAttrs, this>): Mithril.Children {
|
||||
const { className, id, ...attrs } = this.attrs;
|
||||
|
||||
attrs.type ||= 'text';
|
||||
|
@@ -36,6 +36,9 @@ export default class Dropdown extends Component {
|
||||
this.showing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
const items = vnode.children ? listItems(vnode.children) : [];
|
||||
const renderItems = this.attrs.lazyDraw ? this.showing : true;
|
||||
@@ -134,6 +137,9 @@ export default class Dropdown extends Component {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
getMenu(items) {
|
||||
return <ul className={'Dropdown-menu dropdown-menu ' + this.attrs.menuClassName}>{items}</ul>;
|
||||
}
|
||||
|
@@ -45,11 +45,11 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
|
||||
return 'EditUserModal Modal--small';
|
||||
}
|
||||
|
||||
title() {
|
||||
title(): Mithril.Children {
|
||||
return app.translator.trans('core.lib.edit_user.title');
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
const fields = this.fields().toArray();
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
@@ -58,8 +58,8 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
|
||||
);
|
||||
}
|
||||
|
||||
fields() {
|
||||
const items = new ItemList();
|
||||
fields(): ItemList<Mithril.Children> {
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
if (this.attrs.user.canEditCredentials()) {
|
||||
items.add(
|
||||
|
@@ -11,6 +11,9 @@ import listItems from '../helpers/listItems';
|
||||
* The children should be an array of items to show in the fieldset.
|
||||
*/
|
||||
export default class FieldSet extends Component {
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
return (
|
||||
<fieldset className={this.attrs.className}>
|
||||
|
@@ -10,6 +10,9 @@ import extract from '../utils/extract';
|
||||
* `true` for the link to be external.
|
||||
*/
|
||||
export default class Link extends Component {
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
let { options = {}, ...attrs } = vnode.attrs;
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import app from '../../common/app';
|
||||
import Component, { ComponentAttrs } from '../Component';
|
||||
import classList from '../utils/classList';
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
export interface LoadingIndicatorAttrs extends ComponentAttrs {
|
||||
/**
|
||||
@@ -55,7 +56,7 @@ export interface LoadingIndicatorAttrs extends ComponentAttrs {
|
||||
* All other attrs will be assigned as attributes on the DOM element.
|
||||
*/
|
||||
export default class LoadingIndicator extends Component<LoadingIndicatorAttrs> {
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
const { display = 'block', size = 'medium', containerClassName, className, ...attrs } = this.attrs;
|
||||
|
||||
const completeClassName = classList('LoadingIndicator', className);
|
||||
|
@@ -81,7 +81,7 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
|
||||
/**
|
||||
* @todo split into FormModal and Modal in 2.0
|
||||
*/
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
if (this.alertAttrs) {
|
||||
this.alertAttrs.dismissible = false;
|
||||
}
|
||||
|
@@ -19,6 +19,9 @@ import LinkButton from './LinkButton';
|
||||
* there is no more history to pop.
|
||||
*/
|
||||
export default class Navigation extends Component {
|
||||
/**
|
||||
* @returns {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const { history, pane } = app;
|
||||
|
||||
|
@@ -1,19 +0,0 @@
|
||||
import Component from '../Component';
|
||||
|
||||
/**
|
||||
* The `Placeholder` component displays a muted text with some call to action,
|
||||
* usually used as an empty state.
|
||||
*
|
||||
* ### Attrs
|
||||
*
|
||||
* - `text`
|
||||
*/
|
||||
export default class Placeholder extends Component {
|
||||
view() {
|
||||
return (
|
||||
<div className="Placeholder">
|
||||
<p>{this.attrs.text}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
20
framework/core/js/src/common/components/Placeholder.tsx
Normal file
20
framework/core/js/src/common/components/Placeholder.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import type Mithril from 'mithril';
|
||||
import Component, { ComponentAttrs } from '../Component';
|
||||
|
||||
interface IPlaceholderAttrs extends ComponentAttrs {
|
||||
text: Mithril.Children;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Placeholder` component displays a muted text with some call to action,
|
||||
* usually used as an empty state.
|
||||
*/
|
||||
export default class Placeholder<CustomAttrs extends IPlaceholderAttrs = IPlaceholderAttrs> extends Component<CustomAttrs> {
|
||||
view(): Mithril.Children {
|
||||
return (
|
||||
<div className="Placeholder">
|
||||
<p>{this.attrs.text}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
import type Mithril from 'mithril';
|
||||
import type RequestError from '../utils/RequestError';
|
||||
import Modal, { IInternalModalAttrs } from './Modal';
|
||||
|
||||
@@ -15,7 +16,7 @@ export default class RequestErrorModal<CustomAttrs extends IRequestErrorModalAtt
|
||||
return this.attrs.error.xhr ? `${this.attrs.error.xhr.status} ${this.attrs.error.xhr.statusText}` : '';
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
const { error, formattedError } = this.attrs;
|
||||
|
||||
let responseText;
|
||||
|
@@ -16,6 +16,9 @@ import classList from '../utils/classList';
|
||||
* Other attributes are passed directly to the `<select>` element rendered to the DOM.
|
||||
*/
|
||||
export default class Select extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const {
|
||||
options,
|
||||
|
@@ -41,6 +41,9 @@ export default class SelectDropdown extends Dropdown {
|
||||
attrs.className += ' Dropdown--select';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getButtonContent(children) {
|
||||
const activeChild = children.find(isActive);
|
||||
let label = (activeChild && activeChild.children) || this.attrs.defaultLabel;
|
||||
|
@@ -1,14 +1,13 @@
|
||||
import type Mithril from 'mithril';
|
||||
import Component from '../Component';
|
||||
|
||||
/**
|
||||
* The `Separator` component defines a menu separator item.
|
||||
*/
|
||||
class Separator extends Component {
|
||||
view() {
|
||||
export default class Separator extends Component {
|
||||
static isListItem = true;
|
||||
|
||||
view(): Mithril.Children {
|
||||
return <li className="Dropdown-separator" />;
|
||||
}
|
||||
}
|
||||
|
||||
Separator.isListItem = true;
|
||||
|
||||
export default Separator;
|
@@ -14,6 +14,9 @@ export default class SplitDropdown extends Dropdown {
|
||||
attrs.menuClassName += ' Dropdown-menu--right';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getButton(children) {
|
||||
// Make a copy of the attrs of the first child component. We will assign
|
||||
// these attrs to a new button, so that it has exactly the same behaviour as
|
||||
|
@@ -38,6 +38,9 @@ export default class TextEditor extends Component {
|
||||
this.disabled = !!this.attrs.disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<div className="TextEditor">
|
||||
|
@@ -12,6 +12,9 @@ import Tooltip from './Tooltip';
|
||||
* - `title` - Tooltip for the button
|
||||
*/
|
||||
export default class TextEditorButton extends Button {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
const originalView = super.view(vnode);
|
||||
|
||||
|
@@ -13,7 +13,7 @@ export interface AlertState {
|
||||
}
|
||||
|
||||
export default class AlertManagerState {
|
||||
protected activeAlerts: { [id: number]: AlertState } = {};
|
||||
protected activeAlerts: { [id: AlertIdentifier]: AlertState } = {};
|
||||
protected alertId = 0;
|
||||
|
||||
getActiveAlerts() {
|
||||
|
@@ -36,6 +36,9 @@ export default class AvatarEditor extends Component {
|
||||
this.isDraggedOver = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const user = this.attrs.user;
|
||||
|
||||
|
@@ -41,6 +41,9 @@ export default class ChangeEmailModal extends Modal {
|
||||
return app.translator.trans('core.forum.change_email.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
if (this.success) {
|
||||
return (
|
||||
|
@@ -15,6 +15,9 @@ export default class ChangePasswordModal extends Modal {
|
||||
return app.translator.trans('core.forum.change_password.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
|
@@ -33,6 +33,9 @@ export default class Composer extends Component {
|
||||
this.prevPosition = this.state.position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const body = this.state.body;
|
||||
const classes = {
|
||||
|
@@ -47,6 +47,9 @@ export default class ComposerBody extends Component {
|
||||
this.composer.fields.content(this.attrs.originalContent || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<ConfirmDocumentUnload when={this.hasChanges.bind(this)}>
|
||||
|
@@ -20,6 +20,9 @@ export default class ComposerPostPreview extends Component {
|
||||
attrs.surround = attrs.surround || ((preview) => preview());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return <div className={this.attrs.className} />;
|
||||
}
|
||||
|
@@ -10,6 +10,9 @@ import listItems from '../../common/helpers/listItems';
|
||||
* - `discussion`
|
||||
*/
|
||||
export default class DiscussionHero extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<header className="Hero DiscussionHero">
|
||||
|
@@ -13,6 +13,9 @@ import Placeholder from '../../common/components/Placeholder';
|
||||
* - `state` A DiscussionListState object that represents the discussion lists's state.
|
||||
*/
|
||||
export default class DiscussionList extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
/**
|
||||
* @type {import('../states/DiscussionListState').default}
|
||||
|
@@ -62,7 +62,7 @@ export default class DiscussionListItem<CustomAttrs extends IDiscussionListItemA
|
||||
};
|
||||
}
|
||||
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
const discussion = this.attrs.discussion;
|
||||
const user = discussion.user();
|
||||
const isUnread = discussion.isUnread();
|
||||
@@ -164,10 +164,8 @@ export default class DiscussionListItem<CustomAttrs extends IDiscussionListItemA
|
||||
/**
|
||||
* Determine whether or not the number of replies should be shown instead of
|
||||
* the number of unread posts.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
showRepliesCount() {
|
||||
showRepliesCount(): boolean {
|
||||
return this.attrs.params.sort === 'replies';
|
||||
}
|
||||
|
||||
@@ -210,7 +208,7 @@ export default class DiscussionListItem<CustomAttrs extends IDiscussionListItemA
|
||||
return items;
|
||||
}
|
||||
|
||||
replyCountItem() {
|
||||
replyCountItem(): Mithril.Children {
|
||||
const discussion = this.attrs.discussion;
|
||||
const showUnread = !this.showRepliesCount() && discussion.isUnread();
|
||||
|
||||
|
@@ -17,6 +17,9 @@ const hotEdge = (e) => {
|
||||
* - `state` A DiscussionListState object that represents the discussion lists's state.
|
||||
*/
|
||||
export default class DiscussionListPane extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
if (!this.attrs.state.hasItems()) {
|
||||
return;
|
||||
|
@@ -79,7 +79,7 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
|
||||
}
|
||||
}
|
||||
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
return (
|
||||
<div className="DiscussionPage">
|
||||
<DiscussionListPane state={app.discussions} />
|
||||
|
@@ -15,6 +15,9 @@ export default class DiscussionRenamedPost extends EventPost {
|
||||
return 'fas fa-pencil-alt';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
description(data) {
|
||||
const renamed = app.translator.trans('core.forum.post_stream.discussion_renamed_text', data);
|
||||
const oldName = app.translator.trans('core.forum.post_stream.discussion_renamed_old_tooltip', data);
|
||||
@@ -22,6 +25,9 @@ export default class DiscussionRenamedPost extends EventPost {
|
||||
return <span title={extractText(oldName)}>{renamed}</span>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Record<string, unknown>}
|
||||
*/
|
||||
descriptionData() {
|
||||
const post = this.attrs.post;
|
||||
const oldTitle = post.content()[0];
|
||||
|
@@ -24,6 +24,9 @@ export default class DiscussionsUserPage extends UserPage {
|
||||
this.state.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return <div className="DiscussionsUserPage">{DiscussionList.component({ state: this.state })}</div>;
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ export default class ForgotPasswordModal<CustomAttrs extends IForgotPasswordModa
|
||||
return app.translator.trans('core.forum.forgot_password.title');
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
if (this.success) {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
|
@@ -7,6 +7,9 @@ import listItems from '../../common/helpers/listItems';
|
||||
* default skin, these are shown just to the right of the forum title.
|
||||
*/
|
||||
export default class HeaderPrimary extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return <ul className="Header-controls">{listItems(this.items().toArray())}</ul>;
|
||||
}
|
||||
|
@@ -16,6 +16,9 @@ import Search from '../components/Search';
|
||||
* right side of the header.
|
||||
*/
|
||||
export default class HeaderSecondary extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return <ul className="Header-controls">{listItems(this.items().toArray())}</ul>;
|
||||
}
|
||||
|
@@ -45,6 +45,9 @@ export default class IndexPage extends Page {
|
||||
this.scrollTopOnCreate = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<div className="IndexPage">
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import type Mithril from 'mithril';
|
||||
import Component from '../../common/Component';
|
||||
import avatar from '../../common/helpers/avatar';
|
||||
|
||||
@@ -6,7 +7,7 @@ import avatar from '../../common/helpers/avatar';
|
||||
* indicating that the post is loading.
|
||||
*/
|
||||
export default class LoadingPost extends Component {
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
return (
|
||||
<div className="Post CommentPost LoadingPost">
|
||||
<header className="Post-header">
|
@@ -1,3 +1,4 @@
|
||||
import type Mithril from 'mithril';
|
||||
import Component from '../../common/Component';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
|
||||
@@ -5,16 +6,14 @@ import ItemList from '../../common/utils/ItemList';
|
||||
* The `LogInButtons` component displays a collection of social login buttons.
|
||||
*/
|
||||
export default class LogInButtons extends Component {
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
return <div className="LogInButtons">{this.items().toArray()}</div>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of LogInButton components.
|
||||
*
|
||||
* @return {ItemList<import('mithril').Children>}
|
||||
*/
|
||||
items() {
|
||||
return new ItemList();
|
||||
return new ItemList<Mithril.Children>();
|
||||
}
|
||||
}
|
@@ -42,20 +42,20 @@ export default class LogInModal<CustomAttrs extends ILoginModalAttrs = ILoginMod
|
||||
return 'LogInModal Modal--small';
|
||||
}
|
||||
|
||||
title() {
|
||||
title(): Mithril.Children {
|
||||
return app.translator.trans('core.forum.log_in.title');
|
||||
}
|
||||
|
||||
content() {
|
||||
content(): Mithril.Children {
|
||||
return [<div className="Modal-body">{this.body()}</div>, <div className="Modal-footer">{this.footer()}</div>];
|
||||
}
|
||||
|
||||
body() {
|
||||
body(): Mithril.Children {
|
||||
return [<LogInButtons />, <div className="Form Form--centered">{this.fields().toArray()}</div>];
|
||||
}
|
||||
|
||||
fields() {
|
||||
const items = new ItemList();
|
||||
const items = new ItemList<Mithril.Children>();
|
||||
|
||||
const identificationLabel = extractText(app.translator.trans('core.forum.log_in.username_or_email_placeholder'));
|
||||
const passwordLabel = extractText(app.translator.trans('core.forum.log_in.password_placeholder'));
|
||||
@@ -124,7 +124,7 @@ export default class LogInModal<CustomAttrs extends ILoginModalAttrs = ILoginMod
|
||||
return items;
|
||||
}
|
||||
|
||||
footer() {
|
||||
footer(): Mithril.Children {
|
||||
return [
|
||||
<p className="LogInModal-forgotPassword">
|
||||
<a onclick={this.forgotPassword.bind(this)}>{app.translator.trans('core.forum.log_in.forgot_password_link')}</a>
|
||||
|
@@ -18,7 +18,7 @@ export interface INotificationAttrs extends ComponentAttrs {
|
||||
* Subclasses should implement the `icon`, `href`, and `content` methods.
|
||||
*/
|
||||
export default abstract class Notification<CustomAttrs extends INotificationAttrs = INotificationAttrs> extends Component<CustomAttrs> {
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children {
|
||||
const notification = this.attrs.notification;
|
||||
const href = this.href();
|
||||
|
||||
|
@@ -38,6 +38,9 @@ export default class NotificationGrid extends Component {
|
||||
this.types = this.notificationTypes().toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const preferences = this.attrs.user.preferences();
|
||||
|
||||
|
@@ -12,6 +12,9 @@ import ItemList from '../../common/utils/ItemList';
|
||||
* notifications, grouped by discussion.
|
||||
*/
|
||||
export default class NotificationList extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const state = this.attrs.state;
|
||||
|
||||
|
@@ -18,6 +18,9 @@ export default class NotificationsDropdown extends Dropdown {
|
||||
super.initAttrs(attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getButton() {
|
||||
const newNotifications = this.getNewCount();
|
||||
const vdom = super.getButton();
|
||||
@@ -30,6 +33,9 @@ export default class NotificationsDropdown extends Dropdown {
|
||||
return vdom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getButtonContent() {
|
||||
const unread = this.getUnreadCount();
|
||||
|
||||
@@ -40,6 +46,9 @@ export default class NotificationsDropdown extends Dropdown {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getMenu() {
|
||||
return (
|
||||
<div className={classList('Dropdown-menu', this.attrs.menuClassName)} onclick={this.menuClick.bind(this)}>
|
||||
|
@@ -17,6 +17,9 @@ export default class NotificationsPage extends Page {
|
||||
this.bodyClass = 'App--notifications';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
return (
|
||||
<div className="NotificationsPage">
|
||||
|
@@ -45,7 +45,7 @@ export default abstract class Post<CustomAttrs extends IPostAttrs = IPostAttrs>
|
||||
);
|
||||
}
|
||||
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||
view(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children {
|
||||
const attrs = this.elementAttrs();
|
||||
|
||||
attrs.className = this.classes(attrs.className as string | undefined).join(' ');
|
||||
|
@@ -16,6 +16,9 @@ export default class PostEdited extends Component {
|
||||
super.oninit(vnode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const post = this.attrs.post;
|
||||
const editedUser = post.editedUser();
|
||||
|
@@ -13,6 +13,9 @@ import fullTime from '../../common/helpers/fullTime';
|
||||
* - `post`
|
||||
*/
|
||||
export default class PostMeta extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const post = this.attrs.post;
|
||||
const time = post.createdAt();
|
||||
|
@@ -14,6 +14,9 @@ import highlight from '../../common/helpers/highlight';
|
||||
* - `post`
|
||||
*/
|
||||
export default class PostPreview extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const post = this.attrs.post;
|
||||
const user = post.user();
|
||||
|
@@ -26,6 +26,9 @@ export default class PostStream extends Component {
|
||||
this.scrollListener = new ScrollListener(this.onscroll.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
let lastTime;
|
||||
|
||||
|
@@ -23,6 +23,9 @@ export default class PostStreamScrubber extends Component {
|
||||
this.scrollListener = new ScrollListener(this.updateScrubberValues.bind(this, { fromScroll: true, forceHeightChange: true }));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const count = this.stream.count();
|
||||
|
||||
|
@@ -15,6 +15,9 @@ import listItems from '../../common/helpers/listItems';
|
||||
* - `post`
|
||||
*/
|
||||
export default class PostUser extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
const post = this.attrs.post;
|
||||
const user = post.user();
|
||||
|
@@ -45,6 +45,9 @@ export default class PostsUserPage extends UserPage {
|
||||
this.loadUser(m.route.param('username'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
if (this.posts.length === 0 && !this.loading) {
|
||||
return (
|
||||
|
@@ -19,10 +19,16 @@ export default class RenameDiscussionModal extends Modal {
|
||||
return 'RenameDiscussionModal Modal--small';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
title() {
|
||||
return app.translator.trans('core.forum.rename_discussion.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
content() {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
|
@@ -15,6 +15,9 @@ import listItems from '../../common/helpers/listItems';
|
||||
* - `discussion`
|
||||
*/
|
||||
export default class ReplyPlaceholder extends Component {
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view() {
|
||||
if (app.composer.composingReplyTo(this.attrs.discussion)) {
|
||||
return (
|
||||
|
@@ -117,7 +117,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
|
||||
this.searchState = this.attrs.state;
|
||||
}
|
||||
|
||||
view() {
|
||||
view(): Mithril.Children {
|
||||
const currentSearch = this.searchState.getInitialSearch();
|
||||
|
||||
// Initialize search sources in the view rather than the constructor so
|
||||
|
@@ -22,10 +22,16 @@ export default class SessionDropdown extends Dropdown {
|
||||
attrs.accessibleToggleLabel = app.translator.trans('core.forum.header.session_dropdown_accessible_label');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
view(vnode) {
|
||||
return super.view({ ...vnode, children: this.items().toArray() });
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import('mithril').Children}
|
||||
*/
|
||||
getButtonContent() {
|
||||
const user = app.session.user;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user