1
0
mirror of https://github.com/flarum/core.git synced 2025-10-17 17:56:14 +02:00

Use Link component for links instead of mithril route patch (#2315)

This new component now also supports external links.
This commit is contained in:
Alexander Skvortsov
2020-10-02 16:56:40 -04:00
committed by GitHub
parent b66d16e44b
commit 5ecb74fb59
16 changed files with 104 additions and 71 deletions

View File

@@ -47,6 +47,7 @@ import FieldSet from './components/FieldSet';
import Select from './components/Select';
import Navigation from './components/Navigation';
import Alert from './components/Alert';
import Link from './components/Link';
import LinkButton from './components/LinkButton';
import Checkbox from './components/Checkbox';
import SelectDropdown from './components/SelectDropdown';
@@ -118,6 +119,7 @@ export default {
'components/Select': Select,
'components/Navigation': Navigation,
'components/Alert': Alert,
'components/Link': Link,
'components/LinkButton': LinkButton,
'components/Checkbox': Checkbox,
'components/SelectDropdown': SelectDropdown,

View File

@@ -0,0 +1,47 @@
import Component from '../Component';
import extract from '../utils/extract';
/**
* The link component enables both internal and external links.
* It will return a regular HTML link for any links to external sites,
* and it will use Mithril's m.route.Link for any internal links.
*
* Links will default to internal; the 'external' attr must be set to
* `true` for the link to be external.
*/
export default class Link extends Component {
view(vnode) {
let { options = {}, ...attrs } = vnode.attrs;
attrs.href = attrs.href || '';
// For some reason, m.route.Link does not like vnode.text, so if present, we
// need to convert it to text vnodes and store it in children.
const children = vnode.children || { tag: '#', children: vnode.text };
if (attrs.external) {
return <a {...attrs}>{children}</a>;
}
// If the href URL of the link is the same as the current page path
// we will not add a new entry to the browser history.
// This allows us to still refresh the Page component
// without adding endless history entries.
if (attrs.href === m.route.get()) {
if (!('replace' in options)) options.replace = true;
}
// Mithril 2 does not completely rerender the page if a route change leads to the same route
// (or the same component handling a different route).
// Here, the `force` parameter will use Mithril's key system to force a full rerender
// see https://mithril.js.org/route.html#key-parameter
if (extract(attrs, 'force')) {
if (!('state' in options)) options.state = {};
if (!('key' in options.state)) options.state.key = Date.now();
}
attrs.options = options;
return <m.route.Link {...attrs}>{children}</m.route.Link>;
}
}

View File

@@ -1,4 +1,5 @@
import Button from './Button';
import Link from './Link';
/**
* The `LinkButton` component defines a `Button` which links to a route.
@@ -22,7 +23,7 @@ export default class LinkButton extends Button {
view(vnode) {
const vdom = super.view(vnode);
vdom.tag = m.route.Link;
vdom.tag = Link;
vdom.attrs.active = String(vdom.attrs.active);
return vdom;

View File

@@ -1,43 +1,15 @@
import extract from './extract';
import Link from '../components/Link';
import withAttr from './withAttr';
import Stream from './Stream';
let deprecatedMPropWarned = false;
let deprecatedMWithAttrWarned = false;
let deprecatedRouteWarned = false;
export default function patchMithril(global) {
const defaultMithril = global.m;
/**
* If the href URL of the link is the same as the current page path
* we will not add a new entry to the browser history.
*
* This allows us to still refresh the Page component
* without adding endless history entries.
*
* We also add the `force` attribute that adds a custom state key
* for when you want to force a complete refresh of the Page
*/
const defaultLinkView = defaultMithril.route.Link.view;
const modifiedLink = {
view: function (vnode) {
let { href, options = {} } = vnode.attrs;
if (href === m.route.get()) {
if (!('replace' in options)) options.replace = true;
}
if (extract(vnode.attrs, 'force')) {
if (!('state' in options)) options.state = {};
if (!('key' in options.state)) options.state.key = Date.now();
}
vnode.attrs.options = options;
return defaultLinkView(vnode);
},
};
const modifiedMithril = function (comp, ...args) {
const node = defaultMithril.apply(this, arguments);
@@ -48,28 +20,29 @@ export default function patchMithril(global) {
modifiedMithril.bidi(node, node.attrs.bidi);
}
// DEPRECATED, REMOVE BETA 15
// Allows us to use a "route" attr on links, which will automatically convert the link to one which
// supports linking to other pages in the SPA without refreshing the document.
if (node.attrs.route) {
node.attrs.href = node.attrs.route;
node.tag = modifiedLink;
// For some reason, m.route.Link does not like vnode.text, so if present, we
// need to convert it to text vnodes and store it in children.
if (node.text) {
node.children = { tag: '#', children: node.text };
if (!deprecatedRouteWarned) {
deprecatedRouteWarned = true;
console.warn('The route attr patch for links is deprecated, please use the Link component (flarum/components/Link) instead.');
}
node.attrs.href = node.attrs.route;
node.tag = Link;
delete node.attrs.route;
}
// END DEPRECATED
return node;
};
Object.keys(defaultMithril).forEach((key) => (modifiedMithril[key] = defaultMithril[key]));
modifiedMithril.route.Link = modifiedLink;
// BEGIN DEPRECATED MITHRIL 2 BC LAYER
modifiedMithril.prop = modifiedMithril.stream = function (...args) {
if (!deprecatedMPropWarned) {