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

Compare commits

..

147 Commits

Author SHA1 Message Date
Alexander Skvortsov
31a2f67462 Apply fixes from StyleCI
[ci skip] [skip ci]
2021-12-12 19:38:25 +00:00
Alexander Skvortsov
3da7d7d221 Add server metadata in writable paths errors 2021-12-12 14:38:08 -05:00
flarum-bot
02f351001c Bundled output for commit 6a909386b2
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-02 16:21:19 +00:00
Ian Morland
6a909386b2 Move colorItems to ItemList (#3186) 2021-12-02 11:16:50 -05:00
flarum-bot
17d25ba4ce Bundled output for commit c7662a320f
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-01 22:10:25 +00:00
Alexander Skvortsov
c7662a320f Fix app.route initialization
The first argument being an object breaks the forum, since a function can work in `Object.assign` if it is the first argument.
2021-12-01 17:05:57 -05:00
flarum-bot
5a9f60d250 Bundled output for commit c522657212
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-01 20:21:28 +00:00
Alexander Skvortsov
c522657212 Improve avatar upload experience (#3181)
Fixes https://github.com/flarum/core/issues/3055

- On the frontend, accept only image types as a hint to the OS file picker.
- On the backend, add more robust validation to ensure only valid images make it through. This isn't necessary for security, but results in less confusing error mesages.
2021-12-01 15:16:45 -05:00
flarum-bot
2b87f10738 Bundled output for commit 29c290e78f
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-01 16:32:02 +00:00
Alexander Skvortsov
29c290e78f Convert routes to Typescript (#3177) 2021-12-01 11:27:19 -05:00
flarum-bot
38c3ccd6be Bundled output for commit 71cb8c378f
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-26 22:30:49 +00:00
Alexander Skvortsov
71cb8c378f Add typing files for our translator libraries (#3175) 2021-11-26 17:26:37 -05:00
flarum-bot
94370375a5 Bundled output for commit afbf5f4905
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-23 22:58:48 +00:00
David Wheatley
afbf5f4905 fix: incorrect typings for Modal hide() method (#3180)
* fix: incorrect typings for `hide()`

* fix: swap to arrow calling of hide handler
2021-11-23 22:54:26 +00:00
David Sevilla Martin
aa0b68bc8d Convert some common classes/utils to TS (#2929)
* Convert common/Session

* Update common/states/AlertManagerState

* Convert common/utils/extractText

Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-11-23 17:51:04 -05:00
flarum-bot
1832fb090d Bundled output for commit 94c4f266e3
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-23 21:43:22 +00:00
David Sevilla Martin
94c4f266e3 feat: remove color validation in appearance admin page & add color indicator (#3140)
* Remove color validation in basics admin page & add color indicator

* Create ColorInput common component

* Revert 'formGroupAttrs' addition

* Rename component CSS classes

* Fix input type in ColorInput from AdminPage#buildSettingComponent

* Rename component to ColorPreviewInput, remove aliases in admin & export in compat

* Remove leftovers from rebase on master

* feat: add global type definition for a vnode element tag

* fix(a11y): add aria roles to color input

* chore: use new type

* chore: format

Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-11-23 21:38:46 +00:00
flarum-bot
c96fa49853 Bundled output for commit a203469109
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-23 13:06:36 +00:00
Sami Mazouz
a203469109 fix: Modal typings complicate inheritance (#3178) 2021-11-23 14:02:14 +01:00
David Wheatley
86d23a5de2 chore: use @php in Blade templates (#3172)
* chore: remove comment

* chore: use `@php` in blade templates

* chore: use `@php` in blade templates
2021-11-23 12:55:36 +00:00
David Wheatley
bb817d9a90 fix(a11y): show post action items when focus is within the post (#3173)
* fix: show post action items when focus is within the post

* fix: add missing `&`
2021-11-21 20:25:00 +00:00
flarum-bot
9117747d41 Bundled output for commit eaf1b86785
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-21 19:49:09 +00:00
David Wheatley
eaf1b86785 fix(a11y): add focus traps to modals and nav drawer (#3018)
* Add focus trap util

* Add focus trap to Modals

Fixes #2663

* Split tab press into `onTab` handler

* Remove deprecated code

* Use requestAnimationFrame instead of setTimeout

* Reduce code duplication

* Implement focus trap in nav drawer

Fixes #2665

* Hide drawer when window is resized to be bigger

Fixes issue where focus trap would remain on the drawer when it is
just the app header, if the drawer was opened then the window was
made larger.

* Simplify conditional function calls

* Fix modal focus trap

* Remove debug code

* Simplify resize handler conditional statements

* Add info about reasoning of resize handler

* Prefer native JS methods over jQuery

* Update conditional function call to handle `undefined`

* Expose screen sizes as CSS custom properties

* Use `window.matchMedia` rather than resize handler

* Fix spelling error

Co-authored-by: David Sevilla Martin <me@datitisev.me>

* Remove breaking change

Co-authored-by: David Sevilla Martin <me@datitisev.me>
2021-11-21 19:44:31 +00:00
flarum-bot
b2c83debb3 Bundled output for commit d82ae27231
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-19 17:46:08 +00:00
Sami Mazouz
d82ae27231 fix: Post--by-actor not showing when comparing user instances as discussion.user() is not loaded (#3170) 2021-11-19 18:41:13 +01:00
Alexander Skvortsov
7242b18ff0 Fix test cases for SetSettingsController 2021-11-16 16:54:23 -05:00
Alexander Skvortsov
f53a81bc18 Apply fixes from StyleCI
[ci skip] [skip ci]
2021-11-16 21:50:53 +00:00
Alexander Skvortsov
7c12e2c464 Add integration tests for settings API endpoint 2021-11-16 16:48:09 -05:00
flarum-bot
34e0ab6100 Bundled output for commit 390caa51db
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-16 20:55:56 +00:00
Alexander Skvortsov
390caa51db Fix minor typing error on UserListPage 2021-11-16 15:50:54 -05:00
Alexander Skvortsov
924815b6e1 Extension permission typings, fix glitch with extension permissions grid 2021-11-16 15:49:42 -05:00
Alexander Skvortsov
9b639e09f2 Fix errors on 20X responses with no body
`''` is not json-parsable, so  in that case we return null. This was the behavior prior to bac0e594ee
2021-11-16 13:34:28 -05:00
Daniël Klabbers
09fdd4cb6d fix: allow queue restarting (#3166)
By injecting the cache store into the queue, we allow queues to be
restarted using php flarum queue:restart and similar events dispatched
from within Laravelish classes.
2021-11-16 10:46:31 -05:00
flarum-bot
b4a44f70d9 Bundled output for commit c120f28d42
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-16 14:09:23 +00:00
Ian Morland
c120f28d42 Add priority order to discussion controls (#3165) 2021-11-16 15:04:54 +01:00
Garrett Grimm
5993c647a5 fix: enforce 65k character limit for setting values (#3162)
* Enforce 65k limit when attempting to store setting values.

* Add space for style.

* Move setting validation into Saving event listener.

* Use consistent var names

* remove extra space

* Move settings validation into separate class.

* Remove unused class.

* Remove extra line.

* Move ValidateCustomLess to SettingsServiceProvider.  Use existing convention for validator.

* Update src/Settings/SettingsValidator.php

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>

* Revert moving of ValidateCustomLess logic.  Allow for attribute specific setting validation rules.

* Style fixes.

* Style fixes.

* Style fixes.

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-11-12 18:43:57 +00:00
flarum-bot
359e9f6cbb Bundled output for commit d72b8b8d8e
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-12 00:58:35 +00:00
Alexander Skvortsov
d72b8b8d8e Fix some typing errors 2021-11-11 19:53:44 -05:00
flarum-bot
312ff057f8 Bundled output for commit 9b9ca53b81
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-11 20:59:55 +00:00
Garrett Grimm
9b9ca53b81 Add 'Close' & 'Back' aria-label attributes to buttons. (#3161)
* Add aria-label attributes to close buttons in nav, welcome hero, modal close.
* Replace title with aria-label in nav back button.
2021-11-11 15:55:46 -05:00
Garrett Grimm
4ffc26a13a Adjust boolean check of is_email_confirmed to suppress extraneous user activation events (#3163) 2021-11-11 15:51:47 -05:00
flarum-bot
5f110f73e7 Bundled output for commit cab2e797eb
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-11 20:05:26 +00:00
David Wheatley
cab2e797eb Rewrite ItemList; update ItemList typings (#3005)
* Improve typings for ItemList

* Add new `.replace()` syntax

* Update JSDoc

* Add missing `T` type

* Fix typo

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>

* Allow choice to not set `itemName` property when calling `toArray`

* Make `ItemList.items` read-only

* Modify `.replace()`; add `.changePriority()`

* Complete rename

* Update JSDoc

* Add `.toObject()` method; deprecate `.items`

* Rewrite `.toArray()` to use Proxy instead of modifying the item content

- Fixes #3030
- Fixes issue where setting `itemName` property could result in errors depending on the object type (e.g. proxies)
- Fixes unneeded duplication of item list
- Add option to disable setting `itemName` property on primitives

* Simplify condition

* Remove debug code

* Make proxying function protected instead of private

* Update a usage of ItemList as an example

* Make `itemName` property read-only

* Use correct capitalisation of `object`

* Invert `toArray` parameter function

* Simplify isEmpty check

* Update ItemList.ts

* Fix `merge()`

* Remove extra JSDoc comment

* Use `._items` directly for merging

* Rename methods: `replace` -> `set`; `changePriority` -> `setPriority`

This more closely matches our existing method names (`get()`)

* Change `items` getter

* Simplify proxying

* Update URL to source function

* Update compat

* Various changes to toObject

* Remove `Item.key`

* Make item content proxy method private

* Enforce merge typings

* Update TSDoc comments to use `{@link}` for references to methods

* Correct references to deprecated `.replace` method

* Throw error when setting content/priority of non-existent items

* Remove intermediary variable

* Update TSDoc block

* Update js/src/@types/global.d.ts

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-11-11 20:01:10 +00:00
flarum-bot
ec5214f714 Bundled output for commit bac0e594ee
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-11 19:21:56 +00:00
Alexander Skvortsov
bac0e594ee Add typechecks, typescript coverage GH action, fix many type errors (#3136) 2021-11-11 14:17:22 -05:00
David Wheatley
563d40d7da chore: migrate fully to Yarn (#3155)
* chore: migrate to Yarn package manager

* chore: bump deps, move `expose-loader` to correct deps section

* fix: remove package from old typescript shim

* feat: use Yarn Plug'n'Play

* chore: keep `node_modules` ignored for people who choose to use npm anyway

* Revert "feat: use Yarn Plug'n'Play"

This reverts commit 9781c8c8d5.
2021-11-10 20:10:25 +00:00
Daniel Klabbers
bfd81a83cf fix(logs): assign INFO scope to correct argument
Argument for INFO (constant value 200) was assigned to
maxfiles argument incorrectly.
2021-11-09 14:48:53 +01:00
flarum-bot
833c7540a3 Bundled output for commit ad2cef70d2
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-09 03:35:53 +00:00
David Wheatley
ad2cef70d2 chore: better typings for DiscussionListState (#3132) 2021-11-08 22:33:52 -05:00
flarum-bot
541684ee2a Bundled output for commit ec730d2615
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-08 23:55:13 +00:00
David Wheatley
ec730d2615 feat: allow use of any tag in listItems helper (#3147)
* feat: allow use of any tag in `listItems` helper

* fix: fix missing optional chaining

* chore: use more optional chaining

* fix: various typings errors

* chore: replace `Vnode[]` with `Children`
2021-11-08 23:52:47 +00:00
Sami Mazouz
f9f398b532 feat: Use an extensible document title driver implementation (#3109)
* feat: Use an extensible document title driver implementation
* chore: Add todo to use DI in 2.0
2021-11-08 23:15:32 +01:00
flarum-bot
4c61687833 Bundled output for commit b90001d98c
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-08 21:54:19 +00:00
David Sevilla Martin
b90001d98c Convert extend util to TypeScript (#2928)
* Allow using file extension in core compat imports

Necessary for extend imports to have proper typings as we also have an unrelated extend/index.js file

* Add .ts file extension to extend imports for typings

* Fix changes to proxifyCompat regex breaking non-core import paths

* Move utility types to global types

Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-11-08 16:52:13 -05:00
flarum-bot
6aad961545 Bundled output for commit e797276606
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-08 21:35:22 +00:00
Alexander Skvortsov
e797276606 Use calculated offset when loading page in PaginatedListState (#3159) 2021-11-08 16:33:07 -05:00
flarum-bot
8e52ec373e Bundled output for commit 0957cca9e2
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-08 18:42:22 +00:00
Garrett Grimm
0957cca9e2 Add aria-label attribute to navigation drawer button. (#3157)
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-11-08 13:40:17 -05:00
flarum-bot
2daee924c5 Bundled output for commit 8c47b197f0
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-04 21:40:48 +00:00
David Wheatley
8c47b197f0 fix: Component.component argument typings (#3148) 2021-11-04 21:38:50 +00:00
Sami Mazouz
809df29d29 feat: Declare & Use CSS Custom Properties (#3146) 2021-11-04 22:34:18 +01:00
flarum-bot
26bf5d350b Bundled output for commit 6eb05cfbad
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-03 23:23:42 +00:00
David Wheatley
6eb05cfbad chore: replace for ... in with Array.reduce (#3149) 2021-11-03 23:21:47 +00:00
Clark Winkelmann
8a69c890e7 Fix post policy for PHP 8 (#3145)
* Add tests to verify post policy works as intended
* Fix "reply" post edit setting not working on PHP 8

Fixes #3144
2021-11-01 16:38:21 -04:00
flarum-bot
9e1b05a358 Bundled output for commit 497dccee56
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-11-01 15:18:09 +00:00
David Sevilla Martin
497dccee56 Pass null/falsy values through Model.getIdentifier (#3131)
* Pass null/falsy values through Model.getIdentifier

* Add explicit if-return
2021-11-01 11:16:01 -04:00
Sami Mazouz
d8e7aa54b4 feat: Allow registering settings as Less config vars through Settings Extender (#3011)
Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-11-01 15:41:19 +01:00
Sami Mazouz
2b163025d6 feat: Create loadWhere relations extender (#3116) 2021-11-01 10:45:02 +01:00
flarum-bot
7b80d3932d Bundled output for commit c44cf42e2c
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-31 20:20:31 +00:00
Dan Wallis
c44cf42e2c Deprecate unused evented utility (#3125) 2021-10-31 16:18:44 -04:00
Sami Mazouz
fcf23ee8d5 feat: Default Settings Extender (#3127)
Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-10-31 21:09:06 +01:00
flarum-bot
7b2adf3b96 Bundled output for commit cb6405110c
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-31 18:23:34 +00:00
Alexander Skvortsov
cb6405110c Support, update to webpack 5 (#3135) 2021-10-31 14:21:17 -04:00
flarum-bot
89dfad5f38 Bundled output for commit 1e595e752a
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-30 23:18:37 +00:00
David Sevilla Martin
1e595e752a Add textarea setting type to AdminPage#buildSettingComponent (#3141) 2021-10-30 19:16:21 -04:00
flarum-bot
a6f660236f Bundled output for commit f260bd7efe
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-30 23:15:48 +00:00
David Sevilla Martin
f260bd7efe Switch to constructor MIN_SEARCH_LENGTH in Search component (#3130) 2021-10-30 19:13:43 -04:00
flarum-bot
823c337c1e Bundled output for commit f8232b9c1b
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-30 22:46:26 +00:00
David Wheatley
f8232b9c1b chore: rewrite frontend application files to Typescript (#3006)
* Rename files

* Rewrite common Application to TS

* Improve DefaultResolver typings

* Convert mapRoutes to TS

* Fix incorrect JSDoc type

* Add missing default value

* Add debug button string to localisations

* WIP Forum application TS rewrite

* Use union and intersection to remove property duplication

* Address some review comments

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>

* Address some review comments

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>

* Fix build error

* Address some review comments

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>

* Add `type` import qualifier

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-10-30 23:44:27 +01:00
flarum-bot
45927f1068 Bundled output for commit 7db2d0f697
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-30 22:31:34 +00:00
David Wheatley
7db2d0f697 chore: rewrite ModalManager and state to Typescript (#3007)
* Rewrite ModalManagerState into Typescript

- Fixes `attrs` parameter being marked as required
- Add `isModalOpen` method

* Rewrite ModalManager into Typescript

* Fix incorrect type

* Continue modal rewrite

* Update attr typings

* Fix correctly cast `this.constructor` calls

* Cast to bool

* Don't extend ModalAttrs by Record

* Prevent missing abstract methods in child Modals from bricking frontend

* Add missing `app` import

* Address review comment

Co-authored-by: David Sevilla Martin <6401250+datitisev@users.noreply.github.com>

Co-authored-by: David Sevilla Martin <6401250+datitisev@users.noreply.github.com>
2021-10-31 00:29:10 +02:00
David Wheatley
a0a06973c0 chore: rewrite SubtreeRetainer into Typescript (#3137)
* chore: rewrite SubtreeRetainer in Typescript

* chore: mark attributes as protected
2021-10-31 00:28:30 +02:00
flarum-bot
6ba385eea6 Bundled output for commit 70588959eb
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-29 22:39:58 +00:00
David Sevilla Martin
70588959eb fix: remove 'typeof' in 'typeof this' from AdminPage#buildSettingComponent params (#3142) 2021-10-30 00:37:41 +02:00
flarum-bot
8c3d92c427 Bundled output for commit acf16fdf2e
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-29 18:33:41 +00:00
Sami Mazouz
acf16fdf2e chore: Minor Readme CSS code tidy up (#3138) 2021-10-29 19:31:15 +01:00
David Wheatley
a1b5ef5154 fix: issue with CSS styles when in-between whole pixel values for viewport width (#3139)
* fix: issue with CSS styles when in-between whole pixel values for viewport width

Fixes #2915

* chore: add explanatory comment

* fix: add missing slash
2021-10-29 18:57:53 +01:00
flarum-bot
02c2df681d Bundled output for commit 2000727e94
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-29 17:35:09 +00:00
Alexander Skvortsov
2000727e94 Better post loading support (#3100)
Needed for https://github.com/flarum/core/issues/3043.

Some posts are loaded dynamically, and won't be immediately available. In this case, we show a loading indicator instead of displaying content. In this PR:

- We redraw post content if loading state has chnaged
- We show a loading indicator while loading
2021-10-29 13:32:30 -04:00
flarum-bot
33841d1e25 Bundled output for commit 28ead83b04
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-28 01:59:00 +00:00
Ian Morland
28ead83b04 Add README documentation to ExtensionPage (#3094)
Co-authored-by: Alexander Skvortsov <sasha.skvortsov109@gmail.com>
2021-10-27 21:56:56 -04:00
flarum-bot
247ace2f04 Bundled output for commit e0b6190733
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-27 21:01:48 +00:00
David Wheatley
e0b6190733 [A11Y] Improve accessibility for discussion reply count on post stream (#3090)
* Add class to remove all UA styles from a button

* Improve classList utilisation

* Simplify JSX

* Use classlist instead of concatenation

* Fix reply count focusable when not acting as a button

* Add SR only class

* Add new reply count translations

* Use cleaner translations

* Remove unused import

* Add missing new line

* Delete Accessibility.less

* Use existing `.visually-hidden` class

* Format

* Fix locale formatting
2021-10-27 22:59:17 +02:00
flarum-bot
f66a7ef7cc Bundled output for commit e550b15cea
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-27 20:44:05 +00:00
Alexander Skvortsov
e550b15cea Bump ICU MessageFormat (#3122)
This uses `Intl.PluralRules` for plural rules, and fixes a security vulnerability allowing JS injection through translation arguments.
2021-10-27 16:41:49 -04:00
flarum-bot
db6c8b8774 Bundled output for commit 4982efed3a
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-27 20:17:11 +00:00
David Wheatley
4982efed3a chore: bump JS dependencies (#3134) 2021-10-27 16:14:26 -04:00
David Wheatley
57d91b2d87 Revert "chore: better typings for DiscussionListState"
This reverts commit e9b3d3d313.
2021-10-27 17:17:24 +02:00
David Wheatley
e9b3d3d313 chore: better typings for DiscussionListState 2021-10-27 17:17:01 +02:00
Alexander Skvortsov
6200ffef9b Hide webkit search button (#3128) 2021-10-27 09:28:40 -04:00
flarum-bot
5e84490fd0 Bundled output for commit 2b0d55632e
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-26 21:35:14 +00:00
Alexander Skvortsov
2b0d55632e ExtensionPage: rename "Uninstall" to "Purge" (#3123)
https://i.imgur.com/aOOkqhk.png
2021-10-26 17:32:39 -04:00
Alexander Skvortsov
f7a78d85e3 Pass IP address to API Client pipeline (#3124)
The `ProcessIp` middleware won't run twice as that's in the global middleware stack, which the API client doesn't go through.
2021-10-26 17:11:40 -04:00
Sami Mazouz
972411673f fix: Use laravel validator to replace avatar validation error params (#2946) 2021-10-26 14:45:27 +01:00
flarum-bot
7ebf535b25 Bundled output for commit a661376d16
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-25 21:37:01 +00:00
Alexander Skvortsov
a661376d16 Catch errors when uploading white avatar (#3119) 2021-10-25 17:34:39 -04:00
MatusMak
5a1bf08d3f #2492 - Groups filtering & retrieve single endpoint (#3084)
Fixes #2492

* Added api/groups/{id} endpoint for retrieving a single group by its id
* Fixed GroupRepository incorrectly opening query to User instead of Group model
* Added filtering & paging abilities to GET api/groups endpoint
* Added test for sorting for GET api/groups endpoint

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-10-25 11:48:25 -04:00
flarum-bot
a9b1a518a2 Bundled output for commit 9416b1c150
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-25 05:47:17 +00:00
Clark Winkelmann
9416b1c150 Fix mail settings select component never being used (#3120) 2021-10-25 01:44:46 -04:00
Alexander Skvortsov
87f67744a8 Throw error if required route params missing (#3118)
Co-authored-by: Daniël Klabbers <daniel@klabbers.email>
Co-authored-by: luceos <luceos@users.noreply.github.com>
Co-authored-by: David Wheatley <hi@davwheat.dev>
Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>
2021-10-23 14:05:47 -04:00
SychO9
4add23a984 chore: Update version constant to 1.2.0-dev 2021-10-18 21:04:07 +01:00
flarum-bot
c52c0987fb Bundled output for commit 60f0ef0bd5
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-14 18:33:00 +00:00
Alexander Skvortsov
60f0ef0bd5 Handle post rendering errors to avoid bricking (#3061)
Whether it's due to corrupted content, missing tags, caching issues, or other assorted reasons, post content can't be rendered. Currently, this results in an exception that crashes the entire forum and is hard to debug. Instead, we should log the error and show an indicator message that rendering has failed.

Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-10-14 14:30:18 -04:00
flarum-bot
82d67919bb Bundled output for commit 713d95eb36
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-14 13:43:57 +00:00
Sami Mazouz
713d95eb36 fix: import app from common app instead (#3104)
Introduced in #3099
2021-10-14 14:41:22 +01:00
flarum-bot
d053bb5496 Bundled output for commit 05121b928a
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-13 18:58:05 +00:00
David Sevilla Martin
05121b928a Lazy draw dropdowns to improve performance (#2925) 2021-10-13 14:55:32 -04:00
Fransiscus Rolanda Malau
0a7e885eab Add missing autocomplete attributes to input fields (#3088)
* Add missing autocomplete attributes to input fields
* Add autocomplete attributes to password fields
* Attribute should use new-password
2021-10-13 14:53:35 -04:00
Maarten Bicknese
a65488000c Disallow dashes in database prefix (#3089)
As a temporary fix it has been requested to disallow dashes in the database prefix. The installation process fails when the prefix does include a dash.

#3022
2021-10-13 14:52:53 -04:00
Wouter
4146a4c578 Added new translations for the user editing modal (#3093) 2021-10-13 14:52:17 -04:00
flarum-bot
3f2e25b35f Bundled output for commit 2a86c25297
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-13 18:51:06 +00:00
Braunson Yager
2a86c25297 Added ES6 local support for formatNumber helper as per #2951 (#3099) 2021-10-13 14:48:37 -04:00
Sergiy Petrov
919c543cbc Test against php 8.1 (#3102) 2021-10-13 14:48:03 -04:00
Alexander Skvortsov
99112429f9 Release v1.1.0 2021-10-11 21:19:05 -04:00
Daniël Klabbers
b4772e5399 [huntr] adding cache control headers to the admin area (#3097)
This PR forces the `Cache-Control: no-store, max-age=0` header to the response in the Admin Area. This forces cache to be ignored upon browsing back and forth between pages using the browser controls. Although absolutely no fail safe, it should provide better protection against serving cached pages once an admin has signed out.
2021-10-07 18:34:22 -04:00
flarum-bot
2b47e90827 Bundled output for commit 1c2465b2da
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-10-07 03:33:54 +00:00
Alexander Skvortsov
1c2465b2da Support filter params in discussion list state
https://github.com/flarum/core/pull/3068 accidentially broke the user discussions page, as up until this commit, `DiscussionListState`didn't accept any filter params.
2021-10-06 23:30:32 -04:00
Alexander Skvortsov
a6717ee981 Remove .html on all docs urls
Now that Flarum docs have been moved to docusaurus, URLs no longer end with `.html`.

Closes https://github.com/flarum/core/issues/3092
2021-10-05 10:13:19 -04:00
flarum-bot
450ab61620 Bundled output for commit e2f01c040b
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-09-29 15:32:51 +00:00
Sami Mazouz
e2f01c040b fix: Anchors should not have type="button" (#3086) 2021-09-29 11:30:31 -04:00
Sami Mazouz
1d15cff9ca Filter composer icon array to only valid values (#3080) 2021-09-25 18:35:27 +01:00
David Wheatley
88724bb4cb performance(frontend): Preload FontAwesome, JS and CSS (#3057)
* Add preloads support to Document class

* Add frontend extender for asset preloading

* Provide default preloads for FontAwesome

* Add tests for preload extender and default preloads

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Fix typo

* Fix two more typos 🙃

* Preload core JS and CSS

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Reorder preloads

* Remove singular preloads method

* Use filesystem disk driver for getting FA font paths

* Update test to use full URL

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Address review comment

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Fix typo

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Correct callback wrapping

* Update src/Extend/Frontend.php

Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>

* Update src/Extend/Frontend.php

Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>

* Update src/Extend/Frontend.php

* Fix preload extender logic

* Convert base FontAwesome preloads into a Singleton

* Apply fixes from StyleCI

[ci skip] [skip ci]

Co-authored-by: luceos <luceos@users.noreply.github.com>
Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>
Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
Co-authored-by: Alexander Skvortsov <sasha.skvortsov109@gmail.com>
2021-09-20 23:12:09 +01:00
Alexander Skvortsov
1637b90531 Add determinsm to extension order resolution (#3076)
By sorting alphabetically by extension ID before applying topological sort, we ensure that a given set of extensions will always be booted in the same order. This will make it easier to replicate issues caused by complex extension dependencies.
2021-09-20 11:40:00 -04:00
flarum-bot
245d0d2550 Bundled output for commit 5dd48e1b86
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-09-20 15:08:49 +00:00
David Wheatley
5dd48e1b86 [A11Y] Accessibility improvements for the Search component (#3017)
* Remove deprecated code

* Accessibility improvements for Search component
2021-09-20 16:06:15 +01:00
Sami Mazouz
c1a8c6c190 fix: Sanitise integer query parameters (#3064) 2021-09-17 20:50:11 +01:00
David Wheatley
c10a30bae9 [A11Y] Adds missing focus rings back to control elements (#3016)
* Remove the stuff that removes critical accessibility features

* Remove no outline from basic blade layout

* Remove focus outline from FormControls
2021-09-13 23:47:13 +01:00
flarum-bot
b0bc021034 Bundled output for commit 1b193196da
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-09-11 08:26:35 +00:00
Rafael Horvat
1b193196da Use author filter parameter instead of q with gambit to get a user's discussions on the DiscussionsUserPage (#3068) 2021-09-11 09:24:15 +01:00
Sami Mazouz
f56fc11af9 [1.x] Theme Extender to Allow overriding LESS files (#3008)
This PR introduces the ability to just override a LESS file's contents through an extender.
This is mainly useful for theme development, as there are times in extensively customized themes where overriding the actual file makes a huge difference vs overriding CSS styles which can turn into a maintenance hell real fast.

Overriding styles is more tedious than overriding files. When you're designing an element, you would normally rather start from a blank canvas, than a styled element. With an already styled element you have to first override and undo the styles you do not wish to have, only then can you start shaping it, but even then you'd always end up constantly undoing default styles. This mostly applies for more advanced themes. (example: 851c55516d/less/forum/DiscussionList.less)
2021-09-10 13:45:18 -04:00
flarum-bot
ebdc232b11 Bundled output for commit eb0dd1f0d0
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-09-06 00:46:37 +00:00
David Sevilla Martín
eb0dd1f0d0 Add extra error handling for avatar file size & large payload (#3042)
* Add extra error handling for avatar file size & large payload

* Change error message to return 'upload failure' on most errors instead of 'no file' message
2021-09-05 20:43:59 -04:00
Sami Mazouz
1aa61f1f01 fix: Unable to use permission grid dropdowns due to z-index mistake (#3065)
The one I had suggested here: https://github.com/flarum/core/pull/2887#pullrequestreview-690047538
2021-09-05 18:29:18 +01:00
Sami Mazouz
e8153ccc79 feat: NoJs Admin View (#3059)
Adds a nojs blade template to be able to enable/disable extensions when one of them misbehaves.
2021-08-31 09:08:27 +01:00
Alexander Skvortsov
55d8af44a2 Move SECURITY.md file to central org repo 2021-08-30 15:43:52 -04:00
Alexander Skvortsov
4de5ad94f0 Use central FUNDING file 2021-08-30 15:42:07 -04:00
Alexander Skvortsov
735583397c Move PR template to central repo 2021-08-30 15:41:18 -04:00
356 changed files with 12721 additions and 16194 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +0,0 @@
github: flarum
open_collective: flarum

View File

@@ -1,24 +0,0 @@
<!--
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
View File

@@ -1,13 +0,0 @@
# Security Policy
## Versions
Due to the nature of our project - being open source - we have decided to patch only the latest major release (currently v1.x) for security vulnerabilities.
## How to disclose
Please use [huntr.dev](https://huntr.dev/) for security issues that affect our project. If you believe you have found a vulnerability, please disclose it via [this form](https://huntr.dev/bounties/disclose/?target=https://github.com/flarum/core).
This will enable us to **review** the vulnerability, **fix** it promptly, and **reward** you for your efforts.
If you have any questions about the process, feel free to reach out to security@huntr.dev or security@flarum.org.

View File

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

View File

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

2
.gitignore vendored
View File

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

View File

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

9
js/.gitignore vendored Normal file
View File

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

768
js/.yarn/releases/yarn-3.1.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

2
js/.yarnrc.yml Normal file
View File

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

View File

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

View File

@@ -1,3 +1,30 @@
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: {
@@ -11,7 +38,24 @@ export default class AdminApplication extends Application {
backUrl: () => any;
back: () => void;
};
getRequiredPermissions(permission: any): string[];
/**
* 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[];
}
import Application from "../common/Application";
import ExtensionData from "./utils/ExtensionData";

View File

@@ -1,5 +1,5 @@
declare var _default: {
extend: typeof import("../common/extend");
extend: any;
Session: typeof import("../common/Session").default;
Store: typeof import("../common/Store").default;
'utils/BasicEditorDriver': typeof import("../common/utils/BasicEditorDriver").default;
@@ -32,17 +32,15 @@ declare var _default: {
'utils/subclassOf': typeof import("../common/utils/subclassOf").default;
'utils/setRouteWithForcedRefresh': typeof import("../common/utils/setRouteWithForcedRefresh").default;
'utils/patchMithril': typeof import("../common/utils/patchMithril").default;
'utils/proxifyCompat': (compat: {
[key: string]: any;
}, namespace: string) => {
[key: string]: any;
};
'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;
@@ -69,6 +67,7 @@ declare var _default: {
'components/Link': typeof import("../common/components/Link").default;
'components/LinkButton': typeof import("../common/components/LinkButton").default;
'components/Checkbox': typeof import("../common/components/Checkbox").default;
'components/ColorPreviewInput': typeof import("../common/components/ColorPreviewInput").default;
'components/SelectDropdown': typeof import("../common/components/SelectDropdown").default;
'components/ModalManager': typeof import("../common/components/ModalManager").default;
'components/Button': typeof import("../common/components/Button").default;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,14 +2,15 @@
* The `EditGroupModal` component shows a modal dialog which allows the user
* to create or edit a group.
*/
export default class EditGroupModal extends Modal {
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;
fields(): ItemList<any>;
submitData(): {
nameSingular: any;
namePlural: any;

View File

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

View File

@@ -1,7 +1,15 @@
export default class ExtensionPage extends AdminPage<import("../../common/components/Page").IPageAttrs> {
constructor();
extension: any;
changingState: boolean | undefined;
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;
@@ -9,14 +17,16 @@ export default class ExtensionPage extends AdminPage<import("../../common/compon
website: string;
donate: string;
source: string;
} | undefined;
};
oninit(vnode: Mithril.Vnode<Attrs, this>): void;
className(): string;
sections(): ItemList;
topItems(): ItemList;
infoItems(): ItemList;
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: any): void;
onerror(e: RequestError): void;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,4 +1,19 @@
export default class ExtensionPermissionGrid extends PermissionGrid {
extensionId: any;
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>;
}
import PermissionGrid from "./PermissionGrid";

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,36 @@
export default class PermissionGrid extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
permissionItems(): ItemList;
viewItems(): ItemList;
startItems(): ItemList;
replyItems(): ItemList;
moderateItems(): ItemList;
scopeItems(): ItemList;
scopeControlItems(): ItemList;
import Component, { 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>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,10 @@
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 extends DefaultResolver {
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: any, requestedPath: any, route: any): any;
onmatch(args: Attrs & RouteArgs, requestedPath: string, route: string): new () => ExtensionPage<Attrs>;
}

View File

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

View File

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

View File

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

View File

@@ -99,7 +99,7 @@ export default abstract class Component<Attrs extends ComponentAttrs = Component
*
* @see https://mithril.js.org/hyperscript.html#mselector,-attributes,-children
*/
static component(attrs?: {}, children?: null): Mithril.Vnode;
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.

View File

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

View File

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

View File

@@ -1,3 +1,6 @@
/// <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 {
@@ -8,15 +11,15 @@ export default class Translator {
/**
* The underlying ICU MessageFormatter util.
*/
protected formatter: any;
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: any;
select: any;
plural: typeof pluralTypeHandler;
select: typeof selectTypeHandler;
};
/**
* A temporary system to preprocess parameters.
@@ -26,6 +29,6 @@ export default class Translator {
* @internal
*/
protected preprocessParameters(parameters: TranslatorParameters): TranslatorParameters;
trans(id: string, parameters?: TranslatorParameters): any;
trans(id: string, parameters?: TranslatorParameters): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
}
export {};

View File

@@ -1,5 +1,5 @@
declare var _default: {
extend: typeof extend;
extend: any;
Session: typeof Session;
Store: typeof Store;
'utils/BasicEditorDriver': typeof BasicEditorDriver;
@@ -32,17 +32,15 @@ declare var _default: {
'utils/subclassOf': typeof subclassOf;
'utils/setRouteWithForcedRefresh': typeof setRouteWithForcedRefresh;
'utils/patchMithril': typeof patchMithril;
'utils/proxifyCompat': (compat: {
[key: string]: any;
}, namespace: string) => {
[key: string]: any;
};
'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;
@@ -69,6 +67,7 @@ declare var _default: {
'components/Link': typeof Link;
'components/LinkButton': typeof LinkButton;
'components/Checkbox': typeof Checkbox;
'components/ColorPreviewInput': typeof ColorPreviewInput;
'components/SelectDropdown': typeof SelectDropdown;
'components/ModalManager': typeof ModalManager;
'components/Button': typeof Button;
@@ -93,7 +92,6 @@ declare var _default: {
'states/PaginatedListState': typeof PaginatedListState;
};
export default _default;
import * as extend from "./extend";
import Session from "./Session";
import Store from "./Store";
import BasicEditorDriver from "./utils/BasicEditorDriver";
@@ -118,10 +116,13 @@ 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";
@@ -148,6 +149,7 @@ import Alert from "./components/Alert";
import Link from "./components/Link";
import LinkButton from "./components/LinkButton";
import Checkbox from "./components/Checkbox";
import ColorPreviewInput from "./components/ColorPreviewInput";
import SelectDropdown from "./components/SelectDropdown";
import ModalManager from "./components/ModalManager";
import Button from "./components/Button";

View File

@@ -15,5 +15,5 @@ export interface AlertAttrs extends ComponentAttrs {
* some controls, and may be dismissible.
*/
export default class Alert<T extends AlertAttrs = AlertAttrs> extends Component<T> {
view(vnode: Mithril.Vnode): JSX.Element;
view(vnode: Mithril.VnodeDOM<T, this>): JSX.Element;
}

View File

@@ -60,8 +60,8 @@ export interface IButtonAttrs extends ComponentAttrs {
* styles can be applied by providing `className="Button"` to the Button component.
*/
export default class Button<CustomAttrs extends IButtonAttrs = IButtonAttrs> extends Component<CustomAttrs> {
view(vnode: Mithril.Vnode<IButtonAttrs, never>): JSX.Element;
oncreate(vnode: Mithril.VnodeDOM<IButtonAttrs, this>): void;
view(vnode: Mithril.VnodeDOM<CustomAttrs, this>): JSX.Element;
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>): void;
/**
* Get the template for the button's content.
*/

View File

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

View File

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

View File

@@ -1,11 +1,25 @@
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<import("../Component").ComponentAttrs, undefined> {
constructor();
animateShow(readyCallback: any): void;
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;
}
import Component from "../Component";
export {};

View File

@@ -1,3 +1,4 @@
import type Mithril from 'mithril';
import Component from '../Component';
export interface IPageAttrs {
key?: number;
@@ -9,7 +10,19 @@ export interface IPageAttrs {
* @abstract
*/
export default abstract class Page<CustomAttrs extends IPageAttrs = IPageAttrs> extends Component<CustomAttrs> {
oninit(vnode: any): void;
oncreate(vnode: any): void;
onremove(vnode: any): void;
/**
* 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,3 +1,4 @@
export default class RequestErrorModal extends Modal {
export default class RequestErrorModal extends Modal<import("./Modal").IInternalModalAttrs> {
constructor();
}
import Modal from "./Modal";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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