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

Compare commits

...

25 Commits

Author SHA1 Message Date
Alexander Skvortsov
82b9b7e866 chore: rebuild dist types 2022-03-01 17:50:31 -05:00
Alexander Skvortsov
bdf9ddf33a feat: statically bundle mithril types 2022-03-01 17:50:23 -05:00
flarum-bot
9b302a1029 Bundled output for commit 97dfb50f17
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-02-22 14:06:00 +00:00
Clark Winkelmann
97dfb50f17 Fix permission check in edit modal
Previously was checking ability to edit own user instead of user selected in modal
2022-02-22 15:01:30 +01:00
Clark Winkelmann
6a940cd34f Fix pinned pane broken after discussion creation
The pane would appear but the page content would not shift to the right because the hasPane className would be missing
2022-02-22 15:01:02 +01:00
Clark Winkelmann
edd93dad77 Fix active search jumping to last item during loading 2022-02-22 15:00:14 +01:00
flarum-bot
2d18d37ba9 Bundled output for commit b58b3e2224
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-02-21 18:35:03 +00:00
David Wheatley
b58b3e2224 fix: don't submit form when search clear button clicked (#3260) 2022-02-21 19:31:03 +01:00
David Wheatley
2c902c6563 fix: overlap in minimized composer 2022-02-21 11:45:12 +01:00
David Wheatley
a38dc889e9 fix: composer header overlap with controls 2022-02-21 11:45:12 +01:00
flarum-bot
851907b88c Bundled output for commit dfa3b47cf3
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-02-09 23:18:18 +00:00
Alexander Skvortsov
dfa3b47cf3 fix: refer to bundled dist-typing types instead of src ones
This ensures that extensions referring to core's built dist typings don't try to pull from core's src code.
2022-02-09 18:13:32 -05:00
Alexander Skvortsov
289ea49cc7 chore: make translator / rich translator typings available to exts 2022-02-09 18:13:32 -05:00
flarum-bot
d769ee2b7b Bundled output for commit 6e3051b36a
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-02-09 21:02:11 +00:00
David Wheatley
6e3051b36a fix: sort posts by number instead of creation datetime (#3282)
Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
2022-02-09 20:58:11 +00:00
flarum-bot
c622070366 Bundled output for commit 21d3e33613
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-02-06 02:17:08 +00:00
David Wheatley
21d3e33613 chore: remove call to console.log 2022-02-06 02:12:52 +00:00
flarum-bot
b0d9f10280 Bundled output for commit d192185d13
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-30 22:49:44 +00:00
Alexander Skvortsov
d192185d13 chore: regenerate yarn.lock 2022-01-30 17:45:35 -05:00
Alexander Skvortsov
6dba5c8e67 chore: drop unnecessary ci script 2022-01-30 17:38:05 -05:00
Alexander Skvortsov
34c753040c chore: flarum-cli audit infra --fix 2022-01-27 16:45:10 -05:00
flarum-bot
7c4992c401 Bundled output for commit a7254773dd
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-01-24 04:31:39 +00:00
Alexander Skvortsov
a7254773dd chore: bump rich text ICU Message formatter
This fixes https://discuss.flarum.org/d/29914-utf-encoding-error-in-title/6
2022-01-23 23:24:51 -05:00
Daniël Klabbers
1217b11896 Update Application.php
update constant for next version
2022-01-20 14:20:36 +01:00
Daniël Klabbers
7a22527b72 update changelog 2022-01-20 13:56:05 +01:00
43 changed files with 2149 additions and 976 deletions

1
.gitattributes vendored
View File

@@ -14,5 +14,6 @@ js/dist/* -diff
js/dist/* linguist-generated
js/dist-typings/* linguist-generated
js/yarn.lock -diff
js/package-lock.json -diff
* text=auto eol=lf

View File

@@ -12,4 +12,4 @@ jobs:
with:
enable_backend_testing: true
backend_directory: .
backend_directory: .

View File

@@ -15,7 +15,9 @@ jobs:
enable_typescript: true
frontend_directory: ./js
backend_directory: .
js_package_manager: yarn
main_git_branch: master
secrets:
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}

View File

@@ -100,7 +100,8 @@
- `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).
- Fix escaped quotes in window title (https://github.com/flarum/core/pull/3264)
- 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).

View File

@@ -0,0 +1,517 @@
// Type definitions for Mithril 2.0
// Project: https://mithril.js.org/, https://github.com/mithriljs/mithril.js
// Definitions by: Mike Linkovich <https://github.com/spacejack>, András Parditka <https://github.com/andraaspar>, Isiah Meadows <https://github.com/isiahmeadows>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.2
/** Renders a vnode structure into a DOM element. */
declare function render(el: Element, vnodes: Mithril.Children): void;
/** Mounts a component to a DOM element, enabling it to autoredraw on user events. */
declare function mount(element: Element, component: Mithril.ComponentTypes<any, any>): void;
/** Unmounts a component from a DOM element. */
declare function mount(element: Element, component: null): void; // tslint:disable-line unified-signatures
/** Makes an XHR request and returns a promise. */
declare function request<T>(options: Mithril.RequestOptions<T> & { url: string }): Promise<T>;
/** Makes an XHR request and returns a promise. */
declare function request<T>(url: string, options?: Mithril.RequestOptions<T>): Promise<T>;
/** Makes a JSON-P request and returns a promise. */
declare function jsonp<T>(options: Mithril.JsonpOptions & { url: string }): Promise<T>; // tslint:disable-line:no-unnecessary-generics
/** Makes a JSON-P request and returns a promise. */
declare function jsonp<T>(url: string, options?: Mithril.JsonpOptions): Promise<T>; // tslint:disable-line:no-unnecessary-generics
declare namespace Mithril {
interface CommonAttributes<Attrs, State> {
/** The oninit hook is called before a vnode is touched by the virtual DOM engine. */
oninit?(this: State, vnode: Vnode<Attrs, State>): any;
/** The oncreate hook is called after a DOM element is created and attached to the document. */
oncreate?(this: State, vnode: VnodeDOM<Attrs, State>): any;
/** The onbeforeremove hook is called before a DOM element is detached from the document. If a Promise is returned, Mithril only detaches the DOM element after the promise completes. */
onbeforeremove?(this: State, vnode: VnodeDOM<Attrs, State>): Promise<any> | void;
/** The onremove hook is called before a DOM element is removed from the document. */
onremove?(this: State, vnode: VnodeDOM<Attrs, State>): any;
/** The onbeforeupdate hook is called before a vnode is diffed in a update. */
onbeforeupdate?(this: State, vnode: Vnode<Attrs, State>, old: VnodeDOM<Attrs, State>): boolean | void;
/** The onupdate hook is called after a DOM element is updated, while attached to the document. */
onupdate?(this: State, vnode: VnodeDOM<Attrs, State>): any;
/** A key to optionally associate with this element. */
key?: string | number | undefined;
}
interface Hyperscript {
/** Creates a virtual element (Vnode). */
(selector: string, ...children: Children[]): Vnode<any, any>;
/** Creates a virtual element (Vnode). */
(selector: string, attributes: Attributes, ...children: Children[]): Vnode<any, any>;
/** Creates a virtual element (Vnode). */
<Attrs, State>(component: ComponentTypes<Attrs, State>, ...args: Children[]): Vnode<Attrs, State>;
/** Creates a virtual element (Vnode). */
<Attrs, State>(
component: ComponentTypes<Attrs, State>,
attributes: Attrs & CommonAttributes<Attrs, State>,
...args: Children[]
): Vnode<Attrs, State>;
/** Creates a fragment virtual element (Vnode). */
fragment(attrs: CommonAttributes<any, any> & { [key: string]: any }, children: ChildArrayOrPrimitive): Vnode<any, any>;
/** Turns an HTML string into a virtual element (Vnode). Do not use trust on unsanitized user input. */
trust(html: string): Vnode<any, any>;
}
interface RouteResolver<Attrs = {}, State = {}> {
/** The onmatch hook is called when the router needs to find a component to render. */
onmatch?(
this: this,
args: Attrs,
requestedPath: string,
route: string,
): ComponentTypes<any, any> | Promise<any> | void;
/** The render method is called on every redraw for a matching route. */
render?(this: this, vnode: Vnode<Attrs, State>): Children;
}
/** This represents a key-value mapping linking routes to components. */
interface RouteDefs {
/** The key represents the route. The value represents the corresponding component. */
[url: string]: ComponentTypes<any, any> | RouteResolver<any, any>;
}
interface RouteOptions {
/** Routing parameters. If path has routing parameter slots, the properties of this object are interpolated into the path string. */
replace?: boolean | undefined;
/** The state object to pass to the underlying history.pushState / history.replaceState call. */
state?: any;
/** The title string to pass to the underlying history.pushState / history.replaceState call. */
title?: string | undefined;
}
interface RouteLinkAttrs extends Attributes {
href: string;
selector?: string | ComponentTypes<any> | undefined;
options?: RouteOptions | undefined;
}
interface Route {
/** Creates application routes and mounts Components and/or RouteResolvers to a DOM element. */
(element: Element, defaultRoute: string, routes: RouteDefs): void;
/** Returns the last fully resolved routing path, without the prefix. */
get(): string;
/** Redirects to a matching route or to the default route if no matching routes can be found. */
set(route: string, data?: any, options?: RouteOptions): void;
/** Defines a router prefix which is a fragment of the URL that dictates the underlying strategy used by the router. */
prefix: string;
/** This Component renders a link <a href> that will use the current routing strategy */
Link: Component<RouteLinkAttrs>;
/** Returns the named parameter value from the current route. */
param(name: string): string;
/** Gets all route parameters. */
param(): any;
}
interface RequestOptions<T> {
/** The HTTP method to use. */
method?: string | undefined;
/** The data to be interpolated into the URL and serialized into the querystring. */
params?: { [key: string]: any } | undefined;
/** The data to be serialized into the request body. */
body?: (XMLHttpRequest['send'] extends (x: infer R) => any ? R : never) | (object & { [id: string]: any }) | undefined;
/** Whether the request should be asynchronous. Defaults to true. */
async?: boolean | undefined;
/** A username for HTTP authorization. */
user?: string | undefined;
/** A password for HTTP authorization. */
password?: string | undefined;
/** Whether to send cookies to 3rd party domains. */
withCredentials?: boolean | undefined;
/** Exposes the underlying XMLHttpRequest object for low-level configuration. */
config?(xhr: XMLHttpRequest, options: this): XMLHttpRequest | void;
/** Headers to append to the request before sending it. */
headers?: { [key: string]: string } | undefined;
/** A constructor to be applied to each object in the response. */
type?: new (o: any) => any;
/** A serialization method to be applied to data. Defaults to JSON.stringify, or if options.data is an instance of FormData, defaults to the identity function. */
serialize?(data: any): any;
/** A deserialization method to be applied to the response. Defaults to a small wrapper around JSON.parse that returns null for empty responses. */
deserialize?(data: string): T;
/** A hook to specify how the XMLHttpRequest response should be read. Useful for reading response headers and cookies. Defaults to a function that returns xhr.responseText */
extract?(xhr: XMLHttpRequest, options: this): T;
/**
* Force the use of the HTTP body section for data in GET requests when set to true,
* or the use of querystring for other HTTP methods when set to false.
* Defaults to false for GET requests and true for other methods.
*/
useBody?: boolean | undefined;
/** If false, redraws mounted components upon completion of the request. If true, it does not. */
background?: boolean | undefined;
/** Milliseconds a request can take before automatically being terminated. */
timeout?: number | undefined;
/** The expected type of the response, as a legal value of XMLHttpRequest.responseType. */
responseType?: '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | undefined;
}
interface JsonpOptions {
/** The data to be interpolated into the URL and serialized into the querystring. */
params?: { [id: string]: any } | undefined;
/** The data to be serialized into the request body. */
body?: any;
/** A constructor to be applied to each object in the response. */
type?: new (o: any) => any;
/** The name of the function that will be called as the callback. */
callbackName?: string | undefined;
/** The name of the querystring parameter name that specifies the callback name. */
callbackKey?: string | undefined;
/** If false, redraws mounted components upon completion of the request. If true, it does not. */
background?: boolean | undefined;
}
interface Redraw {
/** Manually triggers an asynchronous redraw of mounted components. */
(): void;
/** Manually triggers a synchronous redraw of mounted components. */
sync(): void;
}
type Params = object & ParamsRec;
interface ParamsRec {
// Ideally, it'd be this:
// `[key: string | number]: Params | !symbol & !object`
[key: string]: string | number | boolean | null | undefined | Params;
}
interface Static extends Hyperscript {
route: Route;
mount: typeof mount;
render: typeof render;
redraw: Redraw;
request: typeof request;
jsonp: typeof jsonp;
/** Returns an object with key/value pairs parsed from a string of the form: ?a=1&b=2 */
parseQueryString(queryString: string): Params;
/** Turns the key/value pairs of an object into a string of the form: a=1&b=2 */
buildQueryString(values: Params): string;
/** Parse path name */
parsePathname(url: string): { path: string; params: Params };
/** Build path name */
buildPathname(template: string, params?: Params): string;
}
// Vnode children types
type Child = Vnode<any, any> | string | number | boolean | null | undefined;
interface ChildArray extends Array<Children> {}
type Children = Child | ChildArray;
type ChildArrayOrPrimitive = ChildArray | string | number | boolean;
/** Virtual DOM nodes, or vnodes, are Javascript objects that represent an element (or parts of the DOM). */
interface Vnode<Attrs = {}, State = {}> {
/** The nodeName of a DOM element. It may also be the string [ if a vnode is a fragment, # if it's a text vnode, or < if it's a trusted HTML vnode. Additionally, it may be a component. */
tag: string | ComponentTypes<Attrs, State>;
/** A hashmap of DOM attributes, events, properties and lifecycle methods. */
attrs: Attrs;
/** An object that is persisted between redraws. In component vnodes, state is a shallow clone of the component object. */
state: State;
/** The value used to map a DOM element to its respective item in an array of data. */
key?: string | number | undefined;
/** In most vnode types, the children property is an array of vnodes. For text and trusted HTML vnodes, The children property is either a string, a number or a boolean. */
children?: ChildArrayOrPrimitive | undefined;
/**
* This is used instead of children if a vnode contains a text node as its only child.
* This is done for performance reasons.
* Component vnodes never use the text property even if they have a text node as their only child.
*/
text?: string | number | boolean | undefined;
}
// In some lifecycle methods, Vnode will have a dom property
// and possibly a domSize property.
interface VnodeDOM<Attrs = {}, State = {}> extends Vnode<Attrs, State> {
/** Points to the element that corresponds to the vnode. */
dom: Element;
/** This defines the number of DOM elements that the vnode represents (starting from the element referenced by the dom property). */
domSize?: number | undefined;
}
type _NoLifecycle<T> = Omit<T, keyof Component>;
interface CVnode<A = {}> extends Vnode<A, ClassComponent<A>> {}
interface CVnodeDOM<A = {}> extends VnodeDOM<A, ClassComponent<A>> {}
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any Javascript object that has a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
interface Component<Attrs = {}, State = {}> {
/** The oninit hook is called before a vnode is touched by the virtual DOM engine. */
oninit?(this: _NoLifecycle<this & State>, vnode: Vnode<Attrs, _NoLifecycle<this & State>>): any;
/** The oncreate hook is called after a DOM element is created and attached to the document. */
oncreate?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): any;
/** The onbeforeremove hook is called before a DOM element is detached from the document. If a Promise is returned, Mithril only detaches the DOM element after the promise completes. */
onbeforeremove?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): Promise<any> | void;
/** The onremove hook is called before a DOM element is removed from the document. */
onremove?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): any;
/** The onbeforeupdate hook is called before a vnode is diffed in a update. */
onbeforeupdate?(this: _NoLifecycle<this & State>, vnode: Vnode<Attrs, _NoLifecycle<this & State>>, old: VnodeDOM<Attrs, _NoLifecycle<this & State>>): boolean | void;
/** The onupdate hook is called after a DOM element is updated, while attached to the document. */
onupdate?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): any;
/** Creates a view out of virtual elements. */
view(this: _NoLifecycle<this & State>, vnode: Vnode<Attrs, _NoLifecycle<this & State>>): Children | null | void;
}
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any class that implements a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
interface ClassComponent<A = {}> {
/** The oninit hook is called before a vnode is touched by the virtual DOM engine. */
oninit?(vnode: Vnode<A, this>): any;
/** The oncreate hook is called after a DOM element is created and attached to the document. */
oncreate?(vnode: VnodeDOM<A, this>): any;
/** The onbeforeremove hook is called before a DOM element is detached from the document. If a Promise is returned, Mithril only detaches the DOM element after the promise completes. */
onbeforeremove?(vnode: VnodeDOM<A, this>): Promise<any> | void;
/** The onremove hook is called before a DOM element is removed from the document. */
onremove?(vnode: VnodeDOM<A, this>): any;
/** The onbeforeupdate hook is called before a vnode is diffed in a update. */
onbeforeupdate?(vnode: Vnode<A, this>, old: VnodeDOM<A, this>): boolean | void;
/** The onupdate hook is called after a DOM element is updated, while attached to the document. */
onupdate?(vnode: VnodeDOM<A, this>): any;
/** Creates a view out of virtual elements. */
view(vnode: Vnode<A, this>): Children | null | void;
}
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any function that returns an object with a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
type FactoryComponent<A = {}> = (vnode: Vnode<A>) => Component<A>;
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any function that returns an object with a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
type ClosureComponent<A = {}> = FactoryComponent<A>;
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any Javascript object that has a view method is a Mithril component. Components can be consumed via the m() utility.
*/
type Comp<Attrs = {}, State = {}> = _NoLifecycle<State> & Component<Attrs, _NoLifecycle<State>>;
/** Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse. Components can be consumed via the m() utility. */
type ComponentTypes<A = {}, S = {}> =
| Component<A, S>
| { new (vnode: CVnode<A>): ClassComponent<A> }
| FactoryComponent<A>;
/** This represents the attributes available for configuring virtual elements, beyond the applicable DOM attributes. */
interface Attributes extends CommonAttributes<any, any> {
/** The class name(s) for this virtual element, as a space-separated list. */
className?: string | undefined;
/** The class name(s) for this virtual element, as a space-separated list. */
class?: string | undefined;
/** Any other virtual element properties, including attributes and event handlers. */
[property: string]: any;
}
}
declare global {
namespace JSX {
// tslint:disable-next-line:no-empty-interface
interface Element extends Mithril.Vnode {}
// tslint:disable-next-line:no-empty-interface
interface IntrinsicAttributes extends Mithril.Attributes {}
// tslint:disable-next-line:no-empty-interface
interface IntrinsicClassAttributes extends Mithril.Attributes {}
interface IntrinsicElements {
// HTML
a: Mithril.Attributes;
abbr: Mithril.Attributes;
address: Mithril.Attributes;
area: Mithril.Attributes;
article: Mithril.Attributes;
aside: Mithril.Attributes;
audio: Mithril.Attributes;
b: Mithril.Attributes;
base: Mithril.Attributes;
bdi: Mithril.Attributes;
bdo: Mithril.Attributes;
big: Mithril.Attributes;
blockquote: Mithril.Attributes;
body: Mithril.Attributes;
br: Mithril.Attributes;
button: Mithril.Attributes;
canvas: Mithril.Attributes;
caption: Mithril.Attributes;
cite: Mithril.Attributes;
code: Mithril.Attributes;
col: Mithril.Attributes;
colgroup: Mithril.Attributes;
data: Mithril.Attributes;
datalist: Mithril.Attributes;
dd: Mithril.Attributes;
del: Mithril.Attributes;
details: Mithril.Attributes;
dfn: Mithril.Attributes;
dialog: Mithril.Attributes;
div: Mithril.Attributes;
dl: Mithril.Attributes;
dt: Mithril.Attributes;
em: Mithril.Attributes;
embed: Mithril.Attributes;
fieldset: Mithril.Attributes;
figcaption: Mithril.Attributes;
figure: Mithril.Attributes;
footer: Mithril.Attributes;
form: Mithril.Attributes;
h1: Mithril.Attributes;
h2: Mithril.Attributes;
h3: Mithril.Attributes;
h4: Mithril.Attributes;
h5: Mithril.Attributes;
h6: Mithril.Attributes;
head: Mithril.Attributes;
header: Mithril.Attributes;
hgroup: Mithril.Attributes;
hr: Mithril.Attributes;
html: Mithril.Attributes;
i: Mithril.Attributes;
iframe: Mithril.Attributes;
img: Mithril.Attributes;
input: Mithril.Attributes;
ins: Mithril.Attributes;
kbd: Mithril.Attributes;
keygen: Mithril.Attributes;
label: Mithril.Attributes;
legend: Mithril.Attributes;
li: Mithril.Attributes;
link: Mithril.Attributes;
main: Mithril.Attributes;
map: Mithril.Attributes;
mark: Mithril.Attributes;
menu: Mithril.Attributes;
menuitem: Mithril.Attributes;
meta: Mithril.Attributes;
meter: Mithril.Attributes;
nav: Mithril.Attributes;
noindex: Mithril.Attributes;
noscript: Mithril.Attributes;
object: Mithril.Attributes;
ol: Mithril.Attributes;
optgroup: Mithril.Attributes;
option: Mithril.Attributes;
output: Mithril.Attributes;
p: Mithril.Attributes;
param: Mithril.Attributes;
picture: Mithril.Attributes;
pre: Mithril.Attributes;
progress: Mithril.Attributes;
q: Mithril.Attributes;
rp: Mithril.Attributes;
rt: Mithril.Attributes;
ruby: Mithril.Attributes;
s: Mithril.Attributes;
samp: Mithril.Attributes;
script: Mithril.Attributes;
section: Mithril.Attributes;
select: Mithril.Attributes;
small: Mithril.Attributes;
source: Mithril.Attributes;
span: Mithril.Attributes;
strong: Mithril.Attributes;
style: Mithril.Attributes;
sub: Mithril.Attributes;
summary: Mithril.Attributes;
sup: Mithril.Attributes;
table: Mithril.Attributes;
template: Mithril.Attributes;
tbody: Mithril.Attributes;
td: Mithril.Attributes;
textarea: Mithril.Attributes;
tfoot: Mithril.Attributes;
th: Mithril.Attributes;
thead: Mithril.Attributes;
time: Mithril.Attributes;
title: Mithril.Attributes;
tr: Mithril.Attributes;
track: Mithril.Attributes;
u: Mithril.Attributes;
ul: Mithril.Attributes;
var: Mithril.Attributes;
video: Mithril.Attributes;
wbr: Mithril.Attributes;
webview: Mithril.Attributes;
// SVG
svg: Mithril.Attributes;
animate: Mithril.Attributes;
animateMotion: Mithril.Attributes;
animateTransform: Mithril.Attributes;
circle: Mithril.Attributes;
clipPath: Mithril.Attributes;
defs: Mithril.Attributes;
desc: Mithril.Attributes;
ellipse: Mithril.Attributes;
feBlend: Mithril.Attributes;
feColorMatrix: Mithril.Attributes;
feComponentTransfer: Mithril.Attributes;
feComposite: Mithril.Attributes;
feConvolveMatrix: Mithril.Attributes;
feDiffuseLighting: Mithril.Attributes;
feDisplacementMap: Mithril.Attributes;
feDistantLight: Mithril.Attributes;
feDropShadow: Mithril.Attributes;
feFlood: Mithril.Attributes;
feFuncA: Mithril.Attributes;
feFuncB: Mithril.Attributes;
feFuncG: Mithril.Attributes;
feFuncR: Mithril.Attributes;
feGaussianBlur: Mithril.Attributes;
feImage: Mithril.Attributes;
feMerge: Mithril.Attributes;
feMergeNode: Mithril.Attributes;
feMorphology: Mithril.Attributes;
feOffset: Mithril.Attributes;
fePointLight: Mithril.Attributes;
feSpecularLighting: Mithril.Attributes;
feSpotLight: Mithril.Attributes;
feTile: Mithril.Attributes;
feTurbulence: Mithril.Attributes;
filter: Mithril.Attributes;
foreignObject: Mithril.Attributes;
g: Mithril.Attributes;
image: Mithril.Attributes;
line: Mithril.Attributes;
linearGradient: Mithril.Attributes;
marker: Mithril.Attributes;
mask: Mithril.Attributes;
metadata: Mithril.Attributes;
mpath: Mithril.Attributes;
path: Mithril.Attributes;
pattern: Mithril.Attributes;
polygon: Mithril.Attributes;
polyline: Mithril.Attributes;
radialGradient: Mithril.Attributes;
rect: Mithril.Attributes;
stop: Mithril.Attributes;
switch: Mithril.Attributes;
symbol: Mithril.Attributes;
text: Mithril.Attributes;
textPath: Mithril.Attributes;
tspan: Mithril.Attributes;
use: Mithril.Attributes;
view: Mithril.Attributes;
// Special Mithril types
'[': Mithril.Attributes;
}
}
}
declare const Mithril: Mithril.Static;
export = Mithril;

View File

@@ -0,0 +1,43 @@
// tslint:disable:rulename strict-export-declare-modifiers
/** Creates an empty stream. */
declare function Stream<T>(): Stream<T>; // tslint:disable-line no-unnecessary-generics
/** Creates a stream with an initial value. */
declare function Stream<T>(value: T): Stream<T>; // tslint:disable-line unified-signatures
declare interface Stream<T> {
/** Returns the value of the stream. */
(): T;
/** Sets the value of the stream. */
(value: T): this;
/** Creates a dependent stream whose value is set to the result of the callback function. */
map<U>(f: (current: T) => U | typeof Stream.SKIP): Stream<U>;
/** This method is functionally identical to stream. It exists to conform to Fantasy Land's Applicative specification. */
of(val: T): Stream<T>;
/** Apply. */
ap<U>(f: Stream<(value: T) => U>): Stream<U>;
/** A co-dependent stream that unregisters dependent streams when set to true. */
end: Stream<boolean>;
/** When a stream is passed as the argument to JSON.stringify(), the value of the stream is serialized. */
toJSON(): string;
/** Returns the value of the stream. */
valueOf(): T;
}
declare namespace Stream {
/** Creates a computed stream that reactively updates if any of its upstreams are updated. */
export function combine<T>(combiner: (...streams: any[]) => T, streams: Array<Stream<any>>): Stream<T>;
/** Combines the values of one or more streams into a single stream that is updated whenever one or more of the sources are updated */
export function lift<S extends any[], T>(fn: (...values: S) => T, ...streams: {[I in keyof S]: Stream<S[I]>}): Stream<T>;
/** Creates a stream whose value is the array of values from an array of streams. */
export function merge<S extends any[]>(streams: {[I in keyof S]: Stream<S[I]>}): Stream<{[I in keyof S]: S[I]}>;
/** Creates a new stream with the results of calling the function on every incoming stream with and accumulator and the incoming value. */
export function scan<T, U>(fn: (acc: U, value: T) => U, acc: U, stream: Stream<T>): Stream<U>;
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
export function scanMerge<T, U>(pairs: Array<[Stream<T>, (acc: U, value: T) => U]>, acc: U): Stream<U>;
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
export function scanMerge<U>(pairs: Array<[Stream<any>, (acc: U, value: any) => U]>, acc: U): Stream<U>;
/** A special value that can be returned to stream callbacks to skip execution of downstreams. */
export const SKIP: unique symbol;
}
export = Stream;

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
export interface ILoadingModalAttrs extends IInternalModalAttrs {
}

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import ExtensionReadme from '../models/ExtensionReadme';
import type Mithril from 'mithril';

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import type Mithril from 'mithril';
import type User from '../../common/models/User';
import ItemList from '../../common/utils/ItemList';

View File

@@ -1,4 +1,4 @@
/// <reference path="../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../@types/translator-icu-rich.d.ts" />
import { RichMessageFormatter } from '@askvortsov/rich-icu-message-formatter';
import { pluralTypeHandler, selectTypeHandler } from '@ultraq/icu-message-formatter';
declare type Translations = Record<string, string>;

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from './Modal';
import ItemList from '../utils/ItemList';
import Stream from '../utils/Stream';

View File

@@ -1,4 +1,3 @@
/// <reference types="mithril" />
import Component, { ComponentAttrs } from '../Component';
export interface LoadingIndicatorAttrs extends ComponentAttrs {
/**

View File

@@ -1,4 +1,3 @@
/// <reference types="mithril" />
import type RequestError from '../utils/RequestError';
import Modal, { IInternalModalAttrs } from './Modal';
export interface IRequestErrorModalAttrs extends IInternalModalAttrs {

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import Stream from '../../common/utils/Stream';
import Mithril from 'mithril';

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import ItemList from '../../common/utils/ItemList';
import Stream from '../../common/utils/Stream';

View File

@@ -104,6 +104,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
selectableItems(): JQuery;
/**
* Get the position of the currently selected search result item.
* Returns zero if not found.
*/
getCurrentNumericIndex(): number;
/**

View File

@@ -1,4 +1,4 @@
/// <reference path="../../../src/common/translator-icu-rich.d.ts" />
/// <reference path="../../@types/translator-icu-rich.d.ts" />
import Modal, { IInternalModalAttrs } from '../../common/components/Modal';
import ItemList from '../../common/utils/ItemList';
import Stream from '../../common/utils/Stream';

2
js/dist/admin.js generated vendored

File diff suppressed because one or more lines are too long

2
js/dist/admin.js.LICENSE.txt generated vendored
View File

@@ -48,7 +48,7 @@
*/
/*!
* focus-trap 6.7.1
* focus-trap 6.7.2
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
*/

2
js/dist/admin.js.map generated vendored

File diff suppressed because one or more lines are too long

2
js/dist/forum.js generated vendored

File diff suppressed because one or more lines are too long

2
js/dist/forum.js.LICENSE.txt generated vendored
View File

@@ -48,7 +48,7 @@
*/
/*!
* focus-trap 6.7.1
* focus-trap 6.7.2
* @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
*/

2
js/dist/forum.js.map generated vendored

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@
"name": "@flarum/core",
"prettier": "@flarum/prettier-config",
"dependencies": {
"@askvortsov/rich-icu-message-formatter": "^0.2.3",
"@askvortsov/rich-icu-message-formatter": "^0.2.4",
"@ultraq/icu-message-formatter": "^0.12.0",
"bootstrap": "^3.4.1",
"clsx": "^1.1.1",
@@ -21,7 +21,6 @@
"devDependencies": {
"@flarum/prettier-config": "^1.0.0",
"@types/jquery": "^3.5.10",
"@types/mithril": "^2.0.8",
"@types/punycode": "^2.1.0",
"@types/textarea-caret": "^3.0.1",
"bundlewatch": "^0.3.2",
@@ -39,11 +38,12 @@
"scripts": {
"dev": "webpack --mode development --watch",
"build": "webpack --mode production",
"analyze": "cross-env ANALYZER=true yarn build",
"analyze": "cross-env ANALYZER=true yarn run build",
"format": "prettier --write src",
"format-check": "prettier --check src",
"clean-typings": "npx rimraf dist-typings && mkdir dist-typings",
"build-typings": "npm run clean-typings && tsc && [ -e src/@types ] && cp -r src/@types dist-typings/@types",
"build-typings": "yarn run clean-typings && [ -e src/@types ] && cp -r src/@types dist-typings/@types && tsc && yarn run post-build-typings",
"post-build-typings": "find dist-typings -type f -name '*.d.ts' -print0 | xargs -0 sed -i 's,../src/@types,@types,g'",
"check-typings": "tsc --noEmit --emitDeclarationOnly false",
"check-typings-coverage": "typescript-coverage-report"
},

517
js/src/@types/mithril/index.d.ts vendored Normal file
View File

@@ -0,0 +1,517 @@
// Type definitions for Mithril 2.0
// Project: https://mithril.js.org/, https://github.com/mithriljs/mithril.js
// Definitions by: Mike Linkovich <https://github.com/spacejack>, András Parditka <https://github.com/andraaspar>, Isiah Meadows <https://github.com/isiahmeadows>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.2
/** Renders a vnode structure into a DOM element. */
declare function render(el: Element, vnodes: Mithril.Children): void;
/** Mounts a component to a DOM element, enabling it to autoredraw on user events. */
declare function mount(element: Element, component: Mithril.ComponentTypes<any, any>): void;
/** Unmounts a component from a DOM element. */
declare function mount(element: Element, component: null): void; // tslint:disable-line unified-signatures
/** Makes an XHR request and returns a promise. */
declare function request<T>(options: Mithril.RequestOptions<T> & { url: string }): Promise<T>;
/** Makes an XHR request and returns a promise. */
declare function request<T>(url: string, options?: Mithril.RequestOptions<T>): Promise<T>;
/** Makes a JSON-P request and returns a promise. */
declare function jsonp<T>(options: Mithril.JsonpOptions & { url: string }): Promise<T>; // tslint:disable-line:no-unnecessary-generics
/** Makes a JSON-P request and returns a promise. */
declare function jsonp<T>(url: string, options?: Mithril.JsonpOptions): Promise<T>; // tslint:disable-line:no-unnecessary-generics
declare namespace Mithril {
interface CommonAttributes<Attrs, State> {
/** The oninit hook is called before a vnode is touched by the virtual DOM engine. */
oninit?(this: State, vnode: Vnode<Attrs, State>): any;
/** The oncreate hook is called after a DOM element is created and attached to the document. */
oncreate?(this: State, vnode: VnodeDOM<Attrs, State>): any;
/** The onbeforeremove hook is called before a DOM element is detached from the document. If a Promise is returned, Mithril only detaches the DOM element after the promise completes. */
onbeforeremove?(this: State, vnode: VnodeDOM<Attrs, State>): Promise<any> | void;
/** The onremove hook is called before a DOM element is removed from the document. */
onremove?(this: State, vnode: VnodeDOM<Attrs, State>): any;
/** The onbeforeupdate hook is called before a vnode is diffed in a update. */
onbeforeupdate?(this: State, vnode: Vnode<Attrs, State>, old: VnodeDOM<Attrs, State>): boolean | void;
/** The onupdate hook is called after a DOM element is updated, while attached to the document. */
onupdate?(this: State, vnode: VnodeDOM<Attrs, State>): any;
/** A key to optionally associate with this element. */
key?: string | number | undefined;
}
interface Hyperscript {
/** Creates a virtual element (Vnode). */
(selector: string, ...children: Children[]): Vnode<any, any>;
/** Creates a virtual element (Vnode). */
(selector: string, attributes: Attributes, ...children: Children[]): Vnode<any, any>;
/** Creates a virtual element (Vnode). */
<Attrs, State>(component: ComponentTypes<Attrs, State>, ...args: Children[]): Vnode<Attrs, State>;
/** Creates a virtual element (Vnode). */
<Attrs, State>(
component: ComponentTypes<Attrs, State>,
attributes: Attrs & CommonAttributes<Attrs, State>,
...args: Children[]
): Vnode<Attrs, State>;
/** Creates a fragment virtual element (Vnode). */
fragment(attrs: CommonAttributes<any, any> & { [key: string]: any }, children: ChildArrayOrPrimitive): Vnode<any, any>;
/** Turns an HTML string into a virtual element (Vnode). Do not use trust on unsanitized user input. */
trust(html: string): Vnode<any, any>;
}
interface RouteResolver<Attrs = {}, State = {}> {
/** The onmatch hook is called when the router needs to find a component to render. */
onmatch?(
this: this,
args: Attrs,
requestedPath: string,
route: string,
): ComponentTypes<any, any> | Promise<any> | void;
/** The render method is called on every redraw for a matching route. */
render?(this: this, vnode: Vnode<Attrs, State>): Children;
}
/** This represents a key-value mapping linking routes to components. */
interface RouteDefs {
/** The key represents the route. The value represents the corresponding component. */
[url: string]: ComponentTypes<any, any> | RouteResolver<any, any>;
}
interface RouteOptions {
/** Routing parameters. If path has routing parameter slots, the properties of this object are interpolated into the path string. */
replace?: boolean | undefined;
/** The state object to pass to the underlying history.pushState / history.replaceState call. */
state?: any;
/** The title string to pass to the underlying history.pushState / history.replaceState call. */
title?: string | undefined;
}
interface RouteLinkAttrs extends Attributes {
href: string;
selector?: string | ComponentTypes<any> | undefined;
options?: RouteOptions | undefined;
}
interface Route {
/** Creates application routes and mounts Components and/or RouteResolvers to a DOM element. */
(element: Element, defaultRoute: string, routes: RouteDefs): void;
/** Returns the last fully resolved routing path, without the prefix. */
get(): string;
/** Redirects to a matching route or to the default route if no matching routes can be found. */
set(route: string, data?: any, options?: RouteOptions): void;
/** Defines a router prefix which is a fragment of the URL that dictates the underlying strategy used by the router. */
prefix: string;
/** This Component renders a link <a href> that will use the current routing strategy */
Link: Component<RouteLinkAttrs>;
/** Returns the named parameter value from the current route. */
param(name: string): string;
/** Gets all route parameters. */
param(): any;
}
interface RequestOptions<T> {
/** The HTTP method to use. */
method?: string | undefined;
/** The data to be interpolated into the URL and serialized into the querystring. */
params?: { [key: string]: any } | undefined;
/** The data to be serialized into the request body. */
body?: (XMLHttpRequest['send'] extends (x: infer R) => any ? R : never) | (object & { [id: string]: any }) | undefined;
/** Whether the request should be asynchronous. Defaults to true. */
async?: boolean | undefined;
/** A username for HTTP authorization. */
user?: string | undefined;
/** A password for HTTP authorization. */
password?: string | undefined;
/** Whether to send cookies to 3rd party domains. */
withCredentials?: boolean | undefined;
/** Exposes the underlying XMLHttpRequest object for low-level configuration. */
config?(xhr: XMLHttpRequest, options: this): XMLHttpRequest | void;
/** Headers to append to the request before sending it. */
headers?: { [key: string]: string } | undefined;
/** A constructor to be applied to each object in the response. */
type?: new (o: any) => any;
/** A serialization method to be applied to data. Defaults to JSON.stringify, or if options.data is an instance of FormData, defaults to the identity function. */
serialize?(data: any): any;
/** A deserialization method to be applied to the response. Defaults to a small wrapper around JSON.parse that returns null for empty responses. */
deserialize?(data: string): T;
/** A hook to specify how the XMLHttpRequest response should be read. Useful for reading response headers and cookies. Defaults to a function that returns xhr.responseText */
extract?(xhr: XMLHttpRequest, options: this): T;
/**
* Force the use of the HTTP body section for data in GET requests when set to true,
* or the use of querystring for other HTTP methods when set to false.
* Defaults to false for GET requests and true for other methods.
*/
useBody?: boolean | undefined;
/** If false, redraws mounted components upon completion of the request. If true, it does not. */
background?: boolean | undefined;
/** Milliseconds a request can take before automatically being terminated. */
timeout?: number | undefined;
/** The expected type of the response, as a legal value of XMLHttpRequest.responseType. */
responseType?: '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | undefined;
}
interface JsonpOptions {
/** The data to be interpolated into the URL and serialized into the querystring. */
params?: { [id: string]: any } | undefined;
/** The data to be serialized into the request body. */
body?: any;
/** A constructor to be applied to each object in the response. */
type?: new (o: any) => any;
/** The name of the function that will be called as the callback. */
callbackName?: string | undefined;
/** The name of the querystring parameter name that specifies the callback name. */
callbackKey?: string | undefined;
/** If false, redraws mounted components upon completion of the request. If true, it does not. */
background?: boolean | undefined;
}
interface Redraw {
/** Manually triggers an asynchronous redraw of mounted components. */
(): void;
/** Manually triggers a synchronous redraw of mounted components. */
sync(): void;
}
type Params = object & ParamsRec;
interface ParamsRec {
// Ideally, it'd be this:
// `[key: string | number]: Params | !symbol & !object`
[key: string]: string | number | boolean | null | undefined | Params;
}
interface Static extends Hyperscript {
route: Route;
mount: typeof mount;
render: typeof render;
redraw: Redraw;
request: typeof request;
jsonp: typeof jsonp;
/** Returns an object with key/value pairs parsed from a string of the form: ?a=1&b=2 */
parseQueryString(queryString: string): Params;
/** Turns the key/value pairs of an object into a string of the form: a=1&b=2 */
buildQueryString(values: Params): string;
/** Parse path name */
parsePathname(url: string): { path: string; params: Params };
/** Build path name */
buildPathname(template: string, params?: Params): string;
}
// Vnode children types
type Child = Vnode<any, any> | string | number | boolean | null | undefined;
interface ChildArray extends Array<Children> {}
type Children = Child | ChildArray;
type ChildArrayOrPrimitive = ChildArray | string | number | boolean;
/** Virtual DOM nodes, or vnodes, are Javascript objects that represent an element (or parts of the DOM). */
interface Vnode<Attrs = {}, State = {}> {
/** The nodeName of a DOM element. It may also be the string [ if a vnode is a fragment, # if it's a text vnode, or < if it's a trusted HTML vnode. Additionally, it may be a component. */
tag: string | ComponentTypes<Attrs, State>;
/** A hashmap of DOM attributes, events, properties and lifecycle methods. */
attrs: Attrs;
/** An object that is persisted between redraws. In component vnodes, state is a shallow clone of the component object. */
state: State;
/** The value used to map a DOM element to its respective item in an array of data. */
key?: string | number | undefined;
/** In most vnode types, the children property is an array of vnodes. For text and trusted HTML vnodes, The children property is either a string, a number or a boolean. */
children?: ChildArrayOrPrimitive | undefined;
/**
* This is used instead of children if a vnode contains a text node as its only child.
* This is done for performance reasons.
* Component vnodes never use the text property even if they have a text node as their only child.
*/
text?: string | number | boolean | undefined;
}
// In some lifecycle methods, Vnode will have a dom property
// and possibly a domSize property.
interface VnodeDOM<Attrs = {}, State = {}> extends Vnode<Attrs, State> {
/** Points to the element that corresponds to the vnode. */
dom: Element;
/** This defines the number of DOM elements that the vnode represents (starting from the element referenced by the dom property). */
domSize?: number | undefined;
}
type _NoLifecycle<T> = Omit<T, keyof Component>;
interface CVnode<A = {}> extends Vnode<A, ClassComponent<A>> {}
interface CVnodeDOM<A = {}> extends VnodeDOM<A, ClassComponent<A>> {}
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any Javascript object that has a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
interface Component<Attrs = {}, State = {}> {
/** The oninit hook is called before a vnode is touched by the virtual DOM engine. */
oninit?(this: _NoLifecycle<this & State>, vnode: Vnode<Attrs, _NoLifecycle<this & State>>): any;
/** The oncreate hook is called after a DOM element is created and attached to the document. */
oncreate?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): any;
/** The onbeforeremove hook is called before a DOM element is detached from the document. If a Promise is returned, Mithril only detaches the DOM element after the promise completes. */
onbeforeremove?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): Promise<any> | void;
/** The onremove hook is called before a DOM element is removed from the document. */
onremove?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): any;
/** The onbeforeupdate hook is called before a vnode is diffed in a update. */
onbeforeupdate?(this: _NoLifecycle<this & State>, vnode: Vnode<Attrs, _NoLifecycle<this & State>>, old: VnodeDOM<Attrs, _NoLifecycle<this & State>>): boolean | void;
/** The onupdate hook is called after a DOM element is updated, while attached to the document. */
onupdate?(this: _NoLifecycle<this & State>, vnode: VnodeDOM<Attrs, _NoLifecycle<this & State>>): any;
/** Creates a view out of virtual elements. */
view(this: _NoLifecycle<this & State>, vnode: Vnode<Attrs, _NoLifecycle<this & State>>): Children | null | void;
}
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any class that implements a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
interface ClassComponent<A = {}> {
/** The oninit hook is called before a vnode is touched by the virtual DOM engine. */
oninit?(vnode: Vnode<A, this>): any;
/** The oncreate hook is called after a DOM element is created and attached to the document. */
oncreate?(vnode: VnodeDOM<A, this>): any;
/** The onbeforeremove hook is called before a DOM element is detached from the document. If a Promise is returned, Mithril only detaches the DOM element after the promise completes. */
onbeforeremove?(vnode: VnodeDOM<A, this>): Promise<any> | void;
/** The onremove hook is called before a DOM element is removed from the document. */
onremove?(vnode: VnodeDOM<A, this>): any;
/** The onbeforeupdate hook is called before a vnode is diffed in a update. */
onbeforeupdate?(vnode: Vnode<A, this>, old: VnodeDOM<A, this>): boolean | void;
/** The onupdate hook is called after a DOM element is updated, while attached to the document. */
onupdate?(vnode: VnodeDOM<A, this>): any;
/** Creates a view out of virtual elements. */
view(vnode: Vnode<A, this>): Children | null | void;
}
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any function that returns an object with a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
type FactoryComponent<A = {}> = (vnode: Vnode<A>) => Component<A>;
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any function that returns an object with a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
type ClosureComponent<A = {}> = FactoryComponent<A>;
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any Javascript object that has a view method is a Mithril component. Components can be consumed via the m() utility.
*/
type Comp<Attrs = {}, State = {}> = _NoLifecycle<State> & Component<Attrs, _NoLifecycle<State>>;
/** Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse. Components can be consumed via the m() utility. */
type ComponentTypes<A = {}, S = {}> =
| Component<A, S>
| { new (vnode: CVnode<A>): ClassComponent<A> }
| FactoryComponent<A>;
/** This represents the attributes available for configuring virtual elements, beyond the applicable DOM attributes. */
interface Attributes extends CommonAttributes<any, any> {
/** The class name(s) for this virtual element, as a space-separated list. */
className?: string | undefined;
/** The class name(s) for this virtual element, as a space-separated list. */
class?: string | undefined;
/** Any other virtual element properties, including attributes and event handlers. */
[property: string]: any;
}
}
declare global {
namespace JSX {
// tslint:disable-next-line:no-empty-interface
interface Element extends Mithril.Vnode {}
// tslint:disable-next-line:no-empty-interface
interface IntrinsicAttributes extends Mithril.Attributes {}
// tslint:disable-next-line:no-empty-interface
interface IntrinsicClassAttributes extends Mithril.Attributes {}
interface IntrinsicElements {
// HTML
a: Mithril.Attributes;
abbr: Mithril.Attributes;
address: Mithril.Attributes;
area: Mithril.Attributes;
article: Mithril.Attributes;
aside: Mithril.Attributes;
audio: Mithril.Attributes;
b: Mithril.Attributes;
base: Mithril.Attributes;
bdi: Mithril.Attributes;
bdo: Mithril.Attributes;
big: Mithril.Attributes;
blockquote: Mithril.Attributes;
body: Mithril.Attributes;
br: Mithril.Attributes;
button: Mithril.Attributes;
canvas: Mithril.Attributes;
caption: Mithril.Attributes;
cite: Mithril.Attributes;
code: Mithril.Attributes;
col: Mithril.Attributes;
colgroup: Mithril.Attributes;
data: Mithril.Attributes;
datalist: Mithril.Attributes;
dd: Mithril.Attributes;
del: Mithril.Attributes;
details: Mithril.Attributes;
dfn: Mithril.Attributes;
dialog: Mithril.Attributes;
div: Mithril.Attributes;
dl: Mithril.Attributes;
dt: Mithril.Attributes;
em: Mithril.Attributes;
embed: Mithril.Attributes;
fieldset: Mithril.Attributes;
figcaption: Mithril.Attributes;
figure: Mithril.Attributes;
footer: Mithril.Attributes;
form: Mithril.Attributes;
h1: Mithril.Attributes;
h2: Mithril.Attributes;
h3: Mithril.Attributes;
h4: Mithril.Attributes;
h5: Mithril.Attributes;
h6: Mithril.Attributes;
head: Mithril.Attributes;
header: Mithril.Attributes;
hgroup: Mithril.Attributes;
hr: Mithril.Attributes;
html: Mithril.Attributes;
i: Mithril.Attributes;
iframe: Mithril.Attributes;
img: Mithril.Attributes;
input: Mithril.Attributes;
ins: Mithril.Attributes;
kbd: Mithril.Attributes;
keygen: Mithril.Attributes;
label: Mithril.Attributes;
legend: Mithril.Attributes;
li: Mithril.Attributes;
link: Mithril.Attributes;
main: Mithril.Attributes;
map: Mithril.Attributes;
mark: Mithril.Attributes;
menu: Mithril.Attributes;
menuitem: Mithril.Attributes;
meta: Mithril.Attributes;
meter: Mithril.Attributes;
nav: Mithril.Attributes;
noindex: Mithril.Attributes;
noscript: Mithril.Attributes;
object: Mithril.Attributes;
ol: Mithril.Attributes;
optgroup: Mithril.Attributes;
option: Mithril.Attributes;
output: Mithril.Attributes;
p: Mithril.Attributes;
param: Mithril.Attributes;
picture: Mithril.Attributes;
pre: Mithril.Attributes;
progress: Mithril.Attributes;
q: Mithril.Attributes;
rp: Mithril.Attributes;
rt: Mithril.Attributes;
ruby: Mithril.Attributes;
s: Mithril.Attributes;
samp: Mithril.Attributes;
script: Mithril.Attributes;
section: Mithril.Attributes;
select: Mithril.Attributes;
small: Mithril.Attributes;
source: Mithril.Attributes;
span: Mithril.Attributes;
strong: Mithril.Attributes;
style: Mithril.Attributes;
sub: Mithril.Attributes;
summary: Mithril.Attributes;
sup: Mithril.Attributes;
table: Mithril.Attributes;
template: Mithril.Attributes;
tbody: Mithril.Attributes;
td: Mithril.Attributes;
textarea: Mithril.Attributes;
tfoot: Mithril.Attributes;
th: Mithril.Attributes;
thead: Mithril.Attributes;
time: Mithril.Attributes;
title: Mithril.Attributes;
tr: Mithril.Attributes;
track: Mithril.Attributes;
u: Mithril.Attributes;
ul: Mithril.Attributes;
var: Mithril.Attributes;
video: Mithril.Attributes;
wbr: Mithril.Attributes;
webview: Mithril.Attributes;
// SVG
svg: Mithril.Attributes;
animate: Mithril.Attributes;
animateMotion: Mithril.Attributes;
animateTransform: Mithril.Attributes;
circle: Mithril.Attributes;
clipPath: Mithril.Attributes;
defs: Mithril.Attributes;
desc: Mithril.Attributes;
ellipse: Mithril.Attributes;
feBlend: Mithril.Attributes;
feColorMatrix: Mithril.Attributes;
feComponentTransfer: Mithril.Attributes;
feComposite: Mithril.Attributes;
feConvolveMatrix: Mithril.Attributes;
feDiffuseLighting: Mithril.Attributes;
feDisplacementMap: Mithril.Attributes;
feDistantLight: Mithril.Attributes;
feDropShadow: Mithril.Attributes;
feFlood: Mithril.Attributes;
feFuncA: Mithril.Attributes;
feFuncB: Mithril.Attributes;
feFuncG: Mithril.Attributes;
feFuncR: Mithril.Attributes;
feGaussianBlur: Mithril.Attributes;
feImage: Mithril.Attributes;
feMerge: Mithril.Attributes;
feMergeNode: Mithril.Attributes;
feMorphology: Mithril.Attributes;
feOffset: Mithril.Attributes;
fePointLight: Mithril.Attributes;
feSpecularLighting: Mithril.Attributes;
feSpotLight: Mithril.Attributes;
feTile: Mithril.Attributes;
feTurbulence: Mithril.Attributes;
filter: Mithril.Attributes;
foreignObject: Mithril.Attributes;
g: Mithril.Attributes;
image: Mithril.Attributes;
line: Mithril.Attributes;
linearGradient: Mithril.Attributes;
marker: Mithril.Attributes;
mask: Mithril.Attributes;
metadata: Mithril.Attributes;
mpath: Mithril.Attributes;
path: Mithril.Attributes;
pattern: Mithril.Attributes;
polygon: Mithril.Attributes;
polyline: Mithril.Attributes;
radialGradient: Mithril.Attributes;
rect: Mithril.Attributes;
stop: Mithril.Attributes;
switch: Mithril.Attributes;
symbol: Mithril.Attributes;
text: Mithril.Attributes;
textPath: Mithril.Attributes;
tspan: Mithril.Attributes;
use: Mithril.Attributes;
view: Mithril.Attributes;
// Special Mithril types
'[': Mithril.Attributes;
}
}
}
declare const Mithril: Mithril.Static;
export = Mithril;

43
js/src/@types/mithril/stream/index.d.ts vendored Normal file
View File

@@ -0,0 +1,43 @@
// tslint:disable:rulename strict-export-declare-modifiers
/** Creates an empty stream. */
declare function Stream<T>(): Stream<T>; // tslint:disable-line no-unnecessary-generics
/** Creates a stream with an initial value. */
declare function Stream<T>(value: T): Stream<T>; // tslint:disable-line unified-signatures
declare interface Stream<T> {
/** Returns the value of the stream. */
(): T;
/** Sets the value of the stream. */
(value: T): this;
/** Creates a dependent stream whose value is set to the result of the callback function. */
map<U>(f: (current: T) => U | typeof Stream.SKIP): Stream<U>;
/** This method is functionally identical to stream. It exists to conform to Fantasy Land's Applicative specification. */
of(val: T): Stream<T>;
/** Apply. */
ap<U>(f: Stream<(value: T) => U>): Stream<U>;
/** A co-dependent stream that unregisters dependent streams when set to true. */
end: Stream<boolean>;
/** When a stream is passed as the argument to JSON.stringify(), the value of the stream is serialized. */
toJSON(): string;
/** Returns the value of the stream. */
valueOf(): T;
}
declare namespace Stream {
/** Creates a computed stream that reactively updates if any of its upstreams are updated. */
export function combine<T>(combiner: (...streams: any[]) => T, streams: Array<Stream<any>>): Stream<T>;
/** Combines the values of one or more streams into a single stream that is updated whenever one or more of the sources are updated */
export function lift<S extends any[], T>(fn: (...values: S) => T, ...streams: {[I in keyof S]: Stream<S[I]>}): Stream<T>;
/** Creates a stream whose value is the array of values from an array of streams. */
export function merge<S extends any[]>(streams: {[I in keyof S]: Stream<S[I]>}): Stream<{[I in keyof S]: S[I]}>;
/** Creates a new stream with the results of calling the function on every incoming stream with and accumulator and the incoming value. */
export function scan<T, U>(fn: (acc: U, value: T) => U, acc: U, stream: Stream<T>): Stream<U>;
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
export function scanMerge<T, U>(pairs: Array<[Stream<T>, (acc: U, value: T) => U]>, acc: U): Stream<U>;
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
export function scanMerge<U>(pairs: Array<[Stream<any>, (acc: U, value: any) => U]>, acc: U): Stream<U>;
/** A special value that can be returned to stream callbacks to skip execution of downstreams. */
export const SKIP: unique symbol;
}
export = Stream;

26
js/src/@types/translator-icu-rich.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
declare module '@askvortsov/rich-icu-message-formatter' {
type IValues = Record<string, any>;
type ITypeHandler = (
value: string,
matches: string,
locale: string,
values: IValues,
format: (message: string, values: IValues) => string
) => string;
type IRichHandler = (tag: any, values: IValues, contents: string) => any;
type ValueOrArray<T> = T | ValueOrArray<T>[];
type NestedStringArray = ValueOrArray<string>;
export class RichMessageFormatter {
locale: string | null;
constructor(locale: string | null, typeHandlers: Record<string, ITypeHandler>, richHandler: IRichHandler);
format(message: string, values: IValues): string;
process(message: string, values: IValues): NestedStringArray;
rich(message: string, values: IValues): NestedStringArray;
}
export function mithrilRichHandler(tag: any, values: IValues, contents: string): any;
}

17
js/src/@types/translator-icu.d.ts vendored Normal file
View File

@@ -0,0 +1,17 @@
declare module '@ultraq/icu-message-formatter' {
export function pluralTypeHandler(
value: string,
matches: string,
locale: string,
values: Record<string, any>,
format: (text: string, values: Record<string, any>) => string
): string;
export function selectTypeHandler(
value: string,
matches: string,
locale: string,
values: Record<string, any>,
format: (text: string, values: Record<string, any>) => string
): string;
}

View File

@@ -61,7 +61,7 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
fields() {
const items = new ItemList();
if (app.session.user?.canEditCredentials()) {
if (this.attrs.user.canEditCredentials()) {
items.add(
'username',
<div className="Form-group">
@@ -145,7 +145,7 @@ export default class EditUserModal<CustomAttrs extends IEditUserModalAttrs = IEd
}
}
if (app.session.user?.canEditGroups()) {
if (this.attrs.user.canEditGroups()) {
items.add(
'groups',
<div className="Form-group EditUserModal-groups">

View File

@@ -49,7 +49,6 @@ export default class Drawer {
* @internal
*/
resizeHandler = ((e) => {
console.log(this, e);
if (!e.matches && this.isOpen()) {
// Drawer is open but we've made window bigger, so hide it.
this.hide();

View File

@@ -101,7 +101,7 @@ export default class DiscussionComposer extends ComposerBody {
.save(data)
.then((discussion) => {
this.composer.hide();
app.discussions.refresh({ deferClear: true });
app.discussions.refresh();
m.route.set(app.route.discussion(discussion));
}, this.loaded.bind(this));
}

View File

@@ -53,7 +53,9 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
// page, then we don't want Mithril to redraw the whole page if it did,
// then the pane would redraw which would be slow and would cause problems with
// event handlers.
if (app.discussions.hasItems()) {
// We will also enable the pane if the discussion list is empty but loading,
// because the DiscussionComposer refreshes the list and redirects to the new discussion at the same time.
if (app.discussions.hasItems() || app.discussions.isLoading()) {
app.pane?.enable();
app.pane?.hide();
}
@@ -210,7 +212,7 @@ export default class DiscussionPage<CustomAttrs extends IDiscussionPageAttrs = I
record.relationships.discussion.data.id === discussionId
)
.map((record) => app.store.getById<Post>('posts', record.id))
.sort((a?: Post, b?: Post) => (a?.createdAt()?.getTime() ?? 0) - (b?.createdAt()?.getTime() ?? 0))
.sort((a?: Post, b?: Post) => (a?.number() ?? 0) - (b?.number() ?? 0))
.slice(0, 20);
}

View File

@@ -161,6 +161,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
className="Search-clear Button Button--icon Button--link"
onclick={this.clear.bind(this)}
aria-label={app.translator.trans('core.forum.header.search_clear_button_accessible_label')}
type="button"
>
{icon('fas fa-times-circle')}
</button>
@@ -324,9 +325,10 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
/**
* Get the position of the currently selected search result item.
* Returns zero if not found.
*/
getCurrentNumericIndex(): number {
return this.selectableItems().index(this.getItem(this.index));
return Math.max(0, this.selectableItems().index(this.getItem(this.index)));
}
/**

View File

@@ -289,7 +289,7 @@ class PostStreamState {
if (loadIds.length) {
return app.store.find('posts', loadIds).then((newPosts) => {
return loaded.concat(newPosts).sort((a, b) => a.createdAt() - b.createdAt());
return loaded.concat(newPosts).sort((a, b) => a.number() - b.number());
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -41,18 +41,23 @@
line-height: 1.5em;
color: var(--secondary-color);
&, input, a {
&,
input,
a {
font-size: 14px;
font-weight: normal;
}
input, a {
input,
a {
color: inherit;
}
input {
font-size: 16px;
width: 500px;
&, &[disabled], &:focus {
&,
&[disabled],
&:focus {
background: none;
border: 0;
padding: 0 20px 0 0;
@@ -230,7 +235,8 @@
height: 300px;
transition: background 0.2s, box-shadow 0.2s;
&.active, &.fullScreen {
&.active,
&.fullScreen {
background: var(--body-bg);
}
&.active:not(.fullScreen) {
@@ -258,9 +264,16 @@
}
}
.ComposerBody-header {
margin-right: 120px;
.fullScreen & {
margin-bottom: 20px;
}
.minimized & {
overflow: hidden;
margin-right: 32px;
}
}
.Composer-content {
padding: 20px 20px 0;
@@ -279,7 +292,8 @@
margin-bottom: -17px;
position: relative;
.minimized &, .fullScreen & {
.minimized &,
.fullScreen & {
display: none;
}
}
@@ -287,14 +301,16 @@
float: left;
.Avatar--size(64px);
.minimized &, .fullScreen & {
.minimized &,
.fullScreen & {
display: none;
}
}
.ComposerBody-content {
margin-left: 85px;
.minimized &, .fullScreen & {
.minimized &,
.fullScreen & {
margin-left: 0;
}
}

12
node_modules/.yarn-integrity generated vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"systemParams": "linux-x64-93",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [],
"lockfileEntries": {},
"files": [],
"artifacts": {}
}

View File

@@ -41,7 +41,7 @@ class ListPostsController extends AbstractListController
/**
* {@inheritdoc}
*/
public $sortFields = ['createdAt'];
public $sortFields = ['number', 'createdAt'];
/**
* @var PostFilterer

View File

@@ -132,7 +132,7 @@ class ShowDiscussionController extends AbstractShowController
*/
private function loadPostIds(Discussion $discussion, User $actor)
{
return $discussion->posts()->whereVisibleTo($actor)->orderBy('created_at')->pluck('id')->all();
return $discussion->posts()->whereVisibleTo($actor)->orderBy('number')->pluck('id')->all();
}
/**
@@ -186,7 +186,7 @@ class ShowDiscussionController extends AbstractShowController
{
$query = $discussion->posts()->whereVisibleTo($actor);
$query->orderBy('created_at')->skip($offset)->take($limit)->with($include);
$query->orderBy('number')->skip($offset)->take($limit)->with($include);
$posts = $query->get();

View File

@@ -21,7 +21,7 @@ class Application
*
* @var string
*/
const VERSION = '1.2.0';
const VERSION = '1.3.0-dev';
/**
* The IoC container for the Flarum application.

View File

@@ -19,6 +19,7 @@
<testsuites>
<testsuite name="Flarum Integration Tests">
<directory suffix="Test.php">./integration</directory>
<exclude>./integration/tmp</exclude>
</testsuite>
</testsuites>
</phpunit>