mirror of
https://github.com/flarum/framework.git
synced 2024-11-23 06:01:56 +08:00
[WIP] JS Extender API foundation (#1468)
* Run extenders exported by extensions * Add some basic extenders * Patch Mithril as the very first thing so extension code can run safely * Load the payload into the app before booting extensions * Setup default routes before booting extensions
This commit is contained in:
parent
e3c2ddad2e
commit
805768a9e0
5
js/package-lock.json
generated
5
js/package-lock.json
generated
|
@ -5153,6 +5153,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.10",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz",
|
||||
"integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg=="
|
||||
},
|
||||
"log-symbols": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"flarum-webpack-config": "^0.1.0-beta.8",
|
||||
"jquery": "^3.3.1",
|
||||
"jquery.hotkeys": "^0.1.0",
|
||||
"lodash-es": "^4.17.10",
|
||||
"m.attrs.bidi": "github:tobscure/m.attrs.bidi",
|
||||
"mithril": "^0.2.8",
|
||||
"moment": "^2.22.2",
|
||||
|
|
|
@ -17,13 +17,10 @@ export default class AdminApplication extends Application {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
boot(data) {
|
||||
routes(this);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
super.boot(data);
|
||||
routes(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,13 +1,3 @@
|
|||
import 'expose-loader?$!expose-loader?jQuery!jquery';
|
||||
import 'expose-loader?m!mithril';
|
||||
import 'expose-loader?moment!moment';
|
||||
import 'expose-loader?m.bidi!m.attrs.bidi';
|
||||
import 'bootstrap/js/affix';
|
||||
import 'bootstrap/js/dropdown';
|
||||
import 'bootstrap/js/modal';
|
||||
import 'bootstrap/js/tooltip';
|
||||
import 'bootstrap/js/transition';
|
||||
|
||||
import AdminApplication from './AdminApplication';
|
||||
|
||||
const app = new AdminApplication();
|
||||
|
|
|
@ -10,7 +10,6 @@ import Session from './Session';
|
|||
import extract from './utils/extract';
|
||||
import Drawer from './utils/Drawer';
|
||||
import mapRoutes from './utils/mapRoutes';
|
||||
import patchMithril from './utils/patchMithril';
|
||||
import RequestError from './utils/RequestError';
|
||||
import ScrollListener from './utils/ScrollListener';
|
||||
import { extend } from './extend';
|
||||
|
@ -21,6 +20,7 @@ import Discussion from './models/Discussion';
|
|||
import Post from './models/Post';
|
||||
import Group from './models/Group';
|
||||
import Notification from './models/Notification';
|
||||
import { flattenDeep } from 'lodash-es';
|
||||
|
||||
/**
|
||||
* The `App` class provides a container for an application, as well as various
|
||||
|
@ -115,16 +115,17 @@ export default class Application {
|
|||
*/
|
||||
requestError = null;
|
||||
|
||||
data;
|
||||
|
||||
title = '';
|
||||
titleCount = 0;
|
||||
|
||||
boot(data) {
|
||||
this.data = data;
|
||||
|
||||
this.translator.locale = data.locale;
|
||||
|
||||
patchMithril(window);
|
||||
load(payload) {
|
||||
this.data = payload;
|
||||
this.translator.locale = payload.locale;
|
||||
}
|
||||
|
||||
boot() {
|
||||
this.initializers.toArray().forEach(initializer => initializer(this));
|
||||
|
||||
this.store.pushPayload({data: this.data.resources});
|
||||
|
@ -139,6 +140,18 @@ export default class Application {
|
|||
this.mount();
|
||||
}
|
||||
|
||||
bootExtensions(extensions) {
|
||||
Object.keys(extensions).forEach(name => {
|
||||
const extension = extensions[name];
|
||||
|
||||
const extenders = flattenDeep(extension.extend);
|
||||
|
||||
for (const extender of extenders) {
|
||||
extender.extend(this, { name, exports: extension });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mount() {
|
||||
this.modal = m.mount(document.getElementById('modal'), <ModalManager/>);
|
||||
this.alerts = m.mount(document.getElementById('alerts'), <AlertManager/>);
|
||||
|
|
41
js/src/common/extend/Model.js
Normal file
41
js/src/common/extend/Model.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
export default class Routes {
|
||||
type;
|
||||
attributes = [];
|
||||
hasOnes = [];
|
||||
hasManys = [];
|
||||
|
||||
constructor(type, model = null) {
|
||||
this.type = type;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
attribute(name) {
|
||||
this.attributes.push(name);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
hasOne(type) {
|
||||
this.hasOnes.push(type);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
hasMany(type) {
|
||||
this.hasManys.push(type);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
extend(app, extension) {
|
||||
if (this.model) {
|
||||
app.store.models[this.type] = this.model;
|
||||
}
|
||||
|
||||
const model = app.store.models[this.type];
|
||||
|
||||
this.attributes.forEach(name => model.prototype[name] = model.attribute(name));
|
||||
this.hasOnes.forEach(name => model.prototype[name] = model.hasOne(name));
|
||||
this.hasManys.forEach(name => model.prototype[name] = model.hasMany(name));
|
||||
}
|
||||
}
|
13
js/src/common/extend/PostTypes.js
Normal file
13
js/src/common/extend/PostTypes.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export default class PostTypes {
|
||||
postComponents = {};
|
||||
|
||||
add(name, component) {
|
||||
this.postComponents[name] = component;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
extend(app, extension) {
|
||||
Object.assign(app.postComponents, this.postComponents);
|
||||
}
|
||||
}
|
13
js/src/common/extend/Routes.js
Normal file
13
js/src/common/extend/Routes.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export default class Routes {
|
||||
routes = {};
|
||||
|
||||
add(name, path, component) {
|
||||
this.routes[name] = { path, component };
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
extend(app, extension) {
|
||||
Object.assign(app.routes, this.routes);
|
||||
}
|
||||
}
|
3
js/src/common/extend/index.js
Normal file
3
js/src/common/extend/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { default as Model } from './Model';
|
||||
export { default as PostTypes } from './PostTypes';
|
||||
export { default as Routes } from './Routes';
|
|
@ -0,0 +1,18 @@
|
|||
import 'expose-loader?$!expose-loader?jQuery!jquery';
|
||||
import 'expose-loader?m!mithril';
|
||||
import 'expose-loader?moment!moment';
|
||||
import 'expose-loader?m.bidi!m.attrs.bidi';
|
||||
import 'bootstrap/js/affix';
|
||||
import 'bootstrap/js/dropdown';
|
||||
import 'bootstrap/js/modal';
|
||||
import 'bootstrap/js/tooltip';
|
||||
import 'bootstrap/js/transition';
|
||||
import 'jquery.hotkeys/jquery.hotkeys';
|
||||
|
||||
import patchMithril from './utils/patchMithril';
|
||||
|
||||
patchMithril(window);
|
||||
|
||||
import * as Extend from './extend/index';
|
||||
|
||||
export { Extend };
|
|
@ -63,13 +63,10 @@ export default class ForumApplication extends Application {
|
|||
*/
|
||||
history = new History();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
boot(data) {
|
||||
routes(this);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
super.boot(data);
|
||||
routes(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
import 'expose-loader?$!expose-loader?jQuery!jquery';
|
||||
import 'expose-loader?m!mithril';
|
||||
import 'expose-loader?moment!moment';
|
||||
import 'expose-loader?punycode!punycode';
|
||||
import 'expose-loader?ColorThief!color-thief-browser';
|
||||
import 'expose-loader?m.bidi!m.attrs.bidi';
|
||||
import 'bootstrap/js/affix';
|
||||
import 'bootstrap/js/dropdown';
|
||||
import 'bootstrap/js/modal';
|
||||
import 'bootstrap/js/tooltip';
|
||||
import 'bootstrap/js/transition';
|
||||
import 'jquery.hotkeys/jquery.hotkeys';
|
||||
|
||||
import ForumApplication from './ForumApplication';
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ class Assets implements ExtenderInterface
|
|||
$event->view->getJs()->addString(function () use ($extension) {
|
||||
$name = $extension->getId();
|
||||
|
||||
return 'var module={};'.file_get_contents($this->js).";flarum.extensions['$name']=module.exports";
|
||||
return 'var module={};'.file_get_contents($this->js).";\nflarum.extensions['$name']=module.exports";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
@if ($allowJs)
|
||||
<script>
|
||||
document.getElementById('flarum-loading').style.display = 'block';
|
||||
var flarum={extensions:{}};
|
||||
var flarum = {extensions: {}};
|
||||
</script>
|
||||
|
||||
@foreach ($jsUrls as $url)
|
||||
|
@ -42,7 +42,9 @@
|
|||
@if (! $debug)
|
||||
try {
|
||||
@endif
|
||||
flarum.core.app.boot(@json($payload));
|
||||
flarum.core.app.load(@json($payload));
|
||||
flarum.core.app.bootExtensions(flarum.extensions);
|
||||
flarum.core.app.boot();
|
||||
@if (! $debug)
|
||||
} catch (e) {
|
||||
window.location += (window.location.search ? '&' : '?') + 'nojs=1';
|
||||
|
|
Loading…
Reference in New Issue
Block a user