mirror of
https://github.com/flarum/core.git
synced 2025-08-03 15:07:53 +02:00
revert Application implementation from experimental breaking change to use existing implementation in master
This commit is contained in:
32237
js/dist/forum.js
vendored
32237
js/dist/forum.js
vendored
File diff suppressed because it is too large
Load Diff
2
js/dist/forum.js.map
vendored
2
js/dist/forum.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -1,6 +1,5 @@
|
|||||||
import Mithril from 'mithril';
|
import Mithril from 'mithril';
|
||||||
|
|
||||||
import Bus from './Bus';
|
|
||||||
import Translator from './Translator';
|
import Translator from './Translator';
|
||||||
import Session from './Session';
|
import Session from './Session';
|
||||||
import Store from './Store';
|
import Store from './Store';
|
||||||
@@ -10,6 +9,8 @@ import extract from './utils/extract';
|
|||||||
import mapRoutes from './utils/mapRoutes';
|
import mapRoutes from './utils/mapRoutes';
|
||||||
import Drawer from './utils/Drawer';
|
import Drawer from './utils/Drawer';
|
||||||
import RequestError from './utils/RequestError';
|
import RequestError from './utils/RequestError';
|
||||||
|
import ItemList from './utils/ItemList';
|
||||||
|
import ScrollListener from './utils/ScrollListener';
|
||||||
|
|
||||||
import Forum from './models/Forum';
|
import Forum from './models/Forum';
|
||||||
import Discussion from './models/Discussion';
|
import Discussion from './models/Discussion';
|
||||||
@@ -23,6 +24,8 @@ import Button from './components/Button';
|
|||||||
import ModalManager from './components/ModalManager';
|
import ModalManager from './components/ModalManager';
|
||||||
import RequestErrorModal from './components/RequestErrorModal';
|
import RequestErrorModal from './components/RequestErrorModal';
|
||||||
|
|
||||||
|
import { flattenDeep } from 'lodash-es';
|
||||||
|
|
||||||
export type ApplicationData = {
|
export type ApplicationData = {
|
||||||
apiDocument: any;
|
apiDocument: any;
|
||||||
locale: string;
|
locale: string;
|
||||||
@@ -35,22 +38,39 @@ export default abstract class Application {
|
|||||||
/**
|
/**
|
||||||
* The forum model for this application.
|
* The forum model for this application.
|
||||||
*/
|
*/
|
||||||
forum: Forum;
|
public forum!: Forum;
|
||||||
|
|
||||||
data: ApplicationData;
|
/**
|
||||||
|
* A map of routes, keyed by a unique route name. Each route is an object
|
||||||
|
* containing the following properties:
|
||||||
|
*
|
||||||
|
* - `path` The path that the route is accessed at.
|
||||||
|
* - `component` The Mithril component to render when this route is active.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* app.routes.discussion = {path: '/d/:id', component: DiscussionPage.component()};
|
||||||
|
*/
|
||||||
|
public routes: { [key: string]: { path: string; component: any; [key: string]: any } } = {};
|
||||||
|
|
||||||
translator = new Translator();
|
/**
|
||||||
bus = new Bus();
|
* An ordered list of initializers to bootstrap the application.
|
||||||
|
*/
|
||||||
|
public initializers = new ItemList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The app's session.
|
* The app's session.
|
||||||
*/
|
*/
|
||||||
session: Session;
|
public session!: Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The app's translator.
|
||||||
|
*/
|
||||||
|
public translator = new Translator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The app's data store.
|
* The app's data store.
|
||||||
*/
|
*/
|
||||||
store = new Store({
|
public store = new Store({
|
||||||
forums: Forum,
|
forums: Forum,
|
||||||
users: User,
|
users: User,
|
||||||
discussions: Discussion,
|
discussions: Discussion,
|
||||||
@@ -59,37 +79,38 @@ export default abstract class Application {
|
|||||||
notifications: Notification,
|
notifications: Notification,
|
||||||
});
|
});
|
||||||
|
|
||||||
drawer = new Drawer();
|
|
||||||
|
|
||||||
modal: ModalManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A local cache that can be used to store data at the application level, so
|
* A local cache that can be used to store data at the application level, so
|
||||||
* that is persists between different routes.
|
* that is persists between different routes.
|
||||||
*/
|
*/
|
||||||
cache: { [key: string]: any } = {};
|
public cache: { [key: string]: any } = {};
|
||||||
|
|
||||||
routes = {};
|
/**
|
||||||
|
* Whether or not the app has been booted.
|
||||||
title = '';
|
*/
|
||||||
titleCount = 0;
|
public booted: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Alert that was shown as a result of an AJAX request error. If present,
|
* An Alert that was shown as a result of an AJAX request error. If present,
|
||||||
* it will be dismissed on the next successful request.
|
* it will be dismissed on the next successful request.
|
||||||
*/
|
*/
|
||||||
private requestError: Alert = null;
|
private requestError: Alert | null = null;
|
||||||
|
|
||||||
mount(basePath = '') {
|
data!: ApplicationData;
|
||||||
m.mount(document.getElementById('modal'), new ModalManager());
|
|
||||||
|
|
||||||
// this.alerts = m.mount(document.getElementById('alerts'), <AlertManager />);
|
title = '';
|
||||||
|
titleCount = 0;
|
||||||
|
|
||||||
m.route(document.getElementById('content'), basePath + '/', mapRoutes(this.routes, basePath));
|
drawer = new Drawer();
|
||||||
|
modal!: ModalManager;
|
||||||
|
|
||||||
|
load(payload) {
|
||||||
|
this.data = payload;
|
||||||
|
this.translator.locale = payload.locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
boot(payload: any) {
|
boot() {
|
||||||
this.data = payload;
|
this.initializers.toArray().forEach(initializer => initializer(this));
|
||||||
|
|
||||||
this.store.pushPayload({ data: this.data.resources });
|
this.store.pushPayload({ data: this.data.resources });
|
||||||
|
|
||||||
@@ -97,26 +118,42 @@ export default abstract class Application {
|
|||||||
|
|
||||||
this.session = new Session(this.store.getById('users', this.data.session.userId), this.data.session.csrfToken);
|
this.session = new Session(this.store.getById('users', this.data.session.userId), this.data.session.csrfToken);
|
||||||
|
|
||||||
this.locale();
|
|
||||||
this.plugins();
|
|
||||||
this.setupRoutes();
|
|
||||||
this.mount();
|
this.mount();
|
||||||
|
|
||||||
this.bus.dispatch('app.booting');
|
this.booted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
locale() {
|
bootExtensions(extensions) {
|
||||||
this.translator.locale = this.data.locale;
|
Object.keys(extensions).forEach(name => {
|
||||||
|
const extension = extensions[name];
|
||||||
|
|
||||||
this.bus.dispatch('app.locale');
|
const extenders = flattenDeep(extension.extend);
|
||||||
|
|
||||||
|
for (const extender of extenders) {
|
||||||
|
extender.extend(this, { name, exports: extension });
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins() {
|
mount(basePath = '') {
|
||||||
this.bus.dispatch('app.plugins');
|
m.mount(document.getElementById('modal'), new ModalManager());
|
||||||
}
|
|
||||||
|
|
||||||
setupRoutes() {
|
// this.alerts = m.mount(document.getElementById('alerts'), <AlertManager />);
|
||||||
this.bus.dispatch('app.routes');
|
|
||||||
|
m.route(document.getElementById('content'), basePath + '/', mapRoutes(this.routes, basePath));
|
||||||
|
|
||||||
|
// Add a class to the body which indicates that the page has been scrolled
|
||||||
|
// down.
|
||||||
|
new ScrollListener(top => {
|
||||||
|
const $app = $('#app');
|
||||||
|
const offset = $app.offset().top;
|
||||||
|
|
||||||
|
$app.toggleClass('affix', top >= offset).toggleClass('scrolled', top > offset);
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
$(() => {
|
||||||
|
$('body').addClass('ontouchstart' in window ? 'touch' : 'no-touch');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -3,44 +3,24 @@ import History from './utils/History';
|
|||||||
|
|
||||||
import HeaderPrimary from './components/HeaderPrimary';
|
import HeaderPrimary from './components/HeaderPrimary';
|
||||||
import HeaderSecondary from './components/HeaderSecondary';
|
import HeaderSecondary from './components/HeaderSecondary';
|
||||||
|
|
||||||
import Page from './components/Page';
|
import Page from './components/Page';
|
||||||
import IndexPage from './components/IndexPage';
|
|
||||||
import DiscussionList from './components/DiscussionList';
|
import DiscussionList from './components/DiscussionList';
|
||||||
import DiscussionPage from './components/DiscussionPage';
|
|
||||||
import PostsUserPage from './components/PostsUserPage';
|
|
||||||
import DiscussionsUserPage from './components/DiscussionsUserPage';
|
|
||||||
import SettingsPage from './components/SettingsPage';
|
|
||||||
|
|
||||||
import CommentPost from './components/CommentPost';
|
import CommentPost from './components/CommentPost';
|
||||||
|
|
||||||
import User from '../common/models/User';
|
|
||||||
import Post from '../common/models/Post';
|
|
||||||
import Discussion from '../common/models/Discussion';
|
|
||||||
import Notification from '../common/models/Notification';
|
import Notification from '../common/models/Notification';
|
||||||
|
|
||||||
|
import routes from './routes';
|
||||||
|
|
||||||
export default class Forum extends Application {
|
export default class Forum extends Application {
|
||||||
routes = {
|
|
||||||
index: { path: '/all', component: IndexPage },
|
|
||||||
|
|
||||||
discussion: { path: '/d/:id', component: DiscussionPage },
|
|
||||||
'discussion.near': { path: '/d/:id/:near', component: DiscussionPage },
|
|
||||||
|
|
||||||
user: { path: '/u/:username', component: PostsUserPage },
|
|
||||||
'user.posts': { path: '/u/:username', component: PostsUserPage },
|
|
||||||
'user.discussions': { path: '/u/:username/discussions', component: DiscussionsUserPage },
|
|
||||||
|
|
||||||
settings: { path: '/settings', component: SettingsPage },
|
|
||||||
|
|
||||||
'index.filter': { path: '/:filter', component: IndexPage },
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The app's history stack, which keeps track of which routes the user visits
|
* The app's history stack, which keeps track of which routes the user visits
|
||||||
* so that they can easily navigate back to the previous route.
|
* so that they can easily navigate back to the previous route.
|
||||||
*/
|
*/
|
||||||
history: History = new History();
|
history: History = new History();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
cache: {
|
cache: {
|
||||||
notifications?: Notification[][];
|
notifications?: Notification[][];
|
||||||
discussionList?: DiscussionList;
|
discussionList?: DiscussionList;
|
||||||
@@ -55,6 +35,12 @@ export default class Forum extends Application {
|
|||||||
previous: Page;
|
previous: Page;
|
||||||
current: Page;
|
current: Page;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
routes(this);
|
||||||
|
}
|
||||||
|
|
||||||
mount() {
|
mount() {
|
||||||
// Get the configured default route and update that route's path to be '/'.
|
// Get the configured default route and update that route's path to be '/'.
|
||||||
// Push the homepage as the first route, so that the user will always be
|
// Push the homepage as the first route, so that the user will always be
|
||||||
@@ -97,36 +83,4 @@ export default class Forum extends Application {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setupRoutes() {
|
|
||||||
super.setupRoutes();
|
|
||||||
|
|
||||||
this.route.discussion = (discussion: Discussion, near?: number): string => {
|
|
||||||
const slug = discussion?.slug();
|
|
||||||
const hasNear = near && near !== 1;
|
|
||||||
const params = {
|
|
||||||
id: discussion.id() + (slug.trim() ? '-' + slug : ''),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hasNear) params['near'] = near;
|
|
||||||
|
|
||||||
return this.route(near && near !== 1 ? 'discussion.near' : 'discussion', params);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a URL to a post.
|
|
||||||
*/
|
|
||||||
this.route.post = (post: Post): string => {
|
|
||||||
return this.route.discussion(post.discussion(), post.number());
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a URL to a user.
|
|
||||||
*/
|
|
||||||
this.route.user = (user: User): string => {
|
|
||||||
return this.route('user', {
|
|
||||||
username: user.username(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -5,17 +5,6 @@ const app = new Forum();
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
window.app = app;
|
window.app = app;
|
||||||
|
|
||||||
app.bus.subscribe('app.plugins', () => {
|
|
||||||
// @ts-ignore
|
|
||||||
const extensions = flarum.extensions;
|
|
||||||
|
|
||||||
Object.keys(extensions).forEach(name => {
|
|
||||||
const extension = extensions[name];
|
|
||||||
|
|
||||||
// if (typeof extension === 'function') extension();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export { app };
|
export { app };
|
||||||
|
|
||||||
// Export compat API
|
// Export compat API
|
||||||
|
57
js/src/forum/routes.ts
Normal file
57
js/src/forum/routes.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import IndexPage from './components/IndexPage';
|
||||||
|
import DiscussionPage from './components/DiscussionPage';
|
||||||
|
import PostsUserPage from './components/PostsUserPage';
|
||||||
|
import DiscussionsUserPage from './components/DiscussionsUserPage';
|
||||||
|
import SettingsPage from './components/SettingsPage';
|
||||||
|
|
||||||
|
import Discussion from '../common/models/Discussion';
|
||||||
|
import Post from '../common/models/Post';
|
||||||
|
import User from '../common/models/User';
|
||||||
|
|
||||||
|
export default app => {
|
||||||
|
app.routes = {
|
||||||
|
index: { path: '/all', component: IndexPage },
|
||||||
|
|
||||||
|
discussion: { path: '/d/:id', component: DiscussionPage },
|
||||||
|
'discussion.near': { path: '/d/:id/:near', component: DiscussionPage },
|
||||||
|
|
||||||
|
user: { path: '/u/:username', component: PostsUserPage },
|
||||||
|
'user.posts': { path: '/u/:username', component: PostsUserPage },
|
||||||
|
'user.discussions': { path: '/u/:username/discussions', component: DiscussionsUserPage },
|
||||||
|
|
||||||
|
settings: { path: '/settings', component: SettingsPage },
|
||||||
|
|
||||||
|
'index.filter': { path: '/:filter', component: IndexPage },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a URL to a discussion.
|
||||||
|
*/
|
||||||
|
app.route.discussion = (discussion: Discussion, near?: number): string => {
|
||||||
|
const slug = discussion?.slug();
|
||||||
|
const hasNear = near && near !== 1;
|
||||||
|
const params = {
|
||||||
|
id: discussion.id() + (slug.trim() ? '-' + slug : ''),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hasNear) params['near'] = near;
|
||||||
|
|
||||||
|
return app.route(hasNear ? 'discussion.near' : 'discussion', params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a URL to a post.
|
||||||
|
*/
|
||||||
|
app.route.post = (post: Post): string => {
|
||||||
|
return app.route.discussion(post.discussion(), post.number());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a URL to a user.
|
||||||
|
*/
|
||||||
|
app.route.user = (user: User): string => {
|
||||||
|
return app.route('user', {
|
||||||
|
username: user.username(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
@@ -25,9 +25,9 @@
|
|||||||
document.getElementById('flarum-loading').style.display = 'none';
|
document.getElementById('flarum-loading').style.display = 'none';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
app.boot(@json($payload));
|
flarum.core.app.load(@json($payload));
|
||||||
// flarum.core.app.bootExtensions(flarum.extensions);
|
flarum.core.app.bootExtensions(flarum.extensions);
|
||||||
// flarum.core.app.boot();
|
flarum.core.app.boot();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
var error = document.getElementById('flarum-loading-error');
|
var error = document.getElementById('flarum-loading-error');
|
||||||
error.innerHTML += document.getElementById('flarum-content').textContent;
|
error.innerHTML += document.getElementById('flarum-content').textContent;
|
||||||
|
Reference in New Issue
Block a user