1
0
mirror of https://github.com/flarum/core.git synced 2025-08-13 11:54:32 +02:00

Compare commits

...

143 Commits

Author SHA1 Message Date
Alexander Skvortsov
dd5c516156 Release v1.2.1 2022-03-10 15:47:26 -05:00
Alexander Skvortsov
085c44ec63 chore: rebuild dist js 2022-03-10 15:44:30 -05:00
Alexander Skvortsov
60600f4d2b chore: bump rich text ICU Message formatter
This fixes https://discuss.flarum.org/d/29914-utf-encoding-error-in-title/6
2022-03-10 15:37:44 -05:00
Daniël Klabbers
7a22527b72 update changelog 2022-01-20 13:56:05 +01:00
Daniël Klabbers
bd4d53323c fixing error in tests for missing timezone 2022-01-20 13:42:26 +01:00
Daniel Klabbers
ad69cf84fe Release v1.2 2022-01-20 12:55:30 +01:00
flarum-bot
aa77df46ee Bundled output for commit 19e48617f0
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-20 09:33:26 +00:00
Alexander Skvortsov
19e48617f0 chore: bump rich icu message formatter 2022-01-20 04:27:39 -05:00
Alexander Skvortsov
d8b83cc372 fix: build typings script 2022-01-20 04:24:32 -05:00
Alexander Skvortsov
a04b420295 fix: typings generation script 2022-01-20 04:12:32 -05:00
flarum-bot
5f4b5c0841 Bundled output for commit beae75dab3
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-20 08:25:20 +00:00
Alexander Skvortsov
beae75dab3 chore: fl-dev audit infra --fix 2022-01-20 03:19:22 -05:00
flarum-bot
e304cf7cb5 Bundled output for commit 9f87674626
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-18 18:38:18 +00:00
Alexander Skvortsov
9f87674626 chore: bump @askvortsov/rich-icu-message-formatter (#3264)
Fixes https://github.com/flarum/core/issues/3259
2022-01-18 13:32:30 -05:00
flarum-bot
54329d0827 Bundled output for commit a7aad46068
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-14 05:30:33 +00:00
David Wheatley
a7aad46068 fix: mark near as optional in discussion route (#3257) 2022-01-14 00:25:29 -05:00
flarum-bot
7551a14ae5 Bundled output for commit f4c29db182
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-09 04:01:27 +00:00
Alexander Skvortsov
f4c29db182 fix: Allow outside click on modal focus trap
Without this, alerts triggered while a modal is open can't be dismissed.
2022-01-08 22:55:48 -05:00
Alexander Skvortsov
a291134da1 fix: don't spellcheck custom LESS
This should stop browsers from "correcting" code, and from converting regular quotes to "smart" quotes.
2022-01-08 22:55:48 -05:00
flarum-bot
c702f5e228 Bundled output for commit 749e7e34f7
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-09 00:24:36 +00:00
Alexander Skvortsov
749e7e34f7 Fix frontend branch name 2022-01-08 19:18:02 -05:00
Alexander Skvortsov
67821d95bd fix: Ensure user not false in post component
If no information about a relation exists, it will return false, not undefined. Therefore, the nullsafe operator is not enough to avoid issues here.
2022-01-08 18:26:51 -05:00
StyleCI Bot
aa44677df3 Apply fixes from StyleCI
[ci skip] [skip ci]
2022-01-06 02:47:52 +00:00
Alexander Skvortsov
3978efa533 LogDriver should work in debug mode 2022-01-05 21:47:33 -05:00
Alexander Skvortsov
687e1e2789 Use proper log level depending on debug mode 2022-01-05 21:45:27 -05:00
Alexander Skvortsov
7cec4d1f42 Format 2022-01-04 21:13:42 -05:00
Alexander Skvortsov
fbe1a48bec Fix echo statements not showing up in debug modals or console trace
This was accidentially introduced in the recent Application permissions refactor, where `formattedError`was changed to always be a string array.
2022-01-04 21:13:15 -05:00
David Wheatley
17a8d2c9d8 docs: add missing 1.1.1 changelog
This was present on the 1.1.1 branch, but not `master`.
2022-01-04 15:19:21 +00:00
Alexander Skvortsov
85ee80659d fix: broken post/discussion soft delete (#3249)
* FIx broken post/discussion soft delete

Before the Model typescript rewrite, `pushAttributes` supported including relationship objects, which is hacky but incorrect behavior. With the rewrite, this functionality was broken.

This PR deprecates the functionality, adds a deprecated BC layer with a debug warning, and removes instances of incorrect usage.

* Update js/src/common/Model.ts

Co-authored-by: David Wheatley <hi@davwheat.dev>

* Update js/src/common/Model.ts

Co-authored-by: David Wheatley <hi@davwheat.dev>

* chore: format

Co-authored-by: David Wheatley <hi@davwheat.dev>
2022-01-04 13:26:46 +00:00
Alexander Skvortsov
af77214967 Apply flarum-cli audit fix (#3248) 2022-01-03 16:57:09 -05:00
Alexander Skvortsov
7c3b51fec0 Use v1.0.0 of backend testing properly (#3247) 2022-01-03 16:04:17 -05:00
Sami Mazouz
ed3ea05c1a fix: Until reply renaming permission of discussions broken in php 8 (#3243)
* test: `until reply` rename discussion ability
* fix: `Until reply` renaming of discussions broken in php 8
2021-12-31 20:19:26 +01:00
flarum-bot
9fd6e5d0a2 Bundled output for commit 2541cdec94
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-29 09:43:23 +00:00
David Wheatley
2541cdec94 fix: prevent unwarranted a11y warnings on custom Button subclasses (#3238)
* fix: prevent unwarranted a11y warnings on UploadImageButton

* chore: format

* refactor

* fix: remove attr
2021-12-29 10:37:58 +01:00
David Wheatley
8fac735be0 fix: error in funding composer.json block bricks frontend (#3239)
* fix: error in funding `composer.json` block bricks frontend

* simplify

* Apply fixes from StyleCI

[ci skip] [skip ci]

Co-authored-by: luceos <luceos@users.noreply.github.com>
2021-12-29 03:25:03 +01:00
flarum-bot
53c3d13047 Bundled output for commit 993500aae4
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-28 20:13:43 +00:00
David Wheatley
993500aae4 fix(a11y): fix a11y warning in alert, and other a11y fixes (#3237)
* fix(a11y): fix a11y warning in alert, and other a11y fixes

* chore: correct import

* chore: use `class`
2021-12-28 21:08:34 +01:00
flarum-bot
0e9c169e06 Bundled output for commit 94f9e7f9de
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-28 19:56:55 +00:00
David Wheatley
94f9e7f9de fix: don't fire deprecation warnings for Mithril-originating action (#3236)
* fix: don't fire deprecation warnings for Mithril-originating actions

* Add comment
2021-12-28 20:51:13 +01:00
flarum-bot
4b25b90b48 Bundled output for commit a4fbf16eef
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-28 19:40:54 +00:00
David Wheatley
a4fbf16eef fix: mark render method in RouteResolver as optional (#3235) 2021-12-28 20:36:11 +01:00
David Wheatley
809620750f perf: include request info in first accesstoken touch (#3233) 2021-12-28 10:17:11 +01:00
flarum-bot
066cf02b88 Bundled output for commit cff672424b
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-28 01:30:26 +00:00
Alexander Skvortsov
cff672424b Merge pull request #3228 from flarum/as/v1.2_frontend_fixes
Some v1.2 frontend fixes
2021-12-27 20:24:53 -05:00
David Wheatley
2e94e31bb6 perf: only update last time when current value outdated (#3230)
* perf: only update last seen time when current > 120s ago

* perf: only update `last_activity_at` every 2 mins

* docs: add comment

* fix: add missing param

* test: add tests

* tests: attempt tests fix

* fix(tests): call `$this->app()`

* chore: extract hard-coded values out to private consts

* chore: increase diff

* Apply suggestions from code review
2021-12-28 00:39:42 +01:00
Alexander Skvortsov
b7f2fe2429 Fix consecutive shows of same modal with different attrs
We need to specify a unique key for each modal so that the modals are fully destroyed and recreated. For instance, this fixes the signup modal being empty with OAuth register flows.
2021-12-27 18:28:11 -05:00
flarum-bot
64dab138c4 Bundled output for commit 206aa227f2
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-27 23:18:49 +00:00
Alexander Skvortsov
a55b61e058 Use translations for page titles in frontend
This gives more flexibility for customization, and allows overriding title structure via translations / linguist.
2021-12-27 18:15:12 -05:00
Alexander Skvortsov
206aa227f2 Only retain scroll position if coming from discussion (#3229)
Fixes https://discuss.flarum.org/d/29596-make-tag-hero-visible/8.

If a user has just switched from one tag to another, they want to see the entire new discussion list, and information about which tag that discussion list corresponds to. There's no good reason to not display the hero header when switching tags.
2021-12-27 18:13:29 -05:00
flarum-bot
e926758060 Bundled output for commit ad8ac4e342
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-27 20:37:36 +00:00
David Wheatley
ad8ac4e342 fix: posts tab on users page broken 2021-12-27 21:32:04 +01:00
flarum-bot
2e5cd6f5c3 Bundled output for commit d5cd0bd339
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-27 19:59:19 +00:00
David Wheatley
d5cd0bd339 fix: returning null breaking CommentPosts 2021-12-27 20:54:00 +01:00
flarum-bot
09d1e289de Bundled output for commit d65deeccb5
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-27 19:09:19 +00:00
David Wheatley
d65deeccb5 chore: maintenance pre-1.2 release (#3213)
* chore: bump js dependencies

* chore: bump Yarn to 3.1.1

* chore: re-patch TS binary

* chore: don't show diffs for yarn lockfile
2021-12-27 19:04:42 +00:00
flarum-bot
3d62a6af27 Bundled output for commit d268894e61
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-27 19:02:33 +00:00
David Wheatley
d268894e61 chore: 1.2 JS clean-up (#3214)
* fix: `extend.ts` TS error

* docs: fix incorrect JS docblocks

* chore: simplify some code

* chore: remove usages of prefixed JS function

* chore: consistent empty return types

* chore: format

* fix: typing errors

* chore: remove unneeded `@public` docblock modifiers

* Apply suggestions from code review

* Update js/src/forum/utils/slidable.js

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

* Apply suggestions from code review

Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2021-12-27 18:58:18 +00:00
Alexander Skvortsov
d89031f057 Fix drawer focus trap making login form unclickable on mobile
Adding `clickOutsideDeactivates` seems to fix the issue, contrary to what the focus-trap documentation implies about it being unnecessary.
2021-12-26 22:45:58 -05:00
Alexander Skvortsov
0c95d28e94 Fix Search error when user can't search
If there are no search sources, HTML for the Search component won't be rendered, so trying to attach listeners to it will likely error.

In this PR, we don't attach such listeners/logic if there are no sources. We also stop asserting that sources is defined to help avoid other similar issues in the future.
2021-12-26 20:04:48 -05:00
flarum-bot
4df72e5ac6 Bundled output for commit a2f417e9c5
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-26 06:29:40 +00:00
David Wheatley
a2f417e9c5 fix: incorrect return type on pushPayload (#3226) 2021-12-26 01:25:16 -05:00
flarum-bot
dc661bf144 Bundled output for commit 7a27f494c6
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-22 18:58:42 +00:00
David Wheatley
7a27f494c6 fix: hide WelcomeHero when content is empty (#3219) 2021-12-22 13:54:21 -05:00
Sebastian Kessler
edde6be301 docs: fix broken contribution link in README; add screenshot (#3211) 2021-12-20 14:55:25 -05:00
flarum-bot
96fdaac3ef Bundled output for commit e57655553f
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-20 16:32:17 +00:00
David Wheatley
e57655553f fix: breaking change in Search component - renaming of state property (#3212)
* fix: breaking change in search component's public api

* fix: add setter

* feat: add deprecation warning helper

This reduces bundle size as a result of deprecation warning in our JS, as well as maintaining a consistent format across warnings.

* feat: fire deprecation warning on usage of `Search.state`

* chore: use consistent deprecation warning across core

* fix: `/pull` not `/issue`

* chore: format
2021-12-20 16:28:28 +00:00
David Wheatley
a1cc456f3a fix(postmeta): use app baseUrl instead of location.origin (#3216) 2021-12-20 16:25:04 +00:00
David Wheatley
4ad961c972 feat: allow replacing of blade template namespaces via extender (#3167)
* feat: allow replacing of blade template namespaces

* wip: add `prependNamespace` support

* test: add replace namespace test

* Apply fixes from StyleCI

[ci skip] [skip ci]

* fix: add missing property

* test: add prepend test

* fix: add view namespaces before resolving

Allows `replaceNamespace()` extender to actually remove old routes.

* test: make replace test ensure that replaced view does not exist

* docs: update docblock

* Apply fixes from StyleCI

[ci skip] [skip ci]

* fix: missing `\` before class

* fix: change test view namespace

* chore: simplify test

* Remove replace namespace code

We only really need prepend.

* chore: rename extender

* ci: add override test

* Apply fixes from StyleCI

[ci skip] [skip ci]

* fix(tests): add `trim` call

* revert: 3d46ead14b

Co-authored-by: luceos <luceos@users.noreply.github.com>
2021-12-20 09:56:48 +01:00
flarum-bot
7d9fe8e06b Bundled output for commit a36f98d1fc
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-16 08:36:25 +00:00
Sami Mazouz
a36f98d1fc fix: Add a11y labels to auth modal inputs (#3207) 2021-12-16 09:30:34 +01:00
flarum-bot
5befaa6886 Bundled output for commit 726661fe8c
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-15 15:53:25 +00:00
David Wheatley
726661fe8c fix: replace throw with debug warning to fix breaking change (#3206)
* fix: replace throw with debug warning to fix breaking change

* Add link back to PR in warning

* fix: add missing `return null` for `!allowUnregistered` code path

* Clean up message -- move more info to PR comment

* Add setTimeout to delay call debug warning call until after `app.forum` is defined

* Add backticks around data type
2021-12-15 10:48:46 -05:00
flarum-bot
b8b9f69820 Bundled output for commit c9a8543554
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-14 22:16:16 +00:00
Ian Morland
c9a8543554 feat: extract notification primaryControl items to an ItemList (#3204) 2021-12-14 22:11:48 +00:00
Ian Morland
6136ce8d8c feat: Add events for Notification read / read all (#3203) 2021-12-14 15:38:50 -05:00
David Wheatley
11fd012f70 feat: add Less custom function extender, is-extension-enabled function (#3190)
Co-authored-by: luceos <luceos@users.noreply.github.com>
Co-authored-by: Sami Mazouz <sychocouldy@gmail.com>
2021-12-14 19:25:39 +00:00
Ian Morland
25dc26bac6 Only update notifications that are not already marked as read (#3202) 2021-12-14 19:24:30 +01:00
flarum-bot
10c6694087 Bundled output for commit c88a3e7e89
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-14 17:10:20 +00:00
Alexander Skvortsov
c88a3e7e89 Merge pull request #2961 from the-turk/style-st
Improve selected text stylization
2021-12-14 12:06:22 -05:00
flarum-bot
f7e4413d96 Bundled output for commit e54c5b0924
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-14 03:11:57 +00:00
Alexander Skvortsov
e54c5b0924 Merge pull request #3196 from flarum/as/finish-typing
Finish typing, enable error on TypeScript check failure
2021-12-13 22:07:39 -05:00
Alexander Skvortsov
cbbb574e37 Format and Type Import Cleanup
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-13 22:04:36 -05:00
Alexander Skvortsov
4444357563 Error in GH actions on type failures 2021-12-13 20:20:35 -05:00
Alexander Skvortsov
55dd8f17f3 Fix typing errors with app.modal.show
Unfortunately TypeScript doesn't support higher-kinded types, so we can't write this in a type-safe way.
2021-12-13 20:20:35 -05:00
Alexander Skvortsov
718e01165a Slightly improve AlertManagerState show typing
`typeof Alert` is more correct than `Alert`, since we're accepting classes not instances.
2021-12-13 20:20:35 -05:00
Alexander Skvortsov
311e858c2b VnodeElementTag must be either a string or a class.
Unfortunately, TypeScript only supports strings and classes for JSX tags.
Therefore, our type definition should only allow for those two types.
see https://github.com/microsoft/TypeScript/issues/14789#issuecomment-412247771
2021-12-13 20:20:34 -05:00
Alexander Skvortsov
b13bc70339 Format VnodeElementTag fix 2021-12-13 20:20:34 -05:00
Alexander Skvortsov
a90140928c Modal typescript cleanup and conversions 2021-12-13 20:20:34 -05:00
Alexander Skvortsov
162c60e763 alertAttrs can be null 2021-12-13 20:20:34 -05:00
Alexander Skvortsov
174345cf22 Fix LoadingModal attr typings 2021-12-13 20:20:34 -05:00
Alexander Skvortsov
fe9cec0787 Allow any Mithril Children where appropriate 2021-12-13 20:20:33 -05:00
Alexander Skvortsov
1bdfe0112c extractText from translations where strings expected 2021-12-13 20:20:33 -05:00
Alexander Skvortsov
cc69211977 Fix import of mithril for VnodeElementTag usage 2021-12-13 20:20:33 -05:00
Alexander Skvortsov
02a57bfa8e Don't assume app.session.user is present 2021-12-13 20:20:33 -05:00
flarum-bot
0d45f2a881 Bundled output for commit 6c46fc4228
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-14 00:01:04 +00:00
Alexander Skvortsov
6c46fc4228 Merge pull request #3197 from flarum/as/permission-grid-fixes
Permission grid fixes
2021-12-13 18:56:11 -05:00
Alexander Skvortsov
1567ab0cb8 Return undefined => return null 2021-12-13 18:55:25 -05:00
flarum-bot
2554b9e774 Bundled output for commit b77f13b7c6
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-13 21:35:24 +00:00
Alexander Skvortsov
b77f13b7c6 Merge pull request #3200 from flarum/as/1_2_assorted_frontend_patches
A few frontend fixes for v1.2
2021-12-13 16:31:18 -05:00
Alexander Skvortsov
080442d085 Sync with v2.1 of markdown-toolbar-element 2021-12-13 16:03:34 -05:00
Hasan Özbey
fb82afa97f improve selected text stylization 2021-12-13 15:14:23 -05:00
Alexander Skvortsov
508be96f15 Don't throw errors for undefined relationships 2021-12-13 15:07:30 -05:00
Alexander Skvortsov
364575b3f0 Make sure this.data.attributes is initialized.
`Object.assign` is not type-safe, and does ensure that the property being assigned to is not undefined.
2021-12-13 12:34:51 -05:00
Sami Mazouz
c7791b63f7 perf: Allow loading relations in other discussion endpoints (#3191) 2021-12-13 11:34:26 +01:00
flarum-bot
dc48e2327b Bundled output for commit 6b7dfaa598
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-13 07:03:23 +00:00
Alexander Skvortsov
4ade45e67a Don't lazy draw permissions dropdown
It is already lazy drawn, see 23a70affa6/js/src/admin/components/PermissionDropdown.js (L63-L63)
2021-12-13 02:00:06 -05:00
Alexander Skvortsov
46893a9749 PermissionGrid fixes
Fixes https://github.com/flarum/core/issues/3169#issuecomment-979470794

- Restore wrapping `scope.render` results in a table cell tag. This was accidentially introduced in 924815b6e1, and caused the issue linked above
- Rename the `SettingDropdown` attr `key` to `setting` in order to avoid naming clashes with Mithril vnode keys. `key` still works, but is deprecated.
2021-12-13 02:00:06 -05:00
Alexander Skvortsov
6b7dfaa598 Format 2021-12-13 01:58:47 -05:00
Alexander Skvortsov
d0c160923d Fix listItems to unbrick admin extension pages
https://github.com/flarum/core/pull/3176 accidentially stopped adding a `key` attribute to wrappers of non-vnode inputs. This resulted in "all or no vnodes must have keys" errors.
2021-12-13 01:34:05 -05:00
flarum-bot
c2ec848744 Bundled output for commit 187b5c6f0b
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-13 01:41:29 +00:00
Alexander Skvortsov
187b5c6f0b Merge pull request #3174 from flarum/as/models-typing
Typescript for models
2021-12-12 20:37:32 -05:00
Ian Morland
bd8ebb00a0 feat: Allow switching the ImageManager driver (#3195) 2021-12-12 22:34:10 +01:00
Alexander Skvortsov
f26ad3e32d Minor typefixes, fomat 2021-12-12 15:46:46 -05:00
Alexander Skvortsov
4759395186 Post's discussion should always be present 2021-12-12 15:39:45 -05:00
Alexander Skvortsov
a2c8407dd4 params arguments for id-based app.store.find should be optional 2021-12-12 15:39:28 -05:00
Alexander Skvortsov
306b3a9e8b Type-safe session instantiation 2021-12-12 15:39:06 -05:00
Alexander Skvortsov
4444e7c788 Rename Discussion, User files to allow jsx 2021-12-12 15:18:37 -05:00
Alexander Skvortsov
4bd5bc87ee Update js/src/common/models/User.ts
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 15:18:37 -05:00
Alexander Skvortsov
528c964d94 Update js/src/common/models/User.ts
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 15:18:36 -05:00
Alexander Skvortsov
3bca30121b Update js/src/common/models/Discussion.ts
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 15:18:36 -05:00
Alexander Skvortsov
53180a38ac Update js/src/common/Store.ts
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 15:18:36 -05:00
Alexander Skvortsov
d82073c3a9 Update js/src/common/Model.ts
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 15:18:36 -05:00
Alexander Skvortsov
44efff342d Update js/src/common/Model.ts
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 15:18:36 -05:00
Alexander Skvortsov
0bdb018ad4 Add meta to ApiPayload interfaces 2021-12-12 15:18:35 -05:00
Alexander Skvortsov
b0504597da Review changes, make Model.store non-nullable, include meta in APIPayload signatures 2021-12-12 15:18:35 -05:00
Alexander Skvortsov
b85aa403cc Remove unnecessary nonnull assertions 2021-12-12 15:18:35 -05:00
Alexander Skvortsov
ab2620147a Drop unnecessary JSDocs 2021-12-12 15:18:35 -05:00
Alexander Skvortsov
09a55258a0 format 2021-12-12 15:18:34 -05:00
Alexander Skvortsov
3a8d640dab Clean up model nullability 2021-12-12 15:18:34 -05:00
Alexander Skvortsov
bbc9143404 Convert models to TS 2021-12-12 15:18:34 -05:00
flarum-bot
7be0c02ba1 Bundled output for commit 580be37eb4
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-12 19:55:47 +00:00
Alexander Skvortsov
580be37eb4 listItems typing fix (#3176)
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-12 14:51:05 -05:00
Ian Morland
0e00196d8e Make SlugManager available to blade template (#3194)
* Make SlugManager available to blade template

* Use
2021-12-12 20:40:38 +01:00
flarum-bot
a57ef5a3d5 Bundled output for commit 325b9afca6
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-12 19:35:29 +00:00
Ian Morland
325b9afca6 fix: getPlainContent causes external content to be fetched (#3193) 2021-12-12 14:30:56 -05:00
flarum-bot
1a420828aa Bundled output for commit 57b413ada5
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-11 17:37:26 +00:00
Alexander Skvortsov
57b413ada5 Split up application error handling (#3184)
Co-authored-by: David Wheatley <hi@davwheat.dev>
2021-12-11 12:32:51 -05:00
flarum-bot
326b787130 Bundled output for commit 0f2824e0f4
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-07 18:55:28 +00:00
Rafał Całka
0f2824e0f4 Make StatusWidget tools extensible (#3189) 2021-12-07 13:50:40 -05:00
Daniël Klabbers
7bab6eddf6 Use revision versioner to allow custom asset versioning (#3183) 2021-12-06 12:49:21 -05:00
flarum-bot
b7a9911ffb Bundled output for commit c219699024
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2021-12-06 17:07:57 +00:00
David Wheatley
c219699024 fix: clicking three dots on post opens all dropdowns in .Post-actions (#3185) 2021-12-06 18:03:07 +01:00
Alexander Skvortsov
dcc9868129 Centralize pagination/canonical meta URL generation in Document (#3077)
* Centralize pagination/canonical meta URL generation in Document

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Use translations for title template

* Apply fixes from StyleCI

[ci skip] [skip ci]

* Dont add translator to title driver interface

It's an implementation detail, and can be made available on specific implementations as needed.

Co-authored-by: Alexander Skvortsov <askvortsov1@users.noreply.github.com>
2021-12-03 13:31:50 -05:00
283 changed files with 4790 additions and 3273 deletions

1
.gitattributes vendored
View File

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

15
.github/workflows/backend.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Core PHP
on: [workflow_dispatch, push, pull_request]
# The reusable workflow definitions will be moved to the `flarum/framework` repo soon.
# This will break your current script.
# When this happens, run `flarum-cli audit infra --fix` to update your infrastructure.
jobs:
run:
uses: flarum/.github/.github/workflows/REUSABLE_backend.yml@main
with:
enable_backend_testing: true
backend_directory: .

21
.github/workflows/frontend.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Core JS
on: [workflow_dispatch, push, pull_request]
# The reusable workflow definitions will be moved to the `flarum/framework` repo soon.
# This will break your current script.
# When this happens, run `flarum-cli audit infra --fix` to update your infrastructure.
jobs:
run:
uses: flarum/.github/.github/workflows/REUSABLE_frontend.yml@main
with:
enable_bundlewatch: true
enable_prettier: true
enable_typescript: true
frontend_directory: ./js
main_git_branch: master
secrets:
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}

View File

@@ -1,137 +0,0 @@
name: JS
on: [workflow_dispatch, push, pull_request]
env:
NODE_VERSION: 16
jobs:
prettier:
name: Prettier
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
- name: Install JS dependencies
run: yarn install --immutable
working-directory: ./js
- name: Check JS formatting
run: yarn run format-check
working-directory: ./js
typecheck:
name: Typecheck
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
- name: Install JS dependencies
run: yarn --frozen-lockfile
working-directory: ./js
- name: Typecheck
run: yarn run check-typings || true # REMOVE THIS ONCE TYPE SAFETY REACHED
working-directory: ./js
type-coverage:
name: Type Coverage
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
- name: Install JS dependencies
run: yarn --frozen-lockfile
working-directory: ./js
- name: Check type coverage
run: yarn run check-typings-coverage
working-directory: ./js
build-prod:
name: Build and commit
runs-on: ubuntu-latest
needs: [prettier, typecheck, type-coverage]
# Only commit JS on push to master branch
# Remember to change in `build-test` job too
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
- name: Build production JS
uses: flarum/action-build@2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: yarn
typings_script: build-typings
build-test:
name: Test build
runs-on: ubuntu-latest
needs: [prettier, typecheck, type-coverage]
# Inverse check of `build-prod`
# Remember to change in `build-prod` job too
if: github.ref != 'refs/heads/master' || github.event_name != 'push'
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"
cache-dependency-path: js/yarn.lock
# Our action will install npm, cd into `./js`, run `npm run build` and
# `npm run build-typings`, then commit and upload any changes
- name: Build production JS
uses: flarum/action-build@2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build
package_manager: yarn
typings_script: build-typings
do_not_commit: true

View File

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

View File

@@ -1,79 +0,0 @@
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
php: [7.3, 7.4, '8.0', '8.1']
service: ['mysql:5.7', mariadb]
prefix: ['', flarum_]
include:
- service: 'mysql:5.7'
db: MySQL
- service: mariadb
db: MariaDB
- prefix: flarum_
prefixStr: (prefix)
exclude:
- php: 7.3
service: 'mysql:5.7'
prefix: flarum_
- php: 7.3
service: mariadb
prefix: flarum_
- php: 8.0
service: 'mysql:5.7'
prefix: flarum_
- php: 8.0
service: mariadb
prefix: flarum_
services:
mysql:
image: ${{ matrix.service }}
ports:
- 13306:3306
name: 'PHP ${{ matrix.php }} / ${{ matrix.db }} ${{ matrix.prefixStr }}'
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@0b9d33cd0782337377999751fc10ea079fdd7104 # pin@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
extensions: curl, dom, gd, json, mbstring, openssl, pdo_mysql, tokenizer, zip
tools: phpunit, composer:v2
# The authentication alter is necessary because newer mysql versions use the `caching_sha2_password` driver,
# which isn't supported prior to PHP7.4
# When we drop support for PHP7.3, we should remove this from the setup.
- name: Create MySQL Database
run: |
sudo systemctl start mysql
mysql -uroot -proot -e 'CREATE DATABASE flarum_test;' --port 13306
mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';" --port 13306
- name: Install Composer dependencies
run: composer install
- name: Setup Composer tests
run: composer test:setup
env:
DB_PORT: 13306
DB_PASSWORD: root
DB_PREFIX: ${{ matrix.prefix }}
- name: Run Composer tests
run: composer test
env:
COMPOSER_PROCESS_TIMEOUT: 600

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
/vendor
composer.lock
composer.phar
.DS_Store
Thumbs.db
tests/.phpunit.result.cache

View File

@@ -1,5 +1,120 @@
# Changelog
## [1.2.1](https://github.com/flarum/core/compare/v1.2.0...v1.2.1)
### Fixed
- Don't escape single quotes in discussion title meta tags (60600f4d2b8f0c5dac94c329041427a0a08fad42)
## [1.2.0](https://github.com/flarum/core/compare/v1.1.1...v1.2.0)
### Added
- View `README` documentation in extension pages (https://github.com/flarum/core/pull/3094).
- Declare & Use CSS Custom Properties (https://github.com/flarum/core/pull/3146).
- Lazy draw dropdowns to improve performance (https://github.com/flarum/core/pull/2925).
- Default Settings Extender (https://github.com/flarum/core/pull/3127).
- Add `textarea` setting type to admin pages (https://github.com/flarum/core/pull/3141).
- Allow registering settings as `Less` config vars through Settings Extender (https://github.com/flarum/core/pull/3011).
- Allow replacing of blade template namespaces via extender (https://github.com/flarum/core/pull/3167).
- Update to Webpack 5 (https://github.com/flarum/core/pull/3135).
- Introduce `Less` custom function extender with a `is-extension-enabled` function (https://github.com/flarum/core/pull/3190).
- Support for `few` in ICU Message syntax (https://github.com/flarum/core/pull/3122).
- ES6 local support for number formatting (https://github.com/flarum/core/pull/3099).
- Added dedicated endpoint for retrieving single groups (https://github.com/flarum/core/pull/3084).
- Callback `loadWhere` relation eager loading extender (https://github.com/flarum/core/pull/3116).
- Extensible document title driver implementation (https://github.com/flarum/core/pull/3109).
- Type checks, typescript coverage GH action (https://github.com/flarum/core/pull/3136).
- Add color indicator in appearance admin page instead of validating colors (https://github.com/flarum/core/pull/3140).
- Add typing files for our translator libraries (https://github.com/flarum/core/pull/3175).
- `StatusWidget` tools extensibility (https://github.com/flarum/core/pull/3189).
- Allow switching the `ImageManager` driver (https://github.com/flarum/core/pull/3195).
- Events for notification read/all read actions (https://github.com/flarum/core/pull/3203).
### Changed
- Testing with php8.1 (https://github.com/flarum/core/pull/3102).
- Migrate fully to Yarn (https://github.com/flarum/core/pull/3155).
- Handle post rendering errors to avoid crashes (https://github.com/flarum/core/pull/3061).
- Added basic filtering, sorting, and pagination to groups endpoint (https://github.com/flarum/core/pull/3084).
- Pass IP address to API Client pipeline (https://github.com/flarum/core/pull/3124).
- Rename Extension Page "Uninstall" to "Purge" (https://github.com/flarum/core/pull/3123).
- [A11Y] Improve accessibility for discussion reply count on post stream (https://github.com/flarum/core/pull/3090).
- Improved post loading support (https://github.com/flarum/core/pull/3100).
- Rewrite SubtreeRetainer into Typescript (https://github.com/flarum/core/pull/3137).
- Rewrite ModalManager and state to Typescript (https://github.com/flarum/core/pull/3007).
- Rewrite frontend application files to Typescript (https://github.com/flarum/core/pull/3006).
- Allow extensions to modify the minimum search length in the Search component (https://github.com/flarum/core/pull/3130).
- Allow use of any tag in `listItems` helper (https://github.com/flarum/core/pull/3147).
- Replace `for ... in` with `Array.reduce` (https://github.com/flarum/core/pull/3149).
- Page title format is now implemented through translations (https://github.com/flarum/core/pull/3077, https://github.com/flarum/core/pull/3228)
- Add `aria-label` attribute to the navigation drawer button (https://github.com/flarum/core/pull/3157).
- Convert extend util to TypeScript (https://github.com/flarum/core/pull/2928).
- Better typings for DiscussionListState (https://github.com/flarum/core/pull/3132).
- Rewrite ItemList, update `ItemList` typings (https://github.com/flarum/core/pull/3005).
- Add priority order to discussion page controls (https://github.com/flarum/core/pull/3165).
- Use `@php` in Blade templates (https://github.com/flarum/core/pull/3172).
- Convert some common classes/utils to TS (https://github.com/flarum/core/pull/2929).
- Convert routes to Typescript (https://github.com/flarum/core/pull/3177).
- Move admin `colorItems` to an `ItemList` (https://github.com/flarum/core/pull/3186).
- Centralize pagination/canonical meta URL generation in Document (https://github.com/flarum/core/pull/3077).
- Use revision versioner to allow custom asset versioning (https://github.com/flarum/core/pull/3183).
- Split up application error handling (https://github.com/flarum/core/pull/3184).
- Make SlugManager available to blade template (https://github.com/flarum/core/pull/3194).
- Convert models to TS (https://github.com/flarum/core/pull/3174).
- Allow loading relations in other discussion endpoints (https://github.com/flarum/core/pull/3191).
- Improve selected text stylization (https://github.com/flarum/core/pull/2961).
- Extract notification `primaryControl` items to an ItemList (https://github.com/flarum/core/pull/3204).
- Frontend code housekeeping (#3214, #3213).
- Only retain scroll position if coming from discussion (https://github.com/flarum/core/pull/3229).
- Use `aria-live` regions to focus screenreader attention on alerts as they appear (https://github.com/flarum/core/pull/3237).
- Prevent unwarranted `a11y` warnings on custom Button subclasses (https://github.com/flarum/core/pull/3238).
### Fixed
- Missing locale text in the user editing modal (https://github.com/flarum/core/pull/3093).
- Dashes in table prefix prevent installation (https://github.com/flarum/core/pull/3089).
- Missing autocomplete attributes to input fields (https://github.com/flarum/core/pull/3088).
- Missing route parameters throwing an error (https://github.com/flarum/core/pull/3118).
- Mail settings select component never used (https://github.com/flarum/core/pull/3120).
- White avatar image throws javascript errors on the profile page (https://github.com/flarum/core/pull/3119).
- Unformatted avatar upload validation errors (https://github.com/flarum/core/pull/2946).
- Webkit input clear button shows up with the custom one (https://github.com/flarum/core/pull/3128).
- Media query breakpoints conflict with Windows display scaling (https://github.com/flarum/core/pull/3139).
- `typeof this` not recognized by some IDEs (https://github.com/flarum/core/pull/3142).
- `Model.save()` cannot save `null` `hasOne` relationship (https://github.com/flarum/core/pull/3131).
- Edit post `until reply` policy broken on PHP 8 (https://github.com/flarum/core/pull/3145).
- Inaccurate `Component.component` argument typings (https://github.com/flarum/core/pull/3148).
- Scrolling notification list infinitely repeats (https://github.com/flarum/core/pull/3159).
- Argument for INFO constant was assigned to `maxfiles` argument incorrectly (bfd81a83cfd0fa8125395a147ff0c9ce622f38e3).
- `Activated` event is sent every time an email is confirmed instead of just once (https://github.com/flarum/core/pull/3163).
- [A11Y] Modal close button missing accessible label (https://github.com/flarum/core/pull/3161).
- [A11Y] Auth modal inputs missing accessible labels (https://github.com/flarum/core/pull/3207).
- [A11Y] Triggering click on drawer button can cause layered backdrops (https://github.com/flarum/core/pull/3018).
- [A11Y] Focus can leave open nav drawer on mobile (https://github.com/flarum/core/pull/3018).
- [A11Y] Post action items not showing when focus is within the post (https://github.com/flarum/core/pull/3173).
- [A11Y] Missing accessible label for alert dismiss button (https://github.com/flarum/core/pull/3237).
- Error accessing the forum after saving a setting with more than 65k characters (https://github.com/flarum/core/pull/3162).
- Cannot restart queue from within (https://github.com/flarum/core/pull/3166).
- `Post--by-actor` not showing when comparing user instances (https://github.com/flarum/core/pull/3170).
- Incorrect typings for Modal `hide()` method (https://github.com/flarum/core/pull/3180).
- Avatar Upload throws errors with correct mimetype and incorrect extension (https://github.com/flarum/core/pull/3181).
- Clicking the dropdown button on a post opens all dropdowns in `Post-actions` (https://github.com/flarum/core/pull/3185).
- `getPlainContent()` causes external content to be fetched (https://github.com/flarum/core/pull/3193).
- `listItems` not accepting all `Mithril.Children` (https://github.com/flarum/core/pull/3176).
- Notifications mark as read option updates all notifications including the read ones (https://github.com/flarum/core/pull/3202).
- Post meta permalink not properly generated (https://github.com/flarum/core/pull/3216).
- Broken contribution link in README (https://github.com/flarum/core/pull/3211).
- `WelcomeHero` is displayed when content is empty (https://github.com/flarum/core/pull/3219).
- `last_activity_at, last_seen_at` updated on all API requests (https://github.com/flarum/core/pull/3231).
- `RememberMe` access token updated twice in API requests (https://github.com/flarum/core/pull/3233).
- Error in `funding` item in `composer.json` bricks the frontend (https://github.com/flarum/core/pull/3239).
- Escaped quotes in window title (https://github.com/flarum/core/pull/3264)
- `schedule:list` command fails due to missing timezone configuration.
### Deprecated
- Unused `evented` utility (https://github.com/flarum/core/pull/3125).
## [1.1.1](https://github.com/flarum/core/compare/v1.1.0...v1.1.1)
### Fixed
- Performance issue with very large communities.
## [1.1.0](https://github.com/flarum/core/compare/v1.0.4...v1.1.0)

View File

View File

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

View File

@@ -86,7 +86,7 @@
"wikimedia/less.php": "^3.0"
},
"require-dev": {
"flarum/testing": "1.0@dev"
"flarum/testing": "^1.0.0"
},
"autoload": {
"psr-4": {
@@ -107,6 +107,28 @@
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
},
"flarum-cli": {
"excludeScaffolding": [
"LICENSE.md",
"js/tsconfig.json",
"js/webpack.config.js"
],
"modules": {
"backendTesting": true,
"js": true,
"gitConf": true,
"githubActions": true,
"prettier": true,
"typescript": true,
"bundlewatch": true,
"editorConfig": true,
"styleci": true,
"admin": true,
"forum": true,
"jsCommon": true,
"css": true
}
}
},
"scripts": {

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -1,2 +1,2 @@
export * from './src/common';
export * from './src/admin';
export * from './src/admin';

View File

@@ -21,7 +21,20 @@ declare type KeysOfType<Type extends object, Match> = {
*/
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>;
type Component<A> = import('mithril').Component<A>;
declare type ComponentClass<Attrs = Record<string, unknown>, C extends Component<Attrs> = Component<Attrs>> = {
new (...args: any[]): Component<Attrs>;
prototype: C;
};
/**
* Unfortunately, TypeScript only supports strings and classes for JSX tags.
* Therefore, our type definition should only allow for those two types.
*
* @see https://github.com/microsoft/TypeScript/issues/14789#issuecomment-412247771
*/
declare type VnodeElementTag<Attrs = Record<string, unknown>, C extends Component<Attrs> = Component<Attrs>> = string | ComponentClass<Attrs, C>;
/**
* @deprecated Please import `app` from a namespace instead of using it as a global variable.
@@ -46,6 +59,17 @@ declare const app: never;
declare const m: import('mithril').Static;
declare const dayjs: typeof import('dayjs');
/**
* From https://github.com/lokesh/color-thief/issues/188
*/
declare module 'color-thief-browser' {
type Color = [number, number, number];
export default class ColorThief {
getColor: (img: HTMLImageElement | null) => Color;
getPalette: (img: HTMLImageElement | null) => Color[];
}
}
type ESModule = { __esModule: true; [key: string]: unknown };
/**

View File

@@ -35,7 +35,7 @@ export default class AdminApplication extends Application {
history: {
canGoBack: () => boolean;
getPrevious: () => void;
backUrl: () => any;
backUrl: () => string;
back: () => void;
};
/**

View File

@@ -4,8 +4,8 @@ declare var _default: {
Store: typeof import("../common/Store").default;
'utils/BasicEditorDriver': typeof import("../common/utils/BasicEditorDriver").default;
'utils/evented': {
handlers: Object;
getHandlers(event: string): any[];
handlers: Record<string, unknown>;
getHandlers(event: string): Function[];
trigger(event: string, ...args: any[]): void;
on(event: string, handler: Function): void;
one(event: string, handler: Function): void;

View File

@@ -5,9 +5,9 @@ export default class AdminNav extends Component<import("../../common/Component")
/**
* Build an item list of main links to show in the admin navigation.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
extensionItems(): ItemList<any>;
}
import Component from "../../common/Component";

View File

@@ -2,8 +2,8 @@ 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;
title: Mithril.Children;
description: Mithril.Children;
icon: string;
/**
* Will be used as the class for the AdminPage.

View File

@@ -7,10 +7,12 @@ export default class BasicsPage extends AdminPage<import("../../common/component
* Build a list of options for the default homepage. Each option must be an
* object with `path` and `label` properties.
*
* @return {ItemList}
* @public
* @return {ItemList<{ path: string, label: import('mithril').Children }>}
*/
public homePageItems(): ItemList<any>;
homePageItems(): ItemList<{
path: string;
label: import('mithril').Children;
}>;
}
import AdminPage from "./AdminPage";
import ItemList from "../../common/utils/ItemList";

View File

@@ -3,14 +3,14 @@ export default class DashboardWidget extends Component<import("../../common/Comp
/**
* Get the class name to apply to the widget.
*
* @return {String}
* @return {string}
*/
className(): string;
/**
* Get the content of the widget.
*
* @return {VirtualElement}
* @return {import('mithril').Children}
*/
content(): any;
content(): import('mithril').Children;
}
import Component from "../../common/Component";

View File

@@ -8,9 +8,9 @@ export default class HeaderPrimary extends Component<import("../../common/Compon
/**
* Build an item list for the controls.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -6,9 +6,9 @@ export default class HeaderSecondary extends Component<import("../../common/Comp
/**
* Build an item list for the controls.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,6 +1,8 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal from '../../common/components/Modal';
export default class LoadingModal<ModalAttrs = {}> extends Modal<ModalAttrs> {
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
export interface ILoadingModalAttrs extends IInternalModalAttrs {
}
export default class LoadingModal<ModalAttrs extends ILoadingModalAttrs = ILoadingModalAttrs> extends Modal<ModalAttrs> {
/**
* @inheritdoc
*/

View File

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

View File

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

View File

@@ -13,16 +13,16 @@ export default class UploadImageButton extends Button<import("../../common/compo
/**
* After a successful upload/removal, reload the page.
*
* @param {Object} response
* @param {object} response
* @protected
*/
protected success(response: Object): void;
protected success(response: object): void;
/**
* If upload/removal fails, stop loading.
*
* @param {Object} response
* @param {object} response
* @protected
*/
protected failure(response: Object): void;
protected failure(response: object): void;
}
import Button from "../../common/components/Button";

View File

@@ -1,5 +1,5 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference types="mithril" />
import type Mithril from 'mithril';
import type User from '../../common/models/User';
import ItemList from '../../common/utils/ItemList';
import AdminPage from './AdminPage';
@@ -7,11 +7,11 @@ declare type ColumnData = {
/**
* Column title
*/
name: String;
name: Mithril.Children;
/**
* Component(s) to show for this column.
*/
content: (user: User) => JSX.Element;
content: (user: User) => Mithril.Children;
};
/**
* Admin page which displays a paginated list of all users on the forum.

View File

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

View File

@@ -1,6 +1,6 @@
import ItemList from './utils/ItemList';
import Translator from './Translator';
import Store from './Store';
import Store, { ApiPayload, ApiResponsePlural, ApiResponseSingle } from './Store';
import Session from './Session';
import Drawer from './utils/Drawer';
import RequestError, { InternalFlarumRequestOptions } from './utils/RequestError';
@@ -12,6 +12,7 @@ import type DefaultResolver from './resolvers/DefaultResolver';
import type Mithril from 'mithril';
import type Component from './Component';
import type { ComponentAttrs } from './Component';
import Model, { SavedModelData } from './Model';
export declare type FlarumScreens = 'phone' | 'tablet' | 'desktop' | 'desktop-hd';
export declare type FlarumGenericRoute = RouteItem<any, any, any>;
export interface FlarumRequestOptions<ResponseType> extends Omit<Mithril.RequestOptions<ResponseType>, 'extract'> {
@@ -72,6 +73,8 @@ export interface RouteResolver<Attrs extends ComponentAttrs, Comp extends Compon
*
* Returns the component class, and **not** a Vnode or JSX
* expression.
*
* @see https://mithril.js.org/route.html#routeresolveronmatch
*/
onmatch(this: this, args: RouteArgs, requestedPath: string, route: string): {
new (): Comp;
@@ -79,9 +82,14 @@ export interface RouteResolver<Attrs extends ComponentAttrs, Comp extends Compon
/**
* A function which renders the provided component.
*
* If not specified, the route will default to rendering the
* component on its own, inside of a fragment.
*
* Returns a Mithril Vnode or other children.
*
* @see https://mithril.js.org/route.html#routeresolverrender
*/
render(this: this, vnode: Mithril.Vnode<Attrs, Comp>): Mithril.Children;
render?(this: this, vnode: Mithril.Vnode<Attrs, Comp>): Mithril.Children;
}
/**
* The `App` class provides a container for an application, as well as various
@@ -159,10 +167,10 @@ export default class Application {
*/
drawer: Drawer;
data: {
apiDocument: Record<string, unknown> | null;
apiDocument: ApiPayload | null;
locale: string;
locales: Record<string, string>;
resources: Record<string, unknown>[];
resources: SavedModelData[];
session: {
userId: number;
csrfToken: string;
@@ -190,7 +198,8 @@ export default class Application {
/**
* Get the API response document that has been preloaded into the application.
*/
preloadedApiDocument(): Record<string, unknown> | null;
preloadedApiDocument<M extends Model>(): ApiResponseSingle<M> | null;
preloadedApiDocument<Ms extends Model[]>(): ApiResponsePlural<Ms[number]> | null;
/**
* Determine the current screen mode, based on our media queries.
*/
@@ -213,11 +222,13 @@ export default class Application {
* Make an AJAX request, handling any low-level errors that may occur.
*
* @see https://mithril.js.org/request.html
*
* @param options
* @return {Promise}
*/
request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType | string>;
request<ResponseType>(originalOptions: FlarumRequestOptions<ResponseType>): Promise<ResponseType>;
/**
* By default, show an error alert, and log the error to the console.
*/
protected requestErrorCatch<ResponseType>(error: RequestError, customErrorHandler: FlarumRequestOptions<ResponseType>['errorHandler']): Promise<never>;
protected requestErrorDefaultHandler(e: unknown, isDebug: boolean, formattedErrors: string[]): void;
private showDebug;
/**
* Construct a URL to the route with the given name.

View File

@@ -28,8 +28,8 @@ export default abstract class Fragment {
* containing all of the `li` elements inside the DOM element of this
* fragment.
*
* @param {String} [selector] a jQuery-compatible selector string
* @returns {jQuery} the jQuery object for the DOM node
* @param [selector] a jQuery-compatible selector string
* @returns the jQuery object for the DOM node
* @final
*/
$(selector?: string): JQuery;

View File

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

View File

@@ -5,10 +5,8 @@ export declare type LoginParams = {
* The username/email
*/
identification: string;
/**
* Password
*/
password: string;
remember: boolean;
};
/**
* The `Session` class defines the current user session. It stores a reference

View File

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

View File

@@ -4,8 +4,8 @@ declare var _default: {
Store: typeof Store;
'utils/BasicEditorDriver': typeof BasicEditorDriver;
'utils/evented': {
handlers: Object;
getHandlers(event: string): any[];
handlers: Record<string, unknown>;
getHandlers(event: string): Function[];
trigger(event: string, ...args: any[]): void;
on(event: string, handler: Function): void;
one(event: string, handler: Function): void;

View File

@@ -15,14 +15,14 @@ export default class Checkbox extends Component<import("../Component").Component
/**
* Get the template for the checkbox's display (tick/cross icon).
*
* @return {*}
* @return {import('mithril').Children}
* @protected
*/
protected getDisplay(): any;
protected getDisplay(): import('mithril').Children;
/**
* Run a callback when the state of the checkbox is changed.
*
* @param {Boolean} checked
* @param {boolean} checked
* @protected
*/
protected onchange(checked: boolean): void;

View File

@@ -22,17 +22,17 @@ export default class Dropdown extends Component<import("../Component").Component
/**
* Get the template for the button.
*
* @return {*}
* @return {import('mithril').Children}
* @protected
*/
protected getButton(children: any): any;
protected getButton(children: any): import('mithril').Children;
/**
* Get the template for the button's content.
*
* @return {*}
* @return {import('mithril').Children}
* @protected
*/
protected getButtonContent(children: any): any;
protected getButtonContent(children: any): import('mithril').Children;
getMenu(items: any): JSX.Element;
}
import Component from "../Component";

View File

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

View File

@@ -16,10 +16,10 @@ export default class LinkButton extends Button<import("./Button").IButtonAttrs>
/**
* Determine whether a component with the given attrs is 'active'.
*
* @param {Object} attrs
* @return {Boolean}
* @param {object} attrs
* @return {boolean}
*/
static isActive(attrs: Object): boolean;
static isActive(attrs: object): boolean;
constructor();
}
import Button from "./Button";

View File

@@ -22,8 +22,8 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
/**
* Attributes for an alert component to show below the header.
*/
alertAttrs: AlertAttrs;
oninit(vnode: Mithril.VnodeDOM<ModalAttrs, this>): void;
alertAttrs: AlertAttrs | null;
oninit(vnode: Mithril.Vnode<ModalAttrs, this>): void;
oncreate(vnode: Mithril.VnodeDOM<ModalAttrs, this>): void;
onbeforeremove(vnode: Mithril.VnodeDOM<ModalAttrs, this>): Promise<void> | void;
/**
@@ -37,7 +37,7 @@ export default abstract class Modal<ModalAttrs extends IInternalModalAttrs = IIn
/**
* Get the title of the modal dialog.
*/
abstract title(): string;
abstract title(): Mithril.Children;
/**
* Get the content of the modal.
*/

View File

@@ -18,23 +18,23 @@ export default class Navigation extends Component<import("../Component").Compone
/**
* Get the back button.
*
* @return {Object}
* @return {import('mithril').Children}
* @protected
*/
protected getBackButton(): Object;
protected getBackButton(): import('mithril').Children;
/**
* Get the pane pinned toggle button.
*
* @return {Object|String}
* @return {import('mithril').Children}
* @protected
*/
protected getPaneButton(): Object | string;
protected getPaneButton(): import('mithril').Children;
/**
* Get the drawer toggle button.
*
* @return {Object|String}
* @return {import('mithril').Children}
* @protected
*/
protected getDrawerButton(): Object | string;
protected getDrawerButton(): import('mithril').Children;
}
import Component from "../Component";

View File

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

View File

@@ -7,9 +7,10 @@ export default class SplitDropdown extends Dropdown {
* Get the first child. If the first child is an array, the first item in that
* array will be returned.
*
* @return {*}
* @param {unknown[] | unknown} children
* @return {unknown}
* @protected
*/
protected getFirstChild(children: any): any;
protected getFirstChild(children: unknown[] | unknown): unknown;
}
import Dropdown from "./Dropdown";

View File

@@ -36,19 +36,19 @@ export default class TextEditor extends Component<import("../Component").Compone
/**
* Build an item list for the text editor controls.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
controlItems(): ItemList<any>;
controlItems(): ItemList<import('mithril').Children>;
/**
* Build an item list for the toolbar controls.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
toolbarItems(): ItemList<any>;
toolbarItems(): ItemList<import('mithril').Children>;
/**
* Handle input into the textarea.
*
* @param {String} value
* @param {string} value
*/
oninput(value: string): void;
/**

View File

@@ -23,7 +23,7 @@
* @param methods The name or names of the method(s) to extend
* @param callback A callback which mutates the method's output
*/
export declare function extend<T extends object, K extends KeyOfType<T, Function>>(object: T, methods: K | K[], callback: (this: T, val: ReturnType<T[K]>, ...args: Parameters<T[K]>) => void): void;
export declare function extend<T extends Record<string, any>, 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.
@@ -51,4 +51,4 @@ export declare function extend<T extends object, K extends KeyOfType<T, Function
* @param methods The name or names of the method(s) to override
* @param newMethod The method to replace it with
*/
export declare function override<T extends object, K extends KeyOfType<T, Function>>(object: T, methods: K | K[], newMethod: (this: T, orig: T[K], ...args: Parameters<T[K]>) => void): void;
export declare function override<T extends Record<any, any>, K extends KeyOfType<T, Function>>(object: T, methods: K | K[], newMethod: (this: T, orig: T[K], ...args: Parameters<T[K]>) => void): void;

View File

@@ -10,3 +10,17 @@
* can fix.
*/
export default function fireDebugWarning(...args: Parameters<typeof console.warn>): void;
/**
* Fire a Flarum deprecation warning which is shown in the JS console.
*
* These warnings are only shown when the forum is in debug mode, and the function exists to
* reduce bundle size caused by multiple warnings across our JavaScript.
*
* @param message The message to display. (Short, but sweet, please!)
* @param githubId The PR or Issue ID with more info in relation to this change.
* @param [removedFrom] The version in which this feature will be completely removed. (default: 2.0)
* @param [repo] The repo which the issue or PR is located in. (default: flarum/core)
*
* @see {@link fireDebugWarning}
*/
export declare function fireDeprecationWarning(message: string, githubId: string, removedFrom?: string, repo?: string): void;

View File

@@ -1,16 +1,27 @@
import type Mithril from 'mithril';
import Component, { ComponentAttrs } from '../Component';
export interface ModdedVnodeAttrs {
import { ComponentAttrs } from '../Component';
declare type ModdedVnodeAttrs = {
itemClassName?: string;
key?: string;
}
export declare type ModdedVnode<Attrs> = Mithril.Vnode<ModdedVnodeAttrs, Component<Attrs> | {}> & {
};
declare type ModdedTag = Mithril.Vnode['tag'] & {
isListItem?: boolean;
isActive?: (attrs: ComponentAttrs) => boolean;
};
declare type ModdedVnode = Mithril.Vnode<ModdedVnodeAttrs> & {
itemName?: string;
itemClassName?: string;
tag: Mithril.Vnode['tag'] & {
isListItem?: boolean;
isActive?: (attrs: ComponentAttrs) => boolean;
};
tag: ModdedTag;
};
declare type ModdedChild = ModdedVnode | string | number | boolean | null | undefined;
declare type ModdedChildArray = ModdedChildren[];
declare type ModdedChildren = ModdedChild | ModdedChildArray;
/**
* This type represents an element of a list returned by `ItemList.toArray()`,
* coupled with some static properties used on various components.
*/
export declare type ModdedChildrenWithItemName = ModdedChildren & {
itemName?: string;
};
/**
* The `listItems` helper wraps an array of components in the provided tag,
@@ -19,4 +30,5 @@ export declare type ModdedVnode<Attrs> = Mithril.Vnode<ModdedVnodeAttrs, Compone
* By default, this tag is an `<li>` tag, but this is customisable through the
* second function parameter, `customTag`.
*/
export default function listItems<Attrs extends Record<string, unknown>>(rawItems: ModdedVnode<Attrs> | ModdedVnode<Attrs>[], customTag?: string | Component<Attrs>, attributes?: Attrs): Mithril.Vnode[];
export default function listItems<Attrs extends ComponentAttrs>(rawItems: ModdedChildrenWithItemName[], customTag?: VnodeElementTag<Attrs>, attributes?: Attrs): Mithril.Vnode[];
export {};

View File

@@ -6,7 +6,7 @@
* punctuateSeries(['Toby', 'Franz', 'Dominion']) // Toby, Franz, and Dominion
* ```
*
* @param {Array} items
* @return {VirtualElement}
* @param {import('mithril').Children[]} items
* @return {import('mithril').Children}')}
*/
export default function punctuateSeries(items: any[]): any;
export default function punctuateSeries(items: import('mithril').Children[]): import('mithril').Children;

View File

@@ -4,4 +4,4 @@ import User from '../models/User';
* The `username` helper displays a user's username in a <span class="username">
* tag. If the user doesn't exist, the username will be displayed as [deleted].
*/
export default function username(user: User): Mithril.Vnode;
export default function username(user: User | null | undefined | false): Mithril.Vnode;

View File

@@ -1,3 +1,13 @@
import * as Extend from "./extend/index";
import app from "./app";
import 'expose-loader?exposes=$,jQuery!jquery';
import 'expose-loader?exposes=m!mithril';
import 'expose-loader?exposes=dayjs!dayjs';
import 'bootstrap/js/affix';
import 'bootstrap/js/dropdown';
import 'bootstrap/js/modal';
import 'bootstrap/js/tooltip';
import 'bootstrap/js/transition';
import 'jquery.hotkeys/jquery.hotkeys';
import * as Extend from './extend/index';
import app from './app';
export { Extend, app };
import './utils/arrayFlatPolyfill';

View File

@@ -1,3 +1,48 @@
import Model from '../Model';
import ItemList from '../utils/ItemList';
import Mithril from 'mithril';
import Post from './Post';
import User from './User';
export default class Discussion extends Model {
title(): string;
slug(): string;
createdAt(): Date | undefined;
user(): false | User | null;
firstPost(): false | Post | null;
lastPostedAt(): Date | null | undefined;
lastPostedUser(): false | User | null;
lastPost(): false | Post | null;
lastPostNumber(): number | null | undefined;
commentCount(): number | undefined;
replyCount(): Number;
posts(): false | (Post | undefined)[];
mostRelevantPost(): false | Post | null;
lastReadAt(): Date | null | undefined;
lastReadPostNumber(): number | null | undefined;
isUnread(): boolean;
isRead(): boolean;
hiddenAt(): Date | null | undefined;
hiddenUser(): false | User | null;
isHidden(): boolean;
canReply(): boolean | undefined;
canRename(): boolean | undefined;
canHide(): boolean | undefined;
canDelete(): boolean | undefined;
/**
* Remove a post from the discussion's posts relationship.
*/
removePost(id: string): void;
/**
* Get the estimated number of unread posts in this discussion for the current
* user.
*/
unreadCount(): number;
/**
* Get the Badge components that apply to this discussion.
*/
badges(): ItemList<Mithril.Children>;
/**
* Get a list of all of the post IDs in this discussion.
*/
postIds(): string[];
}
import Model from "../Model";

View File

@@ -1,3 +1,4 @@
import Model from '../Model';
export default class Forum extends Model {
apiEndpoint(): string;
}
import Model from "../Model";

View File

@@ -1,9 +1,11 @@
export default Group;
declare class Group extends Model {
import Model from '../Model';
export default class Group extends Model {
static ADMINISTRATOR_ID: string;
static GUEST_ID: string;
static MEMBER_ID: string;
nameSingular(): string;
namePlural(): string;
color(): string | null;
icon(): string | null;
isHidden(): boolean;
}
declare namespace Group {
const ADMINISTRATOR_ID: string;
const GUEST_ID: string;
const MEMBER_ID: string;
}
import Model from "../Model";

View File

@@ -1,3 +1,11 @@
import Model from '../Model';
import User from './User';
export default class Notification extends Model {
contentType(): string;
content(): string;
createdAt(): Date;
isRead(): boolean;
user(): false | User;
fromUser(): false | User | null;
subject(): false | Model | null;
}
import Model from "../Model";

View File

@@ -1,3 +1,23 @@
import Model from '../Model';
import Discussion from './Discussion';
import User from './User';
export default class Post extends Model {
number(): number;
discussion(): Discussion;
createdAt(): Date;
user(): false | User;
contentType(): string | null;
content(): string | null | undefined;
contentHtml(): string | null | undefined;
renderFailed(): boolean | undefined;
contentPlain(): string | null | undefined;
editedAt(): Date | null | undefined;
editedUser(): false | User | null;
isEdited(): boolean;
hiddenAt(): Date | null | undefined;
hiddenUser(): false | User | null;
isHidden(): boolean;
canEdit(): boolean | undefined;
canHide(): boolean | undefined;
canDelete(): boolean | undefined;
}
import Model from "../Model";

View File

@@ -1,3 +1,46 @@
import { Color } from 'color-thief-browser';
import Model from '../Model';
import ItemList from '../utils/ItemList';
import Mithril from 'mithril';
import Group from './Group';
export default class User extends Model {
username(): string;
slug(): string;
displayName(): string;
email(): string | undefined;
isEmailConfirmed(): boolean | undefined;
password(): string | undefined;
avatarUrl(): string | null;
preferences(): Record<string, any> | null | undefined;
groups(): false | (Group | undefined)[];
joinTime(): Date | null | undefined;
lastSeenAt(): Date | null | undefined;
markedAllAsReadAt(): Date | null | undefined;
unreadNotificationCount(): number | undefined;
newNotificationCount(): number | undefined;
discussionCount(): number | undefined;
commentCount(): number | undefined;
canEdit(): boolean | undefined;
canEditCredentials(): boolean | undefined;
canEditGroups(): boolean | undefined;
canDelete(): boolean | undefined;
color(): string;
protected avatarColor: Color | null;
/**
* Check whether or not the user has been seen in the last 5 minutes.
*/
isOnline(): boolean;
/**
* Get the Badge components that apply to this user.
*/
badges(): ItemList<Mithril.Children>;
/**
* Calculate the dominant color of the user's avatar. The dominant color will
* be set to the `avatarColor` property once it has been calculated.
*/
protected calculateAvatarColor(): void;
/**
* Update the user's preferences.
*/
savePreferences(newPreferences: Record<string, unknown>): Promise<this>;
}
import Model from "../Model";

View File

@@ -20,11 +20,11 @@ export default class AlertManagerState {
/**
* Show an Alert in the alerts area.
*
* @returns The alert's ID, which can be used to dismiss the alert.
* @return The alert's ID, which can be used to dismiss the alert.
*/
show(children: Mithril.Children): AlertIdentifier;
show(attrs: AlertAttrs, children: Mithril.Children): AlertIdentifier;
show(componentClass: Alert, attrs: AlertAttrs, children: Mithril.Children): AlertIdentifier;
show(componentClass: typeof Alert, attrs: AlertAttrs, children: Mithril.Children): AlertIdentifier;
/**
* Dismiss an alert.
*/

View File

@@ -1,4 +1,16 @@
import type Component from '../Component';
import Modal from '../components/Modal';
/**
* Ideally, `show` would take a higher-kinded generic, ala:
* `show<Attrs, C>(componentClass: C<Attrs>, attrs: Attrs): void`
* Unfortunately, TypeScript does not support this:
* https://github.com/Microsoft/TypeScript/issues/1213
* Therefore, we have to use this ugly, messy workaround.
*/
declare type UnsafeModalClass = ComponentClass<any, Modal> & {
isDismissible: boolean;
component: typeof Component.component;
};
/**
* Class used to manage modal state.
*
@@ -9,9 +21,15 @@ export default class ModalManagerState {
* @internal
*/
modal: null | {
componentClass: typeof Modal;
componentClass: UnsafeModalClass;
attrs?: Record<string, unknown>;
key: number;
};
/**
* Used to force re-initialization of modals if a modal
* is replaced by another of the same type.
*/
private key;
private closeTimeout?;
/**
* Shows a modal dialog.
@@ -25,7 +43,7 @@ export default class ModalManagerState {
* // This "hack" is needed due to quirks with nested redraws in Mithril.
* setTimeout(() => app.modal.show(MyCoolModal, { attr: 'value' }), 0);
*/
show(componentClass: typeof Modal, attrs?: Record<string, unknown>): void;
show(componentClass: UnsafeModalClass, attrs?: Record<string, unknown>): void;
/**
* Closes the currently open dialog, if one is open.
*/
@@ -33,7 +51,8 @@ export default class ModalManagerState {
/**
* Checks if a modal is currently open.
*
* @returns `true` if a modal dialog is currently open, otherwise `false`.
* @return `true` if a modal dialog is currently open, otherwise `false`.
*/
isModalOpen(): boolean;
}
export {};

View File

@@ -5,12 +5,11 @@ export default class PageState {
/**
* Determine whether the page matches the given class and data.
*
* @param {object} type The page class to check against. Subclasses are
* accepted as well.
* @param {object} data
* @param {object} type The page class to check against. Subclasses are accepted as well.
* @param {Record<string, unknown>} data
* @return {boolean}
*/
matches(type: object, data?: object): boolean;
matches(type: object, data?: Record<string, unknown>): boolean;
get(key: any): any;
set(key: any, value: any): void;
}

View File

@@ -1,4 +1,5 @@
import Model from '../Model';
import { ApiQueryParamsPlural, ApiResponsePlural } from '../Store';
export interface Page<TModel> {
number: number;
items: TModel[];
@@ -13,6 +14,9 @@ export interface PaginationLocation {
export interface PaginatedListParams {
[key: string]: any;
}
export interface PaginatedListRequestParams extends Omit<ApiQueryParamsPlural, 'include'> {
include?: string | string[];
}
export default abstract class PaginatedListState<T extends Model, P extends PaginatedListParams = PaginatedListParams> {
protected location: PaginationLocation;
protected pageSize: number;
@@ -26,11 +30,11 @@ export default abstract class PaginatedListState<T extends Model, P extends Pagi
clear(): void;
loadPrev(): Promise<void>;
loadNext(): Promise<void>;
protected parseResults(pg: number, results: T[]): void;
protected parseResults(pg: number, results: ApiResponsePlural<T>): void;
/**
* Load a new page of results.
*/
protected loadPage(page?: number): Promise<T[]>;
protected loadPage(page?: number): Promise<ApiResponsePlural<T>>;
/**
* Get the parameters that should be passed in the API request.
* Do not include page offset unless subclass overrides loadPage.
@@ -38,7 +42,7 @@ export default abstract class PaginatedListState<T extends Model, P extends Pagi
* @abstract
* @see loadPage
*/
protected requestParams(): any;
protected requestParams(): PaginatedListRequestParams;
/**
* Update the `this.params` object, calling `refresh` if they have changed.
* Use `requestParams` for converting `this.params` into API parameters
@@ -73,7 +77,7 @@ export default abstract class PaginatedListState<T extends Model, P extends Pagi
/**
* Stored state parameters.
*/
getParams(): any;
getParams(): P;
protected getNextPageNumber(): number;
protected getPrevPageNumber(): number;
protected paramsChanged(newParams: P): boolean;

View File

@@ -34,20 +34,15 @@ export default class Drawer {
* Check whether or not the drawer is currently open.
*
* @return {boolean}
* @public
*/
public isOpen(): boolean;
isOpen(): boolean;
/**
* Hide the drawer.
*
* @public
*/
public hide(): void;
hide(): void;
/**
* Show the drawer.
*
* @public
*/
public show(): void;
show(): void;
$backdrop: JQuery<HTMLElement> | undefined;
}

View File

@@ -192,7 +192,7 @@ export default class ItemList<T> {
*
* @param content The item's content (objects only)
* @param key The item's key
* @returns Proxied content
* @return Proxied content
*
* @internal
*/

View File

@@ -1,6 +1,6 @@
import type Mithril from 'mithril';
import type { AlertAttrs } from '../components/Alert';
export declare type InternalFlarumRequestOptions<ResponseType> = Mithril.RequestOptions<ResponseType> & {
errorHandler: (error: RequestError) => void;
url: string;
};
export default class RequestError<ResponseType = string> {
@@ -16,6 +16,6 @@ export default class RequestError<ResponseType = string> {
[key: string]: unknown;
}[];
} | null;
alert: any;
alert: AlertAttrs | null;
constructor(status: number, responseText: string | null, options: InternalFlarumRequestOptions<ResponseType>, xhr: XMLHttpRequest);
}

View File

@@ -6,7 +6,6 @@ export default class ScrollListener {
/**
* @param {(top: number) => void} callback The callback to run when the scroll position
* changes.
* @public
*/
constructor(callback: (top: number) => void);
callback: (top: number) => void;
@@ -20,21 +19,15 @@ export default class ScrollListener {
protected loop(): void;
/**
* Run the callback, whether there was a scroll event or not.
*
* @public
*/
public update(): void;
update(): void;
/**
* Start listening to and handling the window's scroll position.
*
* @public
*/
public start(): void;
start(): void;
active: (() => void) | null | undefined;
/**
* Stop listening to and handling the window's scroll position.
*
* @public
*/
public stop(): void;
stop(): void;
}

View File

@@ -8,7 +8,7 @@
* position can be anchor to an element that is in or below the viewport, so
* the content in the viewport will stay the same.
*
* @param {DOMElement} element The element to anchor the scroll position to.
* @param {Function} callback The callback to run that will change page content.
* @param {HTMLElement | SVGElement | Element} element The element to anchor the scroll position to.
* @param {() => void} callback The callback to run that will change page content.
*/
export default function anchorScroll(element: any, callback: Function): void;
export default function anchorScroll(element: HTMLElement | SVGElement | Element, callback: () => void): void;

View File

@@ -1,10 +1,10 @@
import Model from '../Model';
/**
* The `computed` utility creates a function that will cache its output until
* any of the dependent values are dirty.
*
* @param {...String} dependentKeys The keys of the dependent values.
* @param {function} compute The function which computes the value using the
* @param dependentKeys The keys of the dependent values.
* @param compute The function which computes the value using the
* dependent values.
* @return {Function}
*/
export default function computed(...dependentKeys: string[]): Function;
export default function computed<T, M = Model>(...args: [...string[], (this: M, ...args: unknown[]) => T]): () => T;

View File

@@ -1,79 +1,97 @@
declare namespace _default {
const handlers: Object;
const handlers: Record<string, unknown>;
/**
* Get all of the registered handlers for an event.
*
* @param {String} event The name of the event.
* @return {Array}
* @param {string} event The name of the event.
* @return {Function[]}
* @protected
*
* @deprecated
*/
function getHandlers(event: string): any[];
function getHandlers(event: string): Function[];
/**
* Get all of the registered handlers for an event.
*
* @param {String} event The name of the event.
* @return {Array}
* @param {string} event The name of the event.
* @return {Function[]}
* @protected
*
* @deprecated
*/
function getHandlers(event: string): any[];
function getHandlers(event: string): Function[];
/**
* Trigger an event.
*
* @param {String} event The name of the event.
* @param {...*} args Arguments to pass to event handlers.
* @public
* @param {string} event The name of the event.
* @param {any[]} args Arguments to pass to event handlers.
*
* @deprecated
*/
function trigger(event: string, ...args: any[]): void;
/**
* Trigger an event.
*
* @param {String} event The name of the event.
* @param {...*} args Arguments to pass to event handlers.
* @public
* @param {string} event The name of the event.
* @param {any[]} args Arguments to pass to event handlers.
*
* @deprecated
*/
function trigger(event: string, ...args: any[]): void;
/**
* Register an event handler.
*
* @param {String} event The name of the event.
* @param {function} handler The function to handle the event.
* @param {string} event The name of the event.
* @param {Function} handler The function to handle the event.
*
* @deprecated
*/
function on(event: string, handler: Function): void;
/**
* Register an event handler.
*
* @param {String} event The name of the event.
* @param {function} handler The function to handle the event.
* @param {string} event The name of the event.
* @param {Function} handler The function to handle the event.
*
* @deprecated
*/
function on(event: string, handler: Function): void;
/**
* Register an event handler so that it will run only once, and then
* unregister itself.
*
* @param {String} event The name of the event.
* @param {function} handler The function to handle the event.
* @param {string} event The name of the event.
* @param {Function} handler The function to handle the event.
*
* @deprecated
*/
function one(event: string, handler: Function): void;
/**
* Register an event handler so that it will run only once, and then
* unregister itself.
*
* @param {String} event The name of the event.
* @param {function} handler The function to handle the event.
* @param {string} event The name of the event.
* @param {Function} handler The function to handle the event.
*
* @deprecated
*/
function one(event: string, handler: Function): void;
/**
* Unregister an event handler.
*
* @param {String} event The name of the event.
* @param {function} handler The function that handles the event.
* @param {string} event The name of the event.
* @param {Function} handler The function that handles the event.
*
* @deprecated
*/
function off(event: string, handler: Function): void;
/**
* Unregister an event handler.
*
* @param {String} event The name of the event.
* @param {function} handler The function that handles the event.
* @param {string} event The name of the event.
* @param {Function} handler The function that handles the event.
*
* @deprecated
*/
function off(event: string, handler: Function): void;
}

View File

@@ -5,8 +5,8 @@
* @example
* class MyClass extends mixin(ExistingClass, evented, etc) {}
*
* @param {Class} Parent The class to extend the new class from.
* @param {...Object} mixins The objects to mix in.
* @return {Class} A new class that extends Parent and contains the mixins.
* @param {object} Parent The class to extend the new class from.
* @param {Record<string, any>[]} mixins The objects to mix in.
* @return {object} A new class that extends Parent and contains the mixins.
*/
export default function mixin(Parent: any, ...mixins: Object[]): any;
export default function mixin(Parent: object, ...mixins: Record<string, any>[]): object;

View File

@@ -9,6 +9,7 @@ interface StyleArgs {
scanFor: string;
surroundWithNewlines: boolean;
orderedList: boolean;
unorderedList: boolean;
trimFirst: boolean;
}
export default function styleSelectedText(textarea: HTMLTextAreaElement, styleArgs: StyleArgs): void;

View File

@@ -4,8 +4,8 @@ declare var _default: {
Store: typeof import("../common/Store").default;
'utils/BasicEditorDriver': typeof BasicEditorDriver;
'utils/evented': {
handlers: Object;
getHandlers(event: string): any[];
handlers: Record<string, unknown>;
getHandlers(event: string): Function[];
trigger(event: string, ...args: any[]): void;
on(event: string, handler: Function): void;
one(event: string, handler: Function): void;
@@ -92,38 +92,38 @@ declare var _default: {
'states/PaginatedListState': typeof import("../common/states/PaginatedListState").default;
} & {
'utils/PostControls': {
controls(post: any, context: any): import("../common/utils/ItemList").default<any>;
userControls(post: any, context: any): import("../common/utils/ItemList").default<any>;
moderationControls(post: any, context: any): import("../common/utils/ItemList").default<any>;
destructiveControls(post: any, context: any): import("../common/utils/ItemList").default<any>;
editAction(): Promise<any>;
hideAction(): Promise<any>;
restoreAction(): Promise<any>;
deleteAction(context: any): Promise<any>;
controls(post: import("../common/models/Post").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
userControls(post: import("../common/models/Post").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
moderationControls(post: import("../common/models/Post").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
destructiveControls(post: import("../common/models/Post").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
editAction(): Promise<void>;
hideAction(): Promise<void>;
restoreAction(): Promise<void>;
deleteAction(context: any): Promise<void>;
};
'utils/KeyboardNavigatable': typeof KeyboardNavigatable;
'utils/slidable': typeof slidable;
'utils/History': typeof History;
'utils/DiscussionControls': {
controls(discussion: any, context: any): import("../common/utils/ItemList").default<any>;
userControls(discussion: any, context: any): import("../common/utils/ItemList").default<any>;
moderationControls(discussion: any): import("../common/utils/ItemList").default<any>;
destructiveControls(discussion: any): import("../common/utils/ItemList").default<any>;
replyAction(goToLast: boolean, forceRefresh: boolean): Promise<any>;
hideAction(): Promise<any>;
restoreAction(): Promise<any>;
deleteAction(): Promise<any>;
renameAction(): Promise<any>;
controls(discussion: import("../common/models/Discussion").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
userControls(discussion: import("../common/models/Discussion").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
moderationControls(discussion: import("../common/models/Discussion").default): import("../common/utils/ItemList").default<import("mithril").Children>;
destructiveControls(discussion: import("../common/models/Discussion").default): import("../common/utils/ItemList").default<import("mithril").Children>;
replyAction(goToLast: boolean, forceRefresh: boolean): Promise<void>;
hideAction(): Promise<void>;
restoreAction(): Promise<void>;
deleteAction(): Promise<void>;
renameAction(): any;
};
'utils/alertEmailConfirmation': typeof alertEmailConfirmation;
'utils/UserControls': {
controls(user: any, context: any): import("../common/utils/ItemList").default<any>;
userControls(): import("../common/utils/ItemList").default<any>;
moderationControls(user: any): import("../common/utils/ItemList").default<any>;
destructiveControls(user: any): import("../common/utils/ItemList").default<any>;
deleteAction(user: any): void;
showDeletionAlert(user: any, type: string): void;
editAction(user: any): void;
controls(user: import("../common/models/User").default, context: import("../common/Component").default<any, any>): import("../common/utils/ItemList").default<import("mithril").Children>;
userControls(): import("../common/utils/ItemList").default<import("mithril").Children>;
moderationControls(user: import("../common/models/User").default): import("../common/utils/ItemList").default<import("mithril").Children>;
destructiveControls(user: import("../common/models/User").default): import("../common/utils/ItemList").default<import("mithril").Children>;
deleteAction(user: import("../common/models/User").default): void;
showDeletionAlert(user: import("../common/models/User").default, type: string): void;
editAction(user: import("../common/models/User").default): void;
};
'utils/Pane': typeof Pane;
'utils/BasicEditorDriver': typeof BasicEditorDriver;

View File

@@ -24,36 +24,36 @@ export default class AvatarEditor extends Component<import("../../common/Compone
/**
* Get the items in the edit avatar dropdown menu.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
controlItems(): ItemList<any>;
controlItems(): ItemList<import('mithril').Children>;
/**
* Enable dragover style
*
* @param {Event} e
* @param {DragEvent} e
*/
enableDragover(e: Event): void;
enableDragover(e: DragEvent): void;
/**
* Disable dragover style
*
* @param {Event} e
* @param {DragEvent} e
*/
disableDragover(e: Event): void;
disableDragover(e: DragEvent): void;
/**
* Upload avatar when file is dropped into dropzone.
*
* @param {Event} e
* @param {DragEvent} e
*/
dropUpload(e: Event): void;
dropUpload(e: DragEvent): void;
/**
* If the user doesn't have an avatar, there's no point in showing the
* controls dropdown, because only one option would be viable: uploading.
* Thus, when the avatar editor's dropdown toggle button is clicked, we prompt
* the user to upload an avatar immediately.
*
* @param {Event} e
* @param {MouseEvent} e
*/
quickUpload(e: Event): void;
quickUpload(e: MouseEvent): void;
/**
* Upload avatar using file picker
*/
@@ -72,17 +72,17 @@ export default class AvatarEditor extends Component<import("../../common/Compone
* After a successful upload/removal, push the updated user data into the
* store, and force a recomputation of the user's avatar color.
*
* @param {Object} response
* @param {object} response
* @protected
*/
protected success(response: Object): void;
protected success(response: object): void;
/**
* If avatar upload/removal fails, stop loading.
*
* @param {Object} response
* @param {object} response
* @protected
*/
protected failure(response: Object): void;
protected failure(response: object): void;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -32,9 +32,9 @@ export default class CommentPost extends Post {
/**
* Build an item list for the post's header.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
headerItems(): ItemList<any>;
headerItems(): ItemList<import('mithril').Children>;
}
import Post from "./Post";
import ItemList from "../../common/utils/ItemList";

View File

@@ -21,9 +21,9 @@ export default class Composer extends Component<import("../../common/Component")
/**
* Resize the composer according to mouse movement.
*
* @param {Event} e
* @param {MouseEvent} e
*/
onmousemove(e: Event): void;
onmousemove(e: MouseEvent): void;
/**
* Finish resizing the composer when the mouse is released.
*/
@@ -83,23 +83,23 @@ export default class Composer extends Component<import("../../common/Component")
/**
* Build an item list for the composer's controls.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
controlItems(): ItemList<any>;
controlItems(): ItemList<import('mithril').Children>;
/**
* Initialize default Composer height.
*/
initializeHeight(): void;
/**
* Default height of the Composer in case none is saved.
* @returns {Integer}
* @returns {number}
*/
defaultHeight(): any;
defaultHeight(): number;
/**
* Save a new Composer height and update the DOM.
* @param {Integer} height
* @param {number} height
*/
changeHeight(height: any): void;
changeHeight(height: number): void;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -27,15 +27,15 @@ export default class ComposerBody extends Component<import("../../common/Compone
/**
* Check if there is any unsaved data.
*
* @return {String}
* @return {boolean}
*/
hasChanges(): string;
hasChanges(): boolean;
/**
* Build an item list for the composer's header.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
headerItems(): ItemList<any>;
headerItems(): ItemList<import('mithril').Children>;
/**
* Handle the submit event of the text editor.
*

View File

@@ -21,14 +21,14 @@ export default class DiscussionComposer extends ComposerBody {
* Handle the title input's keydown event. When the return key is pressed,
* move the focus to the start of the text editor.
*
* @param {Event} e
* @param {KeyboardEvent} e
*/
onkeydown(e: Event): void;
onkeydown(e: KeyboardEvent): void;
/**
* Get the data to submit to the server when the discussion is saved.
*
* @return {Object}
* @return {Record<string, unknown>}
*/
data(): Object;
data(): Record<string, unknown>;
}
import ComposerBody from "./ComposerBody";

View File

@@ -10,9 +10,9 @@ export default class DiscussionHero extends Component<import("../../common/Compo
/**
* Build an item list for the contents of the discussion hero.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -23,7 +23,7 @@ export default class DiscussionListItem extends Component<import("../../common/C
/**
* Determine whether or not the discussion is currently being viewed.
*
* @return {Boolean}
* @return {boolean}
*/
active(): boolean;
/**
@@ -31,14 +31,14 @@ export default class DiscussionListItem extends Component<import("../../common/C
* should be displayed instead of information about the most recent reply to
* the discussion.
*
* @return {Boolean}
* @return {boolean}
*/
showFirstPost(): boolean;
/**
* Determine whether or not the number of replies should be shown instead of
* the number of unread posts.
*
* @return {Boolean}
* @return {boolean}
*/
showRepliesCount(): boolean;
/**
@@ -49,9 +49,9 @@ export default class DiscussionListItem extends Component<import("../../common/C
* Build an item list of info for a discussion listing. By default this is
* just the first/last post indicator.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
infoItems(): ItemList<any>;
infoItems(): ItemList<import('mithril').Children>;
replyCountItem(): JSX.Element;
}
import Component from "../../common/Component";

View File

@@ -3,6 +3,7 @@ import Page, { IPageAttrs } from '../../common/components/Page';
import ItemList from '../../common/utils/ItemList';
import PostStreamState from '../states/PostStreamState';
import Discussion from '../../common/models/Discussion';
import { ApiResponseSingle } from '../../common/Store';
export interface IDiscussionPageAttrs extends IPageAttrs {
id: string;
near?: number;
@@ -30,34 +31,24 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
view(): JSX.Element;
/**
* List of components shown while the discussion is loading.
*
* @returns {ItemList}
*/
loadingItems(): ItemList<unknown>;
loadingItems(): ItemList<Mithril.Children>;
/**
* Function that renders the `sidebarItems` ItemList.
*
* @returns {import('mithril').Children}
*/
sidebar(): JSX.Element;
sidebar(): Mithril.Children;
/**
* Renders the discussion's hero.
*
* @returns {import('mithril').Children}
*/
hero(): JSX.Element;
hero(): Mithril.Children;
/**
* List of items rendered as the main page content.
*
* @returns {ItemList}
*/
pageContent(): ItemList<unknown>;
pageContent(): ItemList<Mithril.Children>;
/**
* List of items rendered inside the main page content container.
*
* @returns {ItemList}
*/
mainContent(): ItemList<unknown>;
mainContent(): ItemList<Mithril.Children>;
/**
* Load the discussion from the API or use the preloaded one.
*/
@@ -65,23 +56,16 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
/**
* Get the parameters that should be passed in the API request to get the
* discussion.
*
* @return {Object}
*/
requestParams(): {
bySlug: boolean;
page: {
near: number;
};
};
requestParams(): Record<string, unknown>;
/**
* Initialize the component to display the given discussion.
*/
show(discussion: Discussion): void;
show(discussion: ApiResponseSingle<Discussion>): void;
/**
* Build an item list for the contents of the sidebar.
*/
sidebarItems(): ItemList<Mithril.Vnode<{}, {}>>;
sidebarItems(): ItemList<Mithril.Children>;
/**
* 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.

View File

@@ -17,8 +17,8 @@ export default class EditPostComposer extends ComposerBody {
/**
* Get the data to submit to the server when the post is saved.
*
* @return {Object}
* @return {Record<string, unknown>}
*/
data(): Object;
data(): Record<string, unknown>;
}
import ComposerBody from "./ComposerBody";

View File

@@ -13,27 +13,27 @@ export default class EventPost extends Post {
/**
* Get the name of the event icon.
*
* @return {String}
* @return {string}
*/
icon(): string;
/**
* Get the description text for the event.
*
* @param {Object} data
* @return {String|Object} The description to render in the DOM
* @param {Record<string, unknown>} data
* @return {import('mithril').Children} The description to render in the DOM
*/
description(data: Object): string | Object;
description(data: Record<string, unknown>): import('mithril').Children;
/**
* Get the translation key for the description of the event.
*
* @return {String}
* @return {string}
*/
descriptionKey(): string;
/**
* Get the translation data for the description of the event.
*
* @return {Object}
* @return {Record<string, unknown>}
*/
descriptionData(): Object;
descriptionData(): Record<string, unknown>;
}
import Post from "./Post";

View File

@@ -1,25 +1,25 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import Stream from '../../common/utils/Stream';
import Mithril from 'mithril';
import RequestError from '../../common/utils/RequestError';
export interface IForgotPasswordModalAttrs extends IInternalModalAttrs {
email?: string;
}
/**
* The `ForgotPasswordModal` component displays a modal which allows the user to
* enter their email address and request a link to reset their password.
*
* ### Attrs
*
* - `email`
*/
export default class ForgotPasswordModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
export default class ForgotPasswordModal<CustomAttrs extends IForgotPasswordModalAttrs = IForgotPasswordModalAttrs> extends Modal<CustomAttrs> {
/**
* The value of the email input.
*
* @type {Function}
*/
email: Function | undefined;
/**
* Whether or not the password reset email was sent successfully.
*
* @type {Boolean}
*/
success: boolean | undefined;
alert: any;
email: Stream<string>;
success: boolean;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
className(): string;
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): JSX.Element;
onsubmit(e: SubmitEvent): void;
onerror(error: RequestError): void;
}
import Modal from "../../common/components/Modal";

View File

@@ -7,9 +7,9 @@ export default class HeaderPrimary extends Component<import("../../common/Compon
/**
* Build an item list for the controls.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -10,49 +10,47 @@ export default class IndexPage extends Page<import("../../common/components/Page
/**
* Get the component to display as the hero.
*
* @return {MithrilComponent}
* @return {import('mithril').Children}
*/
hero(): any;
hero(): import('mithril').Children;
/**
* Build an item list for the sidebar of the index page. By default this is a
* "New Discussion" button, and then a DropdownSelect component containing a
* list of navigation items.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
sidebarItems(): ItemList<any>;
sidebarItems(): ItemList<import('mithril').Children>;
/**
* 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}
* @return {ItemList<import('mithril').Children>}
*/
navItems(): ItemList<any>;
navItems(): ItemList<import('mithril').Children>;
/**
* 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
* the way discussions are sorted.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
viewItems(): ItemList<any>;
viewItems(): ItemList<import('mithril').Children>;
/**
* 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}
* @return {ItemList<import('mithril').Children>}
*/
actionItems(): ItemList<any>;
actionItems(): ItemList<import('mithril').Children>;
/**
* Open the composer for a new discussion or prompt the user to login.
*
* @return {Promise}
* @return {Promise<void>}
*/
newDiscussionAction(): Promise<any>;
newDiscussionAction(): Promise<void>;
/**
* Mark all discussions as read.
*
* @return void
*/
markAllAsRead(): void;
}

View File

@@ -6,10 +6,9 @@ export default class LogInButtons extends Component<import("../../common/Compone
/**
* Build a list of LogInButton components.
*
* @return {ItemList}
* @public
* @return {ItemList<import('mithril').Children>}
*/
public items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,48 +1,45 @@
/**
* The `LogInModal` component displays a modal dialog with a login form.
*
* ### Attrs
*
* - `identification`
* - `password`
*/
export default class LogInModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import ItemList from '../../common/utils/ItemList';
import Stream from '../../common/utils/Stream';
import type Mithril from 'mithril';
import RequestError from '../../common/utils/RequestError';
export interface ILoginModalAttrs extends IInternalModalAttrs {
identification?: string;
password?: string;
remember?: boolean;
}
export default class LogInModal<CustomAttrs extends ILoginModalAttrs = ILoginModalAttrs> extends Modal<CustomAttrs> {
/**
* The value of the identification input.
*
* @type {Function}
*/
identification: Function | undefined;
identification: Stream<string>;
/**
* The value of the password input.
*
* @type {Function}
*/
password: Function | undefined;
password: Stream<string>;
/**
* The value of the remember me input.
*
* @type {Function}
*/
remember: Function | undefined;
remember: Stream<boolean>;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
className(): string;
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): JSX.Element[];
body(): JSX.Element[];
fields(): ItemList<any>;
fields(): ItemList<unknown>;
footer(): (string | JSX.Element)[];
/**
* Open the forgot password modal, prefilling it with an email if the user has
* entered one.
*
* @public
*/
public forgotPassword(): void;
forgotPassword(): void;
/**
* Open the sign up modal, prefilling it with an email/username/password if
* the user has entered one.
*
* @public
*/
public signUp(): void;
signUp(): void;
onready(): void;
onsubmit(e: SubmitEvent): void;
onerror(error: RequestError): void;
}
import Modal from "../../common/components/Modal";
import ItemList from "../../common/utils/ItemList";

View File

@@ -13,31 +13,31 @@ export default class Notification extends Component<import("../../common/Compone
/**
* Get the name of the icon that should be displayed in the notification.
*
* @return {String}
* @return {string}
* @abstract
*/
icon(): string;
/**
* Get the URL that the notification should link to.
*
* @return {String}
* @return {string}
* @abstract
*/
href(): string;
/**
* Get the content of the notification.
*
* @return {VirtualElement}
* @return {import('mithril').Children}
* @abstract
*/
content(): any;
content(): import('mithril').Children;
/**
* Get the excerpt of the notification.
*
* @return {VirtualElement}
* @return {import('mithril').Children}
* @abstract
*/
excerpt(): any;
excerpt(): import('mithril').Children;
/**
* Mark the notification as read.
*/

View File

@@ -11,47 +11,55 @@ export default class NotificationGrid extends Component<import("../../common/Com
/**
* Information about the available notification methods.
*
* @type {Array}
* @type {({ name: string, icon: string, label: import('mithril').Children })[]}
*/
methods: any[] | undefined;
methods: {
name: string;
icon: string;
label: import('mithril').Children;
}[] | undefined;
/**
* A map of which notification checkboxes are loading.
*
* @type {Object}
* @type {Record<string, boolean>}
*/
loading: Object | undefined;
loading: Record<string, boolean> | undefined;
/**
* Information about the available notification types.
*
* @type {Array}
* @type {({ name: string, icon: string, label: import('mithril').Children })[]}
*/
types: any[] | undefined;
types: {
name: string;
icon: string;
label: import('mithril').Children;
}[] | undefined;
/**
* Toggle the state of the given preferences, based on the value of the first
* one.
*
* @param {Array} keys
* @param {string[]} keys
*/
toggle(keys: any[]): void;
toggle(keys: string[]): void;
/**
* Toggle all notification types for the given method.
*
* @param {String} method
* @param {string} method
*/
toggleMethod(method: string): void;
/**
* Toggle all notification methods for the given type.
*
* @param {String} type
* @param {string} type
*/
toggleType(type: string): void;
/**
* Get the name of the preference key for the given notification type-method
* combination.
*
* @param {String} type
* @param {String} method
* @return {String}
* @param {string} type
* @param {string} method
* @return {string}
*/
preferenceKey(type: string, method: string): string;
/**
@@ -63,9 +71,13 @@ export default class NotificationGrid extends Component<import("../../common/Com
* - `icon` The icon to display in the column header.
* - `label` The label to display in the column header.
*
* @return {ItemList}
* @return {ItemList<{ name: string, icon: string, label: import('mithril').Children }>}
*/
notificationMethods(): ItemList<any>;
notificationMethods(): ItemList<{
name: string;
icon: string;
label: import('mithril').Children;
}>;
/**
* Build an item list for the notification types to display in the grid.
*
@@ -75,9 +87,14 @@ export default class NotificationGrid extends Component<import("../../common/Com
* - `icon` The icon to display in the notification grid row.
* - `label` The label to display in the notification grid row.
*
* @return {ItemList}
* @return {ItemList<{ name: string, icon: string, label: import('mithril').Children}>}
*/
notificationTypes(): ItemList<any>;
notificationTypes(): ItemList<{
name: string;
icon: string;
label: import('mithril').Children;
}>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";
import icon from "../../common/helpers/icon";

View File

@@ -4,6 +4,7 @@
*/
export default class NotificationList extends Component<import("../../common/Component").ComponentAttrs, undefined> {
constructor();
controlItems(): ItemList<any>;
content(state: any): any;
$notifications: JQuery<HTMLElement> | undefined;
$scrollParent: JQuery<HTMLElement> | JQuery<Window & typeof globalThis> | undefined;
@@ -16,3 +17,4 @@ export default class NotificationList extends Component<import("../../common/Com
inPanel(): boolean;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

View File

@@ -1,8 +1,8 @@
export default class NotificationsDropdown extends Dropdown {
onclick(): void;
goToRoute(): void;
getUnreadCount(): any;
getNewCount(): any;
getUnreadCount(): number | undefined;
getNewCount(): number | undefined;
menuClick(e: any): void;
}
import Dropdown from "../../common/components/Dropdown";

View File

@@ -25,34 +25,34 @@ export default class Post extends Component<import("../../common/Component").Com
/**
* Get attributes for the post element.
*
* @return {Object}
* @return {Record<string, unknown>}
*/
elementAttrs(): Object;
elementAttrs(): Record<string, unknown>;
/**
* Get the post's content.
*
* @return {Array}
* @return {import('mithril').Children}
*/
content(): any[];
content(): import('mithril').Children;
/**
* Get the post's classes.
*
* @param existing string
* @param {string} existing
* @returns {string[]}
*/
classes(existing: any): string[];
classes(existing: string): string[];
/**
* Build an item list for the post's actions.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
actionItems(): ItemList<any>;
actionItems(): ItemList<import('mithril').Children>;
/**
* Build an item list for the post's footer.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
footerItems(): ItemList<any>;
footerItems(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import SubtreeRetainer from "../../common/utils/SubtreeRetainer";

View File

@@ -12,9 +12,9 @@ export default class PostMeta extends Component<import("../../common/Component")
/**
* Get the permalink for the given post.
*
* @param {Post} post
* @returns {String}
* @param {import('../../common/models/Post').default} post
* @returns {string}
*/
getPermalink(post: any): string;
getPermalink(post: import('../../common/models/Post').default): string;
}
import Component from "../../common/Component";

View File

@@ -20,17 +20,17 @@ export default class PostStream extends Component<import("../../common/Component
triggerScroll(): void;
/**
*
* @param {Integer} top
* @param {number} top
*/
onscroll(top?: any): void;
onscroll(top?: number): void;
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.
*
* @param {Integer} top
* @param {number} top
*/
loadPostsIfNeeded(top?: any): void;
loadPostsIfNeeded(top?: number): void;
updateScrubber(top?: number): void;
/**
* Work out which posts (by number) are currently visible in the viewport, and
@@ -41,43 +41,43 @@ export default class PostStream extends Component<import("../../common/Component
* Get the distance from the top of the viewport to the point at which we
* would consider a post to be the first one visible.
*
* @return {Integer}
* @return {number}
*/
getMarginTop(): any;
getMarginTop(): number;
/**
* Scroll down to a certain post by number and 'flash' it.
*
* @param {Integer} number
* @param {Boolean} animate
* @return {jQuery.Deferred}
* @param {number} number
* @param {boolean} animate
* @return {JQueryDeferred}
*/
scrollToNumber(number: any, animate: boolean): any;
scrollToNumber(number: number, animate: boolean): JQueryDeferred<any>;
/**
* Scroll down to a certain post by index.
*
* @param {Integer} index
* @param {Boolean} animate
* @param {Boolean} reply Whether or not to scroll to the reply placeholder.
* @return {jQuery.Deferred}
* @param {number} index
* @param {boolean} animate
* @param {boolean} reply Whether or not to scroll to the reply placeholder.
* @return {JQueryDeferred}
*/
scrollToIndex(index: any, animate: boolean, reply: boolean): any;
scrollToIndex(index: number, animate: boolean, reply: boolean): JQueryDeferred<any>;
/**
* Scroll down to the given post.
*
* @param {jQuery} $item
* @param {Boolean} animate
* @param {Boolean} force Whether or not to force scrolling to the item, even
* @param {JQuery} $item
* @param {boolean} animate
* @param {boolean} force Whether or not to force scrolling to the item, even
* if it is already in the viewport.
* @param {Boolean} reply Whether or not to scroll to the reply placeholder.
* @return {jQuery.Deferred}
* @param {boolean} reply Whether or not to scroll to the reply placeholder.
* @return {JQueryDeferred}
*/
scrollToItem($item: JQueryStatic, animate: boolean, force: boolean, reply: boolean): any;
scrollToItem($item: JQuery, animate: boolean, force: boolean, reply: boolean): JQueryDeferred<any>;
/**
* 'Flash' the given post, drawing the user's attention to it.
*
* @param {jQuery} $item
* @param {JQuery} $item
*/
flashItem($item: JQueryStatic): void;
flashItem($item: JQuery): void;
}
import Component from "../../common/Component";
import ScrollListener from "../../common/utils/ScrollListener";

View File

@@ -19,9 +19,13 @@ export default class PostStreamScrubber extends Component<import("../../common/C
* Update the scrollbar's position to reflect the current values of the
* index/visible properties.
*
* @param {Boolean} animate
* @param {Partial<{fromScroll: boolean, forceHeightChange: boolean, animate: boolean}>} options
*/
updateScrubberValues(options?: {}): void;
updateScrubberValues(options?: Partial<{
fromScroll: boolean;
forceHeightChange: boolean;
animate: boolean;
}>): void;
adjustingHeight: boolean | undefined;
/**
* Go to the first post in the discussion.
@@ -40,13 +44,16 @@ export default class PostStreamScrubber extends Component<import("../../common/C
* Get the percentage of the height of the scrubber that should be allocated
* to each post.
*
* @return {Object}
* @return {{ index: number, visible: number }}
* @property {Number} index The percent per post for posts on either side of
* the visible part of the scrubber.
* @property {Number} visible The percent per post for the visible part of the
* scrubber.
*/
percentPerPost(): Object;
percentPerPost(): {
index: number;
visible: number;
};
}
import Component from "../../common/Component";
import ScrollListener from "../../common/utils/ScrollListener";

View File

@@ -20,39 +20,35 @@ export default class PostsUserPage extends UserPage {
*
* @type {Post[]}
*/
posts: any[] | undefined;
posts: Post[] | undefined;
/**
* The number of activity items to load per request.
*
* @type {Integer}
* @type {number}
*/
loadLimit: any;
loadLimit: number | undefined;
/**
* Clear and reload the user's activity feed.
*
* @public
*/
public refresh(): void;
refresh(): void;
/**
* Load a new page of the user's activity feed.
*
* @param {Integer} [offset] The position to start getting results from.
* @return {Promise}
* @param {number} [offset] The position to start getting results from.
* @return {Promise<import('../../common/models/Post').default[]>}
* @protected
*/
protected loadResults(offset?: any): Promise<any>;
protected loadResults(offset?: number | undefined): Promise<import('../../common/models/Post').default[]>;
/**
* Load the next page of results.
*
* @public
*/
public loadMore(): void;
loadMore(): void;
/**
* Parse results and append them to the activity feed.
*
* @param {Post[]} results
* @return {Post[]}
* @param {import('../../common/models/Post').default[]} results
* @return {import('../../common/models/Post').default[]}
*/
parseResults(results: any[]): any[];
parseResults(results: import('../../common/models/Post').default[]): import('../../common/models/Post').default[];
}
import UserPage from "./UserPage";

View File

@@ -16,8 +16,8 @@ export default class ReplyComposer extends ComposerBody {
/**
* Get the data to submit to the server when the reply is saved.
*
* @return {Object}
* @return {Record<string, unknown>}
*/
data(): Object;
data(): Record<string, unknown>;
}
import ComposerBody from "./ComposerBody";

View File

@@ -42,12 +42,22 @@ export interface SearchAttrs extends ComponentAttrs {
*
* - state: SearchState instance.
*/
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T> {
export default class Search<T extends SearchAttrs = SearchAttrs> extends Component<T, SearchState> {
/**
* The minimum query length before sources are searched.
*/
protected static MIN_SEARCH_LEN: number;
/**
* The instance of `SearchState` for this component.
*/
protected searchState: SearchState;
/**
* The instance of `SearchState` for this component.
*
* @deprecated Replace with`this.searchState` instead.
*/
protected get state(): SearchState;
protected set state(state: SearchState);
/**
* Whether or not the search input has focus.
*/
@@ -55,7 +65,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
/**
* An array of SearchSources.
*/
protected sources: SearchSource[];
protected sources?: SearchSource[];
/**
* The number of sources that are still loading results.
*/

View File

@@ -6,9 +6,9 @@ export default class SessionDropdown extends Dropdown {
/**
* Build an item list for the contents of the dropdown menu.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
items(): ItemList<any>;
items(): ItemList<import('mithril').Children>;
}
import Dropdown from "../../common/components/Dropdown";
import ItemList from "../../common/utils/ItemList";

View File

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

View File

@@ -1,51 +1,53 @@
/**
* The `SignUpModal` component displays a modal dialog with a singup form.
*
* ### Attrs
*
* - `username`
* - `email`
* - `password`
* - `token` An email token to sign up with.
*/
export default class SignUpModal extends Modal<import("../../common/components/Modal").IInternalModalAttrs> {
constructor();
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import ItemList from '../../common/utils/ItemList';
import Stream from '../../common/utils/Stream';
import type Mithril from 'mithril';
export interface ISignupModalAttrs extends IInternalModalAttrs {
username?: string;
email?: string;
password?: string;
token?: string;
provided?: string[];
}
export declare type SignupBody = {
username: string;
email: string;
} & ({
token: string;
} | {
password: string;
});
export default class SignUpModal<CustomAttrs extends ISignupModalAttrs = ISignupModalAttrs> extends Modal<CustomAttrs> {
/**
* The value of the username input.
*
* @type {Function}
*/
username: Function | undefined;
username: Stream<string>;
/**
* The value of the email input.
*
* @type {Function}
*/
email: Function | undefined;
email: Stream<string>;
/**
* The value of the password input.
*
* @type {Function}
*/
password: Function | undefined;
isProvided(field: any): any;
body(): (string | JSX.Element)[];
fields(): ItemList<any>;
password: Stream<string>;
oninit(vnode: Mithril.Vnode<CustomAttrs, this>): void;
className(): string;
title(): import("@askvortsov/rich-icu-message-formatter").NestedStringArray;
content(): JSX.Element[];
isProvided(field: string): boolean;
body(): (false | JSX.Element)[];
fields(): ItemList<unknown>;
footer(): JSX.Element[];
/**
* Open the log in modal, prefilling it with an email/username/password if
* the user has entered one.
*
* @public
*/
public logIn(): void;
logIn(): void;
onready(): void;
onsubmit(e: SubmitEvent): void;
/**
* Get the data that should be submitted in the sign-up request.
*
* @return {Object}
* @protected
*/
protected submitData(): Object;
submitData(): SignupBody;
}
import Modal from "../../common/components/Modal";
import ItemList from "../../common/utils/ItemList";

View File

@@ -15,9 +15,9 @@ export default class UserCard extends Component<import("../../common/Component")
/**
* Build an item list of tidbits of info to show on this user's profile.
*
* @return {ItemList}
* @return {ItemList<import('mithril').Children>}
*/
infoItems(): ItemList<any>;
infoItems(): ItemList<import('mithril').Children>;
}
import Component from "../../common/Component";
import ItemList from "../../common/utils/ItemList";

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