diff --git a/framework/core/js/package-lock.json b/framework/core/js/package-lock.json index 1eb3fe378..db8dbabeb 100644 --- a/framework/core/js/package-lock.json +++ b/framework/core/js/package-lock.json @@ -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", diff --git a/framework/core/js/package.json b/framework/core/js/package.json index 62604b61f..b9d25ff98 100644 --- a/framework/core/js/package.json +++ b/framework/core/js/package.json @@ -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", diff --git a/framework/core/js/src/admin/AdminApplication.js b/framework/core/js/src/admin/AdminApplication.js index 6212eec09..ca71ee2c2 100644 --- a/framework/core/js/src/admin/AdminApplication.js +++ b/framework/core/js/src/admin/AdminApplication.js @@ -17,13 +17,10 @@ export default class AdminApplication extends Application { } }; - /** - * @inheritdoc - */ - boot(data) { - routes(this); + constructor() { + super(); - super.boot(data); + routes(this); } /** diff --git a/framework/core/js/src/admin/index.js b/framework/core/js/src/admin/index.js index ca7d19d02..b17a192ef 100644 --- a/framework/core/js/src/admin/index.js +++ b/framework/core/js/src/admin/index.js @@ -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(); diff --git a/framework/core/js/src/common/Application.js b/framework/core/js/src/common/Application.js index 05df4d6cb..4a7799110 100644 --- a/framework/core/js/src/common/Application.js +++ b/framework/core/js/src/common/Application.js @@ -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'), ); this.alerts = m.mount(document.getElementById('alerts'), ); diff --git a/framework/core/js/src/common/extend/Model.js b/framework/core/js/src/common/extend/Model.js new file mode 100644 index 000000000..240be8384 --- /dev/null +++ b/framework/core/js/src/common/extend/Model.js @@ -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)); + } +} \ No newline at end of file diff --git a/framework/core/js/src/common/extend/PostTypes.js b/framework/core/js/src/common/extend/PostTypes.js new file mode 100644 index 000000000..4d9df731f --- /dev/null +++ b/framework/core/js/src/common/extend/PostTypes.js @@ -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); + } +} \ No newline at end of file diff --git a/framework/core/js/src/common/extend/Routes.js b/framework/core/js/src/common/extend/Routes.js new file mode 100644 index 000000000..013e52836 --- /dev/null +++ b/framework/core/js/src/common/extend/Routes.js @@ -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); + } +} \ No newline at end of file diff --git a/framework/core/js/src/common/extend/index.js b/framework/core/js/src/common/extend/index.js new file mode 100644 index 000000000..6d17eb79a --- /dev/null +++ b/framework/core/js/src/common/extend/index.js @@ -0,0 +1,3 @@ +export { default as Model } from './Model'; +export { default as PostTypes } from './PostTypes'; +export { default as Routes } from './Routes'; diff --git a/framework/core/js/src/common/index.js b/framework/core/js/src/common/index.js index e69de29bb..00bc255bd 100644 --- a/framework/core/js/src/common/index.js +++ b/framework/core/js/src/common/index.js @@ -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 }; diff --git a/framework/core/js/src/forum/ForumApplication.js b/framework/core/js/src/forum/ForumApplication.js index e3c4ca5a2..34d685843 100644 --- a/framework/core/js/src/forum/ForumApplication.js +++ b/framework/core/js/src/forum/ForumApplication.js @@ -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); } /** diff --git a/framework/core/js/src/forum/index.js b/framework/core/js/src/forum/index.js index f5946c7fe..2a5e26fbd 100644 --- a/framework/core/js/src/forum/index.js +++ b/framework/core/js/src/forum/index.js @@ -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'; diff --git a/framework/core/src/Extend/Assets.php b/framework/core/src/Extend/Assets.php index 0b8f70419..bd5fb6592 100644 --- a/framework/core/src/Extend/Assets.php +++ b/framework/core/src/Extend/Assets.php @@ -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"; }); } } diff --git a/framework/core/views/frontend/app.blade.php b/framework/core/views/frontend/app.blade.php index 1cc8c02d2..4d69331e3 100644 --- a/framework/core/views/frontend/app.blade.php +++ b/framework/core/views/frontend/app.blade.php @@ -30,7 +30,7 @@ @if ($allowJs) @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';