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

Compare commits

..

4 Commits

Author SHA1 Message Date
luceos
43f379093c Apply fixes from StyleCI
[ci skip] [skip ci]
2021-05-31 13:45:05 +00:00
Daniel Klabbers
f5c602c234 wip 2021-05-31 15:44:37 +02:00
luceos
0727f3d6d4 Apply fixes from StyleCI
[ci skip] [skip ci]
2021-05-30 09:53:09 +00:00
Daniël Klabbers
979a471214 modifying migrator and moving files 2021-05-30 11:52:30 +02:00
595 changed files with 18355 additions and 15485 deletions

1
.gitattributes vendored
View File

@@ -12,6 +12,5 @@ tests export-ignore
js/dist/* -diff
js/dist/* linguist-generated
js/dist-typings/* linguist-generated
* text=auto eol=lf

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
github: flarum
open_collective: flarum
tidelift: packagist/flarum/core

24
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,24 @@
<!--
IMPORTANT: We applaud pull requests, they excite us every single time. As we have an obligation to maintain a healthy code standard and quality, we take sufficient time for reviews. Please do create a separate pull request per change/issue/feature; we will ask you to split bundled pull requests.
-->
**Fixes #0000**
**Changes proposed in this pull request:**
<!-- fill this out, mention the pages and/or components which have been impacted -->
**Reviewers should focus on:**
<!-- fill this out, ask for feedback on specific changes you are unsure about -->
**Screenshot**
<!-- include an image of the most relevant user-facing change, if any -->
**Confirmed**
- [ ] Frontend changes: tested on a local Flarum installation.
- [ ] Backend changes: tests are green (run `composer test`).
**Required changes:**
- [ ] Related documentation PR: (Remove if irrelevant)
- [ ] Related core extension PRs: (Remove if irrelevant)

13
.github/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
We will only patch security vulnerabilities in the stable 1.x release.
## Reporting a Vulnerability
If you discover a security vulnerability within Flarum, please send an email to security@flarum.org so we can address it promptly.
We will get back to you as time allows.
Discussions may commence internally, so you may not hear back immediately.
When reporting a vulnerability, please provide your GitHub username (if available), so that we can invite you to collaborate on a [security advisory on GitHub](https://help.github.com/en/articles/about-maintainer-security-advisories).

33
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: JavaScript
on:
push:
branches:
- master
jobs:
build:
name: JS / Build
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Restore npm cache
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('js/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
- name: Build production JS
uses: flarum/action-build@2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: npm
typings_script: build-typings

View File

@@ -1,137 +0,0 @@
name: JS
on: [workflow_dispatch, push, pull_request]
env:
NODE_VERSION: 16
jobs:
prettier:
name: Prettier
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 install --immutable
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
working-directory: ./js
build-prod:
name: Build and commit
runs-on: ubuntu-latest
needs: [prettier, typecheck, type-coverage]
# Only commit JS on push to master branch
# Remember to change in `build-test` job too
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
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
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
- name: Build production JS
uses: flarum/action-build@2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: yarn
typings_script: build-typings
build-test:
name: Test build
runs-on: ubuntu-latest
needs: [prettier, typecheck, type-coverage]
# Inverse check of `build-prod`
# Remember to change in `build-prod` job too
if: github.ref != 'refs/heads/master' || github.event_name != 'push'
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
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
- name: Build production JS
uses: flarum/action-build@2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: yarn
typings_script: build-typings
do_not_commit: true

28
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Lint
on:
workflow_dispatch:
push:
paths:
- 'js/src/**'
pull_request:
paths:
- 'js/src/**'
jobs:
prettier:
name: JS / Prettier
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: "14"
- name: Check JS formatting
run: npx prettier --check src
working-directory: ./js

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,90 +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
- Upgrade to v1.0 resets the "view" permission on all tags (https://github.com/flarum/core/pull/2941)
## [1.0.3](https://github.com/flarum/core/compare/v1.0.2...v1.0.3)
### Changed
- Removed [forum] prefix from Request Password and Email Confirmation emails ([a4a81c0](https://github.com/flarum/core/commit/a4a81c0ec237476cd6e7ca00c1ed9465493af476))
- Adopt huntr.dev for handling our security vulnerability reports (https://github.com/flarum/core/pull/2918)
- Maintenance handler can now be replaced through the service container (ioc) ([4acff91](https://github.com/flarum/core/commit/4acff91f8063fcced9bf8c9a76fbb510d06823c0))
- The colors on the auto generated avatars are now based on the Display Name of the user (https://github.com/flarum/core/pull/2873)
### Fixed
- Avatar in notifications list are incorrectly aligned (https://github.com/flarum/core/pull/2906)
- FilesystemManager is not compatible with upstream Laravel implementation (https://github.com/flarum/core/pull/2936)
## [1.0.2](https://github.com/flarum/core/compare/v1.0.1...v1.0.2)
### Fixed
- Critical XSS vulnerability
## [1.0.1](https://github.com/flarum/core/compare/v1.0.0...v1.0.1)
### Fixed
- Installation fails on environments without proc_* functions enabled or mysql client binary (https://github.com/flarum/core/issues/2890)
## [1.0.0](https://github.com/flarum/core/compare/v0.1.0-beta.16...v1.0.0)
### Added

View File

@@ -5,7 +5,6 @@
<a href="https://packagist.org/packages/flarum/core"><img src="https://img.shields.io/packagist/dt/flarum/core" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/flarum/core"><img src="https://img.shields.io/github/v/release/flarum/core?sort=semver" alt="Latest Version"></a>
<a href="https://packagist.org/packages/flarum/core"><img src="https://img.shields.io/packagist/l/flarum/core" alt="License"></a>
<a href="https://huntr.dev/bounties/disclose/?target=https://github.com/flarum/core"><img src="https://cdn.huntr.dev/huntr_security_badge_mono.svg" alt="huntr"></a>
<a href="https://github.styleci.io/repos/28257573"><img src="https://github.styleci.io/repos/28257573/shield?style=flat" alt="StyleCI"></a>
</p>

View File

@@ -14,26 +14,10 @@
"homepage": "https://flarum.org/team"
}
],
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/flarum"
},
{
"type": "github",
"url": "https://github.com/sponsors/flarum"
},
{
"type": "other",
"url": "https://flarum.org/donate"
}
],
"support": {
"issues": "https://github.com/flarum/core/issues",
"source": "https://github.com/flarum/core",
"docs": "https://docs.flarum.org",
"forum": "https://discuss.flarum.org",
"chat": "https://flarum.org/chat"
"docs": "https://flarum.org/docs/"
},
"require": {
"php": ">=7.3",
@@ -59,7 +43,7 @@
"illuminate/support": "^8.0",
"illuminate/validation": "^8.0",
"illuminate/view": "^8.0",
"intervention/image": "2.5.* || ^2.6.1",
"intervention/image": "^2.5.0",
"laminas/laminas-diactoros": "^2.4.1",
"laminas/laminas-httphandlerrunner": "^1.2.0",
"laminas/laminas-stratigility": "^3.2.2",

9
js/.gitignore vendored
View File

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

6
js/.prettierrc.json Normal file
View File

@@ -0,0 +1,6 @@
{
"printWidth": 150,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}

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

39
js/@types/global/index.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
// Mithril
import Mithril from 'mithril';
// Other third-party libs
import * as _dayjs from 'dayjs';
import * as _$ from 'jquery';
// Globals from flarum/core
import Application from '../../src/common/Application';
import type { TooltipJQueryFunction } from '../tooltips';
/**
* flarum/core exposes several extensions globally:
*
* - jQuery for convenient DOM manipulation
* - Mithril for VDOM and components
* - dayjs for date/time operations
*
* Since these are already part of the global namespace, extensions won't need
* to (and should not) bundle these themselves.
*/
declare global {
// $ is already defined by `@types/jquery`
const m: Mithril.Static;
const dayjs: typeof _dayjs;
// Extend JQuery with our custom functions, defined with $.fn
interface JQuery {
tooltip: TooltipJQueryFunction;
}
}
/**
* All global variables owned by flarum/core.
*/
declare global {
const app: Application;
}

View File

@@ -1,114 +0,0 @@
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.
*
* @example App in forum JS
* ```
* import app from 'flarum/forum/app';
* ```
*
* @example App in admin JS
* ```
* import app from 'flarum/admin/app';
* ```
*
* @example App in common JS
* ```
* import app from 'flarum/common/app';
* ```
*/
declare const app: never;
declare const m: import('mithril').Static;
declare const dayjs: typeof import('dayjs');
type ESModule = { __esModule: true; [key: string]: unknown };
/**
* The global `flarum` variable.
*
* Contains the compiled ES Modules for all Flarum extensions and core.
*
* @example <caption>Check if `flarum-tags` is present</captions>
* if ('flarum-tags' in flarum.extensions) {
* // Tags is installed and enabled!
* }
*/
interface FlarumObject {
/**
* Contains the compiled ES Module for Flarum's core.
*
* You shouldn't need to access this directly for any reason.
*/
core: Readonly<ESModule>;
/**
* Contains the compiled ES Modules for all Flarum extensions.
*
* @example <caption>Check if `flarum-tags` is present</captions>
* if ('flarum-tags' in flarum.extensions) {
* // Tags is installed and enabled!
* }
*/
extensions: Readonly<Record<string, ESModule>>;
}
declare const flarum: FlarumObject;
// Extend JQuery with our custom functions, defined with $.fn
interface JQuery {
/**
* Flarum's tooltip JQuery plugin.
*
* Do not use this directly. Instead use the `<Tooltip>` component that
* is exported from `flarum/common/components/Tooltip`.
*
* This will be removed in a future version of Flarum.
*
* @deprecated
*/
tooltip: import('./tooltips/index').TooltipJQueryFunction;
}
/**
* For more info, see: https://www.typescriptlang.org/docs/handbook/jsx.html#attribute-type-checking
*
* In a nutshell, we need to add `ElementAttributesProperty` to tell Typescript
* what property on component classes to look at for attribute typings. For our
* Component class, this would be `attrs` (e.g. `this.attrs...`)
*/
interface JSX {
ElementAttributesProperty: {
attrs: Record<string, unknown>;
};
}
interface Event {
/**
* Whether this event should trigger a Mithril redraw.
*/
redraw: boolean;
}

View File

@@ -0,0 +1,39 @@
// Mithril
import Mithril from 'mithril';
// Other third-party libs
import * as _dayjs from 'dayjs';
import * as _$ from 'jquery';
// Globals from flarum/core
import Application from '../../src/common/Application';
import type { TooltipJQueryFunction } from '../tooltips';
/**
* flarum/core exposes several extensions globally:
*
* - jQuery for convenient DOM manipulation
* - Mithril for VDOM and components
* - dayjs for date/time operations
*
* Since these are already part of the global namespace, extensions won't need
* to (and should not) bundle these themselves.
*/
declare global {
// $ is already defined by `@types/jquery`
const m: Mithril.Static;
const dayjs: typeof _dayjs;
// Extend JQuery with our custom functions, defined with $.fn
interface JQuery {
tooltip: TooltipJQueryFunction;
}
}
/**
* All global variables owned by flarum/core.
*/
declare global {
const app: Application;
}

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;
@@ -95,7 +96,6 @@ declare var _default: {
'utils/ExtensionData': typeof ExtensionData;
'utils/isExtensionEnabled': typeof isExtensionEnabled;
'utils/getCategorizedExtensions': typeof getCategorizedExtensions;
'utils/generateElementId': typeof generateElementId;
'components/SettingDropdown': typeof SettingDropdown;
'components/EditCustomFooterModal': typeof EditCustomFooterModal;
'components/SessionDropdown': typeof SessionDropdown;
@@ -132,7 +132,6 @@ import saveSettings from "./utils/saveSettings";
import ExtensionData from "./utils/ExtensionData";
import isExtensionEnabled from "./utils/isExtensionEnabled";
import getCategorizedExtensions from "./utils/getCategorizedExtensions";
import generateElementId from "./utils/generateElementId";
import SettingDropdown from "./components/SettingDropdown";
import EditCustomFooterModal from "./components/EditCustomFooterModal";
import SessionDropdown from "./components/SessionDropdown";

View File

@@ -1,4 +1,4 @@
export default class AdminHeader extends Component<import("../../common/Component").ComponentAttrs, undefined> {
export default class AdminHeader extends Component<import("../../common/Component").ComponentAttrs> {
constructor();
}
import Component from "../../common/Component";

View File

@@ -1,4 +1,4 @@
export default class AdminNav extends Component<import("../../common/Component").ComponentAttrs, undefined> {
export default class AdminNav extends Component<import("../../common/Component").ComponentAttrs> {
constructor();
query: Stream<string> | undefined;
scrollToActive(): void;
@@ -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,109 +1,17 @@
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;
export default class AdminPage extends Page {
settings: {} | undefined;
loading: boolean | undefined;
content(): string;
submitButton(): JSX.Element;
header(): JSX.Element;
headerInfo(): {
className: string;
icon: string;
title: string;
description: string;
};
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.
* 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.
@@ -134,34 +42,14 @@ export default abstract class AdminPage<CustomAttrs extends IPageAttrs = IPageAt
* default: 'option1',
* }
*
* @example
*
* () => {
* return <p>My cool component</p>;
* }
*/
buildSettingComponent(entry: ((this: this) => Mithril.Children) | SettingsComponentOptions): Mithril.Children;
/**
* Called when `saveSettings` completes successfully.
* @param setting
* @returns {JSX.Element}
*/
buildSettingComponent(entry: any): JSX.Element;
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.
*/
setting(key: any, fallback?: string): any;
dirty(): {};
isChanged(): number;
/**
* Saves the modified settings to the database.
*/
saveSettings(e: SubmitEvent & {
redraw: boolean;
}): Promise<void>;
saveSettings(e: any): Promise<void>;
}
export {};
import Page from "../../common/components/Page";

View File

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

View File

@@ -1,5 +1,4 @@
export default class BasicsPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
export default class BasicsPage extends AdminPage {
localeOptions: {} | undefined;
displayNameOptions: {} | undefined;
slugDriverOptions: {} | undefined;
@@ -10,7 +9,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,5 @@
export default class DashboardPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
availableWidgets(): ItemList<any>;
export default class DashboardPage extends AdminPage {
availableWidgets(): ItemList;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,4 +1,4 @@
export default class DashboardWidget extends Component<import("../../common/Component").ComponentAttrs, undefined> {
export default class DashboardWidget extends Component<import("../../common/Component").ComponentAttrs> {
constructor();
/**
* Get the class name to apply to the widget.

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,6 @@
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 {
extension: any;
changingState: boolean | undefined;
infoFields: {
discuss: string;
documentation: string;
@@ -17,16 +8,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

@@ -2,7 +2,7 @@
* The `HeaderPrimary` component displays primary header controls. On the
* default skin, these are shown just to the right of the forum title.
*/
export default class HeaderPrimary extends Component<import("../../common/Component").ComponentAttrs, undefined> {
export default class HeaderPrimary extends Component<import("../../common/Component").ComponentAttrs> {
constructor();
config(isInitialized: any, context: any): void;
/**
@@ -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

@@ -1,14 +1,14 @@
/**
* The `HeaderSecondary` component displays secondary header controls.
*/
export default class HeaderSecondary extends Component<import("../../common/Component").ComponentAttrs, undefined> {
export default class HeaderSecondary extends Component<import("../../common/Component").ComponentAttrs> {
constructor();
/**
* Build an item list for the controls.
*
* @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,5 +1,4 @@
export default class MailPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
export default class MailPage extends AdminPage {
sendingTest: boolean | undefined;
refresh(): void;
status: {

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> {
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,4 +1,3 @@
export default class PermissionsPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
export default class PermissionsPage extends AdminPage {
}
import AdminPage from "./AdminPage";

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,5 +1,4 @@
export default class UploadImageButton extends Button<import("../../common/components/Button").IButtonAttrs> {
constructor();
export default class UploadImageButton extends Button {
loading: boolean;
/**
* Prompt the user to upload an image.

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 +0,0 @@
export { nanoid as default } from 'nanoid';

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

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
export interface ComponentAttrs extends Mithril.Attributes {
}
/**
@@ -28,7 +28,7 @@ export interface ComponentAttrs extends Mithril.Attributes {
*
* @see https://mithril.js.org/components.html
*/
export default abstract class Component<Attrs extends ComponentAttrs = ComponentAttrs, State = undefined> implements Mithril.ClassComponent<Attrs> {
export default abstract class Component<T extends ComponentAttrs = ComponentAttrs> implements Mithril.ClassComponent<T> {
/**
* The root DOM element for the component.
*/
@@ -38,47 +38,35 @@ export default abstract class Component<Attrs extends ComponentAttrs = Component
*
* @see https://mithril.js.org/components.html#passing-data-to-components
*/
protected attrs: Attrs;
/**
* Class component state that is persisted between redraws.
*
* Updating this will **not** automatically trigger a redraw, unlike
* other frameworks.
*
* This is different to Vnode state, which is always an instance of your
* class component.
*
* This is `undefined` by default.
*/
protected state: State;
protected attrs: T;
/**
* @inheritdoc
*/
abstract view(vnode: Mithril.Vnode<Attrs, this>): Mithril.Children;
abstract view(vnode: Mithril.Vnode<T, this>): Mithril.Children;
/**
* @inheritdoc
*/
oninit(vnode: Mithril.Vnode<Attrs, this>): void;
oninit(vnode: Mithril.Vnode<T, this>): void;
/**
* @inheritdoc
*/
oncreate(vnode: Mithril.VnodeDOM<Attrs, this>): void;
oncreate(vnode: Mithril.VnodeDOM<T, this>): void;
/**
* @inheritdoc
*/
onbeforeupdate(vnode: Mithril.VnodeDOM<Attrs, this>): void;
onbeforeupdate(vnode: Mithril.VnodeDOM<T, this>): void;
/**
* @inheritdoc
*/
onupdate(vnode: Mithril.VnodeDOM<Attrs, this>): void;
onupdate(vnode: Mithril.VnodeDOM<T, this>): void;
/**
* @inheritdoc
*/
onbeforeremove(vnode: Mithril.VnodeDOM<Attrs, this>): void;
onbeforeremove(vnode: Mithril.VnodeDOM<T, this>): void;
/**
* @inheritdoc
*/
onremove(vnode: Mithril.VnodeDOM<Attrs, this>): void;
onremove(vnode: Mithril.VnodeDOM<T, this>): void;
/**
* Returns a jQuery object for this component's element. If you pass in a
* selector string, this method will return a jQuery object, using the current
@@ -99,7 +87,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

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
/**
* The `Fragment` class represents a chunk of DOM that is rendered once with Mithril and then takes
* over control of its own DOM and lifecycle.
@@ -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,6 +0,0 @@
import type Application from './Application';
declare const _default: Application;
/**
* The instance of Application within the common namespace.
*/
export default _default;

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

@@ -1,5 +1,5 @@
import Component, { ComponentAttrs } from '../Component';
import type Mithril from 'mithril';
import Mithril from 'mithril';
export interface AlertAttrs extends ComponentAttrs {
/** The type of alert this is. Will be used to give the alert a class name of `Alert--{type}`. */
type?: string;
@@ -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

@@ -2,7 +2,8 @@
* The `AlertManager` component provides an area in which `Alert` components can
* be shown and dismissed.
*/
export default class AlertManager extends Component<import("../Component").ComponentAttrs, undefined> {
export default class AlertManager extends Component<import("../Component").ComponentAttrs> {
constructor();
state: any;
}
import Component from "../Component";

View File

@@ -11,7 +11,7 @@
*
* All other attrs will be assigned as attributes on the badge element.
*/
export default class Badge extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Badge extends Component<import("../Component").ComponentAttrs> {
constructor();
}
import Component from "../Component";

View File

@@ -1,69 +1,29 @@
import type Mithril from 'mithril';
import Component, { ComponentAttrs } from '../Component';
export interface IButtonAttrs extends ComponentAttrs {
/**
* Class(es) of an optional icon to be rendered within the button.
*
* If provided, the button will gain a `has-icon` class.
*/
icon?: string;
/**
* Disables button from user input.
*
* Default: `false`
*/
disabled?: boolean;
/**
* Show a loading spinner within the button.
*
* If `true`, also disables the button.
*
* Default: `false`
*/
loading?: boolean;
/**
* **DEPRECATED:** Please use the `aria-label` attribute instead. For tooltips, use
* the `<Tooltip>` component.
*
* Accessible text for the button. This should always be present if the button only
* contains an icon.
*
* The textual content of this attribute is passed to the DOM element as `aria-label`.
*
* @deprecated
*/
title?: string | Mithril.ChildArray;
/**
* Accessible text for the button. This should always be present if the button only
* contains an icon.
*
* The textual content of this attribute is passed to the DOM element as `aria-label`.
*/
'aria-label'?: string | Mithril.ChildArray;
/**
* Button type.
*
* Default: `"button"`
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type
*/
type?: string;
}
/**
* The `Button` component defines an element which, when clicked, performs an
* action.
*
* Other attrs will be assigned as attributes on the `<button>` element.
* ### Attrs
*
* - `icon` The name of the icon class. If specified, the button will be given a
* 'has-icon' class name.
* - `disabled` Whether or not the button is disabled. If truthy, the button
* will be given a 'disabled' class name, and any `onclick` handler will be
* removed.
* - `loading` Whether or not the button should be in a disabled loading state.
*
* All other attrs will be assigned as attributes on the button element.
*
* Note that a Button has no default class names. This is because a Button can
* be used to represent any generic clickable control, like a menu item. Common
* styles can be applied by providing `className="Button"` to the Button component.
* be used to represent any generic clickable control, like a menu item.
*/
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;
export default class Button extends Component<import("../Component").ComponentAttrs> {
constructor();
/**
* Get the template for the button's content.
*
* @return {*}
* @protected
*/
protected getButtonContent(children: Mithril.Children): Mithril.ChildArray;
protected getButtonContent(children: any): any;
}
import Component from "../Component";

View File

@@ -10,7 +10,7 @@
* - `onchange` A callback to run when the checkbox is checked/unchecked.
* - `children` A text label to display next to the checkbox.
*/
export default class Checkbox extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Checkbox extends Component<import("../Component").ComponentAttrs> {
constructor();
/**
* Get the template for the checkbox's display (tick/cross icon).

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

@@ -14,7 +14,7 @@
* another component / DOM element.)
*
*/
export default class ConfirmDocumentUnload extends Component<import("../Component").ComponentAttrs, undefined> {
export default class ConfirmDocumentUnload extends Component<import("../Component").ComponentAttrs> {
constructor();
handler(): any;
boundHandler: (() => any) | undefined;

View File

@@ -15,7 +15,7 @@
*
* The children will be displayed as a list inside of the dropdown menu.
*/
export default class Dropdown extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Dropdown extends Component<import("../Component").ComponentAttrs> {
static initAttrs(attrs: any): void;
constructor();
showing: boolean | undefined;

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

@@ -7,7 +7,7 @@
*
* The children should be an array of items to show in the fieldset.
*/
export default class FieldSet extends Component<import("../Component").ComponentAttrs, undefined> {
export default class FieldSet extends Component<import("../Component").ComponentAttrs> {
constructor();
}
import Component from "../Component";

View File

@@ -6,7 +6,7 @@
* Links will default to internal; the 'external' attr must be set to
* `true` for the link to be external.
*/
export default class Link extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Link extends Component<import("../Component").ComponentAttrs> {
constructor();
}
import Component from "../Component";

View File

@@ -11,7 +11,7 @@
* the `active` prop will automatically be set to true.
* - `force` Whether the page should be fully rerendered. Defaults to `true`.
*/
export default class LinkButton extends Button<import("./Button").IButtonAttrs> {
export default class LinkButton extends Button {
static initAttrs(attrs: any): void;
/**
* Determine whether a component with the given attrs is 'active'.
@@ -20,6 +20,5 @@ export default class LinkButton extends Button<import("./Button").IButtonAttrs>
* @return {Boolean}
*/
static isActive(attrs: Object): boolean;
constructor();
}
import Button from "./Button";

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> {
/**
* 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> {
constructor();
animateShow(readyCallback: any): void;
animateHide(): void;
}
export {};
import Component from "../Component";

View File

@@ -13,7 +13,7 @@
* - `drawer` Whether or not to show a button to toggle the app's drawer if
* there is no more history to pop.
*/
export default class Navigation extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Navigation extends Component<import("../Component").ComponentAttrs> {
constructor();
/**
* Get the back button.

View File

@@ -1,28 +1,27 @@
import type Mithril from 'mithril';
import Component from '../Component';
export interface IPageAttrs {
key?: number;
routeName: string;
}
/**
* The `Page` component
*
* @abstract
*/
export default abstract class Page<CustomAttrs extends IPageAttrs = IPageAttrs> extends Component<CustomAttrs> {
export default class Page extends Component<import("../Component").ComponentAttrs> {
constructor();
/**
* A class name to apply to the body while the route is active.
*
* @type {String}
*/
protected bodyClass: string;
bodyClass: string | undefined;
/**
* Whether we should scroll to the top of the page when its rendered.
*
* @type {Boolean}
*/
protected scrollTopOnCreate: boolean;
scrollTopOnCreate: boolean | undefined;
/**
* Whether the browser should restore scroll state on refreshes.
*
* @type {Boolean}
*/
protected useBrowserScrollRestoration: boolean;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
onremove(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
useBrowserScrollRestoration: boolean | undefined;
}
import Component from "../Component";

View File

@@ -6,7 +6,7 @@
*
* - `text`
*/
export default class Placeholder extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Placeholder extends Component<import("../Component").ComponentAttrs> {
constructor();
}
import Component from "../Component";

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

@@ -6,11 +6,8 @@
* - `onchange` A callback to run when the selected value is changed.
* - `value` The value of the selected option.
* - `disabled` Disabled state for the input.
* - `wrapperAttrs` A map of attrs to be passed to the DOM element wrapping the `<select>`
*
* Other attributes are passed directly to the `<select>` element rendered to the DOM.
*/
export default class Select extends Component<import("../Component").ComponentAttrs, undefined> {
export default class Select extends Component<import("../Component").ComponentAttrs> {
constructor();
}
import Component from "../Component";

View File

@@ -2,7 +2,7 @@ export default Separator;
/**
* The `Separator` component defines a menu separator item.
*/
declare class Separator extends Component<import("../Component").ComponentAttrs, undefined> {
declare class Separator extends Component<import("../Component").ComponentAttrs> {
constructor();
}
declare namespace Separator {

View File

@@ -11,7 +11,7 @@
* - `disabled`
* - `preview`
*/
export default class TextEditor extends Component<import("../Component").ComponentAttrs, undefined> {
export default class TextEditor extends Component<import("../Component").ComponentAttrs> {
constructor();
/**
* The value of the editor.
@@ -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

@@ -1,14 +1,8 @@
/**
* The `TextEditorButton` component displays a button suitable for the text
* editor toolbar.
*
* Automatically creates tooltips using the Tooltip component and provided text.
*
* ## Attrs
* - `title` - Tooltip for the button
*/
export default class TextEditorButton extends Button<import("./Button").IButtonAttrs> {
export default class TextEditorButton extends Button {
static initAttrs(attrs: any): void;
constructor();
}
import Button from "./Button";

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 * as Mithril from 'mithril';
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,12 +0,0 @@
/**
* Calls `console.warn` with the provided arguments, but only if the forum is in debug mode.
*
* This function is intended to provide warnings to extension developers about issues with
* their extensions that may not be easily noticed when testing, such as accessibility
* issues.
*
* These warnings should be hidden on production forums to ensure webmasters are not
* inundated with do-gooders telling them they have an issue when it isn't something they
* can fix.
*/
export default function fireDebugWarning(...args: Parameters<typeof console.warn>): void;

View File

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
/**
* The `fullTime` helper displays a formatted time string wrapped in a <time>
* tag.

View File

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
/**
* The `highlight` helper searches for a word phrase in a string, and wraps
* matches with the <mark> tag.

View File

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
/**
* The `humanTime` helper displays a time in a human-friendly time-ago format
* (e.g. '12 days ago'), wrapped in a <time> tag with other information about

View File

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
/**
* The `icon` helper displays an icon.
*

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;
};
};
import * as Mithril from 'mithril';
/**
* 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

@@ -1,6 +1,6 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
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,4 +1,4 @@
import type Mithril from 'mithril';
import * as Mithril from 'mithril';
import User from '../models/User';
/**
* The `username` helper displays a user's username in a <span class="username">

View File

@@ -1,3 +1,2 @@
export { Extend };
import * as Extend from "./extend/index";
import app from "./app";
export { Extend, app };

View File

@@ -1,30 +1,21 @@
import type Mithril from 'mithril';
import type { RouteResolver } from '../Application';
import type { default as Component, ComponentAttrs } from '../Component';
import Mithril from 'mithril';
/**
* 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

@@ -1,4 +1,4 @@
import type Mithril from 'mithril';
import Mithril from 'mithril';
import Alert, { AlertAttrs } from '../components/Alert';
/**
* Returned by `AlertManagerState.show`. Used to dismiss alerts.
@@ -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);
}

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