From d497782f65346e29ee2ba26d5792fecce3c00662 Mon Sep 17 00:00:00 2001
From: Toby Zerner
Date: Tue, 3 Nov 2015 10:01:52 +1030
Subject: [PATCH] Release 0.1.0-beta.3
---
CHANGELOG.md | 72 +-
js/admin/dist/app.js | 7465 ++++++++++-----------
js/forum/dist/app.js | 10965 ++++++++++++++++---------------
src/Foundation/Application.php | 2 +-
4 files changed, 9407 insertions(+), 9097 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90f08fd13..80c321acc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,36 +2,61 @@
All notable changes to Flarum and its bundled extensions will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
-## [Unreleased][unreleased]
+## [0.1.0-beta.3] - 2015-11-03
+### Architecture improvements
+- **Composer-driven extension architecture.** All extensions are Composer packages installable via Packagist.
+- **Backend codebase & API refactoring.** Classes, namespaces, and events systematically tidied up.
+
+### Improved internationalization
+> A huge thanks to @dcsjapan for the countless hours he put in to make this stuff happen. You're amazing!
+
+- New systematic translation key naming scheme.
+- Make many hardcoded strings translatable, including administration UI and validation messages.
+- More powerful pluralization via use of Symfony's Translation component instead of a proprietary one.
+
+### New moderation tools
+- **Hide/restore discussions.** Discussions can be soft-deleted by moderators or by the OP if no one has replied.
+- **Flags.** New bundled extension that allows posts to be flagged for moderator review.
+- **Approval.** New bundled extension that hides/flags new posts to be approved by the moderation team.
+- **Akismet.** New bundled extension that checks new posts for spam with Akismet.
+- **IP address logging.** IP addresses are stored with posts for use by extensions (e.g. Akismet).
+- **Flood control.** Users must wait at least ten seconds between consecutive posts.
+
+### Other features
+- **Social login.** New bundled extensions that allow users to log in with Facebook, Twitter, and GitHub.
+- **More compact post layout.** All controls are grouped over to the right.
+- **Improved permissions.** The admin Permissions page has been improved with icons and other tweaks.
+- **Improved extension management.** The admin Extensions page has a new look and is easier to use.
+- **Easier debugging.** The "oops" error message has a Debug button to inspect a failed AJAX request.
+- **Improved JavaScript minification.** Minification is done by ClosureCompiler only when debug mode is off, resulting in easier debugging and smaller production assets.
+
### Added
-- Ability to hide and restore discussions.
-- External authentication (social login) API.
-- API to set asset compiler filename.
-- Migration generator, available via generate:migration console command.
-- Tags: Ability to set the tags page as the home page.
-- `bidi` attribute for Mithril elements as a shortcut to set up bidirectional bindings.
-- `route` attribute for Mithril elements as a shortcut to link to a route.
-- Abstract SettingsModal component for quickly building admin config modals.
-- "Debug" button to inspect the response of a failed AJAX request.
-- `Model::afterSave()` API to run callback after a model instance is saved.
-- Improved admin Permissions page with icons and other tweaks.
-- Sticky: Allow permission to be configured.
-- Lock: Allow permission to be configured.
-- Flags: New extension. Allows posts to be flagged for moderator review.
-- Approval: New extension. Flags new posts to be approved by the moderation team.
-- Akismet: New extension. Hides/flags spam posts for moderator approval.
+- Allow HTML tag syntax in translations (#574)
+- Add gzip/caching directives to webserver configuration (#514)
+- API to set the asset compiler's filename
+- Migration generator, available via generate:migration console command
+- Tags: Ability to set the tags page as the home page
+- `bidi` attribute for Mithril elements as a shortcut to set up bidirectional bindings
+- `route` attribute for Mithril elements as a shortcut to link to a route
+- Abstract SettingsModal component for quickly building admin config modals
+- `Model::afterSave()` API to run callback after a model instance is saved
+- Sticky: Allow permission to be configured
+- Lock: Allow permission to be configured
+- Add a third state to header icons (#500)
+- Allow faking of PATCH/DELETE methods (#502)
+- More reliable form validation and error handling
### Changed
-- Migrations must be namespaced under `Flarum\Migrations\{Core|ExtensionName}`. ([#422](https://github.com/flarum/core/issues/422))
-- More compact post layout, with all controls grouped over to the right.
- Rename `notification_read_time` column in discussions table to `notifications_read_time`.
- Update to FontAwesome 4.4.0.
### Fixed
-- Output forum description in meta description tag. ([#506](https://github.com/flarum/core/issues/506))
-- Allow users to edit their last post in a discussion even if it's hidden.
-- Allow users to rename their discussion even if their first post is hidden.
-- Fix several design bugs.
+- Output forum description in meta description tag (#506)
+- Allow users to edit their last post in a discussion even if it's hidden
+- Allow users to rename their discussion even if their first post is hidden
+- API links correctly include the `/api` path (#579)
+- Tags: Fix sub-tag ordering algorithm in Chrome (#325)
+- Fix several design bugs
## [0.1.0-beta.2] - 2015-09-15
### Added
@@ -69,4 +94,5 @@ This project adheres to [Semantic Versioning](http://semver.org/).
First Version
[unreleased]: https://github.com/flarum/core/compare/v0.1.0-beta.2...HEAD
+[0.1.0-beta.3]: https://github.com/flarum/core/compare/v0.1.0-beta.2...v0.1.0-beta.3
[0.1.0-beta.2]: https://github.com/flarum/core/compare/v0.1.0-beta...v0.1.0-beta.2
diff --git a/js/admin/dist/app.js b/js/admin/dist/app.js
index be6dda19c..929624e06 100644
--- a/js/admin/dist/app.js
+++ b/js/admin/dist/app.js
@@ -15935,6 +15935,645 @@ System.register('flarum/app', ['flarum/App', 'flarum/initializers/store', 'flaru
}
};
});;
+System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/Translator', 'flarum/utils/extract', 'flarum/utils/patchMithril', 'flarum/utils/RequestError', 'flarum/extend'], function (_export) {
+
+ /**
+ * The `App` class provides a container for an application, as well as various
+ * utilities for the rest of the app to use.
+ */
+ 'use strict';
+
+ var ItemList, Alert, Button, RequestErrorModal, Translator, extract, patchMithril, RequestError, extend, App;
+ return {
+ setters: [function (_flarumUtilsItemList) {
+ ItemList = _flarumUtilsItemList['default'];
+ }, function (_flarumComponentsAlert) {
+ Alert = _flarumComponentsAlert['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumComponentsRequestErrorModal) {
+ RequestErrorModal = _flarumComponentsRequestErrorModal['default'];
+ }, function (_flarumTranslator) {
+ Translator = _flarumTranslator['default'];
+ }, function (_flarumUtilsExtract) {
+ extract = _flarumUtilsExtract['default'];
+ }, function (_flarumUtilsPatchMithril) {
+ patchMithril = _flarumUtilsPatchMithril['default'];
+ }, function (_flarumUtilsRequestError) {
+ RequestError = _flarumUtilsRequestError['default'];
+ }, function (_flarumExtend) {
+ extend = _flarumExtend.extend;
+ }],
+ execute: function () {
+ App = (function () {
+ function App() {
+ babelHelpers.classCallCheck(this, App);
+
+ patchMithril(window);
+
+ /**
+ * The forum model for this application.
+ *
+ * @type {Forum}
+ * @public
+ */
+ this.forum = null;
+
+ /**
+ * 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()};
+ *
+ * @type {Object}
+ * @public
+ */
+ this.routes = {};
+
+ /**
+ * An object containing data to preload into the application.
+ *
+ * @type {Object}
+ * @property {Object} preload.data An array of resource objects to preload
+ * into the data store.
+ * @property {Object} preload.document An API response document to be used
+ * by the route that is first activated.
+ * @property {Object} preload.session A response from the /api/token
+ * endpoint containing the session's authentication token and user ID.
+ * @public
+ */
+ this.preload = {
+ data: null,
+ document: null,
+ session: null
+ };
+
+ /**
+ * An ordered list of initializers to bootstrap the application.
+ *
+ * @type {ItemList}
+ * @public
+ */
+ this.initializers = new ItemList();
+
+ /**
+ * The app's session.
+ *
+ * @type {Session}
+ * @public
+ */
+ this.session = null;
+
+ /**
+ * The app's translator.
+ *
+ * @type {Translator}
+ * @public
+ */
+ this.translator = new Translator();
+
+ /**
+ * The app's data store.
+ *
+ * @type {Store}
+ * @public
+ */
+ this.store = null;
+
+ /**
+ * A local cache that can be used to store data at the application level, so
+ * that is persists between different routes.
+ *
+ * @type {Object}
+ * @public
+ */
+ this.cache = {};
+
+ /**
+ * Whether or not the app has been booted.
+ *
+ * @type {Boolean}
+ * @public
+ */
+ this.booted = false;
+
+ /**
+ * An Alert that was shown as a result of an AJAX request error. If present,
+ * it will be dismissed on the next successful request.
+ *
+ * @type {null|Alert}
+ * @private
+ */
+ this.requestError = null;
+
+ this.title = '';
+ this.titleCount = 0;
+ }
+
+ /**
+ * Boot the application by running all of the registered initializers.
+ *
+ * @public
+ */
+ babelHelpers.createClass(App, [{
+ key: 'boot',
+ value: function boot() {
+ var _this = this;
+
+ this.translator.locale = this.locale;
+
+ this.initializers.toArray().forEach(function (initializer) {
+ return initializer(_this);
+ });
+ }
+
+ /**
+ * Get the API response document that has been preloaded into the application.
+ *
+ * @return {Object|null}
+ * @public
+ */
+ }, {
+ key: 'preloadedDocument',
+ value: function preloadedDocument() {
+ if (app.preload.document) {
+ var results = app.store.pushPayload(app.preload.document);
+ app.preload.document = null;
+
+ return results;
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the of the page.
+ *
+ * @param {String} title
+ * @public
+ */
+ }, {
+ key: 'setTitle',
+ value: function setTitle(title) {
+ this.title = title;
+ this.updateTitle();
+ }
+
+ /**
+ * Set a number to display in the of the page.
+ *
+ * @param {Integer} count
+ */
+ }, {
+ key: 'setTitleCount',
+ value: function setTitleCount(count) {
+ this.titleCount = count;
+ this.updateTitle();
+ }
+ }, {
+ key: 'updateTitle',
+ value: function updateTitle() {
+ document.title = (this.titleCount ? '(' + this.titleCount + ') ' : '') + (this.title ? this.title + ' - ' : '') + this.forum.attribute('title');
+ }
+
+ /**
+ * Make an AJAX request, handling any low-level errors that may occur.
+ *
+ * @see https://lhorie.github.io/mithril/mithril.request.html
+ * @param {Object} options
+ * @return {Promise}
+ * @public
+ */
+ }, {
+ key: 'request',
+ value: function request(options) {
+ var _this2 = this;
+
+ // Set some default options if they haven't been overridden. We want to
+ // authenticate all requests with the session token. We also want all
+ // requests to run asynchronously in the background, so that they don't
+ // prevent redraws from occurring.
+ options.config = options.config || this.session.authorize.bind(this.session);
+ options.background = options.background || true;
+
+ // If the method is something like PATCH or DELETE, which not all servers
+ // support, then we'll send it as a POST request with a the intended method
+ // specified in the X-Fake-Http-Method header.
+ if (options.method !== 'GET' && options.method !== 'POST') {
+ (function () {
+ var method = options.method;
+ extend(options, 'config', function (result, xhr) {
+ return xhr.setRequestHeader('X-Fake-Http-Method', method);
+ });
+ options.method = 'POST';
+ })();
+ }
+
+ // When we deserialize JSON data, if for some reason the server has provided
+ // a dud response, we don't want the application to crash. We'll show an
+ // error message to the user instead.
+ options.deserialize = options.deserialize || function (responseText) {
+ return responseText;
+ };
+
+ options.errorHandler = options.errorHandler || function (error) {
+ throw error;
+ };
+
+ // When extracting the data from the response, we can check the server
+ // response code and show an error message to the user if something's gone
+ // awry.
+ var original = options.extract;
+ options.extract = function (xhr) {
+ var responseText = undefined;
+
+ if (original) {
+ responseText = original(xhr.responseText);
+ } else {
+ responseText = xhr.responseText.length > 0 ? xhr.responseText : null;
+ }
+
+ var status = xhr.status;
+
+ if (status < 200 || status > 299) {
+ throw new RequestError(status, responseText, options, xhr);
+ }
+
+ try {
+ return JSON.parse(responseText);
+ } catch (e) {
+ throw new RequestError(500, responseText, options, xhr);
+ }
+ };
+
+ if (this.requestError) this.alerts.dismiss(this.requestError.alert);
+
+ // Now make the request. If it's a failure, inspect the error that was
+ // returned and show an alert containing its contents.
+ return m.request(options).then(null, function (error) {
+ _this2.requestError = error;
+
+ var children = undefined;
+
+ switch (error.status) {
+ case 422:
+ children = error.response.errors.map(function (error) {
+ return [error.detail, m('br', null)];
+ }).reduce(function (a, b) {
+ return a.concat(b);
+ }, []).slice(0, -1);
+ break;
+
+ case 401:
+ case 403:
+ children = app.translator.trans('core.lib.error.permission_denied_message');
+ break;
+
+ case 404:
+ case 410:
+ children = app.translator.trans('core.lib.error.not_found_message');
+ break;
+
+ case 429:
+ children = app.translator.trans('core.lib.error.rate_limit_exceeded_message');
+ break;
+
+ default:
+ children = app.translator.trans('core.lib.error.generic_message');
+ }
+
+ error.alert = new Alert({
+ type: 'error',
+ children: children,
+ controls: app.forum.attribute('debug') ? [m(
+ Button,
+ { className: 'Button Button--link', onclick: _this2.showDebug.bind(_this2, error) },
+ 'Debug'
+ )] : undefined
+ });
+
+ try {
+ options.errorHandler(error);
+ } catch (error) {
+ _this2.alerts.show(error.alert);
+ }
+
+ throw error;
+ });
+ }
+
+ /**
+ * @param {RequestError} error
+ * @private
+ */
+ }, {
+ key: 'showDebug',
+ value: function showDebug(error) {
+ this.alerts.dismiss(this.requestErrorAlert);
+
+ this.modal.show(new RequestErrorModal({ error: error }));
+ }
+
+ /**
+ * Construct a URL to the route with the given name.
+ *
+ * @param {String} name
+ * @param {Object} params
+ * @return {String}
+ * @public
+ */
+ }, {
+ key: 'route',
+ value: function route(name) {
+ var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+
+ var url = this.routes[name].path.replace(/:([^\/]+)/g, function (m, key) {
+ return extract(params, key);
+ });
+ var queryString = m.route.buildQueryString(params);
+ var prefix = m.route.mode === 'pathname' ? app.forum.attribute('basePath') : '';
+
+ return prefix + url + (queryString ? '?' + queryString : '');
+ }
+ }]);
+ return App;
+ })();
+
+ _export('default', App);
+ }
+ };
+});;
+System.register('flarum/Component', [], function (_export) {
+ /*
+ * This file is part of Flarum.
+ *
+ * (c) Toby Zerner
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+ /**
+ * The `Component` class defines a user interface 'building block'. A component
+ * can generate a virtual DOM to be rendered on each redraw.
+ *
+ * An instance's virtual DOM can be retrieved directly using the {@link
+ * Component#render} method.
+ *
+ * @example
+ * this.myComponentInstance = new MyComponent({foo: 'bar'});
+ * return m('div', this.myComponentInstance.render());
+ *
+ * Alternatively, components can be nested, letting Mithril take care of
+ * instance persistence. For this, the static {@link Component.component} method
+ * can be used.
+ *
+ * @example
+ * return m('div', MyComponent.component({foo: 'bar'));
+ *
+ * @see https://lhorie.github.io/mithril/mithril.component.html
+ * @abstract
+ */
+ 'use strict';
+
+ var Component;
+ return {
+ setters: [],
+ execute: function () {
+ Component = (function () {
+ /**
+ * @param {Object} props
+ * @param {Array|Object} children
+ * @public
+ */
+
+ function Component() {
+ var props = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+ var children = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
+ babelHelpers.classCallCheck(this, Component);
+
+ if (children) props.children = children;
+
+ this.constructor.initProps(props);
+
+ /**
+ * The properties passed into the component.
+ *
+ * @type {Object}
+ */
+ this.props = props;
+
+ /**
+ * The root DOM element for the component.
+ *
+ * @type DOMElement
+ * @public
+ */
+ this.element = null;
+
+ this.init();
+ }
+
+ /**
+ * Called when the component is constructed.
+ *
+ * @protected
+ */
+ babelHelpers.createClass(Component, [{
+ key: 'init',
+ value: function init() {}
+
+ /**
+ * Called when the component is destroyed, i.e. after a redraw where it is no
+ * longer a part of the view.
+ *
+ * @see https://lhorie.github.io/mithril/mithril.component.html#unloading-components
+ * @param {Object} e
+ * @public
+ */
+ }, {
+ key: 'onunload',
+ value: function onunload() {}
+
+ /**
+ * Get the renderable virtual DOM that represents the component's view.
+ *
+ * This should NOT be overridden by subclasses. Subclasses wishing to define
+ * their virtual DOM should override Component#view instead.
+ *
+ * @example
+ * this.myComponentInstance = new MyComponent({foo: 'bar'});
+ * return m('div', this.myComponentInstance.render());
+ *
+ * @returns {Object}
+ * @final
+ * @public
+ */
+ }, {
+ key: 'render',
+ value: function render() {
+ var _this = this;
+
+ var vdom = this.view();
+
+ // Override the root element's config attribute with our own function, which
+ // will set the component instance's element property to the root DOM
+ // element, and then run the component class' config method.
+ vdom.attrs = vdom.attrs || {};
+
+ var originalConfig = vdom.attrs.config;
+
+ vdom.attrs.config = function () {
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ _this.element = args[0];
+ _this.config.apply(_this, args.slice(1));
+ if (originalConfig) originalConfig.apply(_this, args);
+ };
+
+ return vdom;
+ }
+
+ /**
+ * Returns a jQuery object for this component's element. If you pass in a
+ * selector string, this method will return a jQuery object, using the current
+ * element as its buffer.
+ *
+ * For example, calling `component.$('li')` will return a jQuery object
+ * containing all of the `li` elements inside the DOM element of this
+ * component.
+ *
+ * @param {String} [selector] a jQuery-compatible selector string
+ * @returns {jQuery} the jQuery object for the DOM node
+ * @final
+ * @public
+ */
+ }, {
+ key: '$',
+ value: (function (_$) {
+ function $(_x) {
+ return _$.apply(this, arguments);
+ }
+
+ $.toString = function () {
+ return _$.toString();
+ };
+
+ return $;
+ })(function (selector) {
+ var $element = $(this.element);
+
+ return selector ? $element.find(selector) : $element;
+ })
+
+ /**
+ * Called after the component's root element is redrawn. This hook can be used
+ * to perform any actions on the DOM, both on the initial draw and any
+ * subsequent redraws. See Mithril's documentation for more information.
+ *
+ * @see https://lhorie.github.io/mithril/mithril.html#the-config-attribute
+ * @param {Boolean} isInitialized
+ * @param {Object} context
+ * @param {Object} vdom
+ * @public
+ */
+ }, {
+ key: 'config',
+ value: function config() {}
+
+ /**
+ * Get the virtual DOM that represents the component's view.
+ *
+ * @return {Object} The virtual DOM
+ * @protected
+ */
+ }, {
+ key: 'view',
+ value: function view() {
+ throw new Error('Component#view must be implemented by subclass');
+ }
+
+ /**
+ * Get a Mithril component object for this component, preloaded with props.
+ *
+ * @see https://lhorie.github.io/mithril/mithril.component.html
+ * @param {Object} [props] Properties to set on the component
+ * @param children
+ * @return {Object} The Mithril component object
+ * @property {function} controller
+ * @property {function} view
+ * @property {Object} component The class of this component
+ * @property {Object} props The props that were passed to the component
+ * @public
+ */
+ }], [{
+ key: 'component',
+ value: function component() {
+ var props = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+ var children = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
+
+ var componentProps = babelHelpers._extends({}, props);
+
+ if (children) componentProps.children = children;
+
+ this.initProps(componentProps);
+
+ // Set up a function for Mithril to get the component's view. It will accept
+ // the component's controller (which happens to be the component itself, in
+ // our case), update its props with the ones supplied, and then render the view.
+ var view = function view(component) {
+ component.props = componentProps;
+ return component.render();
+ };
+
+ // Mithril uses this property on the view function to cache component
+ // controllers between redraws, thus persisting component state.
+ view.$original = this.prototype.view;
+
+ // Our output object consists of a controller constructor + a view function
+ // which Mithril will use to instantiate and render the component. We also
+ // attach a reference to the props that were passed through and the
+ // component's class for reference.
+ var output = {
+ controller: this.bind(undefined, componentProps),
+ view: view,
+ props: componentProps,
+ component: this
+ };
+
+ // If a `key` prop was set, then we'll assume that we want that to actually
+ // show up as an attribute on the component object so that Mithril's key
+ // algorithm can be applied.
+ if (componentProps.key) {
+ output.attrs = { key: componentProps.key };
+ }
+
+ return output;
+ }
+
+ /**
+ * Initialize the component's props.
+ *
+ * @param {Object} props
+ * @public
+ */
+ }, {
+ key: 'initProps',
+ value: function initProps(props) {}
+ }]);
+ return Component;
+ })();
+
+ _export('default', Component);
+ }
+ };
+});;
System.register('flarum/components/AddExtensionModal', ['flarum/components/Modal'], function (_export) {
/*
* This file is part of Flarum.
@@ -16158,6 +16797,198 @@ System.register('flarum/components/AdminNav', ['flarum/Component', 'flarum/compo
}
};
});;
+System.register('flarum/components/Alert', ['flarum/Component', 'flarum/components/Button', 'flarum/helpers/listItems', 'flarum/utils/extract'], function (_export) {
+
+ /**
+ * The `Alert` component represents an alert box, which contains a message,
+ * some controls, and may be dismissible.
+ *
+ * The alert may have the following special props:
+ *
+ * - `type` The type of alert this is. Will be used to give the alert a class
+ * name of `Alert--{type}`.
+ * - `controls` An array of controls to show in the alert.
+ * - `dismissible` Whether or not the alert can be dismissed.
+ * - `ondismiss` A callback to run when the alert is dismissed.
+ *
+ * All other props will be assigned as attributes on the alert element.
+ */
+ 'use strict';
+
+ var Component, Button, listItems, extract, Alert;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumHelpersListItems) {
+ listItems = _flarumHelpersListItems['default'];
+ }, function (_flarumUtilsExtract) {
+ extract = _flarumUtilsExtract['default'];
+ }],
+ execute: function () {
+ Alert = (function (_Component) {
+ babelHelpers.inherits(Alert, _Component);
+
+ function Alert() {
+ babelHelpers.classCallCheck(this, Alert);
+ babelHelpers.get(Object.getPrototypeOf(Alert.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Alert, [{
+ key: 'view',
+ value: function view() {
+ var attrs = babelHelpers._extends({}, this.props);
+
+ var type = extract(attrs, 'type');
+ attrs.className = 'Alert Alert--' + type + ' ' + (attrs.className || '');
+
+ var children = extract(attrs, 'children');
+ var controls = extract(attrs, 'controls') || [];
+
+ // If the alert is meant to be dismissible (which is the case by default),
+ // then we will create a dismiss button to append as the final control in
+ // the alert.
+ var dismissible = extract(attrs, 'dismissible');
+ var ondismiss = extract(attrs, 'ondismiss');
+ var dismissControl = [];
+
+ if (dismissible || dismissible === undefined) {
+ dismissControl.push(m(Button, {
+ icon: 'times',
+ className: 'Button Button--link Button--icon Alert-dismiss',
+ onclick: ondismiss }));
+ }
+
+ return m(
+ 'div',
+ attrs,
+ m(
+ 'span',
+ { className: 'Alert-body' },
+ children
+ ),
+ m(
+ 'ul',
+ { className: 'Alert-controls' },
+ listItems(controls.concat(dismissControl))
+ )
+ );
+ }
+ }]);
+ return Alert;
+ })(Component);
+
+ _export('default', Alert);
+ }
+ };
+});;
+System.register('flarum/components/AlertManager', ['flarum/Component', 'flarum/components/Alert'], function (_export) {
+
+ /**
+ * The `AlertManager` component provides an area in which `Alert` components can
+ * be shown and dismissed.
+ */
+ 'use strict';
+
+ var Component, Alert, AlertManager;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsAlert) {
+ Alert = _flarumComponentsAlert['default'];
+ }],
+ execute: function () {
+ AlertManager = (function (_Component) {
+ babelHelpers.inherits(AlertManager, _Component);
+
+ function AlertManager() {
+ babelHelpers.classCallCheck(this, AlertManager);
+ babelHelpers.get(Object.getPrototypeOf(AlertManager.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(AlertManager, [{
+ key: 'init',
+ value: function init() {
+ /**
+ * An array of Alert components which are currently showing.
+ *
+ * @type {Alert[]}
+ * @protected
+ */
+ this.components = [];
+ }
+ }, {
+ key: 'view',
+ value: function view() {
+ return m(
+ 'div',
+ { className: 'AlertManager' },
+ this.components.map(function (component) {
+ return m(
+ 'div',
+ { className: 'AlertManager-alert' },
+ component
+ );
+ })
+ );
+ }
+
+ /**
+ * Show an Alert in the alerts area.
+ *
+ * @param {Alert} component
+ * @public
+ */
+ }, {
+ key: 'show',
+ value: function show(component) {
+ if (!(component instanceof Alert)) {
+ throw new Error('The AlertManager component can only show Alert components');
+ }
+
+ component.props.ondismiss = this.dismiss.bind(this, component);
+
+ this.components.push(component);
+ m.redraw();
+ }
+
+ /**
+ * Dismiss an alert.
+ *
+ * @param {Alert} component
+ * @public
+ */
+ }, {
+ key: 'dismiss',
+ value: function dismiss(component) {
+ var index = this.components.indexOf(component);
+
+ if (index !== -1) {
+ this.components.splice(index, 1);
+ m.redraw();
+ }
+ }
+
+ /**
+ * Clear all alerts.
+ *
+ * @public
+ */
+ }, {
+ key: 'clear',
+ value: function clear() {
+ this.components = [];
+ m.redraw();
+ }
+ }]);
+ return AlertManager;
+ })(Component);
+
+ _export('default', AlertManager);
+ }
+ };
+});;
System.register('flarum/components/AppearancePage', ['flarum/Component', 'flarum/components/Button', 'flarum/components/Switch', 'flarum/components/EditCustomCssModal', 'flarum/utils/saveSettings'], function (_export) {
'use strict';
@@ -16295,6 +17126,77 @@ System.register('flarum/components/AppearancePage', ['flarum/Component', 'flarum
}
};
});;
+System.register('flarum/components/Badge', ['flarum/Component', 'flarum/helpers/icon', 'flarum/utils/extract'], function (_export) {
+
+ /**
+ * The `Badge` component represents a user/discussion badge, indicating some
+ * status (e.g. a discussion is stickied, a user is an admin).
+ *
+ * A badge may have the following special props:
+ *
+ * - `type` The type of badge this is. This will be used to give the badge a
+ * class name of `Badge--{type}`.
+ * - `icon` The name of an icon to show inside the badge.
+ * - `label`
+ *
+ * All other props will be assigned as attributes on the badge element.
+ */
+ 'use strict';
+
+ var Component, icon, extract, Badge;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }, function (_flarumUtilsExtract) {
+ extract = _flarumUtilsExtract['default'];
+ }],
+ execute: function () {
+ Badge = (function (_Component) {
+ babelHelpers.inherits(Badge, _Component);
+
+ function Badge() {
+ babelHelpers.classCallCheck(this, Badge);
+ babelHelpers.get(Object.getPrototypeOf(Badge.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Badge, [{
+ key: 'view',
+ value: function view() {
+ var attrs = babelHelpers._extends({}, this.props);
+ var type = extract(attrs, 'type');
+ var iconName = extract(attrs, 'icon');
+
+ attrs.className = 'Badge ' + (type ? 'Badge--' + type : '') + ' ' + (attrs.className || '');
+ attrs.title = extract(attrs, 'label') || '';
+
+ // Give the badge a unique key so that when badges are displayed together,
+ // and then one is added/removed, Mithril will correctly redraw the series
+ // of badges.
+ attrs.key = attrs.type;
+
+ return m(
+ 'span',
+ attrs,
+ iconName ? icon(iconName, { className: 'Badge-icon' }) : m.trust(' ')
+ );
+ }
+ }, {
+ key: 'config',
+ value: function config(isInitialized) {
+ if (isInitialized) return;
+
+ if (this.props.label) this.$().tooltip({ container: 'body' });
+ }
+ }]);
+ return Badge;
+ })(Component);
+
+ _export('default', Badge);
+ }
+ };
+});;
System.register('flarum/components/BasicsPage', ['flarum/Component', 'flarum/components/FieldSet', 'flarum/components/Select', 'flarum/components/Button', 'flarum/components/Alert', 'flarum/utils/saveSettings', 'flarum/utils/ItemList'], function (_export) {
'use strict';
@@ -16483,6 +17385,195 @@ System.register('flarum/components/BasicsPage', ['flarum/Component', 'flarum/com
}
};
});;
+System.register('flarum/components/Button', ['flarum/Component', 'flarum/helpers/icon', 'flarum/utils/extract', 'flarum/components/LoadingIndicator'], function (_export) {
+
+ /**
+ * The `Button` component defines an element which, when clicked, performs an
+ * action. The button may have the following special props:
+ *
+ * - `icon` The name of the icon class. If specified, the button will be given a
+ * 'has-icon' class name.
+ * - `disabled` Whether or not the button is disabled. If truthy, the button
+ * will be given a 'disabled' class name, and any `onclick` handler will be
+ * removed.
+ * - `loading` Whether or not the button should be in a disabled loading state.
+ *
+ * All other props will be assigned as attributes on the button element.
+ *
+ * Note that a Button has no default class names. This is because a Button can
+ * be used to represent any generic clickable control, like a menu item.
+ */
+ 'use strict';
+
+ var Component, icon, extract, LoadingIndicator, Button;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }, function (_flarumUtilsExtract) {
+ extract = _flarumUtilsExtract['default'];
+ }, function (_flarumComponentsLoadingIndicator) {
+ LoadingIndicator = _flarumComponentsLoadingIndicator['default'];
+ }],
+ execute: function () {
+ Button = (function (_Component) {
+ babelHelpers.inherits(Button, _Component);
+
+ function Button() {
+ babelHelpers.classCallCheck(this, Button);
+ babelHelpers.get(Object.getPrototypeOf(Button.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Button, [{
+ key: 'view',
+ value: function view() {
+ var attrs = babelHelpers._extends({}, this.props);
+
+ delete attrs.children;
+
+ attrs.className = attrs.className || '';
+ attrs.type = attrs.type || 'button';
+
+ var iconName = extract(attrs, 'icon');
+ if (iconName) attrs.className += ' hasIcon';
+
+ var loading = extract(attrs, 'loading');
+ if (attrs.disabled || loading) {
+ attrs.className += ' disabled' + (loading ? ' loading' : '');
+ delete attrs.onclick;
+ }
+
+ return m(
+ 'button',
+ attrs,
+ this.getButtonContent()
+ );
+ }
+
+ /**
+ * Get the template for the button's content.
+ *
+ * @return {*}
+ * @protected
+ */
+ }, {
+ key: 'getButtonContent',
+ value: function getButtonContent() {
+ var iconName = this.props.icon;
+
+ return [iconName && iconName !== true ? icon(iconName, { className: 'Button-icon' }) : '', this.props.children ? m(
+ 'span',
+ { className: 'Button-label' },
+ this.props.children
+ ) : '', this.props.loading ? LoadingIndicator.component({ size: 'tiny', className: 'LoadingIndicator--inline' }) : ''];
+ }
+ }]);
+ return Button;
+ })(Component);
+
+ _export('default', Button);
+ }
+ };
+});;
+System.register('flarum/components/Checkbox', ['flarum/Component', 'flarum/components/LoadingIndicator', 'flarum/helpers/icon'], function (_export) {
+
+ /**
+ * The `Checkbox` component defines a checkbox input.
+ *
+ * ### Props
+ *
+ * - `state` Whether or not the checkbox is checked.
+ * - `className` The class name for the root element.
+ * - `disabled` Whether or not the checkbox is disabled.
+ * - `onchange` A callback to run when the checkbox is checked/unchecked.
+ * - `children` A text label to display next to the checkbox.
+ */
+ 'use strict';
+
+ var Component, LoadingIndicator, icon, Checkbox;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsLoadingIndicator) {
+ LoadingIndicator = _flarumComponentsLoadingIndicator['default'];
+ }, function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }],
+ execute: function () {
+ Checkbox = (function (_Component) {
+ babelHelpers.inherits(Checkbox, _Component);
+
+ function Checkbox() {
+ babelHelpers.classCallCheck(this, Checkbox);
+ babelHelpers.get(Object.getPrototypeOf(Checkbox.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Checkbox, [{
+ key: 'init',
+ value: function init() {
+ /**
+ * Whether or not the checkbox's value is in the process of being saved.
+ *
+ * @type {Boolean}
+ * @public
+ */
+ this.loading = false;
+ }
+ }, {
+ key: 'view',
+ value: function view() {
+ var className = 'Checkbox ' + (this.props.state ? 'on' : 'off') + ' ' + (this.props.className || '');
+ if (this.loading) className += ' loading';
+ if (this.props.disabled) className += ' disabled';
+
+ return m(
+ 'label',
+ { className: className },
+ m('input', { type: 'checkbox',
+ checked: this.props.state,
+ disabled: this.props.disabled,
+ onchange: m.withAttr('checked', this.onchange.bind(this)) }),
+ m(
+ 'div',
+ { className: 'Checkbox-display' },
+ this.getDisplay()
+ ),
+ this.props.children
+ );
+ }
+
+ /**
+ * Get the template for the checkbox's display (tick/cross icon).
+ *
+ * @return {*}
+ * @protected
+ */
+ }, {
+ key: 'getDisplay',
+ value: function getDisplay() {
+ return this.loading ? LoadingIndicator.component({ size: 'tiny' }) : icon(this.props.state ? 'check' : 'times');
+ }
+
+ /**
+ * Run a callback when the state of the checkbox is changed.
+ *
+ * @param {Boolean} checked
+ * @protected
+ */
+ }, {
+ key: 'onchange',
+ value: function onchange(checked) {
+ if (this.props.onchange) this.props.onchange(checked, this);
+ }
+ }]);
+ return Checkbox;
+ })(Component);
+
+ _export('default', Checkbox);
+ }
+ };
+});;
System.register("flarum/components/DashboardPage", ["flarum/Component"], function (_export) {
"use strict";
@@ -16568,6 +17659,147 @@ System.register("flarum/components/DashboardPage", ["flarum/Component"], functio
}
};
});;
+System.register('flarum/components/Dropdown', ['flarum/Component', 'flarum/helpers/icon', 'flarum/helpers/listItems'], function (_export) {
+
+ /**
+ * The `Dropdown` component displays a button which, when clicked, shows a
+ * dropdown menu beneath it.
+ *
+ * ### Props
+ *
+ * - `buttonClassName` A class name to apply to the dropdown toggle button.
+ * - `menuClassName` A class name to apply to the dropdown menu.
+ * - `icon` The name of an icon to show in the dropdown toggle button.
+ * - `caretIcon` The name of an icon to show on the right of the button.
+ * - `label` The label of the dropdown toggle button. Defaults to 'Controls'.
+ * - `onhide`
+ * - `onshow`
+ *
+ * The children will be displayed as a list inside of the dropdown menu.
+ */
+ 'use strict';
+
+ var Component, icon, listItems, Dropdown;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }, function (_flarumHelpersListItems) {
+ listItems = _flarumHelpersListItems['default'];
+ }],
+ execute: function () {
+ Dropdown = (function (_Component) {
+ babelHelpers.inherits(Dropdown, _Component);
+
+ function Dropdown() {
+ babelHelpers.classCallCheck(this, Dropdown);
+ babelHelpers.get(Object.getPrototypeOf(Dropdown.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Dropdown, [{
+ key: 'view',
+ value: function view() {
+ var items = this.props.children ? listItems(this.props.children) : [];
+
+ return m(
+ 'div',
+ { className: 'ButtonGroup Dropdown dropdown ' + this.props.className + ' itemCount' + items.length },
+ this.getButton(),
+ this.getMenu(items)
+ );
+ }
+ }, {
+ key: 'config',
+ value: function config(isInitialized) {
+ var _this = this;
+
+ if (isInitialized) return;
+
+ // When opening the dropdown menu, work out if the menu goes beyond the
+ // bottom of the viewport. If it does, we will apply class to make it show
+ // above the toggle button instead of below it.
+ this.$().on('shown.bs.dropdown', function () {
+ var $menu = _this.$('.Dropdown-menu').removeClass('Dropdown-menu--top');
+
+ $menu.toggleClass('Dropdown-menu--top', $menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height());
+
+ if (_this.props.onshow) {
+ _this.props.onshow();
+ m.redraw();
+ }
+ });
+
+ this.$().on('hidden.bs.dropdown', function () {
+ if (_this.props.onhide) {
+ _this.props.onhide();
+ m.redraw();
+ }
+ });
+ }
+
+ /**
+ * Get the template for the button.
+ *
+ * @return {*}
+ * @protected
+ */
+ }, {
+ key: 'getButton',
+ value: function getButton() {
+ return m(
+ 'button',
+ {
+ className: 'Dropdown-toggle ' + this.props.buttonClassName,
+ 'data-toggle': 'dropdown',
+ onclick: this.props.onclick },
+ this.getButtonContent()
+ );
+ }
+
+ /**
+ * Get the template for the button's content.
+ *
+ * @return {*}
+ * @protected
+ */
+ }, {
+ key: 'getButtonContent',
+ value: function getButtonContent() {
+ return [this.props.icon ? icon(this.props.icon, { className: 'Button-icon' }) : '', m(
+ 'span',
+ { className: 'Button-label' },
+ this.props.label
+ ), this.props.caretIcon ? icon(this.props.caretIcon, { className: 'Button-caret' }) : ''];
+ }
+ }, {
+ key: 'getMenu',
+ value: function getMenu(items) {
+ return m(
+ 'ul',
+ { className: 'Dropdown-menu dropdown-menu ' + this.props.menuClassName },
+ items
+ );
+ }
+ }], [{
+ key: 'initProps',
+ value: function initProps(props) {
+ babelHelpers.get(Object.getPrototypeOf(Dropdown), 'initProps', this).call(this, props);
+
+ props.className = props.className || '';
+ props.buttonClassName = props.buttonClassName || '';
+ props.menuClassName = props.menuClassName || '';
+ props.label = props.label || '';
+ props.caretIcon = typeof props.caretIcon !== 'undefined' ? props.caretIcon : 'caret-down';
+ }
+ }]);
+ return Dropdown;
+ })(Component);
+
+ _export('default', Dropdown);
+ }
+ };
+});;
System.register('flarum/components/EditCustomCssModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/utils/saveSettings'], function (_export) {
'use strict';
@@ -17000,6 +18232,100 @@ System.register('flarum/components/ExtensionsPage', ['flarum/Component', 'flarum
}
};
});;
+System.register('flarum/components/FieldSet', ['flarum/Component', 'flarum/helpers/listItems'], function (_export) {
+
+ /**
+ * The `FieldSet` component defines a collection of fields, displayed in a list
+ * underneath a title. Accepted properties are:
+ *
+ * - `className` The class name for the fieldset.
+ * - `label` The title of this group of fields.
+ *
+ * The children should be an array of items to show in the fieldset.
+ */
+ 'use strict';
+
+ var Component, listItems, FieldSet;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumHelpersListItems) {
+ listItems = _flarumHelpersListItems['default'];
+ }],
+ execute: function () {
+ FieldSet = (function (_Component) {
+ babelHelpers.inherits(FieldSet, _Component);
+
+ function FieldSet() {
+ babelHelpers.classCallCheck(this, FieldSet);
+ babelHelpers.get(Object.getPrototypeOf(FieldSet.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(FieldSet, [{
+ key: 'view',
+ value: function view() {
+ return m(
+ 'fieldset',
+ { className: this.props.className },
+ m(
+ 'legend',
+ null,
+ this.props.label
+ ),
+ m(
+ 'ul',
+ null,
+ listItems(this.props.children)
+ )
+ );
+ }
+ }]);
+ return FieldSet;
+ })(Component);
+
+ _export('default', FieldSet);
+ }
+ };
+});;
+System.register('flarum/components/GroupBadge', ['flarum/components/Badge'], function (_export) {
+ 'use strict';
+
+ var Badge, GroupBadge;
+ return {
+ setters: [function (_flarumComponentsBadge) {
+ Badge = _flarumComponentsBadge['default'];
+ }],
+ execute: function () {
+ GroupBadge = (function (_Badge) {
+ babelHelpers.inherits(GroupBadge, _Badge);
+
+ function GroupBadge() {
+ babelHelpers.classCallCheck(this, GroupBadge);
+ babelHelpers.get(Object.getPrototypeOf(GroupBadge.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(GroupBadge, null, [{
+ key: 'initProps',
+ value: function initProps(props) {
+ babelHelpers.get(Object.getPrototypeOf(GroupBadge), 'initProps', this).call(this, props);
+
+ if (props.group) {
+ props.icon = props.group.icon();
+ props.style = { backgroundColor: props.group.color() };
+ props.label = typeof props.label === 'undefined' ? props.group.nameSingular() : props.label;
+ props.type = 'group--' + props.group.nameSingular();
+
+ delete props.group;
+ }
+ }
+ }]);
+ return GroupBadge;
+ })(Badge);
+
+ _export('default', GroupBadge);
+ }
+ };
+});;
System.register('flarum/components/HeaderPrimary', ['flarum/Component', 'flarum/utils/ItemList', 'flarum/helpers/listItems'], function (_export) {
/**
@@ -17113,6 +18439,127 @@ System.register('flarum/components/HeaderSecondary', ['flarum/Component', 'flaru
}
};
});;
+System.register('flarum/components/LinkButton', ['flarum/components/Button'], function (_export) {
+
+ /**
+ * The `LinkButton` component defines a `Button` which links to a route.
+ *
+ * ### Props
+ *
+ * All of the props accepted by `Button`, plus:
+ *
+ * - `active` Whether or not the page that this button links to is currently
+ * active.
+ * - `href` The URL to link to. If the current URL `m.route()` matches this,
+ * the `active` prop will automatically be set to true.
+ */
+ 'use strict';
+
+ var Button, LinkButton;
+ return {
+ setters: [function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }],
+ execute: function () {
+ LinkButton = (function (_Button) {
+ babelHelpers.inherits(LinkButton, _Button);
+
+ function LinkButton() {
+ babelHelpers.classCallCheck(this, LinkButton);
+ babelHelpers.get(Object.getPrototypeOf(LinkButton.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(LinkButton, [{
+ key: 'view',
+ value: function view() {
+ var vdom = babelHelpers.get(Object.getPrototypeOf(LinkButton.prototype), 'view', this).call(this);
+
+ vdom.tag = 'a';
+
+ return vdom;
+ }
+
+ /**
+ * Determine whether a component with the given props is 'active'.
+ *
+ * @param {Object} props
+ * @return {Boolean}
+ */
+ }], [{
+ key: 'initProps',
+ value: function initProps(props) {
+ props.active = this.isActive(props);
+ props.config = props.config || m.route;
+ }
+ }, {
+ key: 'isActive',
+ value: function isActive(props) {
+ return typeof props.active !== 'undefined' ? props.active : m.route() === props.href;
+ }
+ }]);
+ return LinkButton;
+ })(Button);
+
+ _export('default', LinkButton);
+ }
+ };
+});;
+System.register('flarum/components/LoadingIndicator', ['flarum/Component'], function (_export) {
+
+ /**
+ * The `LoadingIndicator` component displays a loading spinner with spin.js. It
+ * may have the following special props:
+ *
+ * - `size` The spin.js size preset to use. Defaults to 'small'.
+ *
+ * All other props will be assigned as attributes on the element.
+ */
+ 'use strict';
+
+ var Component, LoadingIndicator;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }],
+ execute: function () {
+ LoadingIndicator = (function (_Component) {
+ babelHelpers.inherits(LoadingIndicator, _Component);
+
+ function LoadingIndicator() {
+ babelHelpers.classCallCheck(this, LoadingIndicator);
+ babelHelpers.get(Object.getPrototypeOf(LoadingIndicator.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(LoadingIndicator, [{
+ key: 'view',
+ value: function view() {
+ var attrs = babelHelpers._extends({}, this.props);
+
+ attrs.className = 'LoadingIndicator ' + (attrs.className || '');
+ delete attrs.size;
+
+ return m(
+ 'div',
+ attrs,
+ m.trust(' ')
+ );
+ }
+ }, {
+ key: 'config',
+ value: function config() {
+ var size = this.props.size || 'small';
+
+ $.fn.spin.presets[size].zIndex = 'auto';
+ this.$().spin(size);
+ }
+ }]);
+ return LoadingIndicator;
+ })(Component);
+
+ _export('default', LoadingIndicator);
+ }
+ };
+});;
System.register('flarum/components/LoadingModal', ['flarum/components/Modal'], function (_export) {
'use strict';
@@ -17158,6 +18605,464 @@ System.register('flarum/components/LoadingModal', ['flarum/components/Modal'], f
}
};
});;
+System.register('flarum/components/Modal', ['flarum/Component', 'flarum/components/Alert', 'flarum/components/Button'], function (_export) {
+
+ /**
+ * The `Modal` component displays a modal dialog, wrapped in a form. Subclasses
+ * should implement the `className`, `title`, and `content` methods.
+ *
+ * @abstract
+ */
+ 'use strict';
+
+ var Component, Alert, Button, Modal;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsAlert) {
+ Alert = _flarumComponentsAlert['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }],
+ execute: function () {
+ Modal = (function (_Component) {
+ babelHelpers.inherits(Modal, _Component);
+
+ function Modal() {
+ babelHelpers.classCallCheck(this, Modal);
+ babelHelpers.get(Object.getPrototypeOf(Modal.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Modal, [{
+ key: 'init',
+ value: function init() {
+ /**
+ * An alert component to show below the header.
+ *
+ * @type {Alert}
+ */
+ this.alert = null;
+ }
+ }, {
+ key: 'view',
+ value: function view() {
+ if (this.alert) {
+ this.alert.props.dismissible = false;
+ }
+
+ return m(
+ 'div',
+ { className: 'Modal modal-dialog ' + this.className() },
+ m(
+ 'div',
+ { className: 'Modal-content' },
+ this.isDismissible() ? m(
+ 'div',
+ { className: 'Modal-close App-backControl' },
+ Button.component({
+ icon: 'times',
+ onclick: this.hide.bind(this),
+ className: 'Button Button--icon Button--link'
+ })
+ ) : '',
+ m(
+ 'form',
+ { onsubmit: this.onsubmit.bind(this) },
+ m(
+ 'div',
+ { className: 'Modal-header' },
+ m(
+ 'h3',
+ { className: 'App-titleControl App-titleControl--text' },
+ this.title()
+ )
+ ),
+ alert ? m(
+ 'div',
+ { className: 'Modal-alert' },
+ this.alert
+ ) : '',
+ this.content()
+ )
+ )
+ );
+ }
+
+ /**
+ * Determine whether or not the modal should be dismissible via an 'x' button.
+ *
+ * @return {Boolean}
+ */
+ }, {
+ key: 'isDismissible',
+ value: function isDismissible() {
+ return true;
+ }
+
+ /**
+ * Get the class name to apply to the modal.
+ *
+ * @return {String}
+ * @abstract
+ */
+ }, {
+ key: 'className',
+ value: function className() {}
+
+ /**
+ * Get the title of the modal dialog.
+ *
+ * @return {String}
+ * @abstract
+ */
+ }, {
+ key: 'title',
+ value: function title() {}
+
+ /**
+ * Get the content of the modal.
+ *
+ * @return {VirtualElement}
+ * @abstract
+ */
+ }, {
+ key: 'content',
+ value: function content() {}
+
+ /**
+ * Handle the modal form's submit event.
+ *
+ * @param {Event} e
+ */
+ }, {
+ key: 'onsubmit',
+ value: function onsubmit() {}
+
+ /**
+ * Focus on the first input when the modal is ready to be used.
+ */
+ }, {
+ key: 'onready',
+ value: function onready() {
+ this.$('form :input:first').focus().select();
+ }
+
+ /**
+ * Hide the modal.
+ */
+ }, {
+ key: 'hide',
+ value: function hide() {
+ app.modal.close();
+ }
+
+ /**
+ * Stop loading.
+ */
+ }, {
+ key: 'loaded',
+ value: function loaded() {
+ this.loading = false;
+ m.redraw();
+ }
+
+ /**
+ * Show an alert describing an error returned from the API, and give focus to
+ * the first relevant field.
+ *
+ * @param {RequestError} error
+ */
+ }, {
+ key: 'onerror',
+ value: function onerror(error) {
+ this.alert = error.alert;
+
+ m.redraw();
+
+ if (error.status === 422 && error.response.errors) {
+ this.$('form [name=' + error.response.errors[0].source.pointer.replace('/data/attributes/', '') + ']').select();
+ } else {
+ this.onready();
+ }
+ }
+ }]);
+ return Modal;
+ })(Component);
+
+ _export('default', Modal);
+ }
+ };
+});;
+System.register('flarum/components/ModalManager', ['flarum/Component', 'flarum/components/Modal'], function (_export) {
+
+ /**
+ * The `ModalManager` component manages a modal dialog. Only one modal dialog
+ * can be shown at once; loading a new component into the ModalManager will
+ * overwrite the previous one.
+ */
+ 'use strict';
+
+ var Component, Modal, ModalManager;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsModal) {
+ Modal = _flarumComponentsModal['default'];
+ }],
+ execute: function () {
+ ModalManager = (function (_Component) {
+ babelHelpers.inherits(ModalManager, _Component);
+
+ function ModalManager() {
+ babelHelpers.classCallCheck(this, ModalManager);
+ babelHelpers.get(Object.getPrototypeOf(ModalManager.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(ModalManager, [{
+ key: 'init',
+ value: function init() {
+ this.showing = false;
+ this.component = null;
+ }
+ }, {
+ key: 'view',
+ value: function view() {
+ return m(
+ 'div',
+ { className: 'ModalManager modal fade' },
+ this.component && this.component.render()
+ );
+ }
+ }, {
+ key: 'config',
+ value: function config(isInitialized, context) {
+ if (isInitialized) return;
+
+ context.retain = true;
+
+ this.$().on('hidden.bs.modal', this.clear.bind(this)).on('shown.bs.modal', this.onready.bind(this));
+ }
+
+ /**
+ * Show a modal dialog.
+ *
+ * @param {Modal} component
+ * @public
+ */
+ }, {
+ key: 'show',
+ value: function show(component) {
+ if (!(component instanceof Modal)) {
+ throw new Error('The ModalManager component can only show Modal components');
+ }
+
+ clearTimeout(this.hideTimeout);
+
+ this.showing = true;
+ this.component = component;
+
+ m.redraw(true);
+
+ this.$().modal({ backdrop: this.component.isDismissible() ? true : 'static' }).modal('show');
+ this.onready();
+ }
+
+ /**
+ * Close the modal dialog.
+ *
+ * @public
+ */
+ }, {
+ key: 'close',
+ value: function close() {
+ var _this = this;
+
+ if (!this.showing) return;
+
+ // Don't hide the modal immediately, because if the consumer happens to call
+ // the `show` method straight after to show another modal dialog, it will
+ // cause Bootstrap's modal JS to misbehave. Instead we will wait for a tiny
+ // bit to give the `show` method the opportunity to prevent this from going
+ // ahead.
+ this.hideTimeout = setTimeout(function () {
+ _this.$().modal('hide');
+ _this.showing = false;
+ });
+ }
+
+ /**
+ * Clear content from the modal area.
+ *
+ * @protected
+ */
+ }, {
+ key: 'clear',
+ value: function clear() {
+ this.component = null;
+
+ m.lazyRedraw();
+ }
+
+ /**
+ * When the modal dialog is ready to be used, tell it!
+ *
+ * @protected
+ */
+ }, {
+ key: 'onready',
+ value: function onready() {
+ if (this.component && this.component.onready) {
+ this.component.onready(this.$());
+ }
+ }
+ }]);
+ return ModalManager;
+ })(Component);
+
+ _export('default', ModalManager);
+ }
+ };
+});;
+System.register('flarum/components/Navigation', ['flarum/Component', 'flarum/components/Button', 'flarum/components/LinkButton'], function (_export) {
+
+ /**
+ * The `Navigation` component displays a set of navigation buttons. Typically
+ * this is just a back button which pops the app's History. If the user is on
+ * the root page and there is no history to pop, then in some instances it may
+ * show a button that toggles the app's drawer.
+ *
+ * If the app has a pane, it will also include a 'pin' button which toggles the
+ * pinned state of the pane.
+ *
+ * Accepts the following props:
+ *
+ * - `className` The name of a class to set on the root element.
+ * - `drawer` Whether or not to show a button to toggle the app's drawer if
+ * there is no more history to pop.
+ */
+ 'use strict';
+
+ var Component, Button, LinkButton, Navigation;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumComponentsLinkButton) {
+ LinkButton = _flarumComponentsLinkButton['default'];
+ }],
+ execute: function () {
+ Navigation = (function (_Component) {
+ babelHelpers.inherits(Navigation, _Component);
+
+ function Navigation() {
+ babelHelpers.classCallCheck(this, Navigation);
+ babelHelpers.get(Object.getPrototypeOf(Navigation.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Navigation, [{
+ key: 'view',
+ value: function view() {
+ var _app = app;
+ var history = _app.history;
+ var pane = _app.pane;
+
+ return m(
+ 'div',
+ { className: 'Navigation ButtonGroup ' + (this.props.className || ''),
+ onmouseenter: pane && pane.show.bind(pane),
+ onmouseleave: pane && pane.onmouseleave.bind(pane) },
+ history.canGoBack() ? [this.getBackButton(), this.getPaneButton()] : this.getDrawerButton()
+ );
+ }
+ }, {
+ key: 'config',
+ value: function config(isInitialized, context) {
+ // Since this component is 'above' the content of the page (that is, it is a
+ // part of the global UI that persists between routes), we will flag the DOM
+ // to be retained across route changes.
+ context.retain = true;
+ }
+
+ /**
+ * Get the back button.
+ *
+ * @return {Object}
+ * @protected
+ */
+ }, {
+ key: 'getBackButton',
+ value: function getBackButton() {
+ var _app2 = app;
+ var history = _app2.history;
+
+ return LinkButton.component({
+ className: 'Button Button--icon Navigation-back',
+ href: history.backUrl(),
+ icon: 'chevron-left',
+ config: function config() {},
+ onclick: function onclick(e) {
+ if (e.shiftKey || e.ctrlKey || e.metaKey || e.which === 2) return;
+ e.preventDefault();
+ history.back();
+ }
+ });
+ }
+
+ /**
+ * Get the pane pinned toggle button.
+ *
+ * @return {Object|String}
+ * @protected
+ */
+ }, {
+ key: 'getPaneButton',
+ value: function getPaneButton() {
+ var _app3 = app;
+ var pane = _app3.pane;
+
+ if (!pane || !pane.active) return '';
+
+ return Button.component({
+ className: 'Button Button--icon Navigation-pin' + (pane.pinned ? ' active' : ''),
+ onclick: pane.togglePinned.bind(pane),
+ icon: 'thumb-tack'
+ });
+ }
+
+ /**
+ * Get the drawer toggle button.
+ *
+ * @return {Object|String}
+ * @protected
+ */
+ }, {
+ key: 'getDrawerButton',
+ value: function getDrawerButton() {
+ if (!this.props.drawer) return '';
+
+ var _app4 = app;
+ var drawer = _app4.drawer;
+
+ var user = app.session.user;
+
+ return Button.component({
+ className: 'Button Button--icon Navigation-drawer' + (user && user.newNotificationsCount() ? ' new' : ''),
+ onclick: function onclick(e) {
+ e.stopPropagation();
+ drawer.show();
+ },
+ icon: 'reorder'
+ });
+ }
+ }]);
+ return Navigation;
+ })(Component);
+
+ _export('default', Navigation);
+ }
+ };
+});;
System.register('flarum/components/PermissionDropdown', ['flarum/components/Dropdown', 'flarum/components/Button', 'flarum/components/Separator', 'flarum/models/Group', 'flarum/components/GroupBadge'], function (_export) {
'use strict';
@@ -17677,6 +19582,274 @@ System.register('flarum/components/PermissionsPage', ['flarum/Component', 'flaru
}
};
});;
+System.register("flarum/components/Placeholder", ["flarum/Component"], function (_export) {
+
+ /**
+ * The `Placeholder` component displays a muted text with some call to action,
+ * usually used as an empty state.
+ *
+ * ### Props
+ *
+ * - `text`
+ */
+ "use strict";
+
+ var Component, Placeholder;
+ return {
+ setters: [function (_flarumComponent) {
+ Component = _flarumComponent["default"];
+ }],
+ execute: function () {
+ Placeholder = (function (_Component) {
+ babelHelpers.inherits(Placeholder, _Component);
+
+ function Placeholder() {
+ babelHelpers.classCallCheck(this, Placeholder);
+ babelHelpers.get(Object.getPrototypeOf(Placeholder.prototype), "constructor", this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(Placeholder, [{
+ key: "view",
+ value: function view() {
+ return m(
+ "div",
+ { className: "Placeholder" },
+ m(
+ "p",
+ null,
+ this.props.text
+ )
+ );
+ }
+ }]);
+ return Placeholder;
+ })(Component);
+
+ _export("default", Placeholder);
+ }
+ };
+});;
+System.register('flarum/components/RequestErrorModal', ['flarum/components/Modal'], function (_export) {
+ 'use strict';
+
+ var Modal, RequestErrorModal;
+ return {
+ setters: [function (_flarumComponentsModal) {
+ Modal = _flarumComponentsModal['default'];
+ }],
+ execute: function () {
+ RequestErrorModal = (function (_Modal) {
+ babelHelpers.inherits(RequestErrorModal, _Modal);
+
+ function RequestErrorModal() {
+ babelHelpers.classCallCheck(this, RequestErrorModal);
+ babelHelpers.get(Object.getPrototypeOf(RequestErrorModal.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(RequestErrorModal, [{
+ key: 'className',
+ value: function className() {
+ return 'RequestErrorModal Modal--large';
+ }
+ }, {
+ key: 'title',
+ value: function title() {
+ return this.props.error.xhr ? this.props.error.xhr.status + ' ' + this.props.error.xhr.statusText : '';
+ }
+ }, {
+ key: 'content',
+ value: function content() {
+ var responseText = undefined;
+
+ try {
+ responseText = JSON.stringify(JSON.parse(this.props.error.responseText), null, 2);
+ } catch (e) {
+ responseText = this.props.error.responseText;
+ }
+
+ return m(
+ 'div',
+ { className: 'Modal-body' },
+ m(
+ 'pre',
+ null,
+ this.props.error.options.method,
+ ' ',
+ this.props.error.options.url,
+ m('br', null),
+ m('br', null),
+ responseText
+ )
+ );
+ }
+ }]);
+ return RequestErrorModal;
+ })(Modal);
+
+ _export('default', RequestErrorModal);
+ }
+ };
+});;
+System.register('flarum/components/Select', ['flarum/Component', 'flarum/helpers/icon'], function (_export) {
+
+ /**
+ * The `Select` component displays a
' : '';
+ }),
+ preferences: Model.attribute('preferences'),
+ groups: Model.hasMany('groups'),
+
+ joinTime: Model.attribute('joinTime', Model.transformDate),
+ lastSeenTime: Model.attribute('lastSeenTime', Model.transformDate),
+ readTime: Model.attribute('readTime', Model.transformDate),
+ unreadNotificationsCount: Model.attribute('unreadNotificationsCount'),
+ newNotificationsCount: Model.attribute('newNotificationsCount'),
+
+ discussionsCount: Model.attribute('discussionsCount'),
+ commentsCount: Model.attribute('commentsCount'),
+
+ canEdit: Model.attribute('canEdit'),
+ canDelete: Model.attribute('canDelete'),
+
+ avatarColor: null,
+ color: computed('username', 'avatarUrl', 'avatarColor', function (username, avatarUrl, avatarColor) {
+ // If we've already calculated and cached the dominant color of the user's
+ // avatar, then we can return that in RGB format. If we haven't, we'll want
+ // to calculate it. Unless the user doesn't have an avatar, in which case
+ // we generate a color from their username.
+ if (avatarColor) {
+ return 'rgb(' + avatarColor.join(', ') + ')';
+ } else if (avatarUrl) {
+ this.calculateAvatarColor();
+ return '';
+ }
+
+ return '#' + stringToColor(username);
+ }),
+
+ /**
+ * Check whether or not the user has been seen in the last 5 minutes.
+ *
+ * @return {Boolean}
+ * @public
+ */
+ isOnline: function isOnline() {
+ return this.lastSeenTime() > moment().subtract(5, 'minutes').toDate();
+ },
+
+ /**
+ * Get the Badge components that apply to this user.
+ *
+ * @return {ItemList}
+ */
+ badges: function badges() {
+ var items = new ItemList();
+ var groups = this.groups();
+
+ if (groups) {
+ groups.forEach(function (group) {
+ items.add('group' + group.id(), GroupBadge.component({ group: group }));
+ });
+ }
+
+ return items;
+ },
+
+ /**
+ * Calculate the dominant color of the user's avatar. The dominant color will
+ * be set to the `avatarColor` property once it has been calculated.
+ *
+ * @protected
+ */
+ calculateAvatarColor: function calculateAvatarColor() {
+ var image = new Image();
+ var user = this;
+
+ image.onload = function () {
+ var colorThief = new ColorThief();
+ user.avatarColor = colorThief.getColor(this);
+ user.freshness = new Date();
+ m.redraw();
+ };
+ image.src = this.avatarUrl();
+ },
+
+ /**
+ * Update the user's preferences.
+ *
+ * @param {Object} newPreferences
+ * @return {Promise}
+ */
+ savePreferences: function savePreferences(newPreferences) {
+ var preferences = this.preferences();
+
+ babelHelpers._extends(preferences, newPreferences);
+
+ return this.save({ preferences: preferences });
+ }
+ });
+
+ _export('default', User);
+ }
+ };
+});;
System.register('flarum/Session', [], function (_export) {
/**
* The `Session` class defines the current user session. It stores a reference
@@ -19669,3051 +22282,6 @@ System.register('flarum/Translator', ['flarum/models/User', 'flarum/helpers/user
}
};
});;
-System.register("flarum/extend", [], function (_export) {
- /**
- * Extend an object's method by running its output through a mutating callback
- * every time it is called.
- *
- * The callback accepts the method's return value and should perform any
- * mutations directly on this value. For this reason, this function will not be
- * effective on methods which return scalar values (numbers, strings, booleans).
- *
- * Care should be taken to extend the correct object – in most cases, a class'
- * prototype will be the desired target of extension, not the class itself.
- *
- * @example
- * extend(Discussion.prototype, 'badges', function(badges) {
- * // do something with `badges`
- * });
- *
- * @param {Object} object The object that owns the method
- * @param {String} method The name of the method to extend
- * @param {function} callback A callback which mutates the method's output
- */
- "use strict";
-
- /**
- * Override an object's method by replacing it with a new function, so that the
- * new function will be run every time the object's method is called.
- *
- * The replacement function accepts the original method as its first argument,
- * which is like a call to 'super'. Any arguments passed to the original method
- * are also passed to the replacement.
- *
- * Care should be taken to extend the correct object – in most cases, a class'
- * prototype will be the desired target of extension, not the class itself.
- *
- * @example
- * override(Discussion.prototype, 'badges', function(original) {
- * const badges = original();
- * // do something with badges
- * return badges;
- * });
- *
- * @param {Object} object The object that owns the method
- * @param {String} method The name of the method to override
- * @param {function} newMethod The method to replace it with
- */
-
- _export("extend", extend);
-
- _export("override", override);
-
- function extend(object, method, callback) {
- var original = object[method];
-
- object[method] = function () {
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
-
- var value = original ? original.apply(this, args) : undefined;
-
- callback.apply(this, [value].concat(args));
-
- return value;
- };
-
- babelHelpers._extends(object[method], original);
- }
-
- function override(object, method, newMethod) {
- var original = object[method];
-
- object[method] = function () {
- for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
- args[_key2] = arguments[_key2];
- }
-
- return newMethod.apply(this, [original.bind(this)].concat(args));
- };
-
- babelHelpers._extends(object[method], original);
- }
-
- return {
- setters: [],
- execute: function () {}
- };
-});;
-System.register('flarum/components/Alert', ['flarum/Component', 'flarum/components/Button', 'flarum/helpers/listItems', 'flarum/utils/extract'], function (_export) {
-
- /**
- * The `Alert` component represents an alert box, which contains a message,
- * some controls, and may be dismissible.
- *
- * The alert may have the following special props:
- *
- * - `type` The type of alert this is. Will be used to give the alert a class
- * name of `Alert--{type}`.
- * - `controls` An array of controls to show in the alert.
- * - `dismissible` Whether or not the alert can be dismissed.
- * - `ondismiss` A callback to run when the alert is dismissed.
- *
- * All other props will be assigned as attributes on the alert element.
- */
- 'use strict';
-
- var Component, Button, listItems, extract, Alert;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumComponentsButton) {
- Button = _flarumComponentsButton['default'];
- }, function (_flarumHelpersListItems) {
- listItems = _flarumHelpersListItems['default'];
- }, function (_flarumUtilsExtract) {
- extract = _flarumUtilsExtract['default'];
- }],
- execute: function () {
- Alert = (function (_Component) {
- babelHelpers.inherits(Alert, _Component);
-
- function Alert() {
- babelHelpers.classCallCheck(this, Alert);
- babelHelpers.get(Object.getPrototypeOf(Alert.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Alert, [{
- key: 'view',
- value: function view() {
- var attrs = babelHelpers._extends({}, this.props);
-
- var type = extract(attrs, 'type');
- attrs.className = 'Alert Alert--' + type + ' ' + (attrs.className || '');
-
- var children = extract(attrs, 'children');
- var controls = extract(attrs, 'controls') || [];
-
- // If the alert is meant to be dismissible (which is the case by default),
- // then we will create a dismiss button to append as the final control in
- // the alert.
- var dismissible = extract(attrs, 'dismissible');
- var ondismiss = extract(attrs, 'ondismiss');
- var dismissControl = [];
-
- if (dismissible || dismissible === undefined) {
- dismissControl.push(m(Button, {
- icon: 'times',
- className: 'Button Button--link Button--icon Alert-dismiss',
- onclick: ondismiss }));
- }
-
- return m(
- 'div',
- attrs,
- m(
- 'span',
- { className: 'Alert-body' },
- children
- ),
- m(
- 'ul',
- { className: 'Alert-controls' },
- listItems(controls.concat(dismissControl))
- )
- );
- }
- }]);
- return Alert;
- })(Component);
-
- _export('default', Alert);
- }
- };
-});;
-System.register('flarum/components/AlertManager', ['flarum/Component', 'flarum/components/Alert'], function (_export) {
-
- /**
- * The `AlertManager` component provides an area in which `Alert` components can
- * be shown and dismissed.
- */
- 'use strict';
-
- var Component, Alert, AlertManager;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumComponentsAlert) {
- Alert = _flarumComponentsAlert['default'];
- }],
- execute: function () {
- AlertManager = (function (_Component) {
- babelHelpers.inherits(AlertManager, _Component);
-
- function AlertManager() {
- babelHelpers.classCallCheck(this, AlertManager);
- babelHelpers.get(Object.getPrototypeOf(AlertManager.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(AlertManager, [{
- key: 'init',
- value: function init() {
- /**
- * An array of Alert components which are currently showing.
- *
- * @type {Alert[]}
- * @protected
- */
- this.components = [];
- }
- }, {
- key: 'view',
- value: function view() {
- return m(
- 'div',
- { className: 'AlertManager' },
- this.components.map(function (component) {
- return m(
- 'div',
- { className: 'AlertManager-alert' },
- component
- );
- })
- );
- }
-
- /**
- * Show an Alert in the alerts area.
- *
- * @param {Alert} component
- * @public
- */
- }, {
- key: 'show',
- value: function show(component) {
- if (!(component instanceof Alert)) {
- throw new Error('The AlertManager component can only show Alert components');
- }
-
- component.props.ondismiss = this.dismiss.bind(this, component);
-
- this.components.push(component);
- m.redraw();
- }
-
- /**
- * Dismiss an alert.
- *
- * @param {Alert} component
- * @public
- */
- }, {
- key: 'dismiss',
- value: function dismiss(component) {
- var index = this.components.indexOf(component);
-
- if (index !== -1) {
- this.components.splice(index, 1);
- m.redraw();
- }
- }
-
- /**
- * Clear all alerts.
- *
- * @public
- */
- }, {
- key: 'clear',
- value: function clear() {
- this.components = [];
- m.redraw();
- }
- }]);
- return AlertManager;
- })(Component);
-
- _export('default', AlertManager);
- }
- };
-});;
-System.register('flarum/components/Badge', ['flarum/Component', 'flarum/helpers/icon', 'flarum/utils/extract'], function (_export) {
-
- /**
- * The `Badge` component represents a user/discussion badge, indicating some
- * status (e.g. a discussion is stickied, a user is an admin).
- *
- * A badge may have the following special props:
- *
- * - `type` The type of badge this is. This will be used to give the badge a
- * class name of `Badge--{type}`.
- * - `icon` The name of an icon to show inside the badge.
- * - `label`
- *
- * All other props will be assigned as attributes on the badge element.
- */
- 'use strict';
-
- var Component, icon, extract, Badge;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumHelpersIcon) {
- icon = _flarumHelpersIcon['default'];
- }, function (_flarumUtilsExtract) {
- extract = _flarumUtilsExtract['default'];
- }],
- execute: function () {
- Badge = (function (_Component) {
- babelHelpers.inherits(Badge, _Component);
-
- function Badge() {
- babelHelpers.classCallCheck(this, Badge);
- babelHelpers.get(Object.getPrototypeOf(Badge.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Badge, [{
- key: 'view',
- value: function view() {
- var attrs = babelHelpers._extends({}, this.props);
- var type = extract(attrs, 'type');
- var iconName = extract(attrs, 'icon');
-
- attrs.className = 'Badge ' + (type ? 'Badge--' + type : '') + ' ' + (attrs.className || '');
- attrs.title = extract(attrs, 'label') || '';
-
- // Give the badge a unique key so that when badges are displayed together,
- // and then one is added/removed, Mithril will correctly redraw the series
- // of badges.
- attrs.key = attrs.type;
-
- return m(
- 'span',
- attrs,
- iconName ? icon(iconName, { className: 'Badge-icon' }) : m.trust(' ')
- );
- }
- }, {
- key: 'config',
- value: function config(isInitialized) {
- if (isInitialized) return;
-
- if (this.props.label) this.$().tooltip({ container: 'body' });
- }
- }]);
- return Badge;
- })(Component);
-
- _export('default', Badge);
- }
- };
-});;
-System.register('flarum/components/Button', ['flarum/Component', 'flarum/helpers/icon', 'flarum/utils/extract', 'flarum/components/LoadingIndicator'], function (_export) {
-
- /**
- * The `Button` component defines an element which, when clicked, performs an
- * action. The button may have the following special props:
- *
- * - `icon` The name of the icon class. If specified, the button will be given a
- * 'has-icon' class name.
- * - `disabled` Whether or not the button is disabled. If truthy, the button
- * will be given a 'disabled' class name, and any `onclick` handler will be
- * removed.
- * - `loading` Whether or not the button should be in a disabled loading state.
- *
- * All other props will be assigned as attributes on the button element.
- *
- * Note that a Button has no default class names. This is because a Button can
- * be used to represent any generic clickable control, like a menu item.
- */
- 'use strict';
-
- var Component, icon, extract, LoadingIndicator, Button;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumHelpersIcon) {
- icon = _flarumHelpersIcon['default'];
- }, function (_flarumUtilsExtract) {
- extract = _flarumUtilsExtract['default'];
- }, function (_flarumComponentsLoadingIndicator) {
- LoadingIndicator = _flarumComponentsLoadingIndicator['default'];
- }],
- execute: function () {
- Button = (function (_Component) {
- babelHelpers.inherits(Button, _Component);
-
- function Button() {
- babelHelpers.classCallCheck(this, Button);
- babelHelpers.get(Object.getPrototypeOf(Button.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Button, [{
- key: 'view',
- value: function view() {
- var attrs = babelHelpers._extends({}, this.props);
-
- delete attrs.children;
-
- attrs.className = attrs.className || '';
- attrs.type = attrs.type || 'button';
-
- var iconName = extract(attrs, 'icon');
- if (iconName) attrs.className += ' hasIcon';
-
- var loading = extract(attrs, 'loading');
- if (attrs.disabled || loading) {
- attrs.className += ' disabled' + (loading ? ' loading' : '');
- delete attrs.onclick;
- }
-
- return m(
- 'button',
- attrs,
- this.getButtonContent()
- );
- }
-
- /**
- * Get the template for the button's content.
- *
- * @return {*}
- * @protected
- */
- }, {
- key: 'getButtonContent',
- value: function getButtonContent() {
- var iconName = this.props.icon;
-
- return [iconName && iconName !== true ? icon(iconName, { className: 'Button-icon' }) : '', this.props.children ? m(
- 'span',
- { className: 'Button-label' },
- this.props.children
- ) : '', this.props.loading ? LoadingIndicator.component({ size: 'tiny', className: 'LoadingIndicator--inline' }) : ''];
- }
- }]);
- return Button;
- })(Component);
-
- _export('default', Button);
- }
- };
-});;
-System.register('flarum/components/Checkbox', ['flarum/Component', 'flarum/components/LoadingIndicator', 'flarum/helpers/icon'], function (_export) {
-
- /**
- * The `Checkbox` component defines a checkbox input.
- *
- * ### Props
- *
- * - `state` Whether or not the checkbox is checked.
- * - `className` The class name for the root element.
- * - `disabled` Whether or not the checkbox is disabled.
- * - `onchange` A callback to run when the checkbox is checked/unchecked.
- * - `children` A text label to display next to the checkbox.
- */
- 'use strict';
-
- var Component, LoadingIndicator, icon, Checkbox;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumComponentsLoadingIndicator) {
- LoadingIndicator = _flarumComponentsLoadingIndicator['default'];
- }, function (_flarumHelpersIcon) {
- icon = _flarumHelpersIcon['default'];
- }],
- execute: function () {
- Checkbox = (function (_Component) {
- babelHelpers.inherits(Checkbox, _Component);
-
- function Checkbox() {
- babelHelpers.classCallCheck(this, Checkbox);
- babelHelpers.get(Object.getPrototypeOf(Checkbox.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Checkbox, [{
- key: 'init',
- value: function init() {
- /**
- * Whether or not the checkbox's value is in the process of being saved.
- *
- * @type {Boolean}
- * @public
- */
- this.loading = false;
- }
- }, {
- key: 'view',
- value: function view() {
- var className = 'Checkbox ' + (this.props.state ? 'on' : 'off') + ' ' + (this.props.className || '');
- if (this.loading) className += ' loading';
- if (this.props.disabled) className += ' disabled';
-
- return m(
- 'label',
- { className: className },
- m('input', { type: 'checkbox',
- checked: this.props.state,
- disabled: this.props.disabled,
- onchange: m.withAttr('checked', this.onchange.bind(this)) }),
- m(
- 'div',
- { className: 'Checkbox-display' },
- this.getDisplay()
- ),
- this.props.children
- );
- }
-
- /**
- * Get the template for the checkbox's display (tick/cross icon).
- *
- * @return {*}
- * @protected
- */
- }, {
- key: 'getDisplay',
- value: function getDisplay() {
- return this.loading ? LoadingIndicator.component({ size: 'tiny' }) : icon(this.props.state ? 'check' : 'times');
- }
-
- /**
- * Run a callback when the state of the checkbox is changed.
- *
- * @param {Boolean} checked
- * @protected
- */
- }, {
- key: 'onchange',
- value: function onchange(checked) {
- if (this.props.onchange) this.props.onchange(checked, this);
- }
- }]);
- return Checkbox;
- })(Component);
-
- _export('default', Checkbox);
- }
- };
-});;
-System.register('flarum/components/Dropdown', ['flarum/Component', 'flarum/helpers/icon', 'flarum/helpers/listItems'], function (_export) {
-
- /**
- * The `Dropdown` component displays a button which, when clicked, shows a
- * dropdown menu beneath it.
- *
- * ### Props
- *
- * - `buttonClassName` A class name to apply to the dropdown toggle button.
- * - `menuClassName` A class name to apply to the dropdown menu.
- * - `icon` The name of an icon to show in the dropdown toggle button.
- * - `caretIcon` The name of an icon to show on the right of the button.
- * - `label` The label of the dropdown toggle button. Defaults to 'Controls'.
- * - `onhide`
- * - `onshow`
- *
- * The children will be displayed as a list inside of the dropdown menu.
- */
- 'use strict';
-
- var Component, icon, listItems, Dropdown;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumHelpersIcon) {
- icon = _flarumHelpersIcon['default'];
- }, function (_flarumHelpersListItems) {
- listItems = _flarumHelpersListItems['default'];
- }],
- execute: function () {
- Dropdown = (function (_Component) {
- babelHelpers.inherits(Dropdown, _Component);
-
- function Dropdown() {
- babelHelpers.classCallCheck(this, Dropdown);
- babelHelpers.get(Object.getPrototypeOf(Dropdown.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Dropdown, [{
- key: 'view',
- value: function view() {
- var items = this.props.children ? listItems(this.props.children) : [];
-
- return m(
- 'div',
- { className: 'ButtonGroup Dropdown dropdown ' + this.props.className + ' itemCount' + items.length },
- this.getButton(),
- this.getMenu(items)
- );
- }
- }, {
- key: 'config',
- value: function config(isInitialized) {
- var _this = this;
-
- if (isInitialized) return;
-
- // When opening the dropdown menu, work out if the menu goes beyond the
- // bottom of the viewport. If it does, we will apply class to make it show
- // above the toggle button instead of below it.
- this.$().on('shown.bs.dropdown', function () {
- var $menu = _this.$('.Dropdown-menu').removeClass('Dropdown-menu--top');
-
- $menu.toggleClass('Dropdown-menu--top', $menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height());
-
- if (_this.props.onshow) {
- _this.props.onshow();
- m.redraw();
- }
- });
-
- this.$().on('hidden.bs.dropdown', function () {
- if (_this.props.onhide) {
- _this.props.onhide();
- m.redraw();
- }
- });
- }
-
- /**
- * Get the template for the button.
- *
- * @return {*}
- * @protected
- */
- }, {
- key: 'getButton',
- value: function getButton() {
- return m(
- 'button',
- {
- className: 'Dropdown-toggle ' + this.props.buttonClassName,
- 'data-toggle': 'dropdown',
- onclick: this.props.onclick },
- this.getButtonContent()
- );
- }
-
- /**
- * Get the template for the button's content.
- *
- * @return {*}
- * @protected
- */
- }, {
- key: 'getButtonContent',
- value: function getButtonContent() {
- return [this.props.icon ? icon(this.props.icon, { className: 'Button-icon' }) : '', m(
- 'span',
- { className: 'Button-label' },
- this.props.label
- ), this.props.caretIcon ? icon(this.props.caretIcon, { className: 'Button-caret' }) : ''];
- }
- }, {
- key: 'getMenu',
- value: function getMenu(items) {
- return m(
- 'ul',
- { className: 'Dropdown-menu dropdown-menu ' + this.props.menuClassName },
- items
- );
- }
- }], [{
- key: 'initProps',
- value: function initProps(props) {
- babelHelpers.get(Object.getPrototypeOf(Dropdown), 'initProps', this).call(this, props);
-
- props.className = props.className || '';
- props.buttonClassName = props.buttonClassName || '';
- props.menuClassName = props.menuClassName || '';
- props.label = props.label || '';
- props.caretIcon = typeof props.caretIcon !== 'undefined' ? props.caretIcon : 'caret-down';
- }
- }]);
- return Dropdown;
- })(Component);
-
- _export('default', Dropdown);
- }
- };
-});;
-System.register('flarum/components/FieldSet', ['flarum/Component', 'flarum/helpers/listItems'], function (_export) {
-
- /**
- * The `FieldSet` component defines a collection of fields, displayed in a list
- * underneath a title. Accepted properties are:
- *
- * - `className` The class name for the fieldset.
- * - `label` The title of this group of fields.
- *
- * The children should be an array of items to show in the fieldset.
- */
- 'use strict';
-
- var Component, listItems, FieldSet;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumHelpersListItems) {
- listItems = _flarumHelpersListItems['default'];
- }],
- execute: function () {
- FieldSet = (function (_Component) {
- babelHelpers.inherits(FieldSet, _Component);
-
- function FieldSet() {
- babelHelpers.classCallCheck(this, FieldSet);
- babelHelpers.get(Object.getPrototypeOf(FieldSet.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(FieldSet, [{
- key: 'view',
- value: function view() {
- return m(
- 'fieldset',
- { className: this.props.className },
- m(
- 'legend',
- null,
- this.props.label
- ),
- m(
- 'ul',
- null,
- listItems(this.props.children)
- )
- );
- }
- }]);
- return FieldSet;
- })(Component);
-
- _export('default', FieldSet);
- }
- };
-});;
-System.register('flarum/components/GroupBadge', ['flarum/components/Badge'], function (_export) {
- 'use strict';
-
- var Badge, GroupBadge;
- return {
- setters: [function (_flarumComponentsBadge) {
- Badge = _flarumComponentsBadge['default'];
- }],
- execute: function () {
- GroupBadge = (function (_Badge) {
- babelHelpers.inherits(GroupBadge, _Badge);
-
- function GroupBadge() {
- babelHelpers.classCallCheck(this, GroupBadge);
- babelHelpers.get(Object.getPrototypeOf(GroupBadge.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(GroupBadge, null, [{
- key: 'initProps',
- value: function initProps(props) {
- babelHelpers.get(Object.getPrototypeOf(GroupBadge), 'initProps', this).call(this, props);
-
- if (props.group) {
- props.icon = props.group.icon();
- props.style = { backgroundColor: props.group.color() };
- props.label = typeof props.label === 'undefined' ? props.group.nameSingular() : props.label;
- props.type = 'group--' + props.group.nameSingular();
-
- delete props.group;
- }
- }
- }]);
- return GroupBadge;
- })(Badge);
-
- _export('default', GroupBadge);
- }
- };
-});;
-System.register('flarum/components/LinkButton', ['flarum/components/Button'], function (_export) {
-
- /**
- * The `LinkButton` component defines a `Button` which links to a route.
- *
- * ### Props
- *
- * All of the props accepted by `Button`, plus:
- *
- * - `active` Whether or not the page that this button links to is currently
- * active.
- * - `href` The URL to link to. If the current URL `m.route()` matches this,
- * the `active` prop will automatically be set to true.
- */
- 'use strict';
-
- var Button, LinkButton;
- return {
- setters: [function (_flarumComponentsButton) {
- Button = _flarumComponentsButton['default'];
- }],
- execute: function () {
- LinkButton = (function (_Button) {
- babelHelpers.inherits(LinkButton, _Button);
-
- function LinkButton() {
- babelHelpers.classCallCheck(this, LinkButton);
- babelHelpers.get(Object.getPrototypeOf(LinkButton.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(LinkButton, [{
- key: 'view',
- value: function view() {
- var vdom = babelHelpers.get(Object.getPrototypeOf(LinkButton.prototype), 'view', this).call(this);
-
- vdom.tag = 'a';
-
- return vdom;
- }
-
- /**
- * Determine whether a component with the given props is 'active'.
- *
- * @param {Object} props
- * @return {Boolean}
- */
- }], [{
- key: 'initProps',
- value: function initProps(props) {
- props.active = this.isActive(props);
- props.config = props.config || m.route;
- }
- }, {
- key: 'isActive',
- value: function isActive(props) {
- return typeof props.active !== 'undefined' ? props.active : m.route() === props.href;
- }
- }]);
- return LinkButton;
- })(Button);
-
- _export('default', LinkButton);
- }
- };
-});;
-System.register('flarum/components/LoadingIndicator', ['flarum/Component'], function (_export) {
-
- /**
- * The `LoadingIndicator` component displays a loading spinner with spin.js. It
- * may have the following special props:
- *
- * - `size` The spin.js size preset to use. Defaults to 'small'.
- *
- * All other props will be assigned as attributes on the element.
- */
- 'use strict';
-
- var Component, LoadingIndicator;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }],
- execute: function () {
- LoadingIndicator = (function (_Component) {
- babelHelpers.inherits(LoadingIndicator, _Component);
-
- function LoadingIndicator() {
- babelHelpers.classCallCheck(this, LoadingIndicator);
- babelHelpers.get(Object.getPrototypeOf(LoadingIndicator.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(LoadingIndicator, [{
- key: 'view',
- value: function view() {
- var attrs = babelHelpers._extends({}, this.props);
-
- attrs.className = 'LoadingIndicator ' + (attrs.className || '');
- delete attrs.size;
-
- return m(
- 'div',
- attrs,
- m.trust(' ')
- );
- }
- }, {
- key: 'config',
- value: function config() {
- var size = this.props.size || 'small';
-
- $.fn.spin.presets[size].zIndex = 'auto';
- this.$().spin(size);
- }
- }]);
- return LoadingIndicator;
- })(Component);
-
- _export('default', LoadingIndicator);
- }
- };
-});;
-System.register('flarum/components/Modal', ['flarum/Component', 'flarum/components/Alert', 'flarum/components/Button'], function (_export) {
-
- /**
- * The `Modal` component displays a modal dialog, wrapped in a form. Subclasses
- * should implement the `className`, `title`, and `content` methods.
- *
- * @abstract
- */
- 'use strict';
-
- var Component, Alert, Button, Modal;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumComponentsAlert) {
- Alert = _flarumComponentsAlert['default'];
- }, function (_flarumComponentsButton) {
- Button = _flarumComponentsButton['default'];
- }],
- execute: function () {
- Modal = (function (_Component) {
- babelHelpers.inherits(Modal, _Component);
-
- function Modal() {
- babelHelpers.classCallCheck(this, Modal);
- babelHelpers.get(Object.getPrototypeOf(Modal.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Modal, [{
- key: 'init',
- value: function init() {
- /**
- * An alert component to show below the header.
- *
- * @type {Alert}
- */
- this.alert = null;
- }
- }, {
- key: 'view',
- value: function view() {
- if (this.alert) {
- this.alert.props.dismissible = false;
- }
-
- return m(
- 'div',
- { className: 'Modal modal-dialog ' + this.className() },
- m(
- 'div',
- { className: 'Modal-content' },
- this.isDismissible() ? m(
- 'div',
- { className: 'Modal-close App-backControl' },
- Button.component({
- icon: 'times',
- onclick: this.hide.bind(this),
- className: 'Button Button--icon Button--link'
- })
- ) : '',
- m(
- 'form',
- { onsubmit: this.onsubmit.bind(this) },
- m(
- 'div',
- { className: 'Modal-header' },
- m(
- 'h3',
- { className: 'App-titleControl App-titleControl--text' },
- this.title()
- )
- ),
- alert ? m(
- 'div',
- { className: 'Modal-alert' },
- this.alert
- ) : '',
- this.content()
- )
- )
- );
- }
-
- /**
- * Determine whether or not the modal should be dismissible via an 'x' button.
- *
- * @return {Boolean}
- */
- }, {
- key: 'isDismissible',
- value: function isDismissible() {
- return true;
- }
-
- /**
- * Get the class name to apply to the modal.
- *
- * @return {String}
- * @abstract
- */
- }, {
- key: 'className',
- value: function className() {}
-
- /**
- * Get the title of the modal dialog.
- *
- * @return {String}
- * @abstract
- */
- }, {
- key: 'title',
- value: function title() {}
-
- /**
- * Get the content of the modal.
- *
- * @return {VirtualElement}
- * @abstract
- */
- }, {
- key: 'content',
- value: function content() {}
-
- /**
- * Handle the modal form's submit event.
- *
- * @param {Event} e
- */
- }, {
- key: 'onsubmit',
- value: function onsubmit() {}
-
- /**
- * Focus on the first input when the modal is ready to be used.
- */
- }, {
- key: 'onready',
- value: function onready() {
- this.$('form :input:first').focus().select();
- }
-
- /**
- * Hide the modal.
- */
- }, {
- key: 'hide',
- value: function hide() {
- app.modal.close();
- }
-
- /**
- * Stop loading.
- */
- }, {
- key: 'loaded',
- value: function loaded() {
- this.loading = false;
- m.redraw();
- }
-
- /**
- * Show an alert describing an error returned from the API, and give focus to
- * the first relevant field.
- *
- * @param {RequestError} error
- */
- }, {
- key: 'onerror',
- value: function onerror(error) {
- this.alert = error.alert;
-
- m.redraw();
-
- if (error.status === 422 && error.response.errors) {
- this.$('form [name=' + error.response.errors[0].source.pointer.replace('/data/attributes/', '') + ']').select();
- } else {
- this.onready();
- }
- }
- }]);
- return Modal;
- })(Component);
-
- _export('default', Modal);
- }
- };
-});;
-System.register('flarum/components/ModalManager', ['flarum/Component', 'flarum/components/Modal'], function (_export) {
-
- /**
- * The `ModalManager` component manages a modal dialog. Only one modal dialog
- * can be shown at once; loading a new component into the ModalManager will
- * overwrite the previous one.
- */
- 'use strict';
-
- var Component, Modal, ModalManager;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumComponentsModal) {
- Modal = _flarumComponentsModal['default'];
- }],
- execute: function () {
- ModalManager = (function (_Component) {
- babelHelpers.inherits(ModalManager, _Component);
-
- function ModalManager() {
- babelHelpers.classCallCheck(this, ModalManager);
- babelHelpers.get(Object.getPrototypeOf(ModalManager.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(ModalManager, [{
- key: 'init',
- value: function init() {
- this.showing = false;
- this.component = null;
- }
- }, {
- key: 'view',
- value: function view() {
- return m(
- 'div',
- { className: 'ModalManager modal fade' },
- this.component && this.component.render()
- );
- }
- }, {
- key: 'config',
- value: function config(isInitialized, context) {
- if (isInitialized) return;
-
- context.retain = true;
-
- this.$().on('hidden.bs.modal', this.clear.bind(this)).on('shown.bs.modal', this.onready.bind(this));
- }
-
- /**
- * Show a modal dialog.
- *
- * @param {Modal} component
- * @public
- */
- }, {
- key: 'show',
- value: function show(component) {
- if (!(component instanceof Modal)) {
- throw new Error('The ModalManager component can only show Modal components');
- }
-
- clearTimeout(this.hideTimeout);
-
- this.showing = true;
- this.component = component;
-
- m.redraw(true);
-
- this.$().modal({ backdrop: this.component.isDismissible() ? true : 'static' }).modal('show');
- this.onready();
- }
-
- /**
- * Close the modal dialog.
- *
- * @public
- */
- }, {
- key: 'close',
- value: function close() {
- var _this = this;
-
- if (!this.showing) return;
-
- // Don't hide the modal immediately, because if the consumer happens to call
- // the `show` method straight after to show another modal dialog, it will
- // cause Bootstrap's modal JS to misbehave. Instead we will wait for a tiny
- // bit to give the `show` method the opportunity to prevent this from going
- // ahead.
- this.hideTimeout = setTimeout(function () {
- _this.$().modal('hide');
- _this.showing = false;
- });
- }
-
- /**
- * Clear content from the modal area.
- *
- * @protected
- */
- }, {
- key: 'clear',
- value: function clear() {
- this.component = null;
-
- m.lazyRedraw();
- }
-
- /**
- * When the modal dialog is ready to be used, tell it!
- *
- * @protected
- */
- }, {
- key: 'onready',
- value: function onready() {
- if (this.component && this.component.onready) {
- this.component.onready(this.$());
- }
- }
- }]);
- return ModalManager;
- })(Component);
-
- _export('default', ModalManager);
- }
- };
-});;
-System.register('flarum/components/Navigation', ['flarum/Component', 'flarum/components/Button', 'flarum/components/LinkButton'], function (_export) {
-
- /**
- * The `Navigation` component displays a set of navigation buttons. Typically
- * this is just a back button which pops the app's History. If the user is on
- * the root page and there is no history to pop, then in some instances it may
- * show a button that toggles the app's drawer.
- *
- * If the app has a pane, it will also include a 'pin' button which toggles the
- * pinned state of the pane.
- *
- * Accepts the following props:
- *
- * - `className` The name of a class to set on the root element.
- * - `drawer` Whether or not to show a button to toggle the app's drawer if
- * there is no more history to pop.
- */
- 'use strict';
-
- var Component, Button, LinkButton, Navigation;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent['default'];
- }, function (_flarumComponentsButton) {
- Button = _flarumComponentsButton['default'];
- }, function (_flarumComponentsLinkButton) {
- LinkButton = _flarumComponentsLinkButton['default'];
- }],
- execute: function () {
- Navigation = (function (_Component) {
- babelHelpers.inherits(Navigation, _Component);
-
- function Navigation() {
- babelHelpers.classCallCheck(this, Navigation);
- babelHelpers.get(Object.getPrototypeOf(Navigation.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Navigation, [{
- key: 'view',
- value: function view() {
- var _app = app;
- var history = _app.history;
- var pane = _app.pane;
-
- return m(
- 'div',
- { className: 'Navigation ButtonGroup ' + (this.props.className || ''),
- onmouseenter: pane && pane.show.bind(pane),
- onmouseleave: pane && pane.onmouseleave.bind(pane) },
- history.canGoBack() ? [this.getBackButton(), this.getPaneButton()] : this.getDrawerButton()
- );
- }
- }, {
- key: 'config',
- value: function config(isInitialized, context) {
- // Since this component is 'above' the content of the page (that is, it is a
- // part of the global UI that persists between routes), we will flag the DOM
- // to be retained across route changes.
- context.retain = true;
- }
-
- /**
- * Get the back button.
- *
- * @return {Object}
- * @protected
- */
- }, {
- key: 'getBackButton',
- value: function getBackButton() {
- var _app2 = app;
- var history = _app2.history;
-
- return LinkButton.component({
- className: 'Button Button--icon Navigation-back',
- href: history.backUrl(),
- icon: 'chevron-left',
- config: function config() {},
- onclick: function onclick(e) {
- if (e.shiftKey || e.ctrlKey || e.metaKey || e.which === 2) return;
- e.preventDefault();
- history.back();
- }
- });
- }
-
- /**
- * Get the pane pinned toggle button.
- *
- * @return {Object|String}
- * @protected
- */
- }, {
- key: 'getPaneButton',
- value: function getPaneButton() {
- var _app3 = app;
- var pane = _app3.pane;
-
- if (!pane || !pane.active) return '';
-
- return Button.component({
- className: 'Button Button--icon Navigation-pin' + (pane.pinned ? ' active' : ''),
- onclick: pane.togglePinned.bind(pane),
- icon: 'thumb-tack'
- });
- }
-
- /**
- * Get the drawer toggle button.
- *
- * @return {Object|String}
- * @protected
- */
- }, {
- key: 'getDrawerButton',
- value: function getDrawerButton() {
- if (!this.props.drawer) return '';
-
- var _app4 = app;
- var drawer = _app4.drawer;
-
- var user = app.session.user;
-
- return Button.component({
- className: 'Button Button--icon Navigation-drawer' + (user && user.newNotificationsCount() ? ' new' : ''),
- onclick: function onclick(e) {
- e.stopPropagation();
- drawer.show();
- },
- icon: 'reorder'
- });
- }
- }]);
- return Navigation;
- })(Component);
-
- _export('default', Navigation);
- }
- };
-});;
-System.register("flarum/components/Placeholder", ["flarum/Component"], function (_export) {
-
- /**
- * The `Placeholder` component displays a muted text with some call to action,
- * usually used as an empty state.
- *
- * ### Props
- *
- * - `text`
- */
- "use strict";
-
- var Component, Placeholder;
- return {
- setters: [function (_flarumComponent) {
- Component = _flarumComponent["default"];
- }],
- execute: function () {
- Placeholder = (function (_Component) {
- babelHelpers.inherits(Placeholder, _Component);
-
- function Placeholder() {
- babelHelpers.classCallCheck(this, Placeholder);
- babelHelpers.get(Object.getPrototypeOf(Placeholder.prototype), "constructor", this).apply(this, arguments);
- }
-
- babelHelpers.createClass(Placeholder, [{
- key: "view",
- value: function view() {
- return m(
- "div",
- { className: "Placeholder" },
- m(
- "p",
- null,
- this.props.text
- )
- );
- }
- }]);
- return Placeholder;
- })(Component);
-
- _export("default", Placeholder);
- }
- };
-});;
-System.register('flarum/components/RequestErrorModal', ['flarum/components/Modal'], function (_export) {
- 'use strict';
-
- var Modal, RequestErrorModal;
- return {
- setters: [function (_flarumComponentsModal) {
- Modal = _flarumComponentsModal['default'];
- }],
- execute: function () {
- RequestErrorModal = (function (_Modal) {
- babelHelpers.inherits(RequestErrorModal, _Modal);
-
- function RequestErrorModal() {
- babelHelpers.classCallCheck(this, RequestErrorModal);
- babelHelpers.get(Object.getPrototypeOf(RequestErrorModal.prototype), 'constructor', this).apply(this, arguments);
- }
-
- babelHelpers.createClass(RequestErrorModal, [{
- key: 'className',
- value: function className() {
- return 'RequestErrorModal Modal--large';
- }
- }, {
- key: 'title',
- value: function title() {
- return this.props.error.xhr ? this.props.error.xhr.status + ' ' + this.props.error.xhr.statusText : '';
- }
- }, {
- key: 'content',
- value: function content() {
- var responseText = undefined;
-
- try {
- responseText = JSON.stringify(JSON.parse(this.props.error.responseText), null, 2);
- } catch (e) {
- responseText = this.props.error.responseText;
- }
-
- return m(
- 'div',
- { className: 'Modal-body' },
- m(
- 'pre',
- null,
- this.props.error.options.method,
- ' ',
- this.props.error.options.url,
- m('br', null),
- m('br', null),
- responseText
- )
- );
- }
- }]);
- return RequestErrorModal;
- })(Modal);
-
- _export('default', RequestErrorModal);
- }
- };
-});;
-System.register('flarum/components/Select', ['flarum/Component', 'flarum/helpers/icon'], function (_export) {
-
- /**
- * The `Select` component displays a