Upgrade ember-cli to 0.1.4 and fix related breakage. closes #18

This commit is contained in:
Toby Zerner 2014-12-23 12:45:07 +10:30
parent 9365205ac4
commit 238bb40360
28 changed files with 225 additions and 509 deletions

View File

@ -1,3 +1,4 @@
{
"directory": "vendor"
"directory": "bower_components",
"analytics": false
}

33
ember/.editorconfig Normal file
View File

@ -0,0 +1,33 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.js]
indent_style = space
indent_size = 2
[*.hbs]
indent_style = space
indent_size = 2
[*.css]
indent_style = space
indent_size = 2
[*.html]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false

9
ember/.ember-cli Normal file
View File

@ -0,0 +1,9 @@
{
/**
Ember CLI sends analytics information by default. The data is completely
anonymous, but there are times when you might want to disable this behavior.
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false
}

3
ember/.gitignore vendored
View File

@ -6,8 +6,7 @@
# dependencies
/node_modules
/vendor/*
!/vendor/json-api.js
/bower_components
# misc
/.sass-cache

View File

@ -1,11 +1,11 @@
{
"predef": {
"document": true,
"window": true,
"FlarumENV": true
},
"browser" : true,
"boss" : true,
"predef": [
"document",
"window",
"-Promise"
],
"browser": true,
"boss": true,
"curly": true,
"debug": false,
"devel": true,

20
ember/.travis.yml Normal file
View File

@ -0,0 +1,20 @@
---
language: node_js
sudo: false
cache:
directories:
- node_modules
before_install:
- "npm config set spin false"
- "npm install -g npm@^2"
install:
- npm install -g bower
- npm install
- bower install
script:
- npm test

View File

@ -4,16 +4,15 @@ var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var app = new EmberApp();
app.import('vendor/bootstrap/dist/js/bootstrap.js');
app.import('vendor/spin.js/spin.js');
app.import('vendor/spin.js/jquery.spin.js');
app.import('vendor/moment/moment.js');
app.import('vendor/json-api.js');
app.import('bower_components/bootstrap/dist/js/bootstrap.js');
app.import('bower_components/spin.js/spin.js');
app.import('bower_components/spin.js/jquery.spin.js');
app.import('bower_components/moment/moment.js');
app.import('vendor/font-awesome/fonts/fontawesome-webfont.eot');
app.import('vendor/font-awesome/fonts/fontawesome-webfont.svg');
app.import('vendor/font-awesome/fonts/fontawesome-webfont.ttf');
app.import('vendor/font-awesome/fonts/fontawesome-webfont.woff');
app.import('vendor/font-awesome/fonts/FontAwesome.otf');
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.eot');
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.svg');
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.ttf');
app.import('bower_components/font-awesome/fonts/fontawesome-webfont.woff');
app.import('bower_components/font-awesome/fonts/FontAwesome.otf');
module.exports = app.toTree();

View File

@ -1,26 +1,37 @@
import Ember from 'ember';
import DS from 'ember-data';
export default DS.JsonApiAdapter.extend({
import JsonApiAdapter from 'ember-json-api/json-api-adapter';
export default JsonApiAdapter.extend({
host: '/api',
xhr: [],
ajax: function(url, type, hash) {
var adapter = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
hash = adapter.ajaxOptions(url, type, hash);
hash.success = function(json) {
Ember.run(null, resolve, json);
};
hash.error = function(jqXHR, textStatus, errorThrown) {
Ember.run(null, reject, adapter.ajaxError(jqXHR));
};
adapter.xhr.push(Ember.$.ajax(hash));
}, "DS: RestAdapter#ajax " + type + " to " + url);
},
findQuery: function(store, type, query) {
var ids = null;
if (query.ids) {
ids = query.ids.join(',');
delete query.ids;
}
return this.ajax(this.buildURL(type.typeKey, ids), 'GET', {data: query});
},
});
// export default DS.JsonApiAdapter.extend({
// host: '/api',
// // xhr: [],
// // ajax: function(url, type, hash) {
// // var adapter = this;
// // return new Ember.RSVP.Promise(function(resolve, reject) {
// // hash = adapter.ajaxOptions(url, type, hash);
// // hash.success = function(json) {
// // Ember.run(null, resolve, json);
// // };
// // hash.error = function(jqXHR, textStatus, errorThrown) {
// // Ember.run(null, reject, adapter.ajaxError(jqXHR));
// // };
// // adapter.xhr.push(Ember.$.ajax(hash));
// // }, "DS: RestAdapter#ajax " + type + " to " + url);
// // },
// });

View File

@ -1,21 +1,17 @@
import Ember from 'ember';
import Resolver from 'ember/resolver';
import loadInitializers from 'ember/load-initializers';
import config from './config/environment';
Ember.MODEL_FACTORY_INJECTIONS = true;
var App = Ember.Application.extend({
modulePrefix: 'flarum', // TODO: loaded via config
Resolver: Resolver,
registerPlugin: function(plugin) {
console.log('Plugin loaded: '+plugin.name);
plugin.boot();
}
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver: Resolver
});
loadInitializers(App, 'flarum');
loadInitializers(App, config.modulePrefix);
//-----------------------------------------
// TODO: Move all this to an initializer

View File

@ -1,6 +1,6 @@
import Ember from 'ember';
export default Ember.Handlebars.makeBoundHelper(function(number, options) {
return new Handlebars.SafeString(number);
return new Ember.Handlebars.SafeString(''+number);
});

View File

@ -1,14 +0,0 @@
import Ember from 'ember';
// This helper takes a post as its argument and renders a certain component
// corresponding to the post's type. The naming convention is 'post-type-[type]'
// (for example, post-type-comment for a comment.) Other arguments added to the
// helper are passed through to the component.
export default Ember.Handlebars.makeBoundHelper(function(post, options) {
options.hash.post = post;
var component = 'post-type-'+post.get('type');
var helper = Ember.Handlebars.resolveHelper(options.data.view.container, component);
helper.call(this, options);
});

View File

@ -7,20 +7,19 @@
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{BASE_TAG}}
{{content-for 'head'}}
<link rel="stylesheet" href="assets/vendor.css">
<link rel="stylesheet" href="assets/flarum.css">
{{content-for 'head-footer'}}
</head>
<body>
<script>
window.FlarumENV = {{ENV}};
window.EmberENV = window.FlarumENV.EmberENV;
</script>
{{content-for 'body'}}
<script src="assets/vendor.js"></script>
<script src="assets/flarum.js"></script>
<script>
window.Flarum = require('flarum/app')['default'].create(FlarumENV.APP);
</script>
{{content-for 'body-footer'}}
</body>
</html>

View File

@ -1,12 +1,13 @@
import Ember from 'ember';
import config from './config/environment';
console.log(config.locationType);
var Router = Ember.Router.extend({
location: FlarumENV.locationType
location: config.locationType
});
Router.map(function() {
this.resource('categories', { path: '/categories' });
this.resource('categories', { path: '/categories' });
this.resource('discussions', { path: '/' }, function() {
this.resource('discussion', { path: '/:id/:slug' });
@ -18,7 +19,6 @@ Router.map(function() {
this.route('discussions');
this.route('preferences');
});
});
export default Router;

View File

@ -1,14 +1,12 @@
import Ember from 'ember';
import DS from 'ember-data';
import JsonApiSerializer from 'ember-json-api/json-api-serializer';
export default JsonApiSerializer.extend({
normalize: function(type, hash, property) {
var json = {};
export default DS.JsonApiSerializer.extend({
normalize: function(type, hash, property) {
var json = {};
for (var prop in hash) {
json[prop.camelize()] = hash[prop];
}
for (var prop in hash) {
json[prop.camelize()] = hash[prop];
}
return this._super(type, json, property);
}
});
return this._super(type, json, property);
}
});

View File

@ -10,4 +10,4 @@
{{!-- #{{view.post.number}} (ID: {{view.post.id}}) --}}
{{/link-to}}
{{post-content view.post}}
{{dynamic-component type=view.contentComponent post=view.post}}

View File

@ -1,7 +1,7 @@
<div class="controls btn-group">
{{!-- <div class="controls btn-group">
<button data-toggle="dropdown" class="dropdown-toggle btn btn-default btn-xs btn-icon">{{fa-icon "caret-down"}}</button>
{{menu-list items=view.controls class="dropdown-menu pull-right"}}
</div>
</div> --}}
<div class="discussion">
@ -40,7 +40,7 @@
{{#link-to "user" discussion.lastUser}}{{user-avatar discussion.lastUser class="avatar-thumb"}}{{/link-to}}
{{#link-to "discussion" discussion.content (query-params start="last")}}{{abbreviate-time discussion.lastTime}}{{/link-to}}
{{/if}}
</span>
</span>
<span class="replies">{{abbreviate-number discussion.repliesCount}}</span>

View File

@ -9,6 +9,10 @@ export default Ember.View.extend({
controls: null,
contentComponent: function() {
return 'post-type-'+this.get('post.type');
}.property('post.type'),
classNames: ['post'],
classNameBindings: ['post.deleted', 'post.edited'],

View File

@ -1,17 +1,18 @@
{
"name": "flarum",
"dependencies": {
"handlebars": "~1.3.0",
"handlebars": "2.0.0",
"jquery": "^1.11.1",
"qunit": "~1.12.0",
"ember-qunit": "~0.1.8",
"ember": "~1.7.0",
"ember-resolver": "~0.1.5",
"loader": "stefanpenner/loader.js#1.0.0",
"ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.2",
"ember": "1.9.0",
"ember-data": "1.0.0-beta.12",
"ember-resolver": "~0.1.10",
"loader.js": "stefanpenner/loader.js#1.0.1",
"ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.3",
"ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.0.4",
"ember-load-initializers": "stefanpenner/ember-load-initializers#0.0.2",
"ember-qunit-notifications": "^0.0.3",
"ember-cli-test-loader": "rjackson/ember-cli-test-loader#0.0.2",
"ember-qunit": "0.1.8",
"ember-qunit-notifications": "0.0.4",
"qunit": "~1.15.0",
"bootstrap": "~3.2.0",
"font-awesome": "~4",
"spin.js": "~1.3.3",

View File

@ -2,9 +2,10 @@
module.exports = function(environment) {
var ENV = {
modulePrefix: 'flarum',
environment: environment,
baseURL: '/',
locationType: 'auto',
locationType: 'hash',
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
@ -27,7 +28,15 @@ module.exports = function(environment) {
}
if (environment === 'test') {
// Testem prefers this...
ENV.baseURL = '/';
ENV.locationType = 'none';
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
}
if (environment === 'production') {

View File

@ -4,31 +4,35 @@
"private": true,
"directories": {
"doc": "doc",
"test": "test"
"test": "tests"
},
"scripts": {
"start": "ember server",
"build": "ember build",
"test": "ember test"
},
"repository": "https://github.com/stefanpenner/ember-cli",
"repository": "",
"engines": {
"node": ">= 0.10.0"
},
"author": "",
"license": "MIT",
"devDependencies": {
"body-parser": "^1.2.0",
"broccoli-asset-rev": "0.0.17",
"broccoli-ember-hbs-template-compiler": "^1.5.0",
"broccoli-less-single": "^0.1.4",
"ember-cli": "0.0.40",
"ember-cli-autoprefixer": "^0.1.0",
"ember-cli-ember-data": "0.1.0",
"broccoli-asset-rev": "^1.0.0",
"ember-cli": "0.1.4",
"ember-cli-content-security-policy": "0.3.0",
"ember-cli-dependency-checker": "0.0.6",
"ember-cli-esnext": "0.1.1",
"ember-cli-htmlbars": "^0.5.4",
"ember-cli-ic-ajax": "0.1.1",
"express": "^4.1.1",
"glob": "^3.2.9",
"liquid-fire": "^0.9.2",
"originate": "0.1.5"
"ember-cli-inject-live-reload": "^1.3.0",
"ember-cli-qunit": "0.1.2",
"ember-data": "1.0.0-beta.12",
"ember-dynamic-component": "0.0.4",
"ember-export-application-global": "^1.0.0",
"ember-json-api": "^0.2.3",
"express": "^4.8.5",
"glob": "^4.0.5",
"liquid-fire": "^0.9.2"
}
}

View File

@ -1,6 +1,11 @@
{
"framework": "qunit",
"test_page": "tests/index.html",
"launch_in_ci": ["PhantomJS"],
"launch_in_dev": ["PhantomJS", "Chrome"]
"launch_in_ci": [
"PhantomJS"
],
"launch_in_dev": [
"PhantomJS",
"Chrome"
]
}

View File

@ -5,6 +5,7 @@
"location",
"setTimeout",
"$",
"-Promise",
"QUnit",
"define",
"console",
@ -33,11 +34,11 @@
"fillIn",
"click",
"keyEvent",
"triggerEvent",
"find",
"findWithAssert",
"wait",
"DS",
"keyEvent",
"isolatedContainer",
"startApp",
"andThen",

View File

@ -1,9 +1,11 @@
import Resolver from 'ember/resolver';
import config from '../../config/environment';
var resolver = Resolver.create();
resolver.namespace = {
modulePrefix: 'flarum'
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix
};
export default resolver;

View File

@ -1,30 +1,19 @@
/* global require */
var Application = require('flarum/app')['default'];
var Router = require('flarum/router')['default'];
import Ember from 'ember';
import Application from '../../app';
import Router from '../../router';
import config from '../../config/environment';
export default function startApp(attrs) {
var App;
var attributes = Ember.merge({
// useful Test defaults
rootElement: '#ember-testing',
LOG_ACTIVE_GENERATION:false,
LOG_VIEW_LOOKUPS: false
}, attrs); // but you can override;
var attributes = Ember.merge({}, config.APP);
attributes = Ember.merge(attributes, attrs); // use defaults, but you can override;
Router.reopen({
location: 'none'
});
Ember.run(function(){
Ember.run(function() {
App = Application.create(attributes);
App.setupForTesting();
App.injectTestHelpers();
});
App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"
return App;
}

View File

@ -7,7 +7,8 @@
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{BASE_TAG}}
{{content-for 'head'}}
{{content-for 'test-head'}}
<link rel="stylesheet" href="assets/vendor.css">
<link rel="stylesheet" href="assets/flarum.css">
@ -28,22 +29,21 @@
zoom: 50%;
}
</style>
{{content-for 'head-footer'}}
{{content-for 'test-head-footer'}}
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script>
window.FlarumENV = {{ENV}};
window.EmberENV = window.FlarumENV.EmberENV;
</script>
<script src="assets/test-support.js"></script>
{{content-for 'body'}}
{{content-for 'test-body'}}
<script src="assets/vendor.js"></script>
<script src="assets/test-support.js"></script>
<script src="assets/flarum.js"></script>
<script src="testem.js"></script>
<script>
require('flarum/tests/test-helper');
</script>
<script src="assets/test-loader.js"></script>
{{content-for 'body-footer'}}
{{content-for 'test-body-footer'}}
</body>
</html>

View File

@ -1,6 +1,12 @@
import resolver from './helpers/resolver';
import { setResolver } from 'ember-qunit';
import {
setResolver
} from 'ember-qunit';
setResolver(resolver);
document.write('<div id="ember-testing-container"><div id="ember-testing"></div></div>');
QUnit.config.urlConfig.push({ id: 'nocontainer', label: 'Hide container'});
var containerVisibility = QUnit.urlParams.nocontainer ? 'hidden' : 'visible';
document.getElementById('ember-testing-container').style.visibility = containerVisibility;

View File

@ -1,353 +0,0 @@
/*!
* ember-json-api
* Built on 2014-07-03
* http://github.com/daliwali/ember-json-api
* Copyright (c) 2014 Dali Zheng
*/
(function() {
"use strict";
var get = Ember.get;
var isNone = Ember.isNone;
DS.JsonApiSerializer = DS.RESTSerializer.extend({
/**
* Patch the extractSingle method, since there are no singular records
*/
extractSingle: function(store, primaryType, payload, recordId) {
var primaryTypeName;
if (this.keyForAttribute) {
primaryTypeName = this.keyForAttribute(primaryType.typeKey);
} else {
primaryTypeName = primaryType.typeKey;
}
var json = {};
for (var key in payload) {
var typeName = Ember.String.singularize(key);
if (typeName === primaryTypeName &&
Ember.isArray(payload[key])) {
json[typeName] = payload[key][0];
} else {
json[key] = payload[key];
}
}
return this._super(store, primaryType, json, recordId);
},
extractArray: function(store, primaryType, payload) {
var primaryTypeName;
if (this.keyForAttribute) {
primaryTypeName = this.keyForAttribute(primaryType.typeKey);
} else {
primaryTypeName = primaryType.typeKey;
}
for (var key in payload) {
var typeName = Ember.String.singularize(key);
if (typeName === primaryTypeName &&
! Ember.isArray(payload[key])) {
payload[key] = [payload[key]];
}
}
return this._super(store, primaryType, payload);
},
/**
* Flatten links
*/
normalize: function(type, hash, prop) {
var json = {};
for (var key in hash) {
if (key !== 'links') {
json[key] = hash[key];
} else if (typeof hash[key] === 'object') {
for (var link in hash[key]) {
json[link] = hash[key][link];
}
}
}
return this._super(type, json, prop);
},
/**
* Extract top-level "meta" & "links" before normalizing.
*/
normalizePayload: function(payload) {
// if (payload.meta) {
// this.extractMeta(payload.meta);
// delete payload.meta;
// }
if (payload.links) {
this.extractLinks(payload.links);
delete payload.links;
}
if (payload.linked) {
this.extractLinked(payload.linked);
delete payload.linked;
}
return payload;
},
/**
* Extract top-level "linked" containing associated objects
*/
extractLinked: function(linked) {
var link, values, value, relation;
var store = get(this, 'store');
for (link in linked) {
values = linked[link];
for (var i = values.length - 1; i >= 0; i--) {
value = values[i];
if (value.links) {
for (relation in value.links) {
value[relation] = value.links[relation];
}
delete value.links;
}
}
}
store.pushPayload(linked);
},
/**
* Override this method to parse the top-level "meta" object per type.
*/
// extractMeta: function(meta) {
// console.log(meta);
// // store.metaForType(type, payload.meta);
// },
/**
* Parse the top-level "links" object.
*/
extractLinks: function(links) {
var link, key, value, route;
var extracted = [], linkEntry, linkKey;
for (link in links) {
key = link.split('.').pop();
value = links[link];
if (typeof value === 'string') {
route = value;
} else {
key = value.type || key;
route = value.href;
}
// strip base url
if (route.substr(0, 4).toLowerCase() === 'http') {
route = route.split('//').pop().split('/').slice(1).join('/');
}
// strip prefix slash
if (route.charAt(0) === '/') {
route = route.substr(1);
}
linkEntry = { };
linkKey = Ember.String.singularize(key);
linkEntry[linkKey] = route;
extracted.push(linkEntry);
DS._routes[linkKey] = route;
}
return extracted;
},
// SERIALIZATION
/**
* Use "links" key, remove support for polymorphic type
*/
serializeBelongsTo: function(record, json, relationship) {
var key = relationship.key;
var belongsTo = get(record, key);
if (isNone(belongsTo)) return;
json.links = json.links || {};
json.links[key] = get(belongsTo, 'id');
},
/**
* Use "links" key
*/
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (relationshipType === 'manyToNone' ||
relationshipType === 'manyToMany') {
json.links = json.links || {};
json.links[key] = get(record, key).mapBy('id');
}
}
});
}).call(this);
(function() {
"use strict";
var get = Ember.get;
/**
* Keep a record of routes to resources by type.
*/
// null prototype in es5 browsers wont allow collisions with things on the
// global Object.prototype.
DS._routes = Ember.create(null);
DS.JsonApiAdapter = DS.RESTAdapter.extend({
defaultSerializer: 'DS/jsonApi',
/**
* Look up routes based on top-level links.
*/
buildURL: function(typeName, id) {
// TODO: this basically only works in the simplest of scenarios
var route = DS._routes[typeName];
if (!!route) {
var url = [];
var host = get(this, 'host');
var prefix = this.urlPrefix();
var param = /\{(.*?)\}/g;
if (id) {
if (param.test(route)) {
url.push(route.replace(param, id));
} else {
url.push(route, id);
}
} else {
url.push(route.replace(param, ''));
}
if (prefix) { url.unshift(prefix); }
url = url.join('/');
if (!host && url) { url = '/' + url; }
return url;
}
return this._super(typeName, id);
},
/**
* Fix query URL.
*/
findMany: function(store, type, ids, owner) {
return this.ajax(this.buildURL(type.typeKey, ids.join(',')), 'GET');
},
findQuery: function(store, type, query) {
var ids = null;
if (query.ids) {
ids = query.ids.join(',');
delete query.ids;
}
return this.ajax(this.buildURL(type.typeKey, ids), 'GET', {data: query});
},
/**
* Cast individual record to array,
* and match the root key to the route
*/
createRecord: function(store, type, record) {
var data = {};
data[this.pathForType(type.typeKey)] = [
store.serializerFor(type.typeKey).serialize(record, {
includeId: true
})
];
return this.ajax(this.buildURL(type.typeKey), 'POST', {
data: data
});
},
/**
* Cast individual record to array,
* and match the root key to the route
*/
updateRecord: function(store, type, record) {
var data = {};
data[this.pathForType(type.typeKey)] = [
store.serializerFor(type.typeKey).serialize(record)
];
var id = get(record, 'id');
return this.ajax(this.buildURL(type.typeKey, id), 'PUT', {
data: data
});
},
_tryParseErrorResponse: function(responseText) {
try {
return Ember.$.parseJSON(responseText);
} catch(e) {
return "Something went wrong";
}
},
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
var response;
if (jqXHR && typeof jqXHR === 'object') {
response = this._tryParseErrorResponse(jqXHR.responseText);
var errors = {};
if (response &&
typeof response === 'object' &&
response.errors !== undefined) {
Ember.A(Ember.keys(response.errors)).forEach(function(key) {
errors[Ember.String.camelize(key)] = response.errors[key];
});
}
if (jqXHR.status === 422) {
return new DS.InvalidError(errors);
} else{
return new ServerError(jqXHR.status, response, jqXHR);
}
} else {
return error;
}
},
/**
Underscores the JSON root keys when serializing.
@method serializeIntoHash
@param {Object} hash
@param {subclass of DS.Model} type
@param {DS.Model} record
@param {Object} options
*/
serializeIntoHash: function(data, type, record, options) {
var root = underscore(decamelize(type.typeKey));
data[root] = this.serialize(record, options);
}
});
function ServerError(status, message, xhr) {
this.status = status;
this.message = message;
this.xhr = xhr;
this.stack = new Error().stack;
}
ServerError.prototype = Ember.create(Error.prototype);
ServerError.constructor = ServerError;
DS.JsonApiAdapter.ServerError = ServerError;
}).call(this);

View File

@ -9,19 +9,16 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="flarum/config/environment" content="%7B%22modulePrefix%22%3A%22flarum%22%2C%22environment%22%3A%22development%22%2C%22baseURL%22%3A%22/%22%2C%22locationType%22%3A%22hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%7D%2C%22APP%22%3A%7B%22LOG_ACTIVE_GENERATION%22%3Atrue%2C%22LOG_VIEW_LOOKUPS%22%3Atrue%7D%2C%22contentSecurityPolicyHeader%22%3A%22Content-Security-Policy-Report-Only%22%2C%22contentSecurityPolicy%22%3A%7B%22default-src%22%3A%22%27none%27%22%2C%22script-src%22%3A%22%27self%27%20%27unsafe-eval%27%22%2C%22font-src%22%3A%22%27self%27%22%2C%22connect-src%22%3A%22%27self%27%22%2C%22img-src%22%3A%22%27self%27%22%2C%22style-src%22%3A%22%27self%27%22%2C%22media-src%22%3A%22%27self%27%22%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" />
<base href="/">
{{ app('flarum.web.assetManager')->styles() }}
</head>
<body>
<script>
window.FlarumENV = {"environment":"development","baseURL":"/","EmberENV":{"FEATURES":{"query-params-new":true}},"APP":{"LOG_MODULE_RESOLVER":true,"LOG_TRANSITIONS":true,"LOG_TRANSITIONS_INTERNAL":true},"LOG_MODULE_RESOLVER":true};
window.EmberENV = window.FlarumENV.EmberENV;
</script>
{{ app('flarum.web.assetManager')->scripts() }}
<script>
window.Flarum = require('flarum/app')['default'].create(FlarumENV.APP);
// window.Flarum.registerPlugin(require('flarum/categories')['default']); // todo: make dynamic
</script>
</body>