[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:
Toby Zerner 2018-06-22 10:49:46 +09:30 committed by GitHub
parent e3c2ddad2e
commit 805768a9e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 125 additions and 42 deletions

5
js/package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -17,13 +17,10 @@ export default class AdminApplication extends Application {
}
};
/**
* @inheritdoc
*/
boot(data) {
routes(this);
constructor() {
super();
super.boot(data);
routes(this);
}
/**

View File

@ -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();

View File

@ -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/>);

View 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));
}
}

View 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);
}
}

View 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);
}
}

View File

@ -0,0 +1,3 @@
export { default as Model } from './Model';
export { default as PostTypes } from './PostTypes';
export { default as Routes } from './Routes';

View File

@ -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 };

View File

@ -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);
}
/**

View File

@ -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';

View File

@ -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";
});
}
}

View File

@ -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';