mirror of
https://github.com/flarum/core.git
synced 2025-10-22 04:06:37 +02:00
Slug Driver Support (#2456)
- Support slug drivers for core's sluggable models, easily extends to other models - Add automated testing for affected single-model API routes - Fix nickname selection UI - Serialize slugs as `slug` attribute - Make min search length a constant
This commit is contained in:
@@ -14,6 +14,7 @@ import DiscussionControls from '../utils/DiscussionControls';
|
||||
import slidable from '../utils/slidable';
|
||||
import extractText from '../../common/utils/extractText';
|
||||
import classList from '../../common/utils/classList';
|
||||
import DiscussionPage from './DiscussionPage';
|
||||
|
||||
import { escapeRegExp } from 'lodash-es';
|
||||
/**
|
||||
@@ -156,9 +157,7 @@ export default class DiscussionListItem extends Component {
|
||||
* @return {Boolean}
|
||||
*/
|
||||
active() {
|
||||
const idParam = m.route.param('id');
|
||||
|
||||
return idParam && idParam.split('-')[0] === this.attrs.discussion.id();
|
||||
return app.current.matches(DiscussionPage, { discussion: this.attrs.discussion });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -109,7 +109,7 @@ export default class DiscussionPage extends Page {
|
||||
} else {
|
||||
const params = this.requestParams();
|
||||
|
||||
app.store.find('discussions', m.route.param('id').split('-')[0], params).then(this.show.bind(this));
|
||||
app.store.find('discussions', m.route.param('id'), params).then(this.show.bind(this));
|
||||
}
|
||||
|
||||
m.redraw();
|
||||
@@ -123,6 +123,7 @@ export default class DiscussionPage extends Page {
|
||||
*/
|
||||
requestParams() {
|
||||
return {
|
||||
bySlug: true,
|
||||
page: { near: this.near },
|
||||
};
|
||||
}
|
||||
|
@@ -21,6 +21,8 @@ import UsersSearchSource from './UsersSearchSource';
|
||||
* - state: SearchState instance.
|
||||
*/
|
||||
export default class Search extends Component {
|
||||
static MIN_SEARCH_LEN = 3;
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
this.state = this.attrs.state;
|
||||
@@ -152,7 +154,7 @@ export default class Search extends Component {
|
||||
search.searchTimeout = setTimeout(() => {
|
||||
if (state.isCached(query)) return;
|
||||
|
||||
if (query.length >= 3) {
|
||||
if (query.length >= Search.MIN_SEARCH_LEN) {
|
||||
search.sources.map((source) => {
|
||||
if (!source.search) return;
|
||||
|
||||
|
@@ -102,7 +102,7 @@ export default class UserPage extends Page {
|
||||
});
|
||||
|
||||
if (!this.user) {
|
||||
app.store.find('users', username).then(this.show.bind(this));
|
||||
app.store.find('users', username, { bySlug: true }).then(this.show.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,15 +1,6 @@
|
||||
import DefaultResolver from '../../common/resolvers/DefaultResolver';
|
||||
import DiscussionPage from '../components/DiscussionPage';
|
||||
|
||||
/**
|
||||
* This isn't exported as it is a temporary measure.
|
||||
* A more robust system will be implemented alongside UTF-8 support in beta 15.
|
||||
*/
|
||||
function getDiscussionIdFromSlug(slug: string | undefined) {
|
||||
if (!slug) return;
|
||||
return slug.split('-')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom route resolver for DiscussionPage that generates the same key to all posts
|
||||
* on the same discussion. It triggers a scroll when going from one post to another
|
||||
@@ -18,17 +9,32 @@ function getDiscussionIdFromSlug(slug: string | undefined) {
|
||||
export default class DiscussionPageResolver extends DefaultResolver {
|
||||
static scrollToPostNumber: string | null = null;
|
||||
|
||||
/**
|
||||
* Remove optional parts of a discussion's slug to keep the substring
|
||||
* that bijectively maps to a discussion object. By default this just
|
||||
* extracts the numerical ID from the slug. If a custom discussion
|
||||
* slugging driver is used, this may need to be overriden.
|
||||
* @param slug
|
||||
*/
|
||||
canonicalizeDiscussionSlug(slug: string | undefined) {
|
||||
if (!slug) return;
|
||||
return slug.split('-')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
makeKey() {
|
||||
const params = { ...m.route.param() };
|
||||
if ('near' in params) {
|
||||
delete params.near;
|
||||
}
|
||||
params.id = getDiscussionIdFromSlug(params.id);
|
||||
params.id = this.canonicalizeDiscussionSlug(params.id);
|
||||
return this.routeName.replace('.near', '') + JSON.stringify(params);
|
||||
}
|
||||
|
||||
onmatch(args, requestedPath, route) {
|
||||
if (app.current.matches(DiscussionPage) && getDiscussionIdFromSlug(args.id) === getDiscussionIdFromSlug(m.route.param('id'))) {
|
||||
if (app.current.matches(DiscussionPage) && this.canonicalizeDiscussionSlug(args.id) === this.canonicalizeDiscussionSlug(m.route.param('id'))) {
|
||||
// By default, the first post number of any discussion is 1
|
||||
DiscussionPageResolver.scrollToPostNumber = args.near || '1';
|
||||
}
|
||||
|
@@ -34,9 +34,8 @@ export default function (app) {
|
||||
* @return {String}
|
||||
*/
|
||||
app.route.discussion = (discussion, near) => {
|
||||
const slug = discussion.slug();
|
||||
return app.route(near && near !== 1 ? 'discussion.near' : 'discussion', {
|
||||
id: discussion.id() + (slug.trim() ? '-' + slug : ''),
|
||||
id: discussion.slug(),
|
||||
near: near && near !== 1 ? near : undefined,
|
||||
});
|
||||
};
|
||||
@@ -59,7 +58,7 @@ export default function (app) {
|
||||
*/
|
||||
app.route.user = (user) => {
|
||||
return app.route('user', {
|
||||
username: user.username(),
|
||||
username: user.slug(),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user