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

Compare commits

..

17 Commits

Author SHA1 Message Date
luceos
68cacd5404 Apply fixes from StyleCI
[ci skip] [skip ci]
2020-11-30 23:15:36 +00:00
Matthew Kilgore
345a8e5773 Update UrlGenerator 2020-11-30 18:15:19 -05:00
luceos
1cbaef579c Apply fixes from StyleCI
[ci skip] [skip ci]
2020-11-30 23:03:42 +00:00
Matthew Kilgore
8fb65e9de7 Use Repositories instead of models 2020-11-30 18:03:25 -05:00
Matthew Kilgore
92a5b98b77 Fix some review issues 2020-11-26 20:45:09 -05:00
Matthew Kilgore
1eb316bf44 Make min search length a constant 2020-11-26 08:09:34 -05:00
luceos
47e8990813 Apply fixes from StyleCI
[ci skip] [skip ci]
2020-11-26 08:09:34 -05:00
Matthew Kilgore
dbce6705fd Made frontend discussion slug independent 2020-11-26 08:09:34 -05:00
Matthew Kilgore
9de6ebbe4f Working Admin Page 2020-11-26 08:09:34 -05:00
luceos
f63ca2be3c Apply fixes from StyleCI
[ci skip] [skip ci]
2020-11-26 08:09:34 -05:00
Matthew Kilgore
6a1017d4b1 Slug Extender Test works 2020-11-26 08:09:34 -05:00
luceos
696dc8ef6b Apply fixes from StyleCI
[ci skip] [skip ci]
2020-11-26 08:09:34 -05:00
Matthew Kilgore
a8fa57ad30 WIP Extender 2020-11-26 08:09:34 -05:00
Alexander Skvortsov
9ff02f8822 Format 2020-11-26 08:09:34 -05:00
Alexander Skvortsov
dde718e27f Fix user ShowTests 2020-11-26 08:09:34 -05:00
luceos
a155e41432 Apply fixes from StyleCI
[ci skip] [skip ci]
2020-11-26 08:09:34 -05:00
Matthew Kilgore
4574fa6290 Initial Driver Support (No Extender) 2020-11-26 08:09:34 -05:00
996 changed files with 18412 additions and 43093 deletions

View File

@@ -15,5 +15,5 @@ indent_size = 2
[*.{diff,md}]
trim_trailing_whitespace = false
[*.{php,xml,json}]
[*.{php,xml}]
indent_size = 4

2
.gitattributes vendored
View File

@@ -11,7 +11,5 @@ phpunit.xml export-ignore
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
During the beta phase, we will only patch security vulnerabilities in the latest beta 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).

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

@@ -0,0 +1,16 @@
name: JavaScript
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: flarum/action-build@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,76 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
# Run on:
# - pushes to master, or
# - PRs with a base of `master`
# - which do not **only** consist of changes to .md or .less files
on:
push:
branches: [ master ]
paths-ignore:
- '**/*.md'
- '**/*.less'
pull_request:
branches: [ master ]
paths-ignore:
- '**/*.md'
- '**/*.less'
schedule:
- cron: '0 0 * * 1,3,5'
jobs:
analyze:
name: Analyze / ${{ matrix.language }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

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
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

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

@@ -0,0 +1,31 @@
name: Lint
on:
push:
paths:
- 'js/src/**'
pull_request:
paths:
- 'js/src/**'
jobs:
prettier:
runs-on: ubuntu-latest
name: JS / Prettier
steps:
- uses: actions/checkout@master
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: "12"
- name: Install JS dependencies
run: npm ci
working-directory: ./js
- name: Check JS code for formatting
run: node_modules/.bin/prettier --check src
working-directory: ./js

View File

@@ -1,45 +0,0 @@
name: Bundle size checker
on:
workflow_dispatch:
push:
paths:
- "js/**"
pull_request:
paths:
- "js/**"
jobs:
bundlewatch:
runs-on: ubuntu-latest
name: Bundlewatch
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- name: Use npm v7
run: sudo npm install -g npm@7.x.x
- name: Install JS dependencies
# We need to use `npm install` here. If we don't, the workflow will fail.
run: npm install
working-directory: ./js
- name: Build production assets
run: npm run build
working-directory: ./js
- name: Check bundle size change
run: node_modules/.bin/bundlewatch --config .bundlewatch.config.json
working-directory: ./js
env:
BUNDLEWATCH_GITHUB_TOKEN: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}

View File

@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
php: [7.3, 7.4, '8.0', '8.1']
php: [7.2, 7.3, 7.4]
service: ['mysql:5.7', mariadb]
prefix: ['', flarum_]
@@ -21,16 +21,16 @@ jobs:
prefixStr: (prefix)
exclude:
- php: 7.3
- php: 7.2
service: 'mysql:5.7'
prefix: flarum_
- php: 7.3
- php: 7.2
service: mariadb
prefix: flarum_
- php: 8.0
- php: 7.3
service: 'mysql:5.7'
prefix: flarum_
- php: 8.0
- php: 7.3
service: mariadb
prefix: flarum_
@@ -43,25 +43,15 @@ jobs:
name: 'PHP ${{ matrix.php }} / ${{ matrix.db }} ${{ matrix.prefixStr }}'
steps:
- name: Check out code
uses: actions/checkout@v2
- uses: actions/checkout@master
- name: Setup PHP
uses: shivammathur/setup-php@0b9d33cd0782337377999751fc10ea079fdd7104 # pin@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
extensions: curl, dom, gd, json, mbstring, openssl, pdo_mysql, tokenizer, zip
tools: phpunit, composer:v2
- name: Select PHP version
run: sudo update-alternatives --set php $(which php${{ matrix.php }})
# The authentication alter is necessary because newer mysql versions use the `caching_sha2_password` driver,
# which isn't supported prior to PHP7.4
# When we drop support for PHP7.3, we should remove this from the setup.
- name: Create MySQL Database
run: |
sudo systemctl start mysql
mysql -uroot -proot -e 'CREATE DATABASE flarum_test;' --port 13306
mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';" --port 13306
- name: Install Composer dependencies
run: composer install
@@ -75,5 +65,3 @@ jobs:
- name: Run Composer tests
run: composer test
env:
COMPOSER_PROCESS_TIMEOUT: 600

4
.gitignore vendored
View File

@@ -1,11 +1,9 @@
/vendor
composer.lock
composer.phar
node_modules
.DS_Store
Thumbs.db
tests/.phpunit.result.cache
/tests/integration/tmp
.vagrant
.idea/*
.vscode
js/coverage-ts

View File

@@ -12,3 +12,7 @@ disabled:
- phpdoc_order
- phpdoc_separation
- phpdoc_types
finder:
exclude:
- "stubs"

View File

@@ -1,315 +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
- Task scheduling
- `load()` method on `ApiController` extender to allow eager loading of relations (https://github.com/flarum/core/pull/2724)
- Installation supports enabling a set of extensions (https://github.com/flarum/core/pull/2757)
- RequestUtil helper class added to abstract the logic of the actor, session, locale and route name from the request (https://github.com/flarum/core/pull/2449)
- Code scanning action with GitHub CodeQL (https://github.com/flarum/core/pull/2744)
- The Formatter extender now has an `unparse` method to allow extensions to hook into the unparsing of content (https://github.com/flarum/core/pull/2780)
- A Filesystem extender allows direct modification and addition of filesystem disks (https://github.com/flarum/core/pull/2732)
- A slug driver based on the User ID was introduced (https://github.com/flarum/core/pull/2787)
- An extensible users list was added to the admin area (https://github.com/flarum/core/pull/2626)
- Headers hardened by adding Referer Policy, Xss Protection and Content type (https://github.com/flarum/core/pull/2721)
- Tooltip component (https://github.com/flarum/core/pull/2843)
- Moved `insertText` and `styleSelectedText` from markdown to core (https://github.com/flarum/core/pull/2826)
- A squashed database schema install dump to speed up new installs (https://github.com/flarum/core/pull/2842)
- Pagination in the canonical URL for discussion pages (https://github.com/flarum/core/pull/2853)
- PaginatedListState for the DiscussionList and to support paginated lists in the frontend (https://github.com/flarum/core/pull/2781)
- Introduce the new webpack config and flarum-tsconfig for typehinting (https://github.com/flarum/core/pull/2856)
### Changed
- Now tracking bundle sizes to keep an eye on web performance (https://github.com/flarum/core/pull/2695)
- Eager load relations on ListPostsController to improve performance (https://github.com/flarum/core/pull/2717)
- Replace classList with clsx library (https://github.com/flarum/core/pull/2760)
- Replaced the javascript based loading spinner with a pure CSS version (https://github.com/flarum/core/pull/2764)
- Route names now have to be unique (https://github.com/flarum/core/pull/2771)
- ActorReference is now available from the error handler middleware (https://github.com/flarum/core/pull/2410)
- The `migrations` table now has an Auto Increment ID (https://github.com/flarum/core/pull/2794)
- Assets and avatars are now managed using Laravel filesystem disks (https://github.com/flarum/core/pull/2729)
- Extracted asset publishing (`php flarum assets:publish`) from migrating (https://github.com/flarum/core/pull/2731)
- Assets were compiled in the format `<asset>-<revision>.<js|css>`, this is now `<asset>.<js|css>?v=<revision>` (https://github.com/flarum/core/pull/2805)
- The powered by header can now be configured in the config under `headers` (https://github.com/flarum/core/pull/2777)
- Switched to the ICU format for translation files (https://github.com/flarum/core/pull/2759)
- Allow extend and override to apply to multiple methods in one call
- Notifications dropdown and list refactored (https://github.com/flarum/core/pull/2822)
- Updated validation locale strings based on Laravel 8 changes (https://github.com/flarum/core/pull/2829)
- Caching of permissions is now taken care of centrally, reducing code duplication (https://github.com/flarum/core/pull/2832)
- Replaced lodash-es by throttle-debounce to reduce bundle size (https://github.com/flarum/core/pull/2827)
- Internal API requests are now executed through middleware (https://github.com/flarum/core/pull/2783)
- Permission changes: `viewDiscussions` to `viewForum` and `viewUserList` to `searchUsers` (https://github.com/flarum/core/pull/2854)
### Fixes
- Javascript is shown when editing the title of a discussion (https://github.com/flarum/core/pull/2693)
- Canonical url logic uses request object which causes wrong URL's when a different page is default (https://github.com/flarum/core/pull/2674)
- Dropdown toggle has no aria label (https://github.com/flarum/core/pull/2668)
- Nav drawer is focusable when off-screen on small viewports (https://github.com/flarum/core/pull/2666)
- Search input has no aria-label and no role (https://github.com/flarum/core/pull/2669)
- Code duplication exists between SendConfirmationEmailController and AccountActivationMailer (https://github.com/flarum/core/pull/2493)
- When setting tags as homepage default, visiting a tag will show all posts (https://github.com/flarum/core/pull/2754)
- Locale cache is cleared twice when cache clearing (https://github.com/flarum/core/pull/2738)
- When cache clearing fails an exception can be thrown due to a partial flush (https://github.com/flarum/core/pull/2756)
- Database migrations rely on MyISAM even though the eventual migrated database does not use it (https://github.com/flarum/core/pull/2442)
- Discussion search result is not sorted by relevance by default (https://github.com/flarum/core/pull/2773)
- Extensions cannot register custom searcher classes (https://github.com/flarum/core/pull/2755)
- Searching discussion titles is not possible (https://github.com/flarum/core/pull/2698)
- Boot errors due to failing extenders throw a generic error (https://github.com/flarum/core/pull/2740)
- Required argument to `Component.$()` isn't really required (https://github.com/flarum/core/pull/2844)
- Component does not allows use of all mithril lifecycle functionality (https://github.com/flarum/core/pull/2847)
### Removed
- The `make:migration` command has been removed (https://github.com/flarum/core/pull/2686)
- Background fade on the header has been removed (https://github.com/flarum/core/pull/2685)
- Remove vendor prefixes in less (https://github.com/flarum/core/pull/2766)
- The session is no longer available from the User class (https://github.com/flarum/core/pull/2790)
- The `mail` key is removed from the laravel related config (https://github.com/flarum/core/pull/2796)
## [0.1.0-beta.16](https://github.com/flarum/core/compare/v0.1.0-beta.15...v0.1.0-beta.16)
### Added
- Allow event subscribers (https://github.com/flarum/core/pull/2535)
- Allow Settings extender to have a default value (https://github.com/flarum/core/pull/2495)
- Allow hooking into the sending of notifications before being send (https://github.com/flarum/core/pull/2533)
- PHP 8 support (https://github.com/flarum/core/pull/2507)
- Search extender (https://github.com/flarum/core/pull/2483)
- User badges to post preview (https://github.com/flarum/core/pull/2555)
- Optional extension dependencies allow a booting order (https://github.com/flarum/core/pull/2579)
- Auth extender (https://github.com/flarum/core/pull/2176)
- `X-Powered-By` header added to allow indexers easier data aggregation of Flarum adoption (https://github.com/flarum/core/pull/2618)
### Changed
- Run integration tests in transaction (https://github.com/flarum/core/pull/2304)
- Allow policies to return a boolean for simplified allow/deny (https://github.com/flarum/core/pull/2534)
- Converted highlight helper to typescript (https://github.com/flarum/core/pull/2532)
- Add accessibility attributes to Mark as Read button (https://github.com/flarum/core/pull/2564)
- Dismiss errors on change email modal upon a new request ([00913d5](https://github.com/flarum/core/commit/00913d5b0be2172cfce1f16aaf64a24f3d2e6d4b))
- Disabled extensions now are marked with a red circle instead of a red dot (https://github.com/flarum/core/pull/2562)
- Extension dependency errors now show the extension title instead of the ID (https://github.com/flarum/core/pull/2563)
- Change `mutate` method on ApiSerializer extender to `attributes` (https://github.com/flarum/core/pull/2578)
- Moved locale files to the core from the language pack (https://github.com/flarum/core/pull/2408)
- AdminPage extensibility and generic improvements (https://github.com/flarum/core/pull/2593)
- Remove entry of authors, link to https://flarum.org/team (https://github.com/flarum/core/pull/2625)
- Search and filtering are split (https://github.com/flarum/core/pull/2454)
- Move IP identification into a middleware (https://github.com/flarum/core/pull/2624)
- Editor Driver abstraction introduced (https://github.com/flarum/core/pull/2594)
- Allow overriding routes (https://github.com/flarum/core/pull/2577)
- Split user edit permissions into permissions for editing of user credentials, username, groups and suspending (https://github.com/flarum/core/pull/2620)
- Reduced number of admin extension categories (https://github.com/flarum/core/pull/2604)
- Move search related classes to a dedicated Query namespace (https://github.com/flarum/core/pull/2645)
- Rewrite common helpers into typescript (https://github.com/flarum/core/pull/2541)
- `TextEditor` is moved to the common namespace for use in the admin frontend (https://github.com/flarum/core/pull/2649)
- Update Laravel/Illuminate components to 8 (https://github.com/flarum/core/pull/2576)
- Eager load relations in discussion listing to improve performance (https://github.com/flarum/core/pull/2639)
- Adopt flarum/testing package (https://github.com/flarum/core/pull/2545)
- Replace `user` gambit with `author` gambit ([612a57c](https://github.com/flarum/core/commit/612a57c4664415a3ea120103483645c32acc6f12))
- Posts page of on user profile loads posts using username instead of id ([30017ee](https://github.com/flarum/core/commit/30017eef09ae9e78640c4e2cacd4909fffa8d775))
### Fixed
- Transform css breaks iOS scroll functionality (https://github.com/flarum/core/pull/2527)
- Composer header is hidden on mobile devices (https://github.com/flarum/core/pull/2279)
- Cannot delete a post or discussion of a deleted user (https://github.com/flarum/core/pull/2521)
- DiscussionListPane jumps around not keeping the scroll position (https://github.com/flarum/core/pull/2402)
- Infinite scroll on notifications dropdown broken (https://github.com/flarum/core/pull/2524)
- The show language selector switch remains toggled on ([9347b12](https://github.com/flarum/core/commit/9347b12b47bf4ab97ffb7ca92673604b237c1012))
- Model Visibility extender throws exception on extensions that aren't installed or enabled (https://github.com/flarum/core/pull/2580)
- Extensions are marked as enabled when enabling fails to unmet extension dependencies (https://github.com/flarum/core/pull/2558)
- Routes to admin extension pages without a valid ID break the admin page (https://github.com/flarum/core/pull/2584)
- Disabled fieldset use an incorrect CSS property `disallowed` (https://github.com/flarum/core/pull/2585)
- Scrolling to a post that is already loaded the Load More button shows and does not trigger (https://github.com/flarum/core/pull/2388)
- Opening discussions on some mobile devices require a double tap (https://github.com/flarum/core/pull/2607)
- iOS devices show erratic behavior in the post stream while updating (https://github.com/flarum/core/pull/2548)
- Small mobile screens partially hides the composer when the keyboard is open (https://github.com/flarum/core/pull/2631)
- Clearing cache does not clear the template cache in storage/views (https://github.com/flarum/core/pull/2648)
- Boot errors show critical information (https://github.com/flarum/core/pull/2633)
- List user endpoint discloses last online even if user choose against it (https://github.com/flarum/core/pull/2634)
- Group gambit disclosed hidden groups (https://github.com/flarum/core/pull/2657)
- Search results on small windows not fully visible (https://github.com/flarum/core/pull/2650)
- Composer goes off screen on Safari when starting to type (https://github.com/flarum/core/pull/2660)
- A search that has no results shows the search results dropdown ([b88a7cb](https://github.com/flarum/core/commit/b88a7cb33b56e318f11670e9e2d563aef94db039))
- The composer modal moves around when typing on Safari ([a64c398](https://github.com/flarum/core/commit/a64c39835aba43e831209609f4a9638ae589aa41))
### Removed
- Deprecated CSRF wildcard path match
- Deprecated policy and visibility scoping events
- Deprecated post types event
- Deprecated validation events
- Deprecated notification events
- Deprecated floodgate
- Deprecated user preferences event
- Deprecated formatting events
- Deprecated api events
- Deprecated bootstrap.php support
- PHP 7.2 support (https://github.com/flarum/core/pull/2507)
- Bidi attribute in the rendered HTML (https://github.com/flarum/core/pull/2602)
- `AccessToken::find`, use `AccessToken::findValid` instead (https://github.com/flarum/core/pull/2651)
### Deprecated
- `GetModelIsPrivate` event (https://github.com/flarum/core/pull/2587)
- `CheckingPassword` event (https://github.com/flarum/core/pull/2176)
- `event()` helper (https://github.com/flarum/core/pull/2608)
- `AccessToken::generate` argument `$lifetime` (https://github.com/flarum/core/pull/2651)
- `Rememberer::remember` argument `$token` should receive an instance of `RememberAccessToken` with `AccessToken` being deprecated (https://github.com/flarum/core/pull/2651)
- `Rememberer::rememberUser` (https://github.com/flarum/core/pull/2651)
- `SessionAuthenticator::logIn` argument `$userId`, should be replaced with `AccessToken` (https://github.com/flarum/core/pull/2651)
- `TextEditor` has been moved to `common` (https://github.com/flarum/core/pull/2649)
- `UserFilter` ([91e8b56](https://github.com/flarum/core/commit/91e8b569618957c86757ef89bac666e9102db5ae))
## [0.1.0-beta.15](https://github.com/flarum/core/compare/v0.1.0-beta.14.1...v0.1.0-beta.15)
### Added
- Slug drivers support (https://github.com/flarum/core/pull/2456).
- Notification type extender (https://github.com/flarum/core/pull/2424).
- Validation extender (https://github.com/flarum/core/pull/2102).
- Post extender (https://github.com/flarum/core/pull/2101).
- Notification channel extender (https://github.com/flarum/core/pull/2432).
- Service provider extender (https://github.com/flarum/core/pull/2437).
- API serializer extender (https://github.com/flarum/core/pull/2438).
- User preferences extender (https://github.com/flarum/core/pull/2463).
- Settings extender (https://github.com/flarum/core/pull/2452).
- ApiController extender (https://github.com/flarum/core/pull/2451).
- Model visibility extender (https://github.com/flarum/core/pull/2460).
- Policy extender (https://github.com/flarum/core/pull/2461).
### Changed
- Time helpers converted to Typescript (https://github.com/flarum/core/pull/2391).
- Improved the formatter extender (https://github.com/flarum/core/pull/2098).
- Improve wording on installer when facing file permission issues (https://github.com/flarum/core/pull/2435).
- Background color of checkbox toggles improved for better usability (https://github.com/flarum/core/pull/2443).
- Route resolving refactored (https://github.com/flarum/core/pull/2425).
- Administration panel UX refactored (https://github.com/flarum/core/pull/2409).
- Floodgate moved to middleware and extender added (https://github.com/flarum/core/pull/2170).
- DRY up image uploading logic (https://github.com/flarum/core/pull/2477).
- Process isolation on testing (https://github.com/flarum/core/commit/984f751c718c89501cc09857bc271efa2c7eea8c).
- Forum and admin javascript exports namespaced (https://github.com/flarum/core/pull/2488).
### Fixed
- Web updater does not take into account subfolder installations (https://github.com/flarum/core/pull/2426).
- Callables handling in extenders failed (https://github.com/flarum/core/pull/2423).
- Scrolling on mobile from PostSteam changes didn't work correctly (https://github.com/flarum/core/pull/2385).
- Side pane covers part of the discussion page due to `app.discussions` being empty (https://github.com/flarum/core/commit/102e76b084bf47fdfb4c73f95e1fbb322537f7aa).
- Change email modal keeps showing the previous error message even on success (https://github.com/flarum/core/pull/2467).
- Comment count not updated when discussions are deleted (https://github.com/flarum/core/pull/2472).
- `goToIndex` in PostStream does not trigger an xhr to retrieve new data (https://github.com/flarum/core/commit/09e2736cbcc267594b660beabbd001d9030f9880).
- On refresh the post number is reduced by one (https://github.com/flarum/core/pull/2476).
- Queue worker would instantiate a new Queue factory, not the bound one (https://github.com/flarum/core/pull/2481).
- Header accidentally has a border bottom (https://github.com/flarum/core/pull/2489).
- Namespace mentioned in docblock is incorrect (https://github.com/flarum/core/pull/2494).
- Scrolling inside longer discussions (especially Firefox) skips posts (https://github.com/flarum/core/commit/210a6b3e253d7917bd1eacd3ed8d2f95073ae99d).
- Uploading avatars that are jpg/jpeg fails with a validation error (https://github.com/flarum/core/pull/2497).
### Removed
- MomentJS alias (https://github.com/flarum/core/pull/2428).
- Deprecated user events `GetDisplayName` and `PrepareUserGroups` (https://github.com/flarum/core/pull/2428).
- AssertPermissionTrait (https://github.com/flarum/core/pull/2428).
- Path related helpers and methods in Application (https://github.com/flarum/core/pull/2428).
- Backward compatibility layers from the frontend rewrite (https://github.com/flarum/core/pull/2428).
### Deprecated
- `CheckingForFlooding` (https://github.com/flarum/core/commit/8e25bcb68f86cc992c46dfa70368419fe9f936ac).
## [0.1.0-beta.14.1](https://github.com/flarum/core/compare/v0.1.0-beta.14...v0.1.0-beta.14.1)
### Fixed
- SuperTextarea component is not exported.
- Symfony dependencies do not match those depended on by Laravel (https://github.com/flarum/core/pull/2407).
- Scripts from textformatter aren't executed (https://github.com/flarum/core/pull/2415)
- Sub path installations have no page title.
- Losing focus of Composer area when coming from fullscreen.
## [0.1.0-beta.14](https://github.com/flarum/core/compare/v0.1.0-beta.13...v0.1.0-beta.14)
### Added
@@ -452,7 +142,7 @@
- SES mail support (#2011)
- Backward compatibility layer for `Flarum\Mail\DriverInterface`, new methods from beta.12 are now required
- `Flarum\Util\Str` helper class
- `Flarum\Event\ConfigureMiddleware` event
- `Flarum\Event\ConfigureMiddleware` event
### Deprecated
- `Flarum\Event\AbstractConfigureRoutes` event class

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2019-2021 Stichting Flarum (Flarum Foundation)
Copyright (c) 2019-2020 Stichting Flarum (Flarum Foundation)
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -5,10 +5,10 @@
<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>
## About Flarum
**[Flarum](https://flarum.org/) is a delightfully simple discussion platform for your website.** It's fast and easy to use, with all the features you need to run a successful community. It is designed to be:
@@ -19,15 +19,13 @@
* **Powerful and extensible.** Customize, extend, and integrate Flarum to suit your community. Flarums architecture is amazingly flexible, with a powerful Extension API.
![Screenshot of a Flarum instance, showing multiple discussions and tags.](https://flarum.org/assets/img/home-screenshot.png)
## Installation
This repository contains Flarum's core code. If you want to set up a forum, visit the [Flarum skeleton repository](https://github.com/flarum/flarum). For support, refer to the [documentation](https://docs.flarum.org/), and ask questions on [Flarum Discuss](https://discuss.flarum.org/) (our community forum) or [Discord server](https://flarum.org/discord/).
This repository contains Flarum's core code. If you want to set up a forum, visit the [Flarum skeleton repository](https://github.com/flarum/flarum).
## Contributing
Thank you for considering contributing to Flarum! Please read the **[Contributing guide](https://docs.flarum.org/contributing)** to learn how you can help.
Thank you for considering contributing to Flarum! Please read the **[Contributing guide](https://flarum.org/docs/contributing.html)** to learn how you can help.
## Security Vulnerabilities

View File

@@ -1,73 +1,74 @@
{
"name": "flarum/core",
"description": "Delightfully simple forum software.",
"keywords": [
"forum",
"discussion"
],
"keywords": ["forum", "discussion"],
"homepage": "https://flarum.org/",
"license": "MIT",
"authors": [
{
"name": "Flarum",
"email": "info@flarum.org",
"homepage": "https://flarum.org/team"
}
],
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/flarum"
"name": "Franz Liedke",
"email": "franz@develophp.org"
},
{
"type": "github",
"url": "https://github.com/sponsors/flarum"
"name": "Daniël Klabbers",
"email": "daniel@klabbers.email",
"homepage": "https://luceos.com"
},
{
"type": "other",
"url": "https://flarum.org/donate"
"name": "David Sevilla Martin",
"email": "me+flarum@datitisev.me",
"homepage": "https://datitisev.me"
},
{
"name": "Clark Winkelmann",
"email": "clark.winkelmann@gmail.com",
"homepage": "https://clarkwinkelmann.com"
},
{
"name": "Matthew Kilgore",
"email": "matthew@kilgore.dev"
},
{
"name": "Alexander (Sasha) Skvortsov",
"email": "askvortsov@flarum.org"
}
],
"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",
"php": ">=7.2",
"axy/sourcemap": "^0.1.4",
"components/font-awesome": "^5.14.0",
"dflydev/fig-cookies": "^3.0.0",
"dflydev/fig-cookies": "^2.0.1",
"doctrine/dbal": "^2.7",
"dragonmantank/cron-expression": "^3.1.0",
"franzl/whoops-middleware": "^2.0.0",
"illuminate/bus": "^8.0",
"illuminate/cache": "^8.0",
"illuminate/config": "^8.0",
"illuminate/console": "^8.0",
"illuminate/container": "^8.0",
"illuminate/contracts": "^8.0",
"illuminate/database": "^8.0",
"illuminate/events": "^8.0",
"illuminate/filesystem": "^8.0",
"illuminate/hashing": "^8.0",
"illuminate/mail": "^8.0",
"illuminate/queue": "^8.0",
"illuminate/session": "^8.0",
"illuminate/support": "^8.0",
"illuminate/validation": "^8.0",
"illuminate/view": "^8.0",
"intervention/image": "2.5.* || ^2.6.1",
"laminas/laminas-diactoros": "^2.4.1",
"laminas/laminas-httphandlerrunner": "^1.2.0",
"laminas/laminas-stratigility": "^3.2.2",
"franzl/whoops-middleware": "^0.4.0",
"illuminate/bus": "^6.0",
"illuminate/cache": "^6.0",
"illuminate/config": "^6.0",
"illuminate/container": "^6.0",
"illuminate/contracts": "^6.0",
"illuminate/database": "^6.0",
"illuminate/events": "^6.0",
"illuminate/filesystem": "^6.0",
"illuminate/hashing": "^6.0",
"illuminate/mail": "^6.0",
"illuminate/queue": "^6.0",
"illuminate/session": "^6.0",
"illuminate/support": "^6.0",
"illuminate/validation": "^6.0",
"illuminate/view": "^6.0",
"intervention/image": "^2.5.0",
"laminas/laminas-diactoros": "^1.8.4",
"laminas/laminas-httphandlerrunner": "^1.0",
"laminas/laminas-stratigility": "^3.0",
"league/flysystem": "^1.0.11",
"matthiasmullie/minify": "^1.3",
"middlewares/base-path": "^2.0.1",
"middlewares/base-path-router": "^2.0.1",
"middlewares/request-handler": "^2.0.1",
"middlewares/base-path": "^1.1",
"middlewares/base-path-router": "^0.2.1",
"middlewares/request-handler": "^1.2",
"monolog/monolog": "^1.16.0",
"nesbot/carbon": "^2.0",
"nikic/fast-route": "^0.6",
@@ -75,18 +76,17 @@
"psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0",
"s9e/text-formatter": "^2.3.6",
"symfony/config": "^5.2.2",
"symfony/console": "^5.2.2",
"symfony/event-dispatcher": "^5.2.2",
"symfony/mime": "^5.2.0",
"symfony/polyfill-intl-messageformatter": "^1.22.0",
"symfony/translation": "^5.1.5",
"symfony/yaml": "^5.2.2",
"symfony/config": "^4.3.4",
"symfony/console": "^4.3.4",
"symfony/event-dispatcher": "^4.3.4",
"symfony/translation": "^4.3.4",
"symfony/yaml": "^4.3.4",
"tobscure/json-api": "^0.3.0",
"wikimedia/less.php": "^3.0"
},
"require-dev": {
"flarum/testing": "1.0@dev"
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^7.0"
},
"autoload": {
"psr-4": {
@@ -106,7 +106,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
"dev-master": "0.1.x-dev"
}
},
"scripts": {

View File

@@ -1,8 +0,0 @@
{
"files": [
{
"path": "./dist/*.js"
}
],
"defaultCompression": "gzip"
}

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

View File

@@ -1,2 +1,11 @@
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
export * from './src/common';
export * from './src/admin';

View File

@@ -1,138 +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];
type Component<A> = import('mithril').Component<A>;
declare type ComponentClass<Attrs = Record<string, unknown>, C extends Component<Attrs> = Component<Attrs>> = {
new (...args: any[]): Component<Attrs>;
prototype: C;
};
/**
* Unfortunately, TypeScript only supports strings and classes for JSX tags.
* Therefore, our type definition should only allow for those two types.
*
* @see https://github.com/microsoft/TypeScript/issues/14789#issuecomment-412247771
*/
declare type VnodeElementTag<Attrs = Record<string, unknown>, C extends Component<Attrs> = Component<Attrs>> = string | ComponentClass<Attrs, C>;
/**
* @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');
/**
* From https://github.com/lokesh/color-thief/issues/188
*/
declare module 'color-thief-browser' {
type Color = [number, number, number];
export default class ColorThief {
getColor: (img: HTMLImageElement | null) => Color;
getPalette: (img: HTMLImageElement | null) => Color[];
}
}
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

@@ -1,68 +0,0 @@
/**
* Selection of options accepted by [Bootstrap's tooltips](https://getbootstrap.com/docs/3.3/javascript/#tooltips-options).
*
* ---
*
* Not all options are present from Bootstrap to discourage the use of options
* that will be deprecated in the future.
*
* More commonly used options that will be deprecated remain, but are marked as
* such.
*
* @see https://getbootstrap.com/docs/3.3/javascript/#tooltips-options
*/
export interface TooltipCreationOptions {
/**
* Whether HTML content is allowed in the tooltip.
*
* ---
*
* **Warning:** this is a possible XSS attack vector. This option shouldn't
* be used wherever possible, and will not work when we migrate to CSS-only
* tooltips.
*
* @deprecated
*/
html?: boolean;
/**
* Tooltip position around the target element.
*/
placement?: 'top' | 'bottom' | 'left' | 'right';
/**
* Sets the delay between a trigger state occurring and the tooltip appearing
* on-screen.
*
* ---
*
* **Warning:** this option will be removed when we switch to CSS-only
* tooltips.
*
* @deprecated
*/
delay?: number;
/**
* Value used if no `title` attribute is present on the HTML element.
*
* If a function is given, it will be called with its `this` reference set to
* the element that the tooltip is attached to.
*/
title?: string;
/**
* How the tooltip is triggered.
*
* Either on `hover`, on `hover focus` (either of the two).
*
* ---
*
* **Warning:** `manual`, `click` and `focus` on its own are deprecated options
* which will not be supported in the future.
*/
trigger?: 'hover' | 'hover focus';
}
/**
* Creates a tooltip on a jQuery element reference.
*
* Returns the same jQuery reference to allow for method chaining.
*/
export type TooltipJQueryFunction = (tooltipOptions?: TooltipCreationOptions | 'destroy' | 'show' | 'hide') => JQuery;

View File

@@ -1,61 +0,0 @@
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: {
feature: number;
theme: number;
language: number;
};
history: {
canGoBack: () => boolean;
getPrevious: () => void;
backUrl: () => string;
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[];
}

View File

@@ -1,3 +0,0 @@
import Admin from './AdminApplication';
declare const app: Admin;
export default app;

View File

@@ -1,165 +0,0 @@
declare var _default: {
extend: any;
Session: typeof import("../common/Session").default;
Store: typeof import("../common/Store").default;
'utils/BasicEditorDriver': typeof import("../common/utils/BasicEditorDriver").default;
'utils/evented': {
handlers: Object;
getHandlers(event: string): any[];
trigger(event: string, ...args: any[]): void;
on(event: string, handler: Function): void;
one(event: string, handler: Function): void;
off(event: string, handler: Function): void;
};
'utils/liveHumanTimes': typeof import("../common/utils/liveHumanTimes").default;
'utils/ItemList': typeof import("../common/utils/ItemList").default;
'utils/mixin': typeof import("../common/utils/mixin").default;
'utils/humanTime': typeof import("../common/utils/humanTime").default;
'utils/computed': typeof import("../common/utils/computed").default;
'utils/insertText': typeof import("../common/utils/insertText").default;
'utils/styleSelectedText': typeof import("../common/utils/styleSelectedText").default;
'utils/Drawer': typeof import("../common/utils/Drawer").default;
'utils/anchorScroll': typeof import("../common/utils/anchorScroll").default;
'utils/RequestError': typeof import("../common/utils/RequestError").default;
'utils/abbreviateNumber': typeof import("../common/utils/abbreviateNumber").default;
'utils/string': typeof import("../common/utils/string");
'utils/SubtreeRetainer': typeof import("../common/utils/SubtreeRetainer").default;
'utils/escapeRegExp': typeof import("../common/utils/escapeRegExp").default;
'utils/extract': typeof import("../common/utils/extract").default;
'utils/ScrollListener': typeof import("../common/utils/ScrollListener").default;
'utils/stringToColor': typeof import("../common/utils/stringToColor").default;
'utils/Stream': typeof import("mithril/stream");
'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/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;
'models/Discussion': typeof import("../common/models/Discussion").default;
'models/Group': typeof import("../common/models/Group").default;
'models/Forum': typeof import("../common/models/Forum").default;
Component: typeof import("../common/Component").default;
Fragment: typeof import("../common/Fragment").default;
Translator: typeof import("../common/Translator").default;
'components/AlertManager': typeof import("../common/components/AlertManager").default;
'components/Page': typeof import("../common/components/Page").default;
'components/Switch': typeof import("../common/components/Switch").default;
'components/Badge': typeof import("../common/components/Badge").default;
'components/LoadingIndicator': typeof import("../common/components/LoadingIndicator").default;
'components/Placeholder': typeof import("../common/components/Placeholder").default;
'components/Separator': typeof import("../common/components/Separator").default;
'components/Dropdown': typeof import("../common/components/Dropdown").default;
'components/SplitDropdown': typeof import("../common/components/SplitDropdown").default;
'components/RequestErrorModal': typeof import("../common/components/RequestErrorModal").default;
'components/FieldSet': typeof import("../common/components/FieldSet").default;
'components/Select': typeof import("../common/components/Select").default;
'components/Navigation': typeof import("../common/components/Navigation").default;
'components/Alert': typeof import("../common/components/Alert").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;
'components/Modal': typeof import("../common/components/Modal").default;
'components/GroupBadge': typeof import("../common/components/GroupBadge").default;
'components/TextEditor': typeof import("../common/components/TextEditor").default;
'components/TextEditorButton': typeof import("../common/components/TextEditorButton").default;
'components/Tooltip': typeof import("../common/components/Tooltip").default;
'components/EditUserModal': typeof import("../common/components/EditUserModal").default;
Model: typeof import("../common/Model").default;
Application: typeof import("../common/Application").default;
'helpers/fullTime': typeof import("../common/helpers/fullTime").default;
'helpers/avatar': typeof import("../common/helpers/avatar").default;
'helpers/icon': typeof import("../common/helpers/icon").default;
'helpers/humanTime': typeof import("../common/helpers/humanTime").default;
'helpers/punctuateSeries': typeof import("../common/helpers/punctuateSeries").default;
'helpers/highlight': typeof import("../common/helpers/highlight").default;
'helpers/username': typeof import("../common/helpers/username").default;
'helpers/userOnline': typeof import("../common/helpers/userOnline").default;
'helpers/listItems': typeof import("../common/helpers/listItems").default;
'resolvers/DefaultResolver': typeof import("../common/resolvers/DefaultResolver").default;
'states/PaginatedListState': typeof import("../common/states/PaginatedListState").default;
} & {
'utils/saveSettings': typeof saveSettings;
'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;
'components/HeaderPrimary': typeof HeaderPrimary;
'components/AdminPage': typeof AdminPage;
'components/AppearancePage': typeof AppearancePage;
'components/StatusWidget': typeof StatusWidget;
'components/ExtensionsWidget': typeof ExtensionsWidget;
'components/HeaderSecondary': typeof HeaderSecondary;
'components/SettingsModal': typeof SettingsModal;
'components/DashboardWidget': typeof DashboardWidget;
'components/ExtensionPage': typeof ExtensionPage;
'components/ExtensionLinkButton': typeof ExtensionLinkButton;
'components/PermissionGrid': typeof PermissionGrid;
'components/ExtensionPermissionGrid': typeof ExtensionPermissionGrid;
'components/MailPage': typeof MailPage;
'components/UploadImageButton': typeof UploadImageButton;
'components/LoadingModal': typeof LoadingModal;
'components/DashboardPage': typeof DashboardPage;
'components/BasicsPage': typeof BasicsPage;
'components/UserListPage': typeof UserListPage;
'components/EditCustomHeaderModal': typeof EditCustomHeaderModal;
'components/PermissionsPage': typeof PermissionsPage;
'components/PermissionDropdown': typeof PermissionDropdown;
'components/AdminNav': typeof AdminNav;
'components/AdminHeader': typeof AdminHeader;
'components/EditCustomCssModal': typeof EditCustomCssModal;
'components/EditGroupModal': typeof EditGroupModal;
routes: typeof routes;
AdminApplication: typeof AdminApplication;
};
export default _default;
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";
import HeaderPrimary from "./components/HeaderPrimary";
import AdminPage from "./components/AdminPage";
import AppearancePage from "./components/AppearancePage";
import StatusWidget from "./components/StatusWidget";
import ExtensionsWidget from "./components/ExtensionsWidget";
import HeaderSecondary from "./components/HeaderSecondary";
import SettingsModal from "./components/SettingsModal";
import DashboardWidget from "./components/DashboardWidget";
import ExtensionPage from "./components/ExtensionPage";
import ExtensionLinkButton from "./components/ExtensionLinkButton";
import PermissionGrid from "./components/PermissionGrid";
import ExtensionPermissionGrid from "./components/ExtensionPermissionGrid";
import MailPage from "./components/MailPage";
import UploadImageButton from "./components/UploadImageButton";
import LoadingModal from "./components/LoadingModal";
import DashboardPage from "./components/DashboardPage";
import BasicsPage from "./components/BasicsPage";
import UserListPage from "./components/UserListPage";
import EditCustomHeaderModal from "./components/EditCustomHeaderModal";
import PermissionsPage from "./components/PermissionsPage";
import PermissionDropdown from "./components/PermissionDropdown";
import AdminNav from "./components/AdminNav";
import AdminHeader from "./components/AdminHeader";
import EditCustomCssModal from "./components/EditCustomCssModal";
import EditGroupModal from "./components/EditGroupModal";
import routes from "./routes";
import AdminApplication from "./AdminApplication";

View File

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

View File

@@ -1,15 +0,0 @@
export default class AdminNav extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
query: Stream<string> | undefined;
scrollToActive(): void;
/**
* Build an item list of main links to show in the admin navigation.
*
* @return {ItemList}
*/
items(): ItemList<any>;
extensionItems(): ItemList<any>;
}
import Component from "../../common/Component";
import Stream from "../../common/utils/Stream";
import ItemList from "../../common/utils/ItemList";

View File

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

View File

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

View File

@@ -1,16 +0,0 @@
export default class BasicsPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
localeOptions: {} | undefined;
displayNameOptions: {} | undefined;
slugDriverOptions: {} | undefined;
/**
* Build a list of options for the default homepage. Each option must be an
* object with `path` and `label` properties.
*
* @return {ItemList}
* @public
*/
public homePageItems(): ItemList<any>;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

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

View File

@@ -1,16 +0,0 @@
export default class DashboardWidget extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
/**
* Get the class name to apply to the widget.
*
* @return {String}
*/
className(): string;
/**
* Get the content of the widget.
*
* @return {VirtualElement}
*/
content(): any;
}
import Component from "../../common/Component";

View File

@@ -1,3 +0,0 @@
export default class EditCustomCssModal extends SettingsModal {
}
import SettingsModal from "./SettingsModal";

View File

@@ -1,3 +0,0 @@
export default class EditCustomFooterModal extends SettingsModal {
}
import SettingsModal from "./SettingsModal";

View File

@@ -1,3 +0,0 @@
export default class EditCustomHeaderModal extends SettingsModal {
}
import SettingsModal from "./SettingsModal";

View File

@@ -1,25 +0,0 @@
/**
* 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();
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>;
submitData(): {
nameSingular: any;
namePlural: any;
color: any;
icon: any;
isHidden: any;
};
deleteGroup(): void;
}
import Modal from "../../common/components/Modal";
import Stream from "../../common/utils/Stream";
import ItemList from "../../common/utils/ItemList";

View File

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

View File

@@ -1,32 +0,0 @@
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;
infoFields: {
discuss: string;
documentation: string;
support: string;
website: string;
donate: string;
source: string;
};
oninit(vnode: Mithril.Vnode<Attrs, this>): void;
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>;
toggle(): void;
isEnabled(): any;
onerror(e: RequestError): void;
}

View File

@@ -1,19 +0,0 @@
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>;
}

View File

@@ -1,6 +0,0 @@
export default class ExtensionsWidget extends DashboardWidget {
categorizedExtensions: {} | undefined;
extensionCategory(category: any): JSX.Element;
extensionWidget(extension: any): JSX.Element;
}
import DashboardWidget from "./DashboardWidget";

View File

@@ -1,16 +0,0 @@
/**
* 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> {
constructor();
config(isInitialized: any, context: any): void;
/**
* Build an item list for the controls.
*
* @return {ItemList}
*/
items(): ItemList<any>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,14 +0,0 @@
/**
* The `HeaderSecondary` component displays secondary header controls.
*/
export default class HeaderSecondary extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
/**
* Build an item list for the controls.
*
* @return {ItemList}
*/
items(): ItemList<any>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

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

View File

@@ -1,13 +0,0 @@
export default class MailPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
sendingTest: boolean | undefined;
refresh(): void;
status: {
sending: boolean;
errors: {};
} | undefined;
driverFields: any;
sendTestEmail(): void;
testEmailSuccessAlert: number | undefined;
}
import AdminPage from "./AdminPage";

View File

@@ -1,6 +0,0 @@
export default class PermissionDropdown extends Dropdown {
save(groupIds: any): void;
toggle(groupId: any): void;
isGroupDisabled(id: any): boolean;
}
import Dropdown from "../../common/components/Dropdown";

View File

@@ -1,36 +0,0 @@
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>;
}

View File

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

View File

@@ -1,18 +0,0 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import ExtensionReadme from '../models/ExtensionReadme';
import type Mithril from 'mithril';
import type { Extension } from '../AdminApplication';
export interface IReadmeModalAttrs extends IInternalModalAttrs {
extension: Extension;
}
export default class ReadmeModal<CustomAttrs extends IReadmeModalAttrs = IReadmeModalAttrs> extends Modal<CustomAttrs> {
protected name: string;
protected extName: string;
protected readme: ExtensionReadme;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
className(): string;
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): JSX.Element;
loadReadme(): Promise<void>;
}

View File

@@ -1,14 +0,0 @@
/**
* The `SessionDropdown` component shows a button with the current user's
* avatar/name, with a dropdown of session controls.
*/
export default class SessionDropdown extends Dropdown {
/**
* Build an item list for the contents of the dropdown menu.
*
* @return {ItemList}
*/
items(): ItemList<any>;
}
import Dropdown from "../../common/components/Dropdown";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,3 +0,0 @@
export default class SettingDropdown extends SelectDropdown {
}
import SelectDropdown from "../../common/components/SelectDropdown";

View File

@@ -1,11 +0,0 @@
export default class SettingsModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
settings: {} | undefined;
form(): string;
submitButton(): JSX.Element;
setting(key: any, fallback?: string): any;
dirty(): {};
changed(): number;
onsaved(): void;
}
import Modal from "../../common/components/Modal";

View File

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

View File

@@ -1,28 +0,0 @@
export default class UploadImageButton extends Button<import("../../common/components/Button").IButtonAttrs> {
constructor();
loading: boolean;
/**
* Prompt the user to upload an image.
*/
upload(): void;
/**
* Remove the logo.
*/
remove(): void;
resourceUrl(): string;
/**
* After a successful upload/removal, reload the page.
*
* @param {Object} response
* @protected
*/
protected success(response: Object): void;
/**
* If upload/removal fails, stop loading.
*
* @param {Object} response
* @protected
*/
protected failure(response: Object): void;
}
import Button from "../../common/components/Button";

View File

@@ -1,85 +0,0 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import type Mithril from 'mithril';
import type User from '../../common/models/User';
import ItemList from '../../common/utils/ItemList';
import AdminPage from './AdminPage';
declare type ColumnData = {
/**
* Column title
*/
name: Mithril.Children;
/**
* Component(s) to show for this column.
*/
content: (user: User) => Mithril.Children;
};
/**
* Admin page which displays a paginated list of all users on the forum.
*/
export default class UserListPage extends AdminPage {
/**
* Number of users to load per page.
*/
private numPerPage;
/**
* Current page number. Zero-indexed.
*/
private pageNumber;
/**
* Total number of forum users.
*
* Fetched from the active `AdminApplication` (`app`), with
* data provided by `AdminPayload.php`, or `flarum/statistics`
* if installed.
*/
readonly userCount: number;
/**
* Get total number of user pages.
*/
private getTotalPageCount;
/**
* This page's array of users.
*
* `undefined` when page loads as no data has been fetched.
*/
private pageData;
/**
* Are there more users available?
*/
private moreData;
private isLoadingPage;
/**
* Component to render.
*/
content(): JSX.Element[];
/**
* Build an item list of columns to show for each user.
*
* Each column in the list should be an object with keys `name` and `content`.
*
* `name` is a string that will be used as the column name.
* `content` is a function with the User model passed as the first and only argument.
*
* See `UserListPage.tsx` for examples.
*/
columns(): ItemList<ColumnData>;
headerInfo(): {
className: string;
icon: string;
title: import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
description: import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
};
/**
* Asynchronously fetch the next set of users to be rendered.
*
* Returns an array of Users, plus the raw API payload.
*
* Uses the `this.numPerPage` as the response limit, and automatically calculates the offset required from `pageNumber`.
*
* @param pageNumber The page number to load and display
*/
loadPage(pageNumber: number): Promise<void>;
nextPage(): void;
previousPage(): void;
}
export {};

View File

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

View File

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

View File

@@ -1,10 +0,0 @@
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> {
static extension: string | null;
onmatch(args: Attrs & RouteArgs, requestedPath: string, route: string): new () => ExtensionPage<Attrs>;
}

View File

@@ -1,5 +0,0 @@
import AdminApplication from './AdminApplication';
/**
* The `routes` initializer defines the forum app's routes.
*/
export default function (app: AdminApplication): void;

View File

@@ -1,96 +0,0 @@
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;
/**
* This function simply takes the extension id
*
* @example
* app.extensionData.for('flarum-tags')
*
* flarum/flags -> flarum-flags | acme/extension -> acme-extension
*/
for(extension: string): this;
/**
* This function registers your settings with Flarum
*
* It takes either a settings object or a callback.
*
* @example
*
* .registerSetting({
* setting: 'flarum-flags.guidelines_url',
* 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)
*/
registerSetting(content: SettingConfigInput, priority?: number): this;
/**
* This function registers your permission with Flarum
*
* @example
*
* .registerPermission('permissions', {
* icon: 'fas fa-flag',
* label: app.translator.trans('flarum-flags.admin.permissions.view_flags_label'),
* permission: 'discussion.viewFlags'
* }, 'moderate', 65)
*/
registerPermission(content: PermissionConfig, permissionType: PermissionType, priority?: number): this;
/**
* Replace the default extension page with a custom component.
* This component would typically extend ExtensionPage
*/
registerPage(component: CustomExtensionPage): this;
/**
* Get an extension's registered settings
*/
getSettings(extensionId: string): SettingConfigInternal[] | undefined;
/**
* Get an ItemList of all extensions' registered permissions
*/
getAllExtensionPermissions(type: PermissionType): ItemList<PermissionConfig>;
/**
* Get a singular extension's registered permissions
*/
getExtensionPermissions(extension: string, type: PermissionType): ItemList<PermissionConfig>;
/**
* Checks whether a given extension has registered permissions.
*/
extensionHasPermissions(extension: string): boolean;
/**
* Returns an extension's custom page component if it exists.
*/
getPage<Attrs extends ExtensionPageAttrs = ExtensionPageAttrs>(extension: string): CustomExtensionPage<Attrs> | undefined;
}
export {};

View File

@@ -1 +0,0 @@
export { nanoid as default } from 'nanoid';

View File

@@ -1 +0,0 @@
export default function getCategorizedExtensions(): {};

View File

@@ -1 +0,0 @@
export default function isExtensionEnabled(name: any): any;

View File

@@ -1 +0,0 @@
export default function saveSettings(settings: any): Promise<any>;

View File

@@ -1,233 +0,0 @@
import ItemList from './utils/ItemList';
import Translator from './Translator';
import Store, { ApiPayload, ApiResponsePlural, ApiResponseSingle } 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';
import Model, { SavedModelData } from './Model';
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.
*/
export default class Application {
/**
* The forum model for this application.
*/
forum: Forum;
/**
* A map of routes, keyed by a unique route name. Each route is an object
* containing the following properties:
*
* - `path` The path that the route is accessed at.
* - `component` The Mithril component to render when this route is active.
*
* @example
* app.routes.discussion = { path: '/d/:id', component: DiscussionPage };
*/
routes: Record<string, FlarumGenericRoute>;
/**
* An ordered list of initializers to bootstrap the application.
*/
initializers: ItemList<(app: this) => void>;
/**
* The app's session.
*
* Stores info about the current user.
*/
session: Session;
/**
* The app's translator.
*/
translator: Translator;
/**
* The app's data store.
*/
store: Store;
/**
* A local cache that can be used to store data at the application level, so
* that is persists between different routes.
*/
cache: Record<string, unknown>;
/**
* Whether or not the app has been booted.
*/
booted: boolean;
/**
* 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.
*/
current: PageState;
/**
* The page the app was on before the current page.
*
* 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.
*/
previous: PageState;
/**
* An object that manages modal state.
*/
modal: ModalManagerState;
/**
* An object that manages the state of active alerts.
*/
alerts: AlertManagerState;
/**
* An object that manages the state of the navigation drawer.
*/
drawer: Drawer;
data: {
apiDocument: ApiPayload | null;
locale: string;
locales: Record<string, string>;
resources: SavedModelData[];
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;
boot(): void;
bootExtensions(extensions: Record<string, {
extend?: unknown[];
}>): void;
protected mount(basePath?: string): void;
/**
* Get the API response document that has been preloaded into the application.
*/
preloadedApiDocument<M extends Model>(): ApiResponseSingle<M> | null;
preloadedApiDocument<Ms extends Model[]>(): ApiResponsePlural<Ms[number]> | null;
/**
* Determine the current screen mode, based on our media queries.
*/
screen(): FlarumScreens;
/**
* Set the `<title>` of the page.
*
* @param title New page title
*/
setTitle(title: string): void;
/**
* Set a number to display in the `<title>` of the page.
*
* @param count Number to display in title
*/
setTitleCount(count: number): 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
* @return {Promise}
*/
request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType>;
/**
* By default, show an error alert, and log the error to the console.
*/
protected requestErrorCatch<ResponseType>(error: RequestError, customErrorHandler: FlarumRequestOptions<ResponseType>['errorHandler']): Promise<never>;
protected requestErrorDefaultHandler(e: unknown, isDebug: boolean, formattedErrors: string[]): void;
private showDebug;
/**
* Construct a URL to the route with the given name.
*/
route(name: string, params?: Record<string, unknown>): string;
}

View File

@@ -1,114 +0,0 @@
import type Mithril from 'mithril';
export interface ComponentAttrs extends Mithril.Attributes {
}
/**
* The `Component` class defines a user interface 'building block'. A component
* generates a virtual DOM to be rendered on each redraw.
*
* Essentially, this is a wrapper for Mithril's components that adds several useful features:
*
* - In the `oninit` and `onbeforeupdate` lifecycle hooks, we store vnode attrs in `this.attrs.
* This allows us to use attrs across components without having to pass the vnode to every single
* method.
* - The static `initAttrs` method allows a convenient way to provide defaults (or to otherwise modify)
* the attrs that have been passed into a component.
* - When the component is created in the DOM, we store its DOM element under `this.element`; this lets
* us use jQuery to modify child DOM state from internal methods via the `this.$()` method.
* - A convenience `component` method, which serves as an alternative to hyperscript and JSX.
*
* As with other Mithril components, components extending Component can be initialized
* and nested using JSX, hyperscript, or a combination of both. The `component` method can also
* be used.
*
* @example
* return m('div', <MyComponent foo="bar"><p>Hello World</p></MyComponent>);
*
* @example
* return m('div', MyComponent.component({foo: 'bar'), m('p', 'Hello World!'));
*
* @see https://mithril.js.org/components.html
*/
export default abstract class Component<Attrs extends ComponentAttrs = ComponentAttrs, State = undefined> implements Mithril.ClassComponent<Attrs> {
/**
* The root DOM element for the component.
*/
protected element: Element;
/**
* The attributes passed into the 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;
/**
* @inheritdoc
*/
abstract view(vnode: Mithril.Vnode<Attrs, this>): Mithril.Children;
/**
* @inheritdoc
*/
oninit(vnode: Mithril.Vnode<Attrs, this>): void;
/**
* @inheritdoc
*/
oncreate(vnode: Mithril.VnodeDOM<Attrs, this>): void;
/**
* @inheritdoc
*/
onbeforeupdate(vnode: Mithril.VnodeDOM<Attrs, this>): void;
/**
* @inheritdoc
*/
onupdate(vnode: Mithril.VnodeDOM<Attrs, this>): void;
/**
* @inheritdoc
*/
onbeforeremove(vnode: Mithril.VnodeDOM<Attrs, this>): void;
/**
* @inheritdoc
*/
onremove(vnode: Mithril.VnodeDOM<Attrs, 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
* element as its buffer.
*
* For example, calling `component.$('li')` will return a jQuery object
* containing all of the `li` elements inside the DOM element of this
* component.
*
* @param [selector] a jQuery-compatible selector string
* @returns the jQuery object for the DOM node
* @final
*/
protected $(selector?: string): JQuery;
/**
* Convenience method to attach a component without JSX.
* Has the same effect as calling `m(THIS_CLASS, attrs, children)`.
*
* @see https://mithril.js.org/hyperscript.html#mselector,-attributes,-children
*/
static component<SAttrs extends ComponentAttrs = ComponentAttrs>(attrs?: SAttrs, children?: Mithril.Children): Mithril.Vnode;
/**
* Saves a reference to the vnode attrs after running them through initAttrs,
* and checking for common issues.
*/
private setAttrs;
/**
* Initialize the component's attrs.
*
* This can be used to assign default values for missing, optional attrs.
*/
protected static initAttrs<T>(attrs: T): void;
}

View File

@@ -1,53 +0,0 @@
import type 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.
*
* This is very similar to the `Component` wrapper class, but is used for more fine-grained control over
* the rendering and display of some significant chunks of the DOM. In contrast to components, fragments
* do not offer Mithril's lifecycle hooks.
*
* Use this when you want to enjoy the benefits of JSX / VDOM for initial rendering, combined with
* small helper methods that then make updates to that DOM directly, instead of fully redrawing
* everything through Mithril.
*
* This should only be used when necessary, and only with `m.render`. If you are unsure whether you need
* this or `Component, you probably need `Component`.
*/
export default abstract class Fragment {
/**
* The root DOM element for the fragment.
*/
protected element: Element;
/**
* Returns a jQuery object for this fragment's element. If you pass in a
* selector string, this method will return a jQuery object, using the current
* element as its buffer.
*
* For example, calling `fragment.$('li')` will return a jQuery object
* containing all of the `li` elements inside the DOM element of this
* fragment.
*
* @param {String} [selector] a jQuery-compatible selector string
* @returns {jQuery} the jQuery object for the DOM node
* @final
*/
$(selector?: string): JQuery;
/**
* Get the renderable virtual DOM that represents the fragment's view.
*
* This should NOT be overridden by subclasses. Subclasses wishing to define
* their virtual DOM should override Fragment#view instead.
*
* @example
* const fragment = new MyFragment();
* m.render(document.body, fragment.render());
*
* @final
*/
render(): Mithril.Vnode<Mithril.Attributes, this>;
/**
* Creates a view out of virtual elements.
*/
abstract view(): Mithril.Vnode<Mithril.Attributes, this>;
}

View File

@@ -1,147 +0,0 @@
import { FlarumRequestOptions } from './Application';
import Store, { ApiPayloadSingle, ApiResponseSingle, MetaInformation } from './Store';
export interface ModelIdentifier {
type: string;
id: string;
}
export interface ModelAttributes {
[key: string]: unknown;
}
export interface ModelRelationships {
[relationship: string]: {
data: ModelIdentifier | ModelIdentifier[];
};
}
export interface UnsavedModelData {
type?: string;
attributes?: ModelAttributes;
relationships?: ModelRelationships;
}
export interface SavedModelData {
type: string;
id: string;
attributes?: ModelAttributes;
relationships?: ModelRelationships;
}
export declare type ModelData = UnsavedModelData | SavedModelData;
export interface SaveRelationships {
[relationship: string]: Model | Model[];
}
export interface SaveAttributes {
[key: string]: unknown;
relationships?: SaveRelationships;
}
/**
* The `Model` class represents a local data resource. It provides methods to
* persist changes via the API.
*/
export default abstract class Model {
/**
* The resource object from the API.
*/
data: ModelData;
/**
* The time at which the model's data was last updated. Watching the value
* of this property is a fast way to retain/cache a subtree if data hasn't
* changed.
*/
freshness: Date;
/**
* Whether or not the resource exists on the server.
*/
exists: boolean;
/**
* The data store that this resource should be persisted to.
*/
protected store: Store;
/**
* @param data A resource object from the API.
* @param store The data store that this model should be persisted to.
*/
constructor(data?: ModelData, store?: Store);
/**
* Get the model's ID.
*
* @final
*/
id(): string | undefined;
/**
* Get one of the model's attributes.
*
* @final
*/
attribute<T = unknown>(attribute: string): T;
/**
* Merge new data into this model locally.
*
* @param data A resource object to merge into this model
*/
pushData(data: ModelData | {
relationships?: SaveRelationships;
}): this;
/**
* Merge new attributes into this model locally.
*
* @param attributes The attributes to merge.
*/
pushAttributes(attributes: ModelAttributes): void;
/**
* Merge new attributes into this model, both locally and with persistence.
*
* @param attributes The attributes to save. If a 'relationships' key
* exists, it will be extracted and relationships will also be saved.
*/
save(attributes: SaveAttributes, options?: Omit<FlarumRequestOptions<ApiPayloadSingle>, 'url'> & {
meta?: MetaInformation;
}): Promise<ApiResponseSingle<this>>;
/**
* Send a request to delete the resource.
*
* @param body Data to send along with the DELETE request.
*/
delete(body?: FlarumRequestOptions<void>['body'], options?: Omit<FlarumRequestOptions<void>, 'url'>): Promise<void>;
/**
* Construct a path to the API endpoint for this resource.
*/
protected apiEndpoint(): string;
protected copyData(): ModelData;
protected rawRelationship<M extends Model>(relationship: string): undefined | ModelIdentifier;
protected rawRelationship<M extends Model[]>(relationship: string): undefined | ModelIdentifier[];
/**
* Generate a function which returns the value of the given attribute.
*
* @param transform A function to transform the attribute value
*/
static attribute<T>(name: string): () => T;
static attribute<T, O = unknown>(name: string, transform: (attr: O) => T): () => T;
/**
* Generate a function which returns the value of the given has-one
* relationship.
*
* @return false if no information about the
* relationship exists; undefined if the relationship exists but the model
* has not been loaded; or the model if it has been loaded.
*/
static hasOne<M extends Model>(name: string): () => M | false;
static hasOne<M extends Model | null>(name: string): () => M | null | false;
/**
* Generate a function which returns the value of the given has-many
* relationship.
*
* @return false if no information about the relationship
* exists; an array if it does, containing models if they have been
* loaded, and undefined for those that have not.
*/
static hasMany<M extends Model>(name: string): () => (M | undefined)[] | false;
/**
* Transform the given value into a Date object.
*/
static transformDate(value: string): Date;
static transformDate(value: string | null): Date | null;
static transformDate(value: string | undefined): Date | undefined;
static transformDate(value: string | null | undefined): Date | null | undefined;
/**
* Get a resource identifier object for the given model.
*/
protected static getIdentifier(model: Model): ModelIdentifier;
}

View File

@@ -1,33 +0,0 @@
import User from './models/User';
import { FlarumRequestOptions } from './Application';
export declare type LoginParams = {
/**
* The username/email
*/
identification: string;
password: string;
remember: boolean;
};
/**
* 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 {
/**
* The current authenticated user.
*/
user: User | null;
/**
* The CSRF token.
*/
csrfToken: string;
constructor(user: User | null, csrfToken: string);
/**
* Attempt to log in a user.
*/
login(body: LoginParams, options?: Omit<FlarumRequestOptions<any>, 'url' | 'body' | 'method'>): Promise<any>;
/**
* Log the user out.
*/
logout(): void;
}

View File

@@ -1,127 +0,0 @@
import { FlarumRequestOptions } from './Application';
import Model, { ModelData, SavedModelData } from './Model';
export interface MetaInformation {
[key: string]: any;
}
export interface ApiQueryParamsSingle {
fields?: string[];
include?: string;
bySlug?: boolean;
meta?: MetaInformation;
}
export interface ApiQueryParamsPlural {
fields?: string[];
include?: string;
filter?: {
q: string;
[key: string]: string;
};
page?: {
offset?: number;
number?: number;
limit?: number;
size?: number;
};
sort?: string;
meta?: MetaInformation;
}
export declare type ApiQueryParams = ApiQueryParamsPlural | ApiQueryParamsSingle;
export interface ApiPayloadSingle {
data: SavedModelData;
included?: SavedModelData[];
meta?: MetaInformation;
}
export interface ApiPayloadPlural {
data: SavedModelData[];
included?: SavedModelData[];
links?: {
first: string;
next?: string;
prev?: string;
};
meta?: MetaInformation;
}
export declare type ApiPayload = ApiPayloadSingle | ApiPayloadPlural;
export declare type ApiResponseSingle<M extends Model> = M & {
payload: ApiPayloadSingle;
};
export declare type ApiResponsePlural<M extends Model> = M[] & {
payload: ApiPayloadPlural;
};
export declare type ApiResponse<M extends Model> = ApiResponseSingle<M> | ApiResponsePlural<M>;
interface ApiQueryRequestOptions<ResponseType> extends Omit<FlarumRequestOptions<ResponseType>, 'url'> {
}
interface StoreData {
[type: string]: Partial<Record<string, Model>>;
}
export declare function payloadIsPlural(payload: ApiPayload): payload is ApiPayloadPlural;
/**
* The `Store` class defines a local data store, and provides methods to
* retrieve data from the API.
*/
export default class Store {
/**
* The local data store. A tree of resource types to IDs, such that
* accessing data[type][id] will return the model for that type/ID.
*/
protected data: StoreData;
/**
* The model registry. A map of resource types to the model class that
* should be used to represent resources of that type.
*/
models: Record<string, typeof Model>;
constructor(models: Record<string, typeof Model>);
/**
* Push resources contained within an API payload into the store.
*
* @return The model(s) representing the resource(s) contained
* within the 'data' key of the payload.
*/
pushPayload<M extends Model>(payload: ApiPayloadSingle): ApiResponseSingle<M>;
pushPayload<Ms extends Model[]>(payload: ApiPayloadPlural): ApiResponseSingle<Ms[number]>;
/**
* Create a model to represent a resource object (or update an existing one),
* and push it into the store.
*
* @param data The resource object
* @return The model, or null if no model class has been
* registered for this resource type.
*/
pushObject<M extends Model>(data: SavedModelData): M | null;
pushObject<M extends Model>(data: SavedModelData, allowUnregistered: false): M;
/**
* Make a request to the API to find record(s) of a specific type.
*/
find<M extends Model>(type: string, params: ApiQueryParamsSingle): Promise<ApiResponseSingle<M>>;
find<Ms extends Model[]>(type: string, params: ApiQueryParamsPlural): Promise<ApiResponsePlural<Ms[number]>>;
find<M extends Model>(type: string, id: string, params?: ApiQueryParamsSingle, options?: ApiQueryRequestOptions<ApiPayloadSingle>): Promise<ApiResponseSingle<M>>;
find<Ms extends Model[]>(type: string, ids: string[], params?: ApiQueryParamsPlural, options?: ApiQueryRequestOptions<ApiPayloadPlural>): Promise<ApiResponsePlural<Ms[number]>>;
/**
* Get a record from the store by ID.
*/
getById<M extends Model>(type: string, id: string): M | undefined;
/**
* Get a record from the store by the value of a model attribute.
*
* @param type The resource type.
* @param key The name of the method on the model.
* @param value The value of the model attribute.
*/
getBy<M extends Model, T = unknown>(type: string, key: keyof M, value: T): M | undefined;
/**
* Get all loaded records of a specific type.
*/
all<M extends Model>(type: string): M[];
/**
* Remove the given model from the store.
*/
remove(model: Model): void;
/**
* Create a new record of the given type.
*
* @param type The resource type
* @param data Any data to initialize the model with
*/
createRecord<M extends Model>(type: string, data?: ModelData): M;
}
export {};

View File

@@ -1,34 +0,0 @@
/// <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 {
/**
* A map of translation keys to their translated values.
*/
translations: Translations;
/**
* The underlying ICU MessageFormatter util.
*/
protected formatter: RichMessageFormatter;
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;
};
/**
* A temporary system to preprocess parameters.
* Should not be used by extensions.
* TODO: An extender will be added in v1.x.
*
* @internal
*/
protected preprocessParameters(parameters: TranslatorParameters): TranslatorParameters;
trans(id: string, parameters?: TranslatorParameters): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
}
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,174 +0,0 @@
declare var _default: {
extend: any;
Session: typeof Session;
Store: typeof Store;
'utils/BasicEditorDriver': typeof BasicEditorDriver;
'utils/evented': {
handlers: Object;
getHandlers(event: string): any[];
trigger(event: string, ...args: any[]): void;
on(event: string, handler: Function): void;
one(event: string, handler: Function): void;
off(event: string, handler: Function): void;
};
'utils/liveHumanTimes': typeof liveHumanTimes;
'utils/ItemList': typeof ItemList;
'utils/mixin': typeof mixin;
'utils/humanTime': typeof humanTime;
'utils/computed': typeof computed;
'utils/insertText': typeof insertText;
'utils/styleSelectedText': typeof styleSelectedText;
'utils/Drawer': typeof Drawer;
'utils/anchorScroll': typeof anchorScroll;
'utils/RequestError': typeof RequestError;
'utils/abbreviateNumber': typeof abbreviateNumber;
'utils/string': typeof string;
'utils/SubtreeRetainer': typeof SubtreeRetainer;
'utils/escapeRegExp': typeof escapeRegExp;
'utils/extract': typeof extract;
'utils/ScrollListener': typeof ScrollListener;
'utils/stringToColor': typeof stringToColor;
'utils/Stream': typeof Stream;
'utils/subclassOf': typeof subclassOf;
'utils/setRouteWithForcedRefresh': typeof setRouteWithForcedRefresh;
'utils/patchMithril': typeof patchMithril;
'utils/proxifyCompat': typeof proxifyCompat;
'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;
'models/Discussion': typeof Discussion;
'models/Group': typeof Group;
'models/Forum': typeof Forum;
Component: typeof Component;
Fragment: typeof Fragment;
Translator: typeof Translator;
'components/AlertManager': typeof AlertManager;
'components/Page': typeof Page;
'components/Switch': typeof Switch;
'components/Badge': typeof Badge;
'components/LoadingIndicator': typeof LoadingIndicator;
'components/Placeholder': typeof Placeholder;
'components/Separator': typeof Separator;
'components/Dropdown': typeof Dropdown;
'components/SplitDropdown': typeof SplitDropdown;
'components/RequestErrorModal': typeof RequestErrorModal;
'components/FieldSet': typeof FieldSet;
'components/Select': typeof Select;
'components/Navigation': typeof Navigation;
'components/Alert': typeof Alert;
'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;
'components/Modal': typeof Modal;
'components/GroupBadge': typeof GroupBadge;
'components/TextEditor': typeof TextEditor;
'components/TextEditorButton': typeof TextEditorButton;
'components/Tooltip': typeof Tooltip;
'components/EditUserModal': typeof EditUserModal;
Model: typeof Model;
Application: typeof Application;
'helpers/fullTime': typeof fullTime;
'helpers/avatar': typeof avatar;
'helpers/icon': typeof icon;
'helpers/humanTime': typeof humanTimeHelper;
'helpers/punctuateSeries': typeof punctuateSeries;
'helpers/highlight': typeof highlight;
'helpers/username': typeof username;
'helpers/userOnline': typeof userOnline;
'helpers/listItems': typeof listItems;
'resolvers/DefaultResolver': typeof DefaultResolver;
'states/PaginatedListState': typeof PaginatedListState;
};
export default _default;
import Session from "./Session";
import Store from "./Store";
import BasicEditorDriver from "./utils/BasicEditorDriver";
import liveHumanTimes from "./utils/liveHumanTimes";
import ItemList from "./utils/ItemList";
import mixin from "./utils/mixin";
import humanTime from "./utils/humanTime";
import computed from "./utils/computed";
import insertText from "./utils/insertText";
import styleSelectedText from "./utils/styleSelectedText";
import Drawer from "./utils/Drawer";
import anchorScroll from "./utils/anchorScroll";
import RequestError from "./utils/RequestError";
import abbreviateNumber from "./utils/abbreviateNumber";
import * as string from "./utils/string";
import SubtreeRetainer from "./utils/SubtreeRetainer";
import escapeRegExp from "./utils/escapeRegExp";
import extract from "./utils/extract";
import ScrollListener from "./utils/ScrollListener";
import stringToColor from "./utils/stringToColor";
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";
import Discussion from "./models/Discussion";
import Group from "./models/Group";
import Forum from "./models/Forum";
import Component from "./Component";
import Fragment from "./Fragment";
import Translator from "./Translator";
import AlertManager from "./components/AlertManager";
import Page from "./components/Page";
import Switch from "./components/Switch";
import Badge from "./components/Badge";
import LoadingIndicator from "./components/LoadingIndicator";
import Placeholder from "./components/Placeholder";
import Separator from "./components/Separator";
import Dropdown from "./components/Dropdown";
import SplitDropdown from "./components/SplitDropdown";
import RequestErrorModal from "./components/RequestErrorModal";
import FieldSet from "./components/FieldSet";
import Select from "./components/Select";
import Navigation from "./components/Navigation";
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";
import Modal from "./components/Modal";
import GroupBadge from "./components/GroupBadge";
import TextEditor from "./components/TextEditor";
import TextEditorButton from "./components/TextEditorButton";
import Tooltip from "./components/Tooltip";
import EditUserModal from "./components/EditUserModal";
import Model from "./Model";
import Application from "./Application";
import fullTime from "./helpers/fullTime";
import avatar from "./helpers/avatar";
import icon from "./helpers/icon";
import humanTimeHelper from "./helpers/humanTime";
import punctuateSeries from "./helpers/punctuateSeries";
import highlight from "./helpers/highlight";
import username from "./helpers/username";
import userOnline from "./helpers/userOnline";
import listItems from "./helpers/listItems";
import DefaultResolver from "./resolvers/DefaultResolver";
import PaginatedListState from "./states/PaginatedListState";

View File

@@ -1,19 +0,0 @@
import Component, { ComponentAttrs } from '../Component';
import type 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;
/** An array of controls to show in the alert. */
controls?: Mithril.Children;
/** Whether or not the alert can be dismissed. */
dismissible?: boolean;
/** A callback to run when the alert is dismissed */
ondismiss?: Function;
}
/**
* The `Alert` component represents an alert box, which contains a message,
* 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 File

@@ -1,8 +0,0 @@
/**
* 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> {
constructor();
}
import Component from "../Component";

View File

@@ -1,17 +0,0 @@
/**
* The `Badge` component represents a user/discussion badge, indicating some
* status (e.g. a discussion is stickied, a user is an admin).
*
* A badge may have the following special attrs:
*
* - `type` The type of badge this is. This will be used to give the badge a
* class name of `Badge--{type}`.
* - `icon` The name of an icon to show inside the badge.
* - `label`
*
* All other attrs will be assigned as attributes on the badge element.
*/
export default class Badge extends Component<import("../Component").ComponentAttrs, undefined> {
constructor();
}
import Component from "../Component";

View File

@@ -1,69 +0,0 @@
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.
*
* 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.
*/
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;
/**
* Get the template for the button's content.
*/
protected getButtonContent(children: Mithril.Children): Mithril.ChildArray;
}

View File

@@ -1,30 +0,0 @@
/**
* The `Checkbox` component defines a checkbox input.
*
* ### Attrs
*
* - `state` Whether or not the checkbox is checked.
* - `className` The class name for the root element.
* - `disabled` Whether or not the checkbox is disabled.
* - `loading` Whether or not the checkbox is loading.
* - `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> {
constructor();
/**
* Get the template for the checkbox's display (tick/cross icon).
*
* @return {*}
* @protected
*/
protected getDisplay(): any;
/**
* Run a callback when the state of the checkbox is changed.
*
* @param {Boolean} checked
* @protected
*/
protected onchange(checked: boolean): void;
}
import Component from "../Component";

View File

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

View File

@@ -1,22 +0,0 @@
/**
* The `ConfirmDocumentUnload` component can be used to register a global
* event handler that prevents closing the browser window/tab based on the
* return value of a given callback prop.
*
* ### Attrs
*
* - `when` - a callback returning true when the browser should prompt for
* confirmation before closing the window/tab
*
* ### Children
*
* NOTE: Only the first child will be rendered. (Use this component to wrap
* another component / DOM element.)
*
*/
export default class ConfirmDocumentUnload extends Component<import("../Component").ComponentAttrs, undefined> {
constructor();
handler(): any;
boundHandler: (() => any) | undefined;
}
import Component from "../Component";

View File

@@ -1,38 +0,0 @@
/**
* The `Dropdown` component displays a button which, when clicked, shows a
* dropdown menu beneath it.
*
* ### Attrs
*
* - `buttonClassName` A class name to apply to the dropdown toggle button.
* - `menuClassName` A class name to apply to the dropdown menu.
* - `icon` The name of an icon to show in the dropdown toggle button.
* - `caretIcon` The name of an icon to show on the right of the button.
* - `label` The label of the dropdown toggle button. Defaults to 'Controls'.
* - `accessibleToggleLabel` The label used to describe the dropdown toggle button to assistive readers. Defaults to 'Toggle dropdown menu'.
* - `onhide`
* - `onshow`
*
* The children will be displayed as a list inside of the dropdown menu.
*/
export default class Dropdown extends Component<import("../Component").ComponentAttrs, undefined> {
static initAttrs(attrs: any): void;
constructor();
showing: boolean | undefined;
/**
* Get the template for the button.
*
* @return {*}
* @protected
*/
protected getButton(children: any): any;
/**
* Get the template for the button's content.
*
* @return {*}
* @protected
*/
protected getButtonContent(children: any): any;
getMenu(items: any): JSX.Element;
}
import Component from "../Component";

View File

@@ -1,31 +0,0 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from './Modal';
import ItemList from '../utils/ItemList';
import Stream from '../utils/Stream';
import type Mithril from 'mithril';
import type User from '../models/User';
import type { SaveAttributes } from '../Model';
export interface IEditUserModalAttrs extends IInternalModalAttrs {
user: User;
}
export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEditUserModalAttrs> extends Modal<CustomAttrs> {
protected username: Stream<string>;
protected email: Stream<string>;
protected isEmailConfirmed: Stream<boolean>;
protected setPassword: Stream<boolean>;
protected password: Stream<string>;
protected groups: Record<string, Stream<boolean>>;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
className(): string;
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): JSX.Element;
fields(): ItemList<unknown>;
activate(): void;
data(): SaveAttributes;
onsubmit(e: SubmitEvent): void;
nonAdminEditingAdmin(): boolean | null;
/**
* @internal
*/
protected userIsAdmin(user: User | null): boolean | null;
}

View File

@@ -1,13 +0,0 @@
/**
* The `FieldSet` component defines a collection of fields, displayed in a list
* underneath a title. Accepted properties are:
*
* - `className` The class name for the fieldset.
* - `label` The title of this group of fields.
*
* The children should be an array of items to show in the fieldset.
*/
export default class FieldSet extends Component<import("../Component").ComponentAttrs, undefined> {
constructor();
}
import Component from "../Component";

View File

@@ -1,4 +0,0 @@
export default class GroupBadge extends Badge {
static initAttrs(attrs: any): void;
}
import Badge from "./Badge";

View File

@@ -1,12 +0,0 @@
/**
* The link component enables both internal and external links.
* It will return a regular HTML link for any links to external sites,
* and it will use Mithril's m.route.Link for any internal links.
*
* 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> {
constructor();
}
import Component from "../Component";

View File

@@ -1,25 +0,0 @@
/**
* The `LinkButton` component defines a `Button` which links to a route.
*
* ### Attrs
*
* All of the attrs accepted by `Button`, plus:
*
* - `active` Whether or not the page that this button links to is currently
* active.
* - `href` The URL to link to. If the current URL `m.route()` matches this,
* 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> {
static initAttrs(attrs: any): void;
/**
* Determine whether a component with the given attrs is 'active'.
*
* @param {Object} attrs
* @return {Boolean}
*/
static isActive(attrs: Object): boolean;
constructor();
}
import Button from "./Button";

View File

@@ -1,56 +0,0 @@
/// <reference types="mithril" />
import Component, { ComponentAttrs } from '../Component';
export interface LoadingIndicatorAttrs extends ComponentAttrs {
/**
* Custom classes for the loading indicator's container.
*/
className?: string;
/**
* Custom classes for the loading indicator's container.
*/
containerClassName?: string;
/**
* Optional size for the loading indicator.
*/
size?: 'large' | 'medium' | 'small';
/**
* Optional attributes to apply to the loading indicator's container.
*/
containerAttrs?: Partial<ComponentAttrs>;
/**
* Display type of the spinner.
*
* @default 'block'
*/
display?: 'block' | 'inline' | 'unset';
}
/**
* The `LoadingIndicator` component displays a simple CSS-based loading spinner.
*
* To set a custom color, use the CSS `color` property.
*
* To increase spacing around the spinner, use the CSS `height` property on the
* spinner's **container**. Setting the `display` attribute to `block` will set
* a height of `100px` by default.
*
* To apply a custom size to the loading indicator, set the `--size` and
* `--thickness` CSS custom properties on the loading indicator container.
*
* If you *really* want to change how this looks as part of your custom theme,
* you can override the `border-radius` and `border` then set either a
* background image, or use `content: "\<glyph>"` (e.g. `content: "\f1ce"`)
* and `font-family: 'Font Awesome 5 Free'` to set an FA icon if you'd rather.
*
* ### Attrs
*
* - `containerClassName` Class name(s) to apply to the indicator's parent
* - `className` Class name(s) to apply to the indicator itself
* - `display` Determines how the spinner should be displayed (`inline`, `block` (default) or `unset`)
* - `size` Size of the loading indicator (`small`, `medium` or `large`)
* - `containerAttrs` Optional attrs to be applied to the container DOM element
*
* All other attrs will be assigned as attributes on the DOM element.
*/
export default class LoadingIndicator extends Component<LoadingIndicatorAttrs> {
view(): JSX.Element;
}

View File

@@ -1,68 +0,0 @@
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.
*/
export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IInternalModalAttrs> extends Component<ModalAttrs> {
/**
* Determine whether or not the modal should be dismissible via an 'x' button.
*/
static readonly isDismissible: boolean;
protected loading: boolean;
/**
* Attributes for an alert component to show below the header.
*/
alertAttrs: AlertAttrs | null;
oninit(vnode: Mithril.Vnode<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;
/**
* Get the class name to apply to the modal.
*/
abstract className(): string;
/**
* Get the title of the modal dialog.
*/
abstract title(): Mithril.Children;
/**
* Get the content of the modal.
*/
abstract content(): Mithril.Children;
/**
* 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.
*/
onready(): void;
/**
* Hides the modal.
*/
hide(): void;
/**
* Sets `loading` to false and triggers a redraw.
*/
loaded(): void;
/**
* Shows an alert describing an error returned from the API, and gives focus to
* the first relevant field involved in the error.
*/
onerror(error: RequestError): void;
}

View File

@@ -1,25 +0,0 @@
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;
animateHide(): void;
}
export {};

View File

@@ -1,40 +0,0 @@
/**
* The `Navigation` component displays a set of navigation buttons. Typically
* this is just a back button which pops the app's History. If the user is on
* the root page and there is no history to pop, then in some instances it may
* show a button that toggles the app's drawer.
*
* If the app has a pane, it will also include a 'pin' button which toggles the
* pinned state of the pane.
*
* Accepts the following attrs:
*
* - `className` The name of a class to set on the root element.
* - `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> {
constructor();
/**
* Get the back button.
*
* @return {Object}
* @protected
*/
protected getBackButton(): Object;
/**
* Get the pane pinned toggle button.
*
* @return {Object|String}
* @protected
*/
protected getPaneButton(): Object | string;
/**
* Get the drawer toggle button.
*
* @return {Object|String}
* @protected
*/
protected getDrawerButton(): Object | string;
}
import Component from "../Component";

View File

@@ -1,28 +0,0 @@
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> {
/**
* A class name to apply to the body while the route is active.
*/
protected bodyClass: string;
/**
* Whether we should scroll to the top of the page when its rendered.
*/
protected scrollTopOnCreate: boolean;
/**
* Whether the browser should restore scroll state on refreshes.
*/
protected useBrowserScrollRestoration: boolean;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
onremove(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
}

View File

@@ -1,12 +0,0 @@
/**
* The `Placeholder` component displays a muted text with some call to action,
* usually used as an empty state.
*
* ### Attrs
*
* - `text`
*/
export default class Placeholder extends Component<import("../Component").ComponentAttrs, undefined> {
constructor();
}
import Component from "../Component";

View File

@@ -1,12 +0,0 @@
/// <reference types="mithril" />
import type RequestError from '../utils/RequestError';
import Modal, { IInternalModalAttrs } from './Modal';
export interface IRequestErrorModalAttrs extends IInternalModalAttrs {
error: RequestError;
formattedError: string[];
}
export default class RequestErrorModal<CustomAttrs extends IRequestErrorModalAttrs = IRequestErrorModalAttrs> extends Modal<CustomAttrs> {
className(): string;
title(): string;
content(): JSX.Element;
}

View File

@@ -1,16 +0,0 @@
/**
* The `Select` component displays a <select> input, surrounded with some extra
* elements for styling. It accepts the following attrs:
*
* - `options` A map of option values to labels.
* - `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> {
constructor();
}
import Component from "../Component";

View File

@@ -1,13 +0,0 @@
/**
* The `SelectDropdown` component is the same as a `Dropdown`, except the toggle
* button's label is set as the label of the first child which has a truthy
* `active` prop.
*
* ### Attrs
*
* - `caretIcon`
* - `defaultLabel`
*/
export default class SelectDropdown extends Dropdown {
}
import Dropdown from "./Dropdown";

View File

@@ -1,11 +0,0 @@
export default Separator;
/**
* The `Separator` component defines a menu separator item.
*/
declare class Separator extends Component<import("../Component").ComponentAttrs, undefined> {
constructor();
}
declare namespace Separator {
const isListItem: boolean;
}
import Component from "../Component";

View File

@@ -1,15 +0,0 @@
/**
* The `SplitDropdown` component is similar to `Dropdown`, but the first child
* is displayed as its own button prior to the toggle button.
*/
export default class SplitDropdown extends Dropdown {
/**
* Get the first child. If the first child is an array, the first item in that
* array will be returned.
*
* @return {*}
* @protected
*/
protected getFirstChild(children: any): any;
}
import Dropdown from "./Dropdown";

View File

@@ -1,8 +0,0 @@
/**
* The `Switch` component is a `Checkbox`, but with a switch display instead of
* a tick/cross one.
*/
export default class Switch extends Checkbox {
static initAttrs(attrs: any): void;
}
import Checkbox from "./Checkbox";

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