1
0
mirror of https://github.com/flarum/core.git synced 2025-08-13 20:04:24 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Alexander Skvortsov
766e3390d7 Apply fixes from StyleCI
[ci skip] [skip ci]
2021-09-17 18:10:26 +00:00
Alexander Skvortsov
5ebc101fd5 Add config.php option not to boot extensions
Part of https://github.com/flarum/core/issues/2911

If the `boot_extensions` key is set to false, core will not boot any extensions in the backend, or run any initializers in the frontend. This allows admins to recover their forum without SSH access by disabling extension boot, going to the admin panel, and turning off offending extensions.

**Questions/Concerns for Reviewers**:

- Should we somehow signal to admins that this mode is enabled, possibly via alert? Otherwise, it might be confusing why extensions are indicated as enabled in the admin dashboard. This is challenging, as the alerts we currently have are in `content.blade.php`, and that view does not have access to payload/config.
- Should this require maintenance mode? If we disable all extensions (e.g. tags), some restricted discussions / content will immediately become public. This could lead to leaks via web scraping.
2021-09-17 14:10:06 -04:00
331 changed files with 15770 additions and 11683 deletions

View File

@@ -18,67 +18,21 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
cache: "npm"
cache-dependency-path: js/package-lock.json
- name: Install JS dependencies
run: yarn install --immutable
run: npm ci
working-directory: ./js
- name: Check JS formatting
run: yarn run format-check
working-directory: ./js
typecheck:
name: Typecheck
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
- name: Install JS dependencies
run: yarn --frozen-lockfile
working-directory: ./js
- name: Typecheck
run: yarn run check-typings || true # REMOVE THIS ONCE TYPE SAFETY REACHED
working-directory: ./js
type-coverage:
name: Type Coverage
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
- name: Install JS dependencies
run: yarn --frozen-lockfile
working-directory: ./js
- name: Check type coverage
run: yarn run check-typings-coverage
run: npm run format-check
working-directory: ./js
build-prod:
name: Build and commit
runs-on: ubuntu-latest
needs: [prettier, typecheck, type-coverage]
needs: [prettier]
# Only commit JS on push to master branch
# Remember to change in `build-test` job too
@@ -92,8 +46,8 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
cache: "npm"
cache-dependency-path: js/package-lock.json
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
@@ -102,13 +56,13 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: yarn
package_manager: npm
typings_script: build-typings
build-test:
name: Test build
runs-on: ubuntu-latest
needs: [prettier, typecheck, type-coverage]
needs: [prettier]
# Inverse check of `build-prod`
# Remember to change in `build-prod` job too
@@ -122,8 +76,8 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
cache: "npm"
cache-dependency-path: js/package-lock.json
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
@@ -132,6 +86,6 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: yarn
package_manager: npm
typings_script: build-typings
do_not_commit: true

View File

@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
php: [7.3, 7.4, '8.0', '8.1']
php: [7.3, 7.4, '8.0']
service: ['mysql:5.7', mariadb]
prefix: ['', flarum_]

2
.gitignore vendored
View File

@@ -1,6 +1,7 @@
/vendor
composer.lock
composer.phar
node_modules
.DS_Store
Thumbs.db
tests/.phpunit.result.cache
@@ -8,4 +9,3 @@ tests/.phpunit.result.cache
.vagrant
.idea/*
.vscode
js/coverage-ts

View File

@@ -1,60 +1,5 @@
# Changelog
## [1.1.0](https://github.com/flarum/core/compare/v1.0.4...v1.1.0)
### Added
- Info command now displays MySQL version, queue driver, mail driver (https://github.com/flarum/core/pull/2991)
- Use organization Prettier config (https://github.com/flarum/core/pull/2967)
- Support for global typings in extensions (https://github.com/flarum/core/pull/2992)
- Typings for class component state attribute (https://github.com/flarum/core/pull/2995)
- Custom colorising with CSS custom properties (https://github.com/flarum/core/pull/3001)
- Theme Extender to allow overriding LESS files (https://github.com/flarum/core/pull/3008)
- Update lastSeenAt when authenticating via API (https://github.com/flarum/core/pull/3058)
- NoJs Admin View (https://github.com/flarum/core/pull/3059)
- Preload FontAwesome, JS and CSS, and add `preload` extender (https://github.com/flarum/core/pull/3057)
### Changed
- Move Day.js plugin types import to global typings (https://github.com/flarum/core/pull/2954)
- Avoid resolving excluded middleware on each middleware items
- Allow extra attrs provided to `<Select>` to be passed through to the DOM element (https://github.com/flarum/core/pull/2959)
- Limit height of code blocks (https://github.com/flarum/core/pull/3012)
- Update normalize.css from v3.0.2 to v8.0.1 (https://github.com/flarum/core/pull/3015)
- Permission Grid: stick the headers to handle a lot of tags (https://github.com/flarum/core/pull/2887)
- Use `ItemList` for `DiscussionPage` content (https://github.com/flarum/core/pull/3004)
- Move email confirmation to POST request (https://github.com/flarum/core/pull/3038)
- Minor CSS code cleanup (https://github.com/flarum/core/pull/3026)
- Replace username with display name in more places (https://github.com/flarum/core/pull/3040)
- Rewrite Button to Typescript (https://github.com/flarum/core/pull/2984)
- Rewrite AdminPage abstract component into Typescript (https://github.com/flarum/core/pull/2996)
- Allow adding page parameters to PaginatedListState (https://github.com/flarum/core/pull/2935)
- Pass filter params to getApiDocument (https://github.com/flarum/core/pull/3037)
- Use author filter instead of gambit to get a user's discussions (https://github.com/flarum/core/pull/3068)
- [A11Y] Accessibility improvements for the Search component (https://github.com/flarum/core/pull/3017)
- Add determinsm to extension order resolution (https://github.com/flarum/core/pull/3076)
- Add cache control headers to the admin area (https://github.com/flarum/core/pull/3097)
### Fixed
- HLJS 11 new styles resulting in double padding (https://github.com/flarum/core/pull/2909)
- Internal API client attempting to load an uninstantiated session
- Empty post footer taking visual space (https://github.com/flarum/core/pull/2926)
- Unrecognized component class custom attribute typings (https://github.com/flarum/core/pull/2962)
- User edit groups permission not visually depending on view hidden groups permission (https://github.com/flarum/core/pull/2880)
- Event post excerpt preview triggers error (https://github.com/flarum/core/pull/2964)
- Missing settings defaults for display name driver and User slug driver (https://github.com/flarum/core/pull/2971)
- [A11Y] Icons not hidden from screenreaders (https://github.com/flarum/core/pull/3027)
- [A11Y] Checkboxes not focusable (https://github.com/flarum/core/pull/3014)
- Uploading ICO favicons resulting in server errors (https://github.com/flarum/core/pull/2949)
- Missing proper validation for large avatar upload payload (https://github.com/flarum/core/pull/3042)
- [A11Y] Missing focus rings in control elements (https://github.com/flarum/core/pull/3016)
- Unsanitised integer query parameters (https://github.com/flarum/core/pull/3064)
###### Code Contributors
@lhsazevedo, @Ornanovitch, @pierres, @the-turk, @iPurpl3x
###### Issue Reporters
@uamv, @dannyuk1982, @BurnNoticeSpy, @haarp, @peopleinside, @matteocontrini
## [1.0.4](https://github.com/flarum/core/compare/v1.0.3...v1.0.4)
### Fixed

9
js/.gitignore vendored
View File

@@ -1,9 +0,0 @@
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
node_modules

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
yarnPath: .yarn/releases/yarn-3.1.0.cjs
nodeLinker: node-modules

View File

@@ -1,28 +1,3 @@
declare type Writable<T> = { -readonly [P in keyof T]: T[P] };
declare type DeepWritable<T> = { -readonly [P in keyof T]: DeepWritable<T[P]> };
declare type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> };
/**
* UTILITY TYPES
*/
/**
* Type that returns an array of all keys of a provided object that are of
* of the provided type, or a subtype of the type.
*/
declare type KeysOfType<Type extends object, Match> = {
[Key in keyof Type]-?: Type[Key] extends Match ? Key : never;
};
/**
* Type that matches one of the keys of an object that is of the provided
* type, or a subtype of it.
*/
declare type KeyOfType<Type extends object, Match> = KeysOfType<Type, Match>[keyof Type];
declare type VnodeElementTag<Attrs = Record<string, unknown>, State = Record<string, unknown>> = string | ComponentTypes<Attrs, State>;
/**
* @deprecated Please import `app` from a namespace instead of using it as a global variable.
*
@@ -105,10 +80,3 @@ interface JSX {
attrs: Record<string, unknown>;
};
}
interface Event {
/**
* Whether this event should trigger a Mithril redraw.
*/
redraw: boolean;
}

View File

@@ -1,30 +1,3 @@
import Application from '../common/Application';
import ExtensionData from './utils/ExtensionData';
export declare type Extension = {
id: string;
version: string;
description?: string;
icon?: {
name: string;
};
links: {
authors?: {
name?: string;
link?: string;
}[];
discuss?: string;
documentation?: string;
support?: string;
website?: string;
donate?: string;
source?: string;
};
extra: {
'flarum-extension': {
title: string;
};
};
};
export default class AdminApplication extends Application {
extensionData: ExtensionData;
extensionCategories: {
@@ -38,24 +11,7 @@ export default class AdminApplication extends Application {
backUrl: () => any;
back: () => void;
};
/**
* Settings are serialized to the admin dashboard as strings.
* Additional encoding/decoding is possible, but must take
* place on the client side.
*
* @inheritdoc
*/
data: Application['data'] & {
extensions: Record<string, Extension>;
settings: Record<string, string>;
modelStatistics: Record<string, {
total: number;
}>;
};
constructor();
/**
* @inheritdoc
*/
mount(): void;
getRequiredPermissions(permission: string): string[];
getRequiredPermissions(permission: any): string[];
}
import Application from "../common/Application";
import ExtensionData from "./utils/ExtensionData";

View File

@@ -1,5 +1,5 @@
declare var _default: {
extend: any;
extend: typeof import("../common/extend");
Session: typeof import("../common/Session").default;
Store: typeof import("../common/Store").default;
'utils/BasicEditorDriver': typeof import("../common/utils/BasicEditorDriver").default;
@@ -32,15 +32,17 @@ declare var _default: {
'utils/subclassOf': typeof import("../common/utils/subclassOf").default;
'utils/setRouteWithForcedRefresh': typeof import("../common/utils/setRouteWithForcedRefresh").default;
'utils/patchMithril': typeof import("../common/utils/patchMithril").default;
'utils/proxifyCompat': typeof import("../common/utils/proxifyCompat").default;
'utils/proxifyCompat': (compat: {
[key: string]: any;
}, namespace: string) => {
[key: string]: any;
};
'utils/classList': (...classes: import("clsx").ClassValue[]) => string;
'utils/extractText': typeof import("../common/utils/extractText").default;
'utils/formatNumber': typeof import("../common/utils/formatNumber").default;
'utils/mapRoutes': typeof import("../common/utils/mapRoutes").default;
'utils/withAttr': (key: string, cb: Function) => (this: Element) => void;
'utils/throttleDebounce': typeof import("../common/utils/throttleDebounce");
'utils/isObject': typeof import("../common/utils/isObject").default;
'utils/focusTrap': typeof import("../common/utils/focusTrap");
'models/Notification': typeof import("../common/models/Notification").default;
'models/User': typeof import("../common/models/User").default;
'models/Post': typeof import("../common/models/Post").default;
@@ -67,7 +69,6 @@ declare var _default: {
'components/Link': typeof import("../common/components/Link").default;
'components/LinkButton': typeof import("../common/components/LinkButton").default;
'components/Checkbox': typeof import("../common/components/Checkbox").default;
'components/ColorPreviewInput': typeof import("../common/components/ColorPreviewInput").default;
'components/SelectDropdown': typeof import("../common/components/SelectDropdown").default;
'components/ModalManager': typeof import("../common/components/ModalManager").default;
'components/Button': typeof import("../common/components/Button").default;

View File

@@ -7,8 +7,8 @@ export default class AdminNav extends Component<import("../../common/Component")
*
* @return {ItemList}
*/
items(): ItemList<any>;
extensionItems(): ItemList<any>;
items(): ItemList;
extensionItems(): ItemList;
}
import Component from "../../common/Component";
import Stream from "../../common/utils/Stream";

View File

@@ -1,167 +0,0 @@
import type Mithril from 'mithril';
import Page, { IPageAttrs } from '../../common/components/Page';
import Stream from '../../common/utils/Stream';
export interface AdminHeaderOptions {
title: string;
description: string;
icon: string;
/**
* Will be used as the class for the AdminPage.
*
* Will also be appended with `-header` and set as the class for the `AdminHeader` component.
*/
className: string;
}
/**
* A type that matches any valid value for the `type` attribute on an HTML `<input>` element.
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-type
*
* Note: this will be exported from a different location in the future.
*
* @see https://github.com/flarum/core/issues/3039
*/
export declare type HTMLInputTypes = 'button' | 'checkbox' | 'color' | 'date' | 'datetime-local' | 'email' | 'file' | 'hidden' | 'image' | 'month' | 'number' | 'password' | 'radio' | 'range' | 'reset' | 'search' | 'submit' | 'tel' | 'text' | 'time' | 'url' | 'week';
interface CommonSettingsItemOptions extends Mithril.Attributes {
setting: string;
label: Mithril.Children;
help?: Mithril.Children;
className?: string;
}
/**
* Valid options for the setting component builder to generate an HTML input element.
*/
export interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOptions {
/**
* Any valid HTML input `type` value.
*/
type: HTMLInputTypes;
}
declare const BooleanSettingTypes: readonly ["bool", "checkbox", "switch", "boolean"];
declare const SelectSettingTypes: readonly ["select", "dropdown", "selectdropdown"];
declare const TextareaSettingTypes: readonly ["textarea"];
declare const ColorPreviewSettingType = "color-preview";
/**
* Valid options for the setting component builder to generate a Switch.
*/
export interface SwitchSettingComponentOptions extends CommonSettingsItemOptions {
type: typeof BooleanSettingTypes[number];
}
/**
* Valid options for the setting component builder to generate a Select dropdown.
*/
export interface SelectSettingComponentOptions extends CommonSettingsItemOptions {
type: typeof SelectSettingTypes[number];
/**
* Map of values to their labels
*/
options: {
[value: string]: Mithril.Children;
};
default: string;
}
/**
* Valid options for the setting component builder to generate a Textarea.
*/
export interface TextareaSettingComponentOptions extends CommonSettingsItemOptions {
type: typeof TextareaSettingTypes[number];
}
/**
* Valid options for the setting component builder to generate a ColorPreviewInput.
*/
export interface ColorPreviewSettingComponentOptions extends CommonSettingsItemOptions {
type: typeof ColorPreviewSettingType;
}
/**
* All valid options for the setting component builder.
*/
export declare type SettingsComponentOptions = HTMLInputSettingsComponentOptions | SwitchSettingComponentOptions | SelectSettingComponentOptions | TextareaSettingComponentOptions | ColorPreviewSettingComponentOptions;
/**
* Valid attrs that can be returned by the `headerInfo` function
*/
export declare type AdminHeaderAttrs = AdminHeaderOptions & Partial<Omit<Mithril.Attributes, 'class'>>;
export default abstract class AdminPage<CustomAttrs extends IPageAttrs = IPageAttrs> extends Page<CustomAttrs> {
settings: Record<string, Stream<string>>;
loading: boolean;
view(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children;
/**
* Returns the content of the AdminPage.
*/
abstract content(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children;
/**
* Returns the submit button for this AdminPage.
*
* Calls `this.saveSettings` when the button is clicked.
*/
submitButton(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children;
/**
* Returns the Header component for this AdminPage.
*/
header(vnode: Mithril.Vnode<CustomAttrs, this>): Mithril.Children;
/**
* Returns the options passed to the AdminHeader component.
*/
headerInfo(): AdminHeaderAttrs;
/**
* `buildSettingComponent` takes a settings object and turns it into a component.
* Depending on the type of input, you can set the type to 'bool', 'select', or
* any standard <input> type. Any values inside the 'extra' object will be added
* to the component as an attribute.
*
* Alternatively, you can pass a callback that will be executed in ExtensionPage's
* context to include custom JSX elements.
*
* @example
*
* {
* setting: 'acme.checkbox',
* label: app.translator.trans('acme.admin.setting_label'),
* type: 'bool',
* help: app.translator.trans('acme.admin.setting_help'),
* className: 'Setting-item'
* }
*
* @example
*
* {
* setting: 'acme.select',
* label: app.translator.trans('acme.admin.setting_label'),
* type: 'select',
* options: {
* 'option1': 'Option 1 label',
* 'option2': 'Option 2 label',
* },
* default: 'option1',
* }
*
* @example
*
* () => {
* return <p>My cool component</p>;
* }
*/
buildSettingComponent(entry: ((this: this) => Mithril.Children) | SettingsComponentOptions): Mithril.Children;
/**
* Called when `saveSettings` completes successfully.
*/
onsaved(): void;
/**
* Returns a function that fetches the setting from the `app` global.
*/
setting(key: string, fallback?: string): Stream<string>;
/**
* Returns a map of settings keys to values which includes only those which have been modified but not yet saved.
*/
dirty(): Record<string, string>;
/**
* Returns the number of settings that have been modified.
*/
isChanged(): number;
/**
* Saves the modified settings to the database.
*/
saveSettings(e: SubmitEvent & {
redraw: boolean;
}): Promise<void>;
}
export {};

View File

@@ -1,6 +1,4 @@
export default class AppearancePage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
colorItems(): ItemList<any>;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -10,7 +10,7 @@ export default class BasicsPage extends AdminPage<import("../../common/component
* @return {ItemList}
* @public
*/
public homePageItems(): ItemList<any>;
public homePageItems(): ItemList;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,6 +1,6 @@
export default class DashboardPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
availableWidgets(): ItemList<any>;
availableWidgets(): ItemList;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -2,15 +2,14 @@
* The `EditGroupModal` component shows a modal dialog which allows the user
* to create or edit a group.
*/
export default class EditGroupModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class EditGroupModal extends Modal {
group: any;
nameSingular: Stream<any> | undefined;
namePlural: Stream<any> | undefined;
icon: Stream<any> | undefined;
color: Stream<any> | undefined;
isHidden: Stream<any> | undefined;
fields(): ItemList<any>;
fields(): ItemList;
submitData(): {
nameSingular: any;
namePlural: any;

View File

@@ -1,5 +1,5 @@
export default class ExtensionLinkButton extends LinkButton {
statusItems(name: any): ItemList<any>;
statusItems(name: any): ItemList;
}
import LinkButton from "../../common/components/LinkButton";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,15 +1,7 @@
import ItemList from '../../common/utils/ItemList';
import AdminPage from './AdminPage';
import RequestError from '../../common/utils/RequestError';
import { Extension } from '../AdminApplication';
import { IPageAttrs } from '../../common/components/Page';
import type Mithril from 'mithril';
export interface ExtensionPageAttrs extends IPageAttrs {
id: string;
}
export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs> extends AdminPage<Attrs> {
extension: Extension;
changingState: boolean;
export default class ExtensionPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
extension: any;
changingState: boolean | undefined;
infoFields: {
discuss: string;
documentation: string;
@@ -17,16 +9,14 @@ export default class ExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionP
website: string;
donate: string;
source: string;
};
oninit(vnode: Mithril.Vnode<Attrs, this>): void;
} | undefined;
className(): string;
view(vnode: Mithril.VnodeDOM<Attrs, this>): JSX.Element | null;
header(): JSX.Element[];
sections(vnode: Mithril.VnodeDOM<Attrs, this>): ItemList<unknown>;
content(vnode: Mithril.VnodeDOM<Attrs, this>): JSX.Element;
topItems(): ItemList<Mithril.Children>;
infoItems(): ItemList<Mithril.Children>;
sections(): ItemList;
topItems(): ItemList;
infoItems(): ItemList;
toggle(): void;
isEnabled(): any;
onerror(e: RequestError): void;
onerror(e: any): void;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,19 +1,4 @@
import PermissionGrid, { PermissionGridEntry } from './PermissionGrid';
import ItemList from '../../common/utils/ItemList';
import Mithril from 'mithril';
export interface IExtensionPermissionGridAttrs {
extensionId: string;
}
export default class ExtensionPermissionGrid<CustomAttrs extends IExtensionPermissionGridAttrs = IExtensionPermissionGridAttrs> extends PermissionGrid<CustomAttrs> {
protected extensionId: string;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
permissionItems(): ItemList<{
label: Mithril.Children;
children: PermissionGridEntry[];
}>;
viewItems(): ItemList<import("./PermissionGrid").PermissionConfig>;
startItems(): ItemList<import("./PermissionGrid").PermissionConfig>;
replyItems(): ItemList<import("./PermissionGrid").PermissionConfig>;
moderateItems(): ItemList<import("./PermissionGrid").PermissionConfig>;
scopeControlItems(): ItemList<unknown>;
export default class ExtensionPermissionGrid extends PermissionGrid {
extensionId: any;
}
import PermissionGrid from "./PermissionGrid";

View File

@@ -10,7 +10,7 @@ export default class HeaderPrimary extends Component<import("../../common/Compon
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -8,7 +8,7 @@ export default class HeaderSecondary extends Component<import("../../common/Comp
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,12 +1,3 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal from '../../common/components/Modal';
export default class LoadingModal<ModalAttrs = {}> extends Modal<ModalAttrs> {
/**
* @inheritdoc
*/
static readonly isDismissible: boolean;
className(): string;
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): string;
onsubmit(e: Event): void;
export default class LoadingModal extends Modal {
}
import Modal from "../../common/components/Modal";

View File

@@ -1,36 +1,12 @@
import Component, { ComponentAttrs } from '../../common/Component';
import ItemList from '../../common/utils/ItemList';
import type Mithril from 'mithril';
export interface PermissionConfig {
permission: string;
icon: string;
label: Mithril.Children;
allowGuest?: boolean;
}
export interface PermissionSetting {
setting: () => Mithril.Children;
icon: string;
label: Mithril.Children;
}
export declare type PermissionGridEntry = PermissionConfig | PermissionSetting;
export declare type PermissionType = 'view' | 'start' | 'reply' | 'moderate';
export interface ScopeItem {
label: Mithril.Children;
render: (permission: PermissionGridEntry) => Mithril.Children;
onremove?: () => void;
}
export interface IPermissionGridAttrs extends ComponentAttrs {
}
export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = IPermissionGridAttrs> extends Component<CustomAttrs> {
view(vnode: Mithril.Vnode<CustomAttrs, this>): JSX.Element;
permissionItems(): ItemList<{
label: Mithril.Children;
children: PermissionGridEntry[];
}>;
viewItems(): ItemList<PermissionGridEntry>;
startItems(): ItemList<PermissionGridEntry>;
replyItems(): ItemList<PermissionGridEntry>;
moderateItems(): ItemList<PermissionGridEntry>;
scopeItems(): ItemList<ScopeItem>;
scopeControlItems(): ItemList<unknown>;
export default class PermissionGrid extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
permissionItems(): ItemList;
viewItems(): ItemList;
startItems(): ItemList;
replyItems(): ItemList;
moderateItems(): ItemList;
scopeItems(): ItemList;
scopeControlItems(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,8 +0,0 @@
export default class ReadmeModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
name: any;
extName: any;
loadReadme(): Promise<void>;
readme: any;
}
import Modal from "../../common/components/Modal";

View File

@@ -8,7 +8,7 @@ export default class SessionDropdown extends Dropdown {
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Dropdown from "../../common/components/Dropdown";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,5 +1,4 @@
export default class SettingsModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class SettingsModal extends Modal {
settings: {} | undefined;
form(): string;
submitButton(): JSX.Element;

View File

@@ -1,5 +1,5 @@
export default class StatusWidget extends DashboardWidget {
items(): ItemList<any>;
items(): ItemList;
handleClearCache(e: any): void;
}
import DashboardWidget from "./DashboardWidget";

View File

@@ -1,18 +1,6 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference types="mithril" />
import type User from '../../common/models/User';
import ItemList from '../../common/utils/ItemList';
import AdminPage from './AdminPage';
declare type ColumnData = {
/**
* Column title
*/
name: String;
/**
* Component(s) to show for this column.
*/
content: (user: User) => JSX.Element;
};
/**
* Admin page which displays a paginated list of all users on the forum.
*/
@@ -62,12 +50,12 @@ export default class UserListPage extends AdminPage {
*
* See `UserListPage.tsx` for examples.
*/
columns(): ItemList<ColumnData>;
columns(): ItemList;
headerInfo(): {
className: string;
icon: string;
title: import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
description: import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
title: any;
description: any;
};
/**
* Asynchronously fetch the next set of users to be rendered.
@@ -82,4 +70,3 @@ export default class UserListPage extends AdminPage {
nextPage(): void;
previousPage(): void;
}
export {};

View File

@@ -1,3 +1,5 @@
import app from './app';
export { app };
export declare const compat: Record<string, unknown>;
export declare const compat: {
[key: string]: any;
};

View File

@@ -1,4 +0,0 @@
export default class ExtensionReadme extends Model {
content: any;
}
import Model from "../../common/Model";

View File

@@ -1,10 +1,9 @@
import DefaultResolver from '../../common/resolvers/DefaultResolver';
import ExtensionPage, { ExtensionPageAttrs } from '../components/ExtensionPage';
/**
* A custom route resolver for ExtensionPage that generates handles routes
* to default extension pages or a page provided by an extension.
*/
export default class ExtensionPageResolver<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs, RouteArgs extends Record<string, unknown> = {}> extends DefaultResolver<Attrs, ExtensionPage<Attrs>, RouteArgs> {
export default class ExtensionPageResolver extends DefaultResolver {
static extension: string | null;
onmatch(args: Attrs & RouteArgs, requestedPath: string, route: string): new () => ExtensionPage<Attrs>;
onmatch(args: any, requestedPath: any, route: any): any;
}

View File

@@ -1,5 +1,6 @@
import AdminApplication from './AdminApplication';
/**
* The `routes` initializer defines the forum app's routes.
*
* @param {App} app
*/
export default function (app: AdminApplication): void;
export default function _default(app: any): void;

View File

@@ -1,46 +1,17 @@
import type Mithril from 'mithril';
import ItemList from '../../common/utils/ItemList';
import { SettingsComponentOptions } from '../components/AdminPage';
import ExtensionPage, { ExtensionPageAttrs } from '../components/ExtensionPage';
import { PermissionConfig, PermissionType } from '../components/PermissionGrid';
declare type SettingConfigInput = SettingsComponentOptions | (() => Mithril.Children);
declare type SettingConfigInternal = SettingsComponentOptions | ((() => Mithril.Children) & {
setting: string;
});
export declare type CustomExtensionPage<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs> = new () => ExtensionPage<Attrs>;
declare type ExtensionConfig = {
settings?: ItemList<SettingConfigInternal>;
permissions?: {
view?: ItemList<PermissionConfig>;
start?: ItemList<PermissionConfig>;
reply?: ItemList<PermissionConfig>;
moderate?: ItemList<PermissionConfig>;
};
page?: CustomExtensionPage;
};
declare type InnerDataNoActiveExtension = {
currentExtension: null;
data: {
[key: string]: ExtensionConfig | undefined;
};
};
declare type InnerDataActiveExtension = {
currentExtension: string;
data: {
[key: string]: ExtensionConfig;
};
};
export default class ExtensionData {
protected state: InnerDataActiveExtension | InnerDataNoActiveExtension;
data: {};
currentExtension: any;
/**
* This function simply takes the extension id
*
* @example
* app.extensionData.for('flarum-tags')
* app.extensionData.load('flarum-tags')
*
* flarum/flags -> flarum-flags | acme/extension -> acme-extension
*
* @param extension
*/
for(extension: string): this;
for(extension: any): ExtensionData;
/**
* This function registers your settings with Flarum
*
@@ -53,8 +24,13 @@ export default class ExtensionData {
* type: 'text', // This will be inputted into the input tag for the setting (text/number/etc)
* label: app.translator.trans('flarum-flags.admin.settings.guidelines_url_label')
* }, 15) // priority is optional (ItemList)
*
*
* @param content
* @param priority
* @returns {ExtensionData}
*/
registerSetting(content: SettingConfigInput, priority?: number): this;
registerSetting(content: any, priority?: number): ExtensionData;
/**
* This function registers your permission with Flarum
*
@@ -65,32 +41,58 @@ export default class ExtensionData {
* label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),
* permission: 'discussion.viewFlags'
* }, 'moderate', 65)
*
* @param content
* @param permissionType
* @param priority
* @returns {ExtensionData}
*/
registerPermission(content: PermissionConfig, permissionType: PermissionType, priority?: number): this;
registerPermission(content: any, permissionType?: any, priority?: number): ExtensionData;
/**
* Replace the default extension page with a custom component.
* This component would typically extend ExtensionPage
*
* @param component
* @returns {ExtensionData}
*/
registerPage(component: CustomExtensionPage): this;
registerPage(component: any): ExtensionData;
/**
* Get an extension's registered settings
*
* @param extensionId
* @returns {boolean|*}
*/
getSettings(extensionId: string): SettingConfigInternal[] | undefined;
getSettings(extensionId: any): boolean | any;
/**
*
* Get an ItemList of all extensions' registered permissions
*
* @param extension
* @param type
* @returns {ItemList}
*/
getAllExtensionPermissions(type: PermissionType): ItemList<PermissionConfig>;
getAllExtensionPermissions(type: any): ItemList;
/**
* Get a singular extension's registered permissions
*
* @param extension
* @param type
* @returns {boolean|*}
*/
getExtensionPermissions(extension: string, type: PermissionType): ItemList<PermissionConfig>;
getExtensionPermissions(extension: any, type: any): boolean | any;
/**
* Checks whether a given extension has registered permissions.
*
* @param extension
* @returns {boolean}
*/
extensionHasPermissions(extension: string): boolean;
extensionHasPermissions(extension: any): boolean;
/**
* Returns an extension's custom page component if it exists.
*
* @param extension
* @returns {boolean|*}
*/
getPage<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs>(extension: string): CustomExtensionPage<Attrs> | undefined;
getPage(extension: any): boolean | any;
}
export {};
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,88 +1,3 @@
import ItemList from './utils/ItemList';
import Translator from './Translator';
import Store from './Store';
import Session from './Session';
import Drawer from './utils/Drawer';
import RequestError, { InternalFlarumRequestOptions } from './utils/RequestError';
import Forum from './models/Forum';
import PageState from './states/PageState';
import ModalManagerState from './states/ModalManagerState';
import AlertManagerState from './states/AlertManagerState';
import type DefaultResolver from './resolvers/DefaultResolver';
import type Mithril from 'mithril';
import type Component from './Component';
import type { ComponentAttrs } from './Component';
export declare type FlarumScreens = 'phone' | 'tablet' | 'desktop' | 'desktop-hd';
export declare type FlarumGenericRoute = RouteItem<any, any, any>;
export interface FlarumRequestOptions<ResponseType> extends Omit<Mithril.RequestOptions<ResponseType>, 'extract'> {
errorHandler?: (error: RequestError) => void;
url: string;
/**
* Manipulate the response text before it is parsed into JSON.
*
* @deprecated Please use `modifyText` instead.
*/
extract?: (responseText: string) => string;
/**
* Manipulate the response text before it is parsed into JSON.
*
* This overrides any `extract` method provided.
*/
modifyText?: (responseText: string) => string;
}
/**
* A valid route definition.
*/
export declare type RouteItem<Attrs extends ComponentAttrs, Comp extends Component<Attrs & {
routeName: string;
}>, RouteArgs extends Record<string, unknown> = {}> = {
/**
* The path for your route.
*
* This might be a specific URL path (e.g.,`/myPage`), or it might
* contain a variable used by a resolver (e.g., `/myPage/:id`).
*
* @see https://docs.flarum.org/extend/frontend-pages.html#route-resolvers-advanced
*/
path: `/${string}`;
} & ({
/**
* The component to render when this route matches.
*/
component: new () => Comp;
/**
* A custom resolver class.
*
* This should be the class itself, and **not** an instance of the
* class.
*/
resolverClass?: new (component: new () => Comp, routeName: string) => DefaultResolver<Attrs, Comp, RouteArgs>;
} | {
/**
* An instance of a route resolver.
*/
resolver: RouteResolver<Attrs, Comp, RouteArgs>;
});
export interface RouteResolver<Attrs extends ComponentAttrs, Comp extends Component<Attrs & {
routeName: string;
}>, RouteArgs extends Record<string, unknown> = {}> {
/**
* A method which selects which component to render based on
* conditional logic.
*
* Returns the component class, and **not** a Vnode or JSX
* expression.
*/
onmatch(this: this, args: RouteArgs, requestedPath: string, route: string): {
new (): Comp;
};
/**
* A function which renders the provided component.
*
* Returns a Mithril Vnode or other children.
*/
render(this: this, vnode: Mithril.Vnode<Attrs, Comp>): Mithril.Children;
}
/**
* The `App` class provides a container for an application, as well as various
* utilities for the rest of the app to use.
@@ -90,8 +5,11 @@ export interface RouteResolver<Attrs extends ComponentAttrs, Comp extends Compon
export default class Application {
/**
* The forum model for this application.
*
* @type {Forum}
* @public
*/
forum: Forum;
public forum: Forum;
/**
* A map of routes, keyed by a unique route name. Each route is an object
* containing the following properties:
@@ -100,42 +18,71 @@ export default class Application {
* - `component` The Mithril component to render when this route is active.
*
* @example
* app.routes.discussion = { path: '/d/:id', component: DiscussionPage };
* app.routes.discussion = {path: '/d/:id', component: DiscussionPage.component()};
*
* @type {Object}
* @public
*/
routes: Record<string, FlarumGenericRoute>;
public routes: Object;
/**
* An ordered list of initializers to bootstrap the application.
*
* @type {ItemList}
* @public
*/
initializers: ItemList<(app: this) => void>;
public initializers: ItemList;
/**
* The app's session.
*
* Stores info about the current user.
* @type {Session}
* @public
*/
session: Session;
public session: Session;
/**
* The app's translator.
*
* @type {Translator}
* @public
*/
translator: Translator;
public translator: Translator;
/**
* The app's data store.
*
* @type {Store}
* @public
*/
store: Store;
public store: Store;
/**
* A local cache that can be used to store data at the application level, so
* that is persists between different routes.
*
* @type {Object}
* @public
*/
cache: Record<string, unknown>;
public cache: Object;
/**
* Whether or not the app has been booted.
*
* @type {Boolean}
* @public
*/
booted: boolean;
public booted: boolean;
/**
* The key for an Alert that was shown as a result of an AJAX request error.
* If present, it will be dismissed on the next successful request.
*
* @type {int}
* @private
*/
private requestErrorAlert;
/**
* The page the app is currently on.
*
* This object holds information about the type of page we are currently
* visiting, and sometimes additional arbitrary page state that may be
* relevant to lower-level components.
*
* @type {PageState}
*/
current: PageState;
/**
@@ -144,83 +91,84 @@ export default class Application {
* Once the application navigates to another page, the object previously
* assigned to this.current will be moved to this.previous, while this.current
* is re-initialized.
*
* @type {PageState}
*/
previous: PageState;
/**
* An object that manages modal state.
*/
modal: ModalManagerState;
/**
* An object that manages the state of active alerts.
*
* @type {AlertManagerState}
*/
alerts: AlertManagerState;
/**
* An object that manages the state of the navigation drawer.
*/
drawer: Drawer;
data: {
apiDocument: Record<string, unknown> | null;
locale: string;
locales: Record<string, string>;
resources: Record<string, unknown>[];
session: {
userId: number;
csrfToken: string;
};
[key: string]: unknown;
};
private _title;
private _titleCount;
private set title(value);
get title(): string;
private set titleCount(value);
get titleCount(): number;
/**
* The key for an Alert that was shown as a result of an AJAX request error.
* If present, it will be dismissed on the next successful request.
*/
private requestErrorAlert;
initialRoute: string;
load(payload: Application['data']): void;
data: any;
title: string;
titleCount: number;
initialRoute: any;
load(payload: any): void;
boot(): void;
bootExtensions(extensions: Record<string, {
extend?: unknown[];
}>): void;
protected mount(basePath?: string): void;
bootExtensions(extensions: any): void;
mount(basePath?: string): void;
drawer: Drawer | undefined;
/**
* Get the API response document that has been preloaded into the application.
*
* @return {Object|null}
* @public
*/
preloadedApiDocument(): Record<string, unknown> | null;
public preloadedApiDocument(): Object | null;
/**
* Determine the current screen mode, based on our media queries.
*/
screen(): FlarumScreens;
/**
* Set the `<title>` of the page.
*
* @param title New page title
* @returns {String} - one of "phone", "tablet", "desktop" or "desktop-hd"
*/
setTitle(title: string): void;
screen(): string;
/**
* Set a number to display in the `<title>` of the page.
* Set the <title> of the page.
*
* @param count Number to display in title
* @param {String} title
* @public
*/
setTitleCount(count: number): void;
public setTitle(title: string): void;
/**
* Set a number to display in the <title> of the page.
*
* @param {Integer} count
*/
setTitleCount(count: any): void;
updateTitle(): void;
protected transformRequestOptions<ResponseType>(flarumOptions: FlarumRequestOptions<ResponseType>): InternalFlarumRequestOptions<ResponseType>;
/**
* Make an AJAX request, handling any low-level errors that may occur.
*
* @see https://mithril.js.org/request.html
*
* @param options
* @param {Object} options
* @return {Promise}
* @public
*/
public request(originalOptions: any): Promise<any>;
/**
* @param {RequestError} error
* @param {string[]} [formattedError]
* @private
*/
request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType | string>;
private showDebug;
/**
* Construct a URL to the route with the given name.
*
* @param {String} name
* @param {Object} params
* @return {String}
* @public
*/
route(name: string, params?: Record<string, unknown>): string;
public route(name: string, params?: Object): string;
}
import Forum from "./models/Forum";
import ItemList from "./utils/ItemList";
import Session from "./Session";
import Translator from "./Translator";
import Store from "./Store";
import PageState from "./states/PageState";
import ModalManagerState from "./states/ModalManagerState";
import AlertManagerState from "./states/AlertManagerState";
import Drawer from "./utils/Drawer";

View File

@@ -99,7 +99,7 @@ export default abstract class Component<Attrs extends ComponentAttrs = Component
*
* @see https://mithril.js.org/hyperscript.html#mselector,-attributes,-children
*/
static component<SAttrs extends ComponentAttrs = ComponentAttrs>(attrs?: SAttrs, children?: Mithril.Children): Mithril.Vnode;
static component(attrs?: {}, children?: null): Mithril.Vnode;
/**
* Saves a reference to the vnode attrs after running them through initAttrs,
* and checking for common issues.

View File

@@ -32,7 +32,7 @@ export default abstract class Fragment {
* @returns {jQuery} the jQuery object for the DOM node
* @final
*/
$(selector?: string): JQuery;
$(selector: any): JQuery<any>;
/**
* Get the renderable virtual DOM that represents the fragment's view.
*

View File

@@ -1,35 +1,37 @@
import User from './models/User';
import { FlarumRequestOptions } from './Application';
export declare type LoginParams = {
/**
* The username/email
*/
identification: string;
/**
* Password
*/
password: string;
};
/**
* The `Session` class defines the current user session. It stores a reference
* to the current authenticated user, and provides methods to log in/out.
*/
export default class Session {
constructor(user: any, csrfToken: any);
/**
* The current authenticated user.
*
* @type {User|null}
* @public
*/
user: User | null;
public user: any | null;
/**
* The CSRF token.
*
* @type {String|null}
* @public
*/
csrfToken: string;
constructor(user: User | null, csrfToken: string);
public csrfToken: string | null;
/**
* Attempt to log in a user.
*
* @param {String} identification The username/email.
* @param {String} password
* @param {Object} [options]
* @return {Promise}
* @public
*/
login(body: LoginParams, options?: Omit<FlarumRequestOptions<any>, 'url' | 'body' | 'method'>): Promise<any>;
public login(body: any, options?: Object | undefined): Promise<any>;
/**
* Log the user out.
*
* @public
*/
logout(): void;
public logout(): void;
}

View File

@@ -1,6 +1,3 @@
/// <reference path="../../src/common/translator-icu-rich.d.ts" />
import { RichMessageFormatter } from '@askvortsov/rich-icu-message-formatter';
import { pluralTypeHandler, selectTypeHandler } from '@ultraq/icu-message-formatter';
declare type Translations = Record<string, string>;
declare type TranslatorParameters = Record<string, unknown>;
export default class Translator {
@@ -11,15 +8,15 @@ export default class Translator {
/**
* The underlying ICU MessageFormatter util.
*/
protected formatter: RichMessageFormatter;
protected formatter: any;
setLocale(locale: string): void;
addTranslations(translations: Translations): void;
/**
* An extensible entrypoint for extenders to register type handlers for translations.
*/
protected formatterTypeHandlers(): {
plural: typeof pluralTypeHandler;
select: typeof selectTypeHandler;
plural: any;
select: any;
};
/**
* A temporary system to preprocess parameters.
@@ -29,6 +26,6 @@ export default class Translator {
* @internal
*/
protected preprocessParameters(parameters: TranslatorParameters): TranslatorParameters;
trans(id: string, parameters?: TranslatorParameters): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
trans(id: string, parameters?: TranslatorParameters): any;
}
export {};

View File

@@ -1,5 +1,5 @@
declare var _default: {
extend: any;
extend: typeof extend;
Session: typeof Session;
Store: typeof Store;
'utils/BasicEditorDriver': typeof BasicEditorDriver;
@@ -32,15 +32,17 @@ declare var _default: {
'utils/subclassOf': typeof subclassOf;
'utils/setRouteWithForcedRefresh': typeof setRouteWithForcedRefresh;
'utils/patchMithril': typeof patchMithril;
'utils/proxifyCompat': typeof proxifyCompat;
'utils/proxifyCompat': (compat: {
[key: string]: any;
}, namespace: string) => {
[key: string]: any;
};
'utils/classList': (...classes: import("clsx").ClassValue[]) => string;
'utils/extractText': typeof extractText;
'utils/formatNumber': typeof formatNumber;
'utils/mapRoutes': typeof mapRoutes;
'utils/withAttr': (key: string, cb: Function) => (this: Element) => void;
'utils/throttleDebounce': typeof ThrottleDebounce;
'utils/isObject': typeof isObject;
'utils/focusTrap': typeof FocusTrap;
'models/Notification': typeof Notification;
'models/User': typeof User;
'models/Post': typeof Post;
@@ -67,7 +69,6 @@ declare var _default: {
'components/Link': typeof Link;
'components/LinkButton': typeof LinkButton;
'components/Checkbox': typeof Checkbox;
'components/ColorPreviewInput': typeof ColorPreviewInput;
'components/SelectDropdown': typeof SelectDropdown;
'components/ModalManager': typeof ModalManager;
'components/Button': typeof Button;
@@ -92,6 +93,7 @@ declare var _default: {
'states/PaginatedListState': typeof PaginatedListState;
};
export default _default;
import * as extend from "./extend";
import Session from "./Session";
import Store from "./Store";
import BasicEditorDriver from "./utils/BasicEditorDriver";
@@ -116,13 +118,10 @@ import Stream from "./utils/Stream";
import subclassOf from "./utils/subclassOf";
import setRouteWithForcedRefresh from "./utils/setRouteWithForcedRefresh";
import patchMithril from "./utils/patchMithril";
import proxifyCompat from "./utils/proxifyCompat";
import extractText from "./utils/extractText";
import formatNumber from "./utils/formatNumber";
import mapRoutes from "./utils/mapRoutes";
import * as ThrottleDebounce from "./utils/throttleDebounce";
import isObject from "./utils/isObject";
import * as FocusTrap from "./utils/focusTrap";
import Notification from "./models/Notification";
import User from "./models/User";
import Post from "./models/Post";
@@ -149,7 +148,6 @@ import Alert from "./components/Alert";
import Link from "./components/Link";
import LinkButton from "./components/LinkButton";
import Checkbox from "./components/Checkbox";
import ColorPreviewInput from "./components/ColorPreviewInput";
import SelectDropdown from "./components/SelectDropdown";
import ModalManager from "./components/ModalManager";
import Button from "./components/Button";

View File

@@ -15,5 +15,5 @@ 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>): JSX.Element;
view(vnode: Mithril.Vnode): JSX.Element;
}

View File

@@ -60,8 +60,8 @@ 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>): JSX.Element;
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
view(vnode: Mithril.Vnode<IButtonAttrs, never>): JSX.Element;
oncreate(vnode: Mithril.VnodeDOM<IButtonAttrs, this>): void;
/**
* Get the template for the button's content.
*/

View File

@@ -1,6 +0,0 @@
import type Mithril from 'mithril';
import Component, { ComponentAttrs } from '../Component';
export default class ColorPreviewInput extends Component {
value?: string;
view(vnode: Mithril.Vnode<ComponentAttrs, this>): JSX.Element;
}

View File

@@ -1,15 +1,14 @@
/**
* The `EditUserModal` component displays a modal dialog with a login form.
*/
export default class EditUserModal extends Modal<import("./Modal").IInternalModalAttrs> {
constructor();
export default class EditUserModal extends Modal {
username: Stream<any> | undefined;
email: Stream<any> | undefined;
isEmailConfirmed: Stream<any> | undefined;
setPassword: Stream<boolean> | undefined;
password: Stream<any> | undefined;
groups: {} | undefined;
fields(): ItemList<any>;
fields(): ItemList;
activate(): void;
data(): {
relationships: {};

View File

@@ -1,68 +1,67 @@
import Component from '../Component';
import { AlertAttrs } from './Alert';
import type Mithril from 'mithril';
import type ModalManagerState from '../states/ModalManagerState';
import type RequestError from '../utils/RequestError';
import type ModalManager from './ModalManager';
export interface IInternalModalAttrs {
state: ModalManagerState;
animateShow: ModalManager['animateShow'];
animateHide: ModalManager['animateHide'];
}
/**
* The `Modal` component displays a modal dialog, wrapped in a form. Subclasses
* should implement the `className`, `title`, and `content` methods.
*
* @abstract
*/
export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IInternalModalAttrs> extends Component<ModalAttrs> {
export default class Modal extends Component<import("../Component").ComponentAttrs, undefined> {
/**
* Determine whether or not the modal should be dismissible via an 'x' button.
*/
static readonly isDismissible: boolean;
protected loading: boolean;
static isDismissible: boolean;
constructor();
/**
* Attributes for an alert component to show below the header.
*
* @type {object}
*/
alertAttrs: AlertAttrs;
oninit(vnode: Mithril.VnodeDOM<ModalAttrs, this>): void;
oncreate(vnode: Mithril.VnodeDOM<ModalAttrs, this>): void;
onbeforeremove(vnode: Mithril.VnodeDOM<ModalAttrs, this>): Promise<void> | void;
/**
* @todo split into FormModal and Modal in 2.0
*/
view(): JSX.Element;
alertAttrs: object;
/**
* Get the class name to apply to the modal.
*
* @return {String}
* @abstract
*/
abstract className(): string;
className(): string;
/**
* Get the title of the modal dialog.
*
* @return {String}
* @abstract
*/
abstract title(): string;
title(): string;
/**
* Get the content of the modal.
*
* @return {VirtualElement}
* @abstract
*/
abstract content(): Mithril.Children;
content(): any;
/**
* Handle the modal form's submit event.
*/
onsubmit(e: SubmitEvent): void;
/**
* Callback executed when the modal is shown and ready to be interacted with.
*
* @remark Focuses the first input in the modal.
* @param {Event} e
*/
onsubmit(): void;
/**
* Focus on the first input when the modal is ready to be used.
*/
onready(): void;
/**
* Hides the modal.
* Hide the modal.
*/
hide(): void;
/**
* Sets `loading` to false and triggers a redraw.
* Stop loading.
*/
loaded(): void;
loading: boolean | undefined;
/**
* Shows an alert describing an error returned from the API, and gives focus to
* the first relevant field involved in the error.
* Show an alert describing an error returned from the API, and give focus to
* the first relevant field.
*
* @param {RequestError} error
*/
onerror(error: RequestError): void;
onerror(error: any): void;
}
import Component from "../Component";

View File

@@ -1,25 +1,11 @@
import Component from '../Component';
import { FocusTrap } from '../utils/focusTrap';
import type ModalManagerState from '../states/ModalManagerState';
import type Mithril from 'mithril';
interface IModalManagerAttrs {
state: ModalManagerState;
}
/**
* The `ModalManager` component manages a modal dialog. Only one modal dialog
* can be shown at once; loading a new component into the ModalManager will
* overwrite the previous one.
*/
export default class ModalManager extends Component<IModalManagerAttrs> {
protected focusTrap: FocusTrap | undefined;
/**
* Whether a modal is currently shown by this modal manager.
*/
protected modalShown: boolean;
view(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): Mithril.Children;
oncreate(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): void;
onupdate(vnode: Mithril.VnodeDOM<IModalManagerAttrs, this>): void;
animateShow(readyCallback: () => void): void;
export default class ModalManager extends Component<import("../Component").ComponentAttrs, undefined> {
constructor();
animateShow(readyCallback: any): void;
animateHide(): void;
}
export {};
import Component from "../Component";

View File

@@ -1,4 +1,3 @@
import type Mithril from 'mithril';
import Component from '../Component';
export interface IPageAttrs {
key?: number;
@@ -10,19 +9,7 @@ export interface IPageAttrs {
* @abstract
*/
export default abstract class Page<CustomAttrs extends IPageAttrs = IPageAttrs> extends Component<CustomAttrs> {
/**
* A class name to apply to the body while the route is active.
*/
protected bodyClass: string;
/**
* Whether we should scroll to the top of the page when its rendered.
*/
protected scrollTopOnCreate: boolean;
/**
* Whether the browser should restore scroll state on refreshes.
*/
protected useBrowserScrollRestoration: boolean;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
onremove(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
oninit(vnode: any): void;
oncreate(vnode: any): void;
onremove(vnode: any): void;
}

View File

@@ -1,4 +1,3 @@
export default class RequestErrorModal extends Modal<import("./Modal").IInternalModalAttrs> {
constructor();
export default class RequestErrorModal extends Modal {
}
import Modal from "./Modal";

View File

@@ -38,13 +38,13 @@ export default class TextEditor extends Component<import("../Component").Compone
*
* @return {ItemList}
*/
controlItems(): ItemList<any>;
controlItems(): ItemList;
/**
* Build an item list for the toolbar controls.
*
* @return {ItemList}
*/
toolbarItems(): ItemList<any>;
toolbarItems(): ItemList;
/**
* Handle input into the textarea.
*

View File

@@ -19,11 +19,11 @@
* // something that needs to be run on creation and update
* });
*
* @param object The object that owns the method
* @param methods The name or names of the method(s) to extend
* @param callback A callback which mutates the method's output
* @param {object} object The object that owns the method
* @param {string|string[]} methods The name or names of the method(s) to extend
* @param {function} callback A callback which mutates the method's output
*/
export declare function extend<T extends object, K extends KeyOfType<T, Function>>(object: T, methods: K | K[], callback: (this: T, val: ReturnType<T[K]>, ...args: Parameters<T[K]>) => void): void;
export function extend(object: object, methods: string | string[], callback: Function): void;
/**
* Override an object's method by replacing it with a new function, so that the
* new function will be run every time the object's method is called.
@@ -47,8 +47,8 @@ export declare function extend<T extends object, K extends KeyOfType<T, Function
* // something that needs to be run on creation and update
* });
*
* @param object The object that owns the method
* @param methods The name or names of the method(s) to override
* @param newMethod The method to replace it with
* @param {object} object The object that owns the method
* @param {string|string[]} method The name or names of the method(s) to override
* @param {function} newMethod The method to replace it with
*/
export declare function override<T extends object, K extends KeyOfType<T, Function>>(object: T, methods: K | K[], newMethod: (this: T, orig: T[K], ...args: Parameters<T[K]>) => void): void;
export function override(object: object, methods: any, newMethod: Function): void;

View File

@@ -1,5 +1,5 @@
export default class Model {
constructor(type: any, model?: null);
constructor(type: any, model?: any);
type: any;
attributes: any[];
hasOnes: any[];

View File

@@ -1,12 +1,9 @@
import type Mithril from 'mithril';
import type { ComponentAttrs } from '../Component';
import User from '../models/User';
export interface AvatarAttrs extends ComponentAttrs {
}
/**
* The `avatar` helper displays a user's avatar.
*
* @param user
* @param attrs Attributes to apply to the avatar element
*/
export default function avatar(user: User, attrs?: ComponentAttrs): Mithril.Vnode;
export default function avatar(user: User, attrs?: Object): Mithril.Vnode;

View File

@@ -1,22 +1,6 @@
import type Mithril from 'mithril';
import Component, { ComponentAttrs } from '../Component';
export interface ModdedVnodeAttrs {
itemClassName?: string;
key?: string;
}
export declare type ModdedVnode<Attrs> = Mithril.Vnode<ModdedVnodeAttrs, Component<Attrs> | {}> & {
itemName?: string;
itemClassName?: string;
tag: Mithril.Vnode['tag'] & {
isListItem?: boolean;
isActive?: (attrs: ComponentAttrs) => boolean;
};
};
/**
* The `listItems` helper wraps an array of components in the provided tag,
* The `listItems` helper wraps a collection of components in <li> tags,
* stripping out any unnecessary `Separator` components.
*
* By default, this tag is an `<li>` tag, but this is customisable through the
* second function parameter, `customTag`.
*/
export default function listItems<Attrs extends Record<string, unknown>>(rawItems: ModdedVnode<Attrs> | ModdedVnode<Attrs>[], customTag?: string | Component<Attrs>, attributes?: Attrs): Mithril.Vnode[];
export default function listItems(items: Mithril.Vnode | Array<Mithril.Vnode>): Array<Mithril.Vnode>;

View File

@@ -3,4 +3,4 @@ import User from '../models/User';
/**
* The `useronline` helper displays a green circle if the user is online
*/
export default function userOnline(user: User): Mithril.Vnode<{}, {}> | null;
export default function userOnline(user: User): Mithril.Vnode;

View File

@@ -1,30 +1,21 @@
import type Mithril from 'mithril';
import type { RouteResolver } from '../Application';
import type { default as Component, ComponentAttrs } from '../Component';
/**
* Generates a route resolver for a given component.
*
* In addition to regular route resolver functionality:
* - It provide the current route name as an attr
* - It sets a key on the component so a rerender will be triggered on route change.
*/
export default class DefaultResolver<Attrs extends ComponentAttrs, Comp extends Component<Attrs & {
export default class DefaultResolver {
component: Mithril.Component;
routeName: string;
}>, RouteArgs extends Record<string, unknown> = {}> implements RouteResolver<Attrs, Comp, RouteArgs> {
component: new () => Comp;
routeName: string;
constructor(component: new () => Comp, routeName: string);
constructor(component: any, routeName: any);
/**
* When a route change results in a changed key, a full page
* rerender occurs. This method can be overriden in subclasses
* to prevent rerenders on some route changes.
*/
makeKey(): string;
makeAttrs(vnode: Mithril.Vnode<Attrs, Comp>): Attrs & {
routeName: string;
};
onmatch(args: RouteArgs, requestedPath: string, route: string): {
new (): Comp;
};
render(vnode: Mithril.Vnode<Attrs, Comp>): Mithril.Children;
makeAttrs(vnode: any): any;
onmatch(args: any, requestedPath: any, route: any): Mithril.Component<{}, {}>;
render(vnode: any): any[];
}

View File

@@ -28,7 +28,7 @@ export default class AlertManagerState {
/**
* Dismiss an alert.
*/
dismiss(key: AlertIdentifier | null): void;
dismiss(key: AlertIdentifier): void;
/**
* Clear all alerts.
*/

View File

@@ -1,39 +1,19 @@
import Modal from '../components/Modal';
/**
* Class used to manage modal state.
*
* Accessible on the `app` object via `app.modal` property.
*/
export default class ModalManagerState {
modal: {
componentClass: any;
attrs: any;
} | null;
/**
* @internal
* Show a modal dialog.
*
* @public
*/
modal: null | {
componentClass: typeof Modal;
attrs?: Record<string, unknown>;
};
private closeTimeout?;
public show(componentClass: any, attrs: any): void;
/**
* Shows a modal dialog.
* Close the modal dialog.
*
* If a modal is already open, the existing one will close and the new modal will replace it.
*
* @example <caption>Show a modal</caption>
* app.modal.show(MyCoolModal, { attr: 'value' });
*
* @example <caption>Show a modal from a lifecycle method (`oncreate`, `view`, etc.)</caption>
* // This "hack" is needed due to quirks with nested redraws in Mithril.
* setTimeout(() => app.modal.show(MyCoolModal, { attr: 'value' }), 0);
* @public
*/
show(componentClass: typeof Modal, attrs?: Record<string, unknown>): void;
/**
* Closes the currently open dialog, if one is open.
*/
close(): void;
/**
* Checks if a modal is currently open.
*
* @returns `true` if a modal dialog is currently open, otherwise `false`.
*/
isModalOpen(): boolean;
public close(): void;
closeTimeout: number | undefined;
}

View File

@@ -10,18 +10,15 @@ export interface PaginationLocation {
startIndex?: number;
endIndex?: number;
}
export interface PaginatedListParams {
[key: string]: any;
}
export default abstract class PaginatedListState<T extends Model, P extends PaginatedListParams = PaginatedListParams> {
export default abstract class PaginatedListState<T extends Model> {
protected location: PaginationLocation;
protected pageSize: number;
protected pages: Page<T>[];
protected params: P;
protected params: any;
protected initialLoading: boolean;
protected loadingPrev: boolean;
protected loadingNext: boolean;
protected constructor(params?: P, page?: number, pageSize?: number);
protected constructor(params?: any, page?: number, pageSize?: number);
abstract get type(): string;
clear(): void;
loadPrev(): Promise<void>;
@@ -47,8 +44,8 @@ export default abstract class PaginatedListState<T extends Model, P extends Pagi
* @param page
* @see requestParams
*/
refreshParams(newParams: P, page: number): Promise<void>;
refresh(page?: number): Promise<void>;
refreshParams(newParams: any, page: number): any;
refresh(page?: number): any;
getPages(): Page<T>[];
getLocation(): PaginationLocation;
isLoading(): boolean;
@@ -76,6 +73,6 @@ export default abstract class PaginatedListState<T extends Model, P extends Pagi
getParams(): any;
protected getNextPageNumber(): number;
protected getPrevPageNumber(): number;
protected paramsChanged(newParams: P): boolean;
protected paramsChanged(newParams: any): boolean;
protected getAllItems(): T[];
}

View File

@@ -3,8 +3,8 @@ import ItemList from './ItemList';
export default class BasicEditorDriver implements EditorDriverInterface {
el: HTMLTextAreaElement;
constructor(dom: HTMLElement, params: EditorDriverParams);
protected build(dom: HTMLElement, params: EditorDriverParams): void;
protected keyHandlers(params: EditorDriverParams): ItemList<(e: KeyboardEvent) => void>;
build(dom: HTMLElement, params: EditorDriverParams): void;
keyHandlers(params: EditorDriverParams): ItemList;
moveCursorTo(position: number): void;
getSelectionRange(): Array<number>;
getLastNChars(n: number): string;

View File

@@ -4,36 +4,10 @@
* footer.
*/
export default class Drawer {
/**
* @type {import('./focusTrap').FocusTrap}
*/
focusTrap: import('./focusTrap').FocusTrap;
/**
* @type {HTMLDivElement}
*/
appElement: HTMLDivElement;
/**
* @internal
* @type {MediaQueryList}
*/
drawerAvailableMediaQuery: MediaQueryList;
/**
* Handler for the `resize` event on `window`.
*
* This is used to close the drawer when the viewport is widened past the `phone` size.
* At this point, the drawer turns into the standard header that we see on desktop, but
* the drawer is still registered as 'open' internally.
*
* This causes issues with the focus trap, resulting in focus becoming trapped within
* the header on desktop viewports.
*
* @internal
*/
resizeHandler: (e: any) => void;
/**
* Check whether or not the drawer is currently open.
*
* @return {boolean}
* @return {Boolean}
* @public
*/
public isOpen(): boolean;

View File

@@ -1,31 +1,20 @@
export interface IItemObject<T> {
content: T;
itemName: string;
declare class Item {
content: any;
priority: number;
}
declare class Item<T> {
content: T;
priority: number;
constructor(content: T, priority: number);
key?: number;
constructor(content: any, priority?: number);
}
/**
* The `ItemList` class collects items and then arranges them into an array
* by priority.
*/
export default class ItemList<T> {
export default class ItemList {
/**
* The items in the list.
* The items in the list
*/
protected _items: Record<string, Item<T>>;
/**
* A **read-only copy** of items in the list.
*
* We don't allow adding new items to the ItemList via setting new properties,
* nor do we allow modifying existing items directly.
*
* @deprecated Use {@link ItemList.toObject} instead.
*/
get items(): DeepReadonly<Record<string, Item<T>>>;
items: {
[key: string]: Item;
};
/**
* Check whether the list is empty.
*/
@@ -37,165 +26,33 @@ export default class ItemList<T> {
/**
* Get the content of an item.
*/
get(key: string): T;
/**
* Get the priority of an item.
*/
getPriority(key: string): number;
get(key: string): any;
/**
* Add an item to the list.
*
* @param key A unique key for the item.
* @param content The item's content.
* @param priority The priority of the item. Items with a higher priority
* will be positioned before items with a lower priority.
* @param [priority] The priority of the item. Items with a higher
* priority will be positioned before items with a lower priority.
*/
add(key: string, content: T, priority?: number): this;
add(key: string, content: any, priority?: number): this;
/**
* Replace an item and/or priority in the list, only if it is already present.
*
* If `content` or `priority` are `null`, these values will not be replaced.
*
* If the provided `key` is not present, nothing will happen.
*
* @deprecated Please use the {@link ItemList.setContent} and {@link ItemList.setPriority}
* methods to replace items and their priorities. This method will be removed in Flarum 2.0.
*
* @param key The key of the item in the list
* @param content The item's new content
* @param priority The item's new priority
*
* @example <caption>Replace priority and not content.</caption>
* items.replace('myItem', null, 10);
*
* @example <caption>Replace content and not priority.</caption>
* items.replace('myItem', <p>My new value.</p>);
*
* @example <caption>Replace content and priority.</caption>
* items.replace('myItem', <p>My new value.</p>, 10);
* Replace an item in the list, only if it is already present.
*/
replace(key: string, content?: T | null, priority?: number | null): this;
/**
* Replaces an item's content, if the provided item key exists.
*
* If the provided `key` is not present, nothing will happen.
*
* @param key The key of the item in the list
* @param content The item's new content
*
* @example <caption>Replace item content.</caption>
* items.setContent('myItem', <p>My new value.</p>);
*
* @example <caption>Replace item content and priority.</caption>
* items
* .setContent('myItem', <p>My new value.</p>)
* .setPriority('myItem', 10);
*
* @throws If the provided `key` is not present in the ItemList.
*/
setContent(key: string, content: T): this;
/**
* Replaces an item's priority, if the provided item key exists.
*
* If the provided `key` is not present, nothing will happen.
*
* @param key The key of the item in the list
* @param priority The item's new priority
*
* @example <caption>Replace item priority.</caption>
* items.setPriority('myItem', 10);
*
* @example <caption>Replace item priority and content.</caption>
* items
* .setPriority('myItem', 10)
* .setContent('myItem', <p>My new value.</p>);
*
* @throws If the provided `key` is not present in the ItemList.
*/
setPriority(key: string, priority: number): this;
replace(key: string, content?: any, priority?: number): this;
/**
* Remove an item from the list.
*/
remove(key: string): this;
/**
* Merge another list's items into this one.
*
* The list passed to this function will overwrite items which already exist
* with the same key.
*/
merge(otherList: ItemList<T>): ItemList<T>;
merge(items: this): this;
/**
* Convert the list into an array of item content arranged by priority.
*
* This **does not** preserve the original types of primitives and proxies
* all content values to make `itemName` accessible on them.
*
* **NOTE:** If your ItemList holds primitive types (such as numbers, booleans
* or strings), these will be converted to their object counterparts if you do
* not provide `true` to this function.
*
* **NOTE:** Modifying any objects in the final array may also update the
* content of the original ItemList.
*
* @param keepPrimitives Converts item content to objects and sets the
* `itemName` property on them.
*
* @see https://github.com/flarum/core/issues/3030
* Convert the list into an array of item content arranged by priority. Each
* item's content will be assigned an `itemName` property equal to the item's
* unique key.
*/
toArray(keepPrimitives?: false): (T & {
itemName: string;
})[];
/**
* Convert the list into an array of item content arranged by priority.
*
* Content values that are already objects will be proxied and have
* `itemName` accessible on them. Primitive values will not have the
* `itemName` property accessible.
*
* **NOTE:** Modifying any objects in the final array may also update the
* content of the original ItemList.
*
* @param keepPrimitives Converts item content to objects and sets the
* `itemName` property on them.
*/
toArray(keepPrimitives: true): (T extends object ? T & Readonly<{
itemName: string;
}> : T)[];
/**
* A read-only map of all keys to their respective items in no particular order.
*
* We don't allow adding new items to the ItemList via setting new properties,
* nor do we allow modifying existing items directly. You should use the
* {@link ItemList.add}, {@link ItemList.setContent} and
* {@link ItemList.setPriority} methods instead.
*
* To match the old behaviour of the `ItemList.items` property, call
* `Object.values(ItemList.toObject())`.
*
* @example
* const items = new ItemList();
* items.add('b', 'My cool value', 20);
* items.add('a', 'My value', 10);
* items.toObject();
* // {
* // a: { content: 'My value', priority: 10, itemName: 'a' },
* // b: { content: 'My cool value', priority: 20, itemName: 'b' },
* // }
*/
toObject(): DeepReadonly<Record<string, IItemObject<T>>>;
/**
* Proxies an item's content, adding the `itemName` readonly property to it.
*
* @example
* createItemContentProxy({ foo: 'bar' }, 'myItem');
* // { foo: 'bar', itemName: 'myItem' }
*
* @param content The item's content (objects only)
* @param key The item's key
* @returns Proxied content
*
* @internal
*/
private createItemContentProxy;
toArray(): any[];
}
export {};

View File

@@ -1,21 +1,9 @@
import type Mithril from 'mithril';
export declare type InternalFlarumRequestOptions<ResponseType> = Mithril.RequestOptions<ResponseType> & {
errorHandler: (error: RequestError) => void;
url: string;
};
export default class RequestError<ResponseType = string> {
status: number;
options: InternalFlarumRequestOptions<ResponseType>;
export default class RequestError {
status: string;
options: object;
xhr: XMLHttpRequest;
responseText: string | null;
response: {
[key: string]: unknown;
errors?: {
detail?: string;
code?: string;
[key: string]: unknown;
}[];
} | null;
response: object | null;
alert: any;
constructor(status: number, responseText: string | null, options: InternalFlarumRequestOptions<ResponseType>, xhr: XMLHttpRequest);
constructor(status: string, responseText: string | null, options: object, xhr: XMLHttpRequest);
}

View File

@@ -4,12 +4,12 @@
*/
export default class ScrollListener {
/**
* @param {(top: number) => void} callback The callback to run when the scroll position
* @param {Function} callback The callback to run when the scroll position
* changes.
* @public
*/
constructor(callback: (top: number) => void);
callback: (top: number) => void;
constructor(callback: Function);
callback: Function;
ticking: boolean;
/**
* On each animation frame, as long as the listener is active, run the

View File

@@ -22,23 +22,31 @@
* @see https://mithril.js.org/lifecycle-methods.html#onbeforeupdate
*/
export default class SubtreeRetainer {
protected callbacks: (() => any)[];
protected data: Record<string, any>;
/**
* @param callbacks Functions returning data to keep track of.
* @param {...callbacks} callbacks Functions returning data to keep track of.
*/
constructor(...callbacks: (() => any)[]);
constructor(...callbacks: any[]);
callbacks: any[];
data: {};
/**
* Return whether any data has changed since the last check.
* If so, Mithril needs to re-diff the vnode and its children.
*
* @return {boolean}
* @public
*/
needsRebuild(): boolean;
public needsRebuild(): boolean;
/**
* Add another callback to be checked.
*
* @param {...Function} callbacks
* @public
*/
check(...callbacks: (() => any)[]): void;
public check(...callbacks: Function[]): void;
/**
* Invalidate the subtree, forcing it to be redrawn.
* Invalidate the subtree, forcing it to be rerendered.
*
* @public
*/
invalidate(): void;
public invalidate(): void;
}

View File

@@ -1,5 +1,7 @@
import type Mithril from 'mithril';
/**
* Extract the text nodes from a virtual element.
*
* @param {VirtualElement} vdom
* @return {String}
*/
export default function extractText(vdom: Mithril.Children): string;
export default function extractText(vdom: any): string;

View File

@@ -1,20 +0,0 @@
import { createFocusTrap as _createFocusTrap } from 'focus-trap';
/**
* Creates a focus trap for the given element with the given options.
*
* This function applies some default options that are different to the library.
* Your own options still override these custom defaults:
*
* ```json
* {
escapeDeactivates: false,
* }
* ```
*
* @param element The element to be the focus trap, or a selector that will be used to find the element.
*
* @see https://github.com/focus-trap/focus-trap#readme - Library documentation
*/
declare function createFocusTrap(...args: Parameters<typeof _createFocusTrap>): ReturnType<typeof _createFocusTrap>;
export * from 'focus-trap';
export { createFocusTrap };

View File

@@ -1,9 +1,9 @@
/**
* The `formatNumber` utility localizes a number into a string with the
* appropriate punctuation based on the provided locale otherwise will default to the users locale.
* appropriate punctuation.
*
* @example
* formatNumber(1234);
* // 1,234
*/
export default function formatNumber(number: number, locale?: string): string;
export default function formatNumber(number: number): string;

View File

@@ -1,6 +1,5 @@
import dayjs from 'dayjs';
/**
* The `humanTime` utility converts a date to a localized, human-readable time-
* ago string.
*/
export default function humanTime(time: dayjs.ConfigType): string;
export default function humanTime(time: Date): string;

View File

@@ -1,24 +0,0 @@
/**
* Returns if the passed value is an object.
*
* In this context, "object" refers to **any non-primitive value**, including
* arrays, function, maps, dates, and more.
*
* @example
* isObject({}); // true
* @example
* isObject([]); // true
* @example
* isObject(function () {}); // true
* @example
* isObject(Object(1)); // true
* @example
* isObject(null); // false
* @example
* isObject(1); // false
* @example
* isObject("hello world"); // false
*
* @see https://github.com/jashkenas/underscore/blob/943977e34e2279503528a71ddcc2dd5f96483945/underscore.js#L87-L91
*/
export default function isObject(obj: unknown): obj is object;

View File

@@ -1,13 +1,11 @@
import type { FlarumGenericRoute, RouteResolver } from '../Application';
import type Component from '../Component';
/**
* The `mapRoutes` utility converts a map of named application routes into a
* format that can be understood by Mithril, and wraps them in route resolvers
* to provide each route with the current route name.
*
* @see https://mithril.js.org/route.html#signature
* @param {Object} routes
* @param {String} [basePath]
* @return {Object}
*/
export default function mapRoutes(routes: Record<string, FlarumGenericRoute>, basePath?: string): Record<string, RouteResolver<Record<string, unknown>, Component<{
[key: string]: unknown;
routeName: string;
}, undefined>, Record<string, unknown>>>;
export default function mapRoutes(routes: Object, basePath?: string | undefined): Object;

View File

@@ -1 +1,6 @@
export default function proxifyCompat(compat: Record<string, unknown>, namespace: string): Record<string, unknown>;
declare const _default: (compat: {
[key: string]: any;
}, namespace: string) => {
[key: string]: any;
};
export default _default;

View File

@@ -1,60 +1,51 @@
import History from './utils/History';
import Pane from './utils/Pane';
import { makeRouteHelpers } from './routes';
import Application from '../common/Application';
import NotificationListState from './states/NotificationListState';
import GlobalSearchState from './states/GlobalSearchState';
import DiscussionListState from './states/DiscussionListState';
import ComposerState from './states/ComposerState';
import type Notification from './components/Notification';
import type Post from './components/Post';
import Discussion from '../common/models/Discussion';
export default class ForumApplication extends Application {
/**
* A map of notification types to their components.
*
* @type {Object}
*/
notificationComponents: Record<string, typeof Notification>;
notificationComponents: Object;
/**
* A map of post types to their components.
*
* @type {Object}
*/
postComponents: Record<string, typeof Post>;
postComponents: Object;
/**
* An object which controls the state of the page's side pane.
*
* @type {Pane}
*/
pane: Pane | null;
pane: Pane;
/**
* The app's history stack, which keeps track of which routes the user visits
* so that they can easily navigate back to the previous route.
*
* @type {History}
*/
history: History;
/**
* An object which controls the state of the user's notifications.
*
* @type {NotificationListState}
*/
notifications: NotificationListState;
/**
* An object which stores previously searched queries and provides convenient
* tools for retrieving and managing search values.
*/
search: GlobalSearchState;
/**
* An object which controls the state of the composer.
*/
composer: ComposerState;
/**
* An object which controls the state of the cached discussion list, which
* is used in the index page and the slideout pane.
*
* @type {DiscussionListState}
*/
discussions: DiscussionListState;
route: typeof Application.prototype.route & ReturnType<typeof makeRouteHelpers>;
constructor();
/**
* @inheritdoc
*/
mount(): void;
/**
* Check whether or not the user is currently viewing a discussion.
*
* @param {Discussion} discussion
* @return {Boolean}
*/
viewingDiscussion(discussion: Discussion): boolean;
viewingDiscussion(discussion: any): boolean;
/**
* Callback for when an external authenticator (social login) action has
* completed.
@@ -62,6 +53,18 @@ export default class ForumApplication extends Application {
* If the payload indicates that the user has been logged in, then the page
* will be reloaded. Otherwise, a SignUpModal will be opened, prefilled
* with the provided details.
*
* @param {Object} payload A dictionary of attrs to pass into the sign up
* modal. A truthy `loggedIn` attr indicates that the user has logged
* in, and thus the page is reloaded.
* @public
*/
authenticationComplete(payload: Record<string, unknown>): void;
public authenticationComplete(payload: Object): void;
}
import Application from "../common/Application";
import Pane from "./utils/Pane";
import History from "./utils/History";
import NotificationListState from "./states/NotificationListState";
import GlobalSearchState from "./states/GlobalSearchState";
import ComposerState from "./states/ComposerState";
import DiscussionListState from "./states/DiscussionListState";

View File

@@ -1,5 +1,5 @@
declare var _default: {
extend: any;
extend: typeof import("../common/extend");
Session: typeof import("../common/Session").default;
Store: typeof import("../common/Store").default;
'utils/BasicEditorDriver': typeof BasicEditorDriver;
@@ -32,15 +32,17 @@ declare var _default: {
'utils/subclassOf': typeof import("../common/utils/subclassOf").default;
'utils/setRouteWithForcedRefresh': typeof import("../common/utils/setRouteWithForcedRefresh").default;
'utils/patchMithril': typeof import("../common/utils/patchMithril").default;
'utils/proxifyCompat': typeof import("../common/utils/proxifyCompat").default;
'utils/proxifyCompat': (compat: {
[key: string]: any;
}, namespace: string) => {
[key: string]: any;
};
'utils/classList': (...classes: import("clsx").ClassValue[]) => string;
'utils/extractText': typeof import("../common/utils/extractText").default;
'utils/formatNumber': typeof import("../common/utils/formatNumber").default;
'utils/mapRoutes': typeof import("../common/utils/mapRoutes").default;
'utils/withAttr': (key: string, cb: Function) => (this: Element) => void;
'utils/throttleDebounce': typeof import("../common/utils/throttleDebounce");
'utils/isObject': typeof import("../common/utils/isObject").default;
'utils/focusTrap': typeof import("../common/utils/focusTrap");
'models/Notification': typeof import("../common/models/Notification").default;
'models/User': typeof import("../common/models/User").default;
'models/Post': typeof import("../common/models/Post").default;
@@ -67,7 +69,6 @@ declare var _default: {
'components/Link': typeof import("../common/components/Link").default;
'components/LinkButton': typeof import("../common/components/LinkButton").default;
'components/Checkbox': typeof import("../common/components/Checkbox").default;
'components/ColorPreviewInput': typeof import("../common/components/ColorPreviewInput").default;
'components/SelectDropdown': typeof import("../common/components/SelectDropdown").default;
'components/ModalManager': typeof import("../common/components/ModalManager").default;
'components/Button': typeof import("../common/components/Button").default;
@@ -92,10 +93,10 @@ declare var _default: {
'states/PaginatedListState': typeof import("../common/states/PaginatedListState").default;
} & {
'utils/PostControls': {
controls(post: any, context: any): import("../common/utils/ItemList").default<any>;
userControls(post: any, context: any): import("../common/utils/ItemList").default<any>;
moderationControls(post: any, context: any): import("../common/utils/ItemList").default<any>;
destructiveControls(post: any, context: any): import("../common/utils/ItemList").default<any>;
controls(post: any, context: any): import("../common/utils/ItemList").default;
userControls(post: any, context: any): import("../common/utils/ItemList").default;
moderationControls(post: any, context: any): import("../common/utils/ItemList").default;
destructiveControls(post: any, context: any): import("../common/utils/ItemList").default;
editAction(): Promise<any>;
hideAction(): Promise<any>;
restoreAction(): Promise<any>;
@@ -105,10 +106,10 @@ declare var _default: {
'utils/slidable': typeof slidable;
'utils/History': typeof History;
'utils/DiscussionControls': {
controls(discussion: any, context: any): import("../common/utils/ItemList").default<any>;
userControls(discussion: any, context: any): import("../common/utils/ItemList").default<any>;
moderationControls(discussion: any): import("../common/utils/ItemList").default<any>;
destructiveControls(discussion: any): import("../common/utils/ItemList").default<any>;
controls(discussion: any, context: any): import("../common/utils/ItemList").default;
userControls(discussion: any, context: any): import("../common/utils/ItemList").default;
moderationControls(discussion: any): import("../common/utils/ItemList").default;
destructiveControls(discussion: any): import("../common/utils/ItemList").default;
replyAction(goToLast: boolean, forceRefresh: boolean): Promise<any>;
hideAction(): Promise<any>;
restoreAction(): Promise<any>;
@@ -117,10 +118,10 @@ declare var _default: {
};
'utils/alertEmailConfirmation': typeof alertEmailConfirmation;
'utils/UserControls': {
controls(user: any, context: any): import("../common/utils/ItemList").default<any>;
userControls(): import("../common/utils/ItemList").default<any>;
moderationControls(user: any): import("../common/utils/ItemList").default<any>;
destructiveControls(user: any): import("../common/utils/ItemList").default<any>;
controls(user: any, context: any): import("../common/utils/ItemList").default;
userControls(): import("../common/utils/ItemList").default;
moderationControls(user: any): import("../common/utils/ItemList").default;
destructiveControls(user: any): import("../common/utils/ItemList").default;
deleteAction(user: any): void;
showDeletionAlert(user: any, type: string): void;
editAction(user: any): void;

View File

@@ -26,7 +26,7 @@ export default class AvatarEditor extends Component<import("../../common/Compone
*
* @return {ItemList}
*/
controlItems(): ItemList<any>;
controlItems(): ItemList;
/**
* Enable dragover style
*

View File

@@ -2,8 +2,7 @@
* The `ChangeEmailModal` component shows a modal dialog which allows the user
* to change their email address.
*/
export default class ChangeEmailModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class ChangeEmailModal extends Modal {
/**
* Whether or not the email has been changed successfully.
*

View File

@@ -2,7 +2,6 @@
* The `ChangePasswordModal` component shows a modal dialog which allows the
* user to send themself a password reset email.
*/
export default class ChangePasswordModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class ChangePasswordModal extends Modal {
}
import Modal from "../../common/components/Modal";

View File

@@ -34,7 +34,7 @@ export default class CommentPost extends Post {
*
* @return {ItemList}
*/
headerItems(): ItemList<any>;
headerItems(): ItemList;
}
import Post from "./Post";
import ItemList from "../../common/utils/ItemList";

View File

@@ -85,7 +85,7 @@ export default class Composer extends Component<import("../../common/Component")
*
* @return {ItemList}
*/
controlItems(): ItemList<any>;
controlItems(): ItemList;
/**
* Initialize default Composer height.
*/

View File

@@ -35,7 +35,7 @@ export default class ComposerBody extends Component<import("../../common/Compone
*
* @return {ItemList}
*/
headerItems(): ItemList<any>;
headerItems(): ItemList;
/**
* Handle the submit event of the text editor.
*

View File

@@ -13,6 +13,6 @@
export default class ComposerPostPreview extends Component<import("../../common/Component").ComponentAttrs, undefined> {
static initAttrs(attrs: any): void;
constructor();
updateInterval: NodeJS.Timer | undefined;
updateInterval: number | undefined;
}
import Component from "../../common/Component";

View File

@@ -12,7 +12,7 @@ export default class DiscussionHero extends Component<import("../../common/Compo
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -51,8 +51,7 @@ export default class DiscussionListItem extends Component<import("../../common/C
*
* @return {ItemList}
*/
infoItems(): ItemList<any>;
replyCountItem(): JSX.Element;
infoItems(): ItemList;
}
import Component from "../../common/Component";
import SubtreeRetainer from "../../common/utils/SubtreeRetainer";

View File

@@ -1,63 +1,53 @@
import type Mithril from 'mithril';
import Page, { IPageAttrs } from '../../common/components/Page';
import ItemList from '../../common/utils/ItemList';
import PostStreamState from '../states/PostStreamState';
import Discussion from '../../common/models/Discussion';
export interface IDiscussionPageAttrs extends IPageAttrs {
id: string;
near?: number;
}
/**
* The `DiscussionPage` component displays a whole discussion page, including
* the discussion list pane, the hero, the posts, and the sidebar.
*/
export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = IDiscussionPageAttrs> extends Page<CustomAttrs> {
export default class DiscussionPage extends Page<import("../../common/components/Page").IPageAttrs> {
constructor();
useBrowserScrollRestoration: boolean | undefined;
/**
* The discussion that is being viewed.
*
* @type {Discussion}
*/
protected discussion: Discussion | null;
/**
* A public API for interacting with the post stream.
*/
protected stream: PostStreamState | null;
discussion: any;
/**
* The number of the first post that is currently visible in the viewport.
*
* @type {number}
*/
protected near: number;
protected useBrowserScrollRestoration: boolean;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
onremove(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
view(): JSX.Element;
near: number | undefined;
bodyClass: string | undefined;
/**
* List of components shown while the discussion is loading.
*
* @returns {ItemList}
*/
loadingItems(): ItemList<unknown>;
loadingItems(): ItemList;
/**
* Function that renders the `sidebarItems` ItemList.
*
* @returns {import('mithril').Children}
*/
sidebar(): JSX.Element;
sidebar(): import('mithril').Children;
/**
* Renders the discussion's hero.
*
* @returns {import('mithril').Children}
*/
hero(): JSX.Element;
hero(): import('mithril').Children;
/**
* List of items rendered as the main page content.
*
* @returns {ItemList}
*/
pageContent(): ItemList<unknown>;
pageContent(): ItemList;
/**
* List of items rendered inside the main page content container.
*
* @returns {ItemList}
*/
mainContent(): ItemList<unknown>;
mainContent(): ItemList;
/**
* Load the discussion from the API or use the preloaded one.
*/
@@ -68,23 +58,29 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
*
* @return {Object}
*/
requestParams(): {
bySlug: boolean;
page: {
near: number;
};
};
requestParams(): Object;
/**
* Initialize the component to display the given discussion.
*
* @param {Discussion} discussion
*/
show(discussion: Discussion): void;
show(discussion: any): void;
stream: PostStreamState | undefined;
/**
* Build an item list for the contents of the sidebar.
*
* @return {ItemList}
*/
sidebarItems(): ItemList<Mithril.Vnode<{}, {}>>;
sidebarItems(): ItemList;
/**
* When the posts that are visible in the post stream change (i.e. the user
* scrolls up or down), then we update the URL and mark the posts as read.
*
* @param {Integer} startNumber
* @param {Integer} endNumber
*/
positionChanged(startNumber: number, endNumber: number): void;
positionChanged(startNumber: any, endNumber: any): void;
}
import Page from "../../common/components/Page";
import ItemList from "../../common/utils/ItemList";
import PostStreamState from "../states/PostStreamState";

View File

@@ -1,12 +1,11 @@
import { SearchSource } from './Search';
import type Mithril from 'mithril';
import Discussion from '../../common/models/Discussion';
/**
* The `DiscussionsSearchSource` finds and displays discussion search results in
* the search dropdown.
*/
export default class DiscussionsSearchSource implements SearchSource {
protected results: Map<string, Discussion[]>;
search(query: string): Promise<void>;
protected results: Map<string, unknown[]>;
search(query: string): Promise<Map<string, unknown[]>>;
view(query: string): Array<Mithril.Vnode>;
}

View File

@@ -6,8 +6,7 @@
*
* - `email`
*/
export default class ForgotPasswordModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class ForgotPasswordModal extends Modal {
/**
* The value of the email input.
*

View File

@@ -9,7 +9,7 @@ export default class HeaderPrimary extends Component<import("../../common/Compon
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -10,7 +10,7 @@ export default class HeaderSecondary extends Component<import("../../common/Comp
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -6,6 +6,8 @@ export default class IndexPage extends Page<import("../../common/components/Page
static providesInitialSearch: boolean;
constructor();
lastDiscussion: any;
bodyClass: string | undefined;
scrollTopOnCreate: boolean | undefined;
setTitle(): void;
/**
* Get the component to display as the hero.
@@ -20,14 +22,14 @@ export default class IndexPage extends Page<import("../../common/components/Page
*
* @return {ItemList}
*/
sidebarItems(): ItemList<any>;
sidebarItems(): ItemList;
/**
* Build an item list for the navigation in the sidebar of the index page. By
* default this is just the 'All Discussions' link.
*
* @return {ItemList}
*/
navItems(): ItemList<any>;
navItems(): ItemList;
/**
* Build an item list for the part of the toolbar which is concerned with how
* the results are displayed. By default this is just a select box to change
@@ -35,14 +37,14 @@ export default class IndexPage extends Page<import("../../common/components/Page
*
* @return {ItemList}
*/
viewItems(): ItemList<any>;
viewItems(): ItemList;
/**
* Build an item list for the part of the toolbar which is about taking action
* on the results. By default this is just a "mark all as read" button.
*
* @return {ItemList}
*/
actionItems(): ItemList<any>;
actionItems(): ItemList;
/**
* Open the composer for a new discussion or prompt the user to login.
*

View File

@@ -9,7 +9,7 @@ export default class LogInButtons extends Component<import("../../common/Compone
* @return {ItemList}
* @public
*/
public items(): ItemList<any>;
public items(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -6,8 +6,7 @@
* - `identification`
* - `password`
*/
export default class LogInModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class LogInModal extends Modal {
/**
* The value of the identification input.
*
@@ -27,7 +26,7 @@ export default class LogInModal extends Modal<import("../../common/components/Mo
*/
remember: Function | undefined;
body(): JSX.Element[];
fields(): ItemList<any>;
fields(): ItemList;
footer(): (string | JSX.Element)[];
/**
* Open the forgot password modal, prefilling it with an email if the user has

View File

@@ -65,7 +65,7 @@ export default class NotificationGrid extends Component<import("../../common/Com
*
* @return {ItemList}
*/
notificationMethods(): ItemList<any>;
notificationMethods(): ItemList;
/**
* Build an item list for the notification types to display in the grid.
*
@@ -77,7 +77,7 @@ export default class NotificationGrid extends Component<import("../../common/Com
*
* @return {ItemList}
*/
notificationTypes(): ItemList<any>;
notificationTypes(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -4,5 +4,6 @@
*/
export default class NotificationsPage extends Page<import("../../common/components/Page").IPageAttrs> {
constructor();
bodyClass: string | undefined;
}
import Page from "../../common/components/Page";

View File

@@ -11,9 +11,6 @@
*/
export default class Post extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
/**
* May be set by subclasses.
*/
loading: boolean | undefined;
/**
* Set up a subtree retainer so that the post will not be redrawn
@@ -37,7 +34,7 @@ export default class Post extends Component<import("../../common/Component").Com
/**
* Get the post's classes.
*
* @param existing string
* @param string classes
* @returns {string[]}
*/
classes(existing: any): string[];
@@ -46,13 +43,13 @@ export default class Post extends Component<import("../../common/Component").Com
*
* @return {ItemList}
*/
actionItems(): ItemList<any>;
actionItems(): ItemList;
/**
* Build an item list for the post's footer.
*
* @return {ItemList}
*/
footerItems(): ItemList<any>;
footerItems(): ItemList;
}
import Component from "../../common/Component";
import SubtreeRetainer from "../../common/utils/SubtreeRetainer";

View File

@@ -23,7 +23,7 @@ export default class PostStream extends Component<import("../../common/Component
* @param {Integer} top
*/
onscroll(top?: any): void;
calculatePositionTimeout: NodeJS.Timeout | undefined;
calculatePositionTimeout: number | undefined;
/**
* Check if either extreme of the post stream is in the viewport,
* and if so, trigger loading the next/previous page.

View File

@@ -1,8 +1,7 @@
/**
* The 'RenameDiscussionModal' displays a modal dialog with an input to rename a discussion
*/
export default class RenameDiscussionModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class RenameDiscussionModal extends Modal {
discussion: any;
currentTitle: any;
newTitle: Stream<any> | undefined;

View File

@@ -1,4 +1,3 @@
/// <reference types="node" />
import Component, { ComponentAttrs } from '../../common/Component';
import ItemList from '../../common/utils/ItemList';
import KeyboardNavigatable from '../utils/KeyboardNavigatable';
@@ -17,9 +16,8 @@ import type Mithril from 'mithril';
export interface SearchSource {
/**
* Make a request to get results for the given query.
* The results will be updated internally in the search source, not exposed.
*/
search(query: string): Promise<void>;
search(query: string): any;
/**
* Get an array of virtual <li>s that list the search results for the given
* query.
@@ -43,11 +41,8 @@ export interface SearchAttrs extends ComponentAttrs {
* - state: SearchState instance.
*/
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T> {
/**
* The minimum query length before sources are searched.
*/
protected static MIN_SEARCH_LEN: number;
protected searchState: SearchState;
static MIN_SEARCH_LEN: number;
protected state: SearchState;
/**
* Whether or not the search input has focus.
*/
@@ -68,14 +63,14 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
*/
protected index: number;
protected navigator: KeyboardNavigatable;
protected searchTimeout?: NodeJS.Timeout;
protected searchTimeout?: number;
private updateMaxHeightHandler?;
oninit(vnode: Mithril.Vnode<T, this>): void;
view(): JSX.Element;
updateMaxHeight(): void;
onupdate(vnode: Mithril.VnodeDOM<T, this>): void;
oncreate(vnode: Mithril.VnodeDOM<T, this>): void;
onremove(vnode: Mithril.VnodeDOM<T, this>): void;
onupdate(vnode: any): void;
oncreate(vnode: any): void;
onremove(vnode: any): void;
/**
* Navigate to the currently selected search result and close the list.
*/
@@ -87,7 +82,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
/**
* Build an item list of SearchSources.
*/
sourceItems(): ItemList<SearchSource>;
sourceItems(): ItemList;
/**
* Get all of the search result items that are selectable.
*/

View File

@@ -8,7 +8,7 @@ export default class SessionDropdown extends Dropdown {
*
* @return {ItemList}
*/
items(): ItemList<any>;
items(): ItemList;
}
import Dropdown from "../../common/components/Dropdown";
import ItemList from "../../common/utils/ItemList";

View File

@@ -8,25 +8,25 @@ export default class SettingsPage extends UserPage {
*
* @return {ItemList}
*/
settingsItems(): ItemList<any>;
settingsItems(): ItemList;
/**
* Build an item list for the user's account settings.
*
* @return {ItemList}
*/
accountItems(): ItemList<any>;
accountItems(): ItemList;
/**
* Build an item list for the user's notification settings.
*
* @return {ItemList}
*/
notificationsItems(): ItemList<any>;
notificationsItems(): ItemList;
/**
* Build an item list for the user's privacy settings.
*
* @return {ItemList}
*/
privacyItems(): ItemList<any>;
privacyItems(): ItemList;
discloseOnlineLoading: boolean | undefined;
}
import UserPage from "./UserPage";

View File

@@ -8,8 +8,7 @@
* - `password`
* - `token` An email token to sign up with.
*/
export default class SignUpModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class SignUpModal extends Modal {
/**
* The value of the username input.
*
@@ -30,7 +29,7 @@ export default class SignUpModal extends Modal<import("../../common/components/M
password: Function | undefined;
isProvided(field: any): any;
body(): (string | JSX.Element)[];
fields(): ItemList<any>;
fields(): ItemList;
footer(): JSX.Element[];
/**
* Open the log in modal, prefilling it with an email/username/password if

View File

@@ -17,7 +17,7 @@ export default class UserCard extends Component<import("../../common/Component")
*
* @return {ItemList}
*/
infoItems(): ItemList<any>;
infoItems(): ItemList;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -13,6 +13,7 @@ export default class UserPage extends Page<import("../../common/components/Page"
* @type {User}
*/
user: any;
bodyClass: string | undefined;
/**
* Get the content to display in the user page.
*
@@ -39,13 +40,13 @@ export default class UserPage extends Page<import("../../common/components/Page"
*
* @return {ItemList}
*/
sidebarItems(): ItemList<any>;
sidebarItems(): ItemList;
/**
* Build an item list for the navigation in the sidebar.
*
* @return {ItemList}
*/
navItems(): ItemList<any>;
navItems(): ItemList;
}
import Page from "../../common/components/Page";
import ItemList from "../../common/utils/ItemList";

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