diff --git a/js/admin/dist/app.js b/js/admin/dist/app.js
index a1ccfea3d..3a6e9db20 100644
--- a/js/admin/dist/app.js
+++ b/js/admin/dist/app.js
@@ -15935,7 +15935,7 @@ 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) {
+System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/components/ConfirmPasswordModal', '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
@@ -15943,7 +15943,7 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
*/
'use strict';
- var ItemList, Alert, Button, RequestErrorModal, Translator, extract, patchMithril, RequestError, extend, App;
+ var ItemList, Alert, Button, RequestErrorModal, ConfirmPasswordModal, Translator, extract, patchMithril, RequestError, extend, App;
return {
setters: [function (_flarumUtilsItemList) {
ItemList = _flarumUtilsItemList['default'];
@@ -15953,6 +15953,8 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
Button = _flarumComponentsButton['default'];
}, function (_flarumComponentsRequestErrorModal) {
RequestErrorModal = _flarumComponentsRequestErrorModal['default'];
+ }, function (_flarumComponentsConfirmPasswordModal) {
+ ConfirmPasswordModal = _flarumComponentsConfirmPasswordModal['default'];
}, function (_flarumTranslator) {
Translator = _flarumTranslator['default'];
}, function (_flarumUtilsExtract) {
@@ -16150,24 +16152,29 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
*/
}, {
key: 'request',
- value: function request(options) {
+ value: function request(originalOptions) {
var _this2 = this;
+ var options = babelHelpers._extends({}, originalOptions);
+
// 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;
+ extend(options, 'config', function (result, xhr) {
+ return xhr.setRequestHeader('X-CSRF-Token', _this2.session.csrfToken);
+ });
+
// 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.
+ // and clients support, then we'll send it as a POST request with the
+ // intended method specified in the X-HTTP-Method-Override 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);
+ return xhr.setRequestHeader('X-HTTP-Method-Override', method);
});
options.method = 'POST';
})();
@@ -16194,7 +16201,7 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
if (original) {
responseText = original(xhr.responseText);
} else {
- responseText = xhr.responseText.length > 0 ? xhr.responseText : null;
+ responseText = xhr.responseText || null;
}
var status = xhr.status;
@@ -16203,6 +16210,11 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
throw new RequestError(status, responseText, options, xhr);
}
+ if (xhr.getResponseHeader) {
+ var csrfToken = xhr.getResponseHeader('X-CSRF-Token');
+ if (csrfToken) app.session.csrfToken = csrfToken;
+ }
+
try {
return JSON.parse(responseText);
} catch (e) {
@@ -16214,9 +16226,22 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/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) {
+ var deferred = m.deferred();
+
+ m.request(options).then(function (response) {
+ return deferred.resolve(response);
+ }, function (error) {
_this2.requestError = error;
+ if (error.response && error.response.errors && error.response.errors[0] && error.response.errors[0].code === 'invalid_access_token') {
+ _this2.modal.show(new ConfirmPasswordModal({
+ deferredRequest: originalOptions,
+ deferred: deferred,
+ error: error
+ }));
+ return;
+ }
+
var children = undefined;
switch (error.status) {
@@ -16262,8 +16287,10 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
_this2.alerts.show(error.alert);
}
- throw error;
+ deferred.reject(error);
});
+
+ return deferred.promise;
}
/**
@@ -16619,29 +16646,17 @@ System.register('flarum/components/AddExtensionModal', ['flarum/components/Modal
m(
'p',
null,
- 'One day in the not-too-distant future, this dialog will allow you to add an extension to your forum with ease. We\'re building an ecosystem as we speak!'
+ app.translator.trans('core.admin.add_extension.temporary_text')
),
m(
'p',
null,
- 'In the meantime, if you manage to get your hands on a new extension, simply drop it in your forum\'s ',
- m(
- 'code',
- null,
- 'extensions'
- ),
- ' directory.'
+ app.translator.trans('core.admin.add_extension.install_text', { a: m('a', { href: 'https://discuss.flarum.org/t/extensions', target: '_blank' }) })
),
m(
'p',
null,
- 'If you\'re a developer, you can ',
- m(
- 'a',
- { href: 'http://flarum.org/docs/extend' },
- 'read the docs'
- ),
- ' and have a go at building your own.'
+ app.translator.trans('core.admin.add_extension.developer_text', { a: m('a', { href: 'http://flarum.org/docs/extend', target: '_blank' }) })
)
);
}
@@ -17171,11 +17186,6 @@ System.register('flarum/components/Badge', ['flarum/Component', 'flarum/helpers/
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,
@@ -17574,6 +17584,121 @@ System.register('flarum/components/Checkbox', ['flarum/Component', 'flarum/compo
}
};
});;
+System.register('flarum/components/ConfirmPasswordModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/utils/extractText'], function (_export) {
+ 'use strict';
+
+ var Modal, Button, extractText, ConfirmPasswordModal;
+ return {
+ setters: [function (_flarumComponentsModal) {
+ Modal = _flarumComponentsModal['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumUtilsExtractText) {
+ extractText = _flarumUtilsExtractText['default'];
+ }],
+ execute: function () {
+ ConfirmPasswordModal = (function (_Modal) {
+ babelHelpers.inherits(ConfirmPasswordModal, _Modal);
+
+ function ConfirmPasswordModal() {
+ babelHelpers.classCallCheck(this, ConfirmPasswordModal);
+ babelHelpers.get(Object.getPrototypeOf(ConfirmPasswordModal.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(ConfirmPasswordModal, [{
+ key: 'init',
+ value: function init() {
+ babelHelpers.get(Object.getPrototypeOf(ConfirmPasswordModal.prototype), 'init', this).call(this);
+
+ this.password = m.prop('');
+ }
+ }, {
+ key: 'className',
+ value: function className() {
+ return 'ConfirmPasswordModal Modal--small';
+ }
+ }, {
+ key: 'title',
+ value: function title() {
+ return app.translator.trans('core.forum.confirm_password.title');
+ }
+ }, {
+ key: 'content',
+ value: function content() {
+ return m(
+ 'div',
+ { className: 'Modal-body' },
+ m(
+ 'div',
+ { className: 'Form Form--centered' },
+ m(
+ 'div',
+ { className: 'Form-group' },
+ m('input', {
+ type: 'password',
+ className: 'FormControl',
+ bidi: this.password,
+ placeholder: extractText(app.translator.trans('core.forum.confirm_password.password_placeholder')),
+ disabled: this.loading })
+ ),
+ m(
+ 'div',
+ { className: 'Form-group' },
+ m(
+ Button,
+ {
+ type: 'submit',
+ className: 'Button Button--primary Button--block',
+ loading: this.loading },
+ app.translator.trans('core.forum.confirm_password.submit_button')
+ )
+ )
+ )
+ );
+ }
+ }, {
+ key: 'onsubmit',
+ value: function onsubmit(e) {
+ var _this = this;
+
+ e.preventDefault();
+
+ this.loading = true;
+
+ app.session.login(app.session.user.email(), this.password(), { errorHandler: this.onerror.bind(this) }).then(function () {
+ _this.success = true;
+ _this.hide();
+ app.request(_this.props.deferredRequest).then(function (response) {
+ return _this.props.deferred.resolve(response);
+ }, function (response) {
+ return _this.props.deferred.reject(response);
+ });
+ })['catch'](this.loaded.bind(this));
+ }
+ }, {
+ key: 'onerror',
+ value: function onerror(error) {
+ if (error.status === 401) {
+ error.alert.props.children = app.translator.trans('core.forum.log_in.invalid_login_message');
+ }
+
+ babelHelpers.get(Object.getPrototypeOf(ConfirmPasswordModal.prototype), 'onerror', this).call(this, error);
+ }
+ }, {
+ key: 'onhide',
+ value: function onhide() {
+ if (this.success) return;
+
+ this.props.deferred.reject(this.props.error);
+ }
+ }]);
+ return ConfirmPasswordModal;
+ })(Modal);
+
+ _export('default', ConfirmPasswordModal);
+ }
+ };
+});;
System.register("flarum/components/DashboardPage", ["flarum/Component"], function (_export) {
"use strict";
@@ -17603,7 +17728,7 @@ System.register("flarum/components/DashboardPage", ["flarum/Component"], functio
m(
"h2",
null,
- "Welcome to Flarum Beta"
+ app.translator.trans('core.admin.dashboard.welcome_text')
),
m(
"p",
@@ -17720,10 +17845,14 @@ System.register('flarum/components/Dropdown', ['flarum/Component', 'flarum/helpe
// 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');
+ var $menu = _this.$('.Dropdown-menu');
+ var isRight = $menu.hasClass('Dropdown-menu--right');
+ $menu.removeClass('Dropdown-menu--top Dropdown-menu--right');
$menu.toggleClass('Dropdown-menu--top', $menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height());
+ $menu.toggleClass('Dropdown-menu--right', isRight || $menu.offset().left + $menu.width() > $(window).scrollLeft() + $(window).width());
+
if (_this.props.onshow) {
_this.props.onshow();
m.redraw();
@@ -17834,7 +17963,7 @@ System.register('flarum/components/EditCustomCssModal', ['flarum/components/Moda
}, {
key: 'title',
value: function title() {
- return 'Edit Custom CSS';
+ return app.translator.trans('core.admin.edit_css.title');
}
}, {
key: 'content',
@@ -17845,13 +17974,7 @@ System.register('flarum/components/EditCustomCssModal', ['flarum/components/Moda
m(
'p',
null,
- 'Customize your forum\'s appearance by adding your own LESS/CSS code to be applied on top of Flarum\'s default styles. ',
- m(
- 'a',
- { href: 'http://flarum.org/docs/extend/themes/' },
- 'Read the documentation'
- ),
- ' for more information.'
+ app.translator.trans('core.admin.edit_css.customize_text', { a: m('a', { href: 'https://github.com/flarum/core/tree/master/less', target: '_blank' }) })
),
m(
'div',
@@ -17867,7 +17990,7 @@ System.register('flarum/components/EditCustomCssModal', ['flarum/components/Moda
Button.component({
className: 'Button Button--primary',
type: 'submit',
- children: 'Save Changes',
+ children: app.translator.trans('core.admin.edit_css.submit_button'),
loading: this.loading
})
)
@@ -18744,8 +18867,11 @@ System.register('flarum/components/Modal', ['flarum/Component', 'flarum/componen
}, {
key: 'onready',
value: function onready() {
- this.$('form :input:first').focus().select();
+ this.$('form').find('input, select, textarea').first().focus().select();
}
+ }, {
+ key: 'onhide',
+ value: function onhide() {}
/**
* Hide the modal.
@@ -18898,6 +19024,10 @@ System.register('flarum/components/ModalManager', ['flarum/Component', 'flarum/c
}, {
key: 'clear',
value: function clear() {
+ if (this.component) {
+ this.component.onhide();
+ }
+
this.component = null;
m.lazyRedraw();
@@ -20052,7 +20182,7 @@ System.register('flarum/components/SettingsModal', ['flarum/components/Modal', '
className: 'Button Button--primary',
loading: this.loading,
disabled: !this.changed() },
- 'Save Changes'
+ app.translator.trans('core.admin.settings.submit_button')
);
}
}, {
@@ -20548,7 +20678,8 @@ System.register('flarum/helpers/listItems', ['flarum/components/Separator', 'fla
return [isListItem ? item : m(
'li',
- { className: classList([item.itemName ? 'item-' + item.itemName : '', className, active ? 'active' : '']) },
+ { className: classList([item.itemName ? 'item-' + item.itemName : '', className, active ? 'active' : '']),
+ key: item.itemName },
item
), ' '];
});
@@ -20621,7 +20752,7 @@ System.register("flarum/helpers/username", [], function (_export) {
_export("default", username);
function username(user) {
- var name = user && user.username() || app.translator.trans('core.lib.deleted_user_text');
+ var name = user && user.username() || app.translator.trans('core.lib.username.deleted_text');
return m(
"span",
@@ -20635,6 +20766,37 @@ System.register("flarum/helpers/username", [], function (_export) {
execute: function () {}
};
});;
+System.register('flarum/helpers/userOnline', ['flarum/helpers/icon'], function (_export) {
+
+ /**
+ * The `useronline` helper displays a green circle if the user is online
+ *
+ * @param {User} user
+ * @return {Object}
+ */
+ 'use strict';
+
+ var icon;
+
+ _export('default', userOnline);
+
+ function userOnline(user) {
+ if (user.lastSeenTime() && user.isOnline()) {
+ return m(
+ 'span',
+ { className: 'UserOnline' },
+ icon('circle')
+ );
+ }
+ }
+
+ return {
+ setters: [function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }],
+ execute: function () {}
+ };
+});;
System.register('flarum/initializers/boot', ['flarum/utils/ScrollListener', 'flarum/utils/Drawer', 'flarum/utils/mapRoutes', 'flarum/components/Navigation', 'flarum/components/HeaderPrimary', 'flarum/components/HeaderSecondary', 'flarum/components/AdminNav', 'flarum/components/ModalManager', 'flarum/components/AlertManager'], function (_export) {
/*global FastClick*/
@@ -20779,7 +20941,7 @@ System.register('flarum/initializers/preload', ['flarum/Session'], function (_ex
app.forum = app.store.getById('forums', 1);
- app.session = new Session(app.preload.session.token, app.store.getById('users', app.preload.session.userId));
+ app.session = new Session(app.store.getById('users', app.preload.session.userId), app.preload.session.csrfToken);
}
return {
@@ -21047,7 +21209,7 @@ System.register('flarum/Model', [], function (_export) {
// Before we update the model's data, we should make a copy of the model's
// old data so that we can revert back to it if something goes awry during
// persistence.
- var oldData = JSON.parse(JSON.stringify(this.data));
+ var oldData = this.copyData();
this.pushData(data);
@@ -21112,6 +21274,11 @@ System.register('flarum/Model', [], function (_export) {
value: function apiEndpoint() {
return '/' + this.data.type + (this.exists ? '/' + this.data.id : '');
}
+ }, {
+ key: 'copyData',
+ value: function copyData() {
+ return JSON.parse(JSON.stringify(this.data));
+ }
/**
* Generate a function which returns the value of the given attribute.
@@ -21581,7 +21748,7 @@ System.register('flarum/models/User', ['flarum/Model', 'flarum/utils/mixin', 'fl
avatarUrl: Model.attribute('avatarUrl'),
bio: Model.attribute('bio'),
bioHtml: computed('bio', function (bio) {
- return bio ? '
' + $('
').text(bio).html().replace(/\n/g, '
').autoLink() + '' : '';
+ return bio ? '' + $('
').text(bio).html().replace(/\n/g, '
').autoLink({ rel: 'nofollow' }) + '' : '';
}),
preferences: Model.attribute('preferences'),
groups: Model.hasMany('groups'),
@@ -21692,7 +21859,7 @@ System.register('flarum/Session', [], function (_export) {
setters: [],
execute: function () {
Session = (function () {
- function Session(token, user) {
+ function Session(user, csrfToken) {
babelHelpers.classCallCheck(this, Session);
/**
@@ -21704,12 +21871,12 @@ System.register('flarum/Session', [], function (_export) {
this.user = user;
/**
- * The token that was used for authentication.
+ * The CSRF token.
*
* @type {String|null}
* @public
*/
- this.token = token;
+ this.csrfToken = csrfToken;
}
/**
@@ -21730,9 +21897,7 @@ System.register('flarum/Session', [], function (_export) {
method: 'POST',
url: app.forum.attribute('baseUrl') + '/login',
data: { identification: identification, password: password }
- }, options)).then(function () {
- return window.location.reload();
- });
+ }, options));
}
/**
@@ -21743,22 +21908,7 @@ System.register('flarum/Session', [], function (_export) {
}, {
key: 'logout',
value: function logout() {
- window.location = app.forum.attribute('baseUrl') + '/logout?token=' + this.token;
- }
-
- /**
- * Apply an authorization header with the current token to the given
- * XMLHttpRequest object.
- *
- * @param {XMLHttpRequest} xhr
- * @public
- */
- }, {
- key: 'authorize',
- value: function authorize(xhr) {
- if (this.token) {
- xhr.setRequestHeader('Authorization', 'Token ' + this.token);
- }
+ window.location = app.forum.attribute('baseUrl') + '/logout?token=' + this.csrfToken;
}
}]);
return Session;
diff --git a/js/forum/dist/app.js b/js/forum/dist/app.js
index 5ebd5c5f1..2adf0e28a 100644
--- a/js/forum/dist/app.js
+++ b/js/forum/dist/app.js
@@ -17592,7 +17592,7 @@ System.register('flarum/app', ['flarum/ForumApp', 'flarum/initializers/store', '
}
};
});;
-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) {
+System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/components/ConfirmPasswordModal', '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
@@ -17600,7 +17600,7 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
*/
'use strict';
- var ItemList, Alert, Button, RequestErrorModal, Translator, extract, patchMithril, RequestError, extend, App;
+ var ItemList, Alert, Button, RequestErrorModal, ConfirmPasswordModal, Translator, extract, patchMithril, RequestError, extend, App;
return {
setters: [function (_flarumUtilsItemList) {
ItemList = _flarumUtilsItemList['default'];
@@ -17610,6 +17610,8 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
Button = _flarumComponentsButton['default'];
}, function (_flarumComponentsRequestErrorModal) {
RequestErrorModal = _flarumComponentsRequestErrorModal['default'];
+ }, function (_flarumComponentsConfirmPasswordModal) {
+ ConfirmPasswordModal = _flarumComponentsConfirmPasswordModal['default'];
}, function (_flarumTranslator) {
Translator = _flarumTranslator['default'];
}, function (_flarumUtilsExtract) {
@@ -17807,24 +17809,29 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
*/
}, {
key: 'request',
- value: function request(options) {
+ value: function request(originalOptions) {
var _this2 = this;
+ var options = babelHelpers._extends({}, originalOptions);
+
// 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;
+ extend(options, 'config', function (result, xhr) {
+ return xhr.setRequestHeader('X-CSRF-Token', _this2.session.csrfToken);
+ });
+
// 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.
+ // and clients support, then we'll send it as a POST request with the
+ // intended method specified in the X-HTTP-Method-Override 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);
+ return xhr.setRequestHeader('X-HTTP-Method-Override', method);
});
options.method = 'POST';
})();
@@ -17851,7 +17858,7 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
if (original) {
responseText = original(xhr.responseText);
} else {
- responseText = xhr.responseText.length > 0 ? xhr.responseText : null;
+ responseText = xhr.responseText || null;
}
var status = xhr.status;
@@ -17860,6 +17867,11 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
throw new RequestError(status, responseText, options, xhr);
}
+ if (xhr.getResponseHeader) {
+ var csrfToken = xhr.getResponseHeader('X-CSRF-Token');
+ if (csrfToken) app.session.csrfToken = csrfToken;
+ }
+
try {
return JSON.parse(responseText);
} catch (e) {
@@ -17871,9 +17883,22 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/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) {
+ var deferred = m.deferred();
+
+ m.request(options).then(function (response) {
+ return deferred.resolve(response);
+ }, function (error) {
_this2.requestError = error;
+ if (error.response && error.response.errors && error.response.errors[0] && error.response.errors[0].code === 'invalid_access_token') {
+ _this2.modal.show(new ConfirmPasswordModal({
+ deferredRequest: originalOptions,
+ deferred: deferred,
+ error: error
+ }));
+ return;
+ }
+
var children = undefined;
switch (error.status) {
@@ -17919,8 +17944,10 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
_this2.alerts.show(error.alert);
}
- throw error;
+ deferred.reject(error);
});
+
+ return deferred.promise;
}
/**
@@ -18678,11 +18705,6 @@ System.register('flarum/components/Badge', ['flarum/Component', 'flarum/helpers/
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,
@@ -18922,11 +18944,18 @@ System.register('flarum/components/ChangeEmailModal', ['flarum/components/Modal'
return;
}
+ var oldEmail = app.session.user.email();
+
this.loading = true;
app.session.user.save({ email: this.email() }, { errorHandler: this.onerror.bind(this) }).then(function () {
return _this.success = true;
})['finally'](this.loaded.bind(this));
+
+ // The save method will update the cached email address on the user model...
+ // But in the case of a "sudo" password prompt, we'll still want to have
+ // the old email address on file for the purposes of logging in.
+ app.session.user.pushAttributes({ email: oldEmail });
}
}]);
return ChangeEmailModal;
@@ -19224,7 +19253,7 @@ System.register('flarum/components/CommentPost', ['flarum/components/Post', 'fla
}, {
key: 'isEditing',
value: function isEditing() {
- return app.composer.component instanceof EditPostComposer && app.composer.component.props.post === this.props.post && app.composer.position !== Composer.PositionEnum.MINIMIZED;
+ return app.composer.component instanceof EditPostComposer && app.composer.component.props.post === this.props.post;
}
}, {
key: 'attrs',
@@ -19407,6 +19436,7 @@ System.register('flarum/components/Composer', ['flarum/Component', 'flarum/utils
var _this = this;
var classes = {
+ 'normal': this.position === Composer.PositionEnum.NORMAL,
'minimized': this.position === Composer.PositionEnum.MINIMIZED,
'fullScreen': this.position === Composer.PositionEnum.FULLSCREEN,
'active': this.active
@@ -19581,7 +19611,7 @@ System.register('flarum/components/Composer', ['flarum/Component', 'flarum/utils
var paddingBottom = parseInt($flexible.css('padding-bottom'), 10);
var footerHeight = this.$('.TextEditor-controls').outerHeight(true);
- $flexible.height(height - headerHeight - paddingBottom - footerHeight);
+ $flexible.height(this.$().outerHeight() - headerHeight - paddingBottom - footerHeight);
}
}
@@ -19593,7 +19623,7 @@ System.register('flarum/components/Composer', ['flarum/Component', 'flarum/utils
}, {
key: 'updateBodyPadding',
value: function updateBodyPadding() {
- var visible = this.position !== Composer.PositionEnum.HIDDEN && this.position !== Composer.PositionEnum.MINIMIZED;
+ var visible = this.position !== Composer.PositionEnum.HIDDEN && this.position !== Composer.PositionEnum.MINIMIZED && this.$().css('position') !== 'absolute';
var paddingBottom = visible ? this.computedHeight() - parseInt($('#app').css('padding-bottom'), 10) : 0;
$('#content').css({ paddingBottom: paddingBottom });
@@ -19683,6 +19713,11 @@ System.register('flarum/components/Composer', ['flarum/Component', 'flarum/utils
this.oldPosition = this.position;
}
+ }, {
+ key: 'isMobile',
+ value: function isMobile() {
+ return this.$backdrop && this.$backdrop.length;
+ }
/**
* Confirm with the user that they want to close the composer and lose their
@@ -19962,7 +19997,7 @@ System.register('flarum/components/ComposerBody', ['flarum/Component', 'flarum/c
return m(
'div',
- { className: 'ComposerBody' },
+ { className: 'ComposerBody ' + (this.props.className || '') },
avatar(this.props.user, { className: 'ComposerBody-avatar' }),
m(
'div',
@@ -20079,6 +20114,121 @@ System.register('flarum/components/ComposerButton', ['flarum/components/Button']
}
};
});;
+System.register('flarum/components/ConfirmPasswordModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/utils/extractText'], function (_export) {
+ 'use strict';
+
+ var Modal, Button, extractText, ConfirmPasswordModal;
+ return {
+ setters: [function (_flarumComponentsModal) {
+ Modal = _flarumComponentsModal['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
+ }, function (_flarumUtilsExtractText) {
+ extractText = _flarumUtilsExtractText['default'];
+ }],
+ execute: function () {
+ ConfirmPasswordModal = (function (_Modal) {
+ babelHelpers.inherits(ConfirmPasswordModal, _Modal);
+
+ function ConfirmPasswordModal() {
+ babelHelpers.classCallCheck(this, ConfirmPasswordModal);
+ babelHelpers.get(Object.getPrototypeOf(ConfirmPasswordModal.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ babelHelpers.createClass(ConfirmPasswordModal, [{
+ key: 'init',
+ value: function init() {
+ babelHelpers.get(Object.getPrototypeOf(ConfirmPasswordModal.prototype), 'init', this).call(this);
+
+ this.password = m.prop('');
+ }
+ }, {
+ key: 'className',
+ value: function className() {
+ return 'ConfirmPasswordModal Modal--small';
+ }
+ }, {
+ key: 'title',
+ value: function title() {
+ return app.translator.trans('core.forum.confirm_password.title');
+ }
+ }, {
+ key: 'content',
+ value: function content() {
+ return m(
+ 'div',
+ { className: 'Modal-body' },
+ m(
+ 'div',
+ { className: 'Form Form--centered' },
+ m(
+ 'div',
+ { className: 'Form-group' },
+ m('input', {
+ type: 'password',
+ className: 'FormControl',
+ bidi: this.password,
+ placeholder: extractText(app.translator.trans('core.forum.confirm_password.password_placeholder')),
+ disabled: this.loading })
+ ),
+ m(
+ 'div',
+ { className: 'Form-group' },
+ m(
+ Button,
+ {
+ type: 'submit',
+ className: 'Button Button--primary Button--block',
+ loading: this.loading },
+ app.translator.trans('core.forum.confirm_password.submit_button')
+ )
+ )
+ )
+ );
+ }
+ }, {
+ key: 'onsubmit',
+ value: function onsubmit(e) {
+ var _this = this;
+
+ e.preventDefault();
+
+ this.loading = true;
+
+ app.session.login(app.session.user.email(), this.password(), { errorHandler: this.onerror.bind(this) }).then(function () {
+ _this.success = true;
+ _this.hide();
+ app.request(_this.props.deferredRequest).then(function (response) {
+ return _this.props.deferred.resolve(response);
+ }, function (response) {
+ return _this.props.deferred.reject(response);
+ });
+ })['catch'](this.loaded.bind(this));
+ }
+ }, {
+ key: 'onerror',
+ value: function onerror(error) {
+ if (error.status === 401) {
+ error.alert.props.children = app.translator.trans('core.forum.log_in.invalid_login_message');
+ }
+
+ babelHelpers.get(Object.getPrototypeOf(ConfirmPasswordModal.prototype), 'onerror', this).call(this, error);
+ }
+ }, {
+ key: 'onhide',
+ value: function onhide() {
+ if (this.success) return;
+
+ this.props.deferred.reject(this.props.error);
+ }
+ }]);
+ return ConfirmPasswordModal;
+ })(Modal);
+
+ _export('default', ConfirmPasswordModal);
+ }
+ };
+});;
System.register('flarum/components/DiscussionComposer', ['flarum/components/ComposerBody', 'flarum/utils/extractText'], function (_export) {
/**
@@ -20128,6 +20278,12 @@ System.register('flarum/components/DiscussionComposer', ['flarum/components/Comp
var items = babelHelpers.get(Object.getPrototypeOf(DiscussionComposer.prototype), 'headerItems', this).call(this);
items.add('title', m(
+ 'h3',
+ null,
+ app.translator.trans('core.forum.composer_discussion.title')
+ ), 100);
+
+ items.add('discussionTitle', m(
'h3',
null,
m('input', { className: 'FormControl',
@@ -20199,6 +20355,7 @@ System.register('flarum/components/DiscussionComposer', ['flarum/components/Comp
props.submitLabel = props.submitLabel || app.translator.trans('core.forum.composer_discussion.submit_button');
props.confirmExit = props.confirmExit || extractText(app.translator.trans('core.forum.composer_discussion.discard_confirmation'));
props.titlePlaceholder = props.titlePlaceholder || extractText(app.translator.trans('core.forum.composer_discussion.title_placeholder'));
+ props.className = 'ComposerBody--discussion';
}
}]);
return DiscussionComposer;
@@ -20438,7 +20595,7 @@ System.register('flarum/components/DiscussionList', ['flarum/Component', 'flarum
map.latest = '-lastTime';
map.top = '-commentsCount';
map.newest = '-startTime';
- map.oldest = '+startTime';
+ map.oldest = 'startTime';
return map;
}
@@ -20796,8 +20953,12 @@ System.register('flarum/components/DiscussionListItem', ['flarum/Component', 'fl
var discussion = this.props.discussion;
if (discussion.isUnread()) {
- discussion.save({ readNumber: discussion.lastPostNumber() });
- m.redraw();
+ var confirmation = confirm(app.translator.trans('core.forum.discussion_list.mark_all_as_read_confirmation'));
+
+ if (confirmation) {
+ discussion.save({ readNumber: discussion.lastPostNumber() });
+ m.redraw();
+ }
}
}
@@ -21482,10 +21643,14 @@ System.register('flarum/components/Dropdown', ['flarum/Component', 'flarum/helpe
// 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');
+ var $menu = _this.$('.Dropdown-menu');
+ var isRight = $menu.hasClass('Dropdown-menu--right');
+ $menu.removeClass('Dropdown-menu--top Dropdown-menu--right');
$menu.toggleClass('Dropdown-menu--top', $menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height());
+ $menu.toggleClass('Dropdown-menu--right', isRight || $menu.offset().left + $menu.width() > $(window).scrollLeft() + $(window).width());
+
if (_this.props.onshow) {
_this.props.onshow();
m.redraw();
@@ -21600,6 +21765,16 @@ System.register('flarum/components/EditPostComposer', ['flarum/components/Compos
babelHelpers.get(Object.getPrototypeOf(EditPostComposer.prototype), 'init', this).call(this);
this.editor.props.preview = function () {
+ // If the composer backdrop is visible, assume we're on mobile and need to
+ // minimize the composer in order to see the preview. We do this as a
+ // timeout so that it occurs after the click handler on the composer
+ // itself that shows the composer if minimized.
+ if (app.composer.isMobile()) {
+ setTimeout(function () {
+ return app.composer.minimize();
+ }, 0);
+ }
+
m.route(app.route.post(_this.props.post));
};
}
@@ -22835,7 +23010,11 @@ System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/compone
}, {
key: 'markAllAsRead',
value: function markAllAsRead() {
- app.session.user.save({ readTime: new Date() });
+ var confirmation = confirm(app.translator.trans('core.forum.index.mark_all_as_read_confirmation'));
+
+ if (confirmation) {
+ app.session.user.save({ readTime: new Date() });
+ }
}
}]);
return IndexPage;
@@ -23051,8 +23230,8 @@ System.register('flarum/components/LogInButton', ['flarum/components/Button'], f
props.className = (props.className || '') + ' LogInButton';
props.onclick = function () {
- var width = 1000;
- var height = 500;
+ var width = 600;
+ var height = 400;
var $window = $(window);
window.open(app.forum.attribute('baseUrl') + props.path, 'logInPopup', 'width=' + width + ',' + ('height=' + height + ',') + ('top=' + ($window.height() / 2 - height / 2) + ',') + ('left=' + ($window.width() / 2 - width / 2) + ',') + 'status=no,scrollbars=no,resizable=no');
@@ -23200,7 +23379,7 @@ System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'fla
m(
'div',
{ className: 'Form-group' },
- m('input', { className: 'FormControl', name: 'email', placeholder: extractText(app.translator.trans('core.forum.log_in.username_or_email_placeholder')),
+ m('input', { className: 'FormControl', name: 'email', type: 'text', placeholder: extractText(app.translator.trans('core.forum.log_in.username_or_email_placeholder')),
value: this.email(),
onchange: m.withAttr('value', this.email),
disabled: this.loading })
@@ -23289,7 +23468,9 @@ System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'fla
var email = this.email();
var password = this.password();
- app.session.login(email, password, { errorHandler: this.onerror.bind(this) })['catch'](this.loaded.bind(this));
+ app.session.login(email, password, { errorHandler: this.onerror.bind(this) }).then(function () {
+ return window.location.reload();
+ }, this.loaded.bind(this));
}
}, {
key: 'onerror',
@@ -23452,8 +23633,11 @@ System.register('flarum/components/Modal', ['flarum/Component', 'flarum/componen
}, {
key: 'onready',
value: function onready() {
- this.$('form :input:first').focus().select();
+ this.$('form').find('input, select, textarea').first().focus().select();
}
+ }, {
+ key: 'onhide',
+ value: function onhide() {}
/**
* Hide the modal.
@@ -23606,6 +23790,10 @@ System.register('flarum/components/ModalManager', ['flarum/Component', 'flarum/c
}, {
key: 'clear',
value: function clear() {
+ if (this.component) {
+ this.component.onhide();
+ }
+
this.component = null;
m.lazyRedraw();
@@ -24685,6 +24873,8 @@ System.register('flarum/components/Post', ['flarum/Component', 'flarum/utils/Sub
value: function init() {
var _this = this;
+ this.loading = false;
+
/**
* Set up a subtree retainer so that the post will not be redrawn
* unless new data comes in.
@@ -24707,7 +24897,7 @@ System.register('flarum/components/Post', ['flarum/Component', 'flarum/utils/Sub
var attrs = this.attrs();
- attrs.className = 'Post ' + (attrs.className || '');
+ attrs.className = 'Post ' + (this.loading ? 'Post--loading ' : '') + (attrs.className || '');
return m(
'article',
@@ -25043,7 +25233,7 @@ System.register('flarum/components/PostPreview', ['flarum/Component', 'flarum/he
}
};
});;
-System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/utils/ScrollListener', 'flarum/components/LoadingPost', 'flarum/utils/anchorScroll', 'flarum/utils/mixin', 'flarum/utils/evented', 'flarum/components/ReplyPlaceholder'], function (_export) {
+System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/utils/ScrollListener', 'flarum/components/LoadingPost', 'flarum/utils/anchorScroll', 'flarum/utils/mixin', 'flarum/utils/evented', 'flarum/components/ReplyPlaceholder', 'flarum/components/Button'], function (_export) {
/**
* The `PostStream` component displays an infinitely-scrollable wall of posts in
@@ -25056,7 +25246,7 @@ System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/uti
*/
'use strict';
- var Component, ScrollListener, PostLoading, anchorScroll, mixin, evented, ReplyPlaceholder, PostStream;
+ var Component, ScrollListener, PostLoading, anchorScroll, mixin, evented, ReplyPlaceholder, Button, PostStream;
return {
setters: [function (_flarumComponent) {
Component = _flarumComponent['default'];
@@ -25072,6 +25262,8 @@ System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/uti
evented = _flarumUtilsEvented['default'];
}, function (_flarumComponentsReplyPlaceholder) {
ReplyPlaceholder = _flarumComponentsReplyPlaceholder['default'];
+ }, function (_flarumComponentsButton) {
+ Button = _flarumComponentsButton['default'];
}],
execute: function () {
PostStream = (function (_Component) {
@@ -25131,7 +25323,9 @@ System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/uti
return this.goToLast().then(function () {
$('html,body').stop(true).animate({
scrollTop: $(document).height() - $(window).height()
- }, 'fast');
+ }, 'fast', function () {
+ _this.flashItem(_this.$('.PostStream-item:last-child'));
+ });
});
}
@@ -25296,64 +25490,82 @@ System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/uti
this.visibleEnd = this.sanitizeIndex(this.visibleEnd);
this.viewingEnd = this.visibleEnd === this.count();
+ var posts = this.posts();
var postIds = this.discussion.postIds();
+ var items = posts.map(function (post, i) {
+ var content = undefined;
+ var attrs = { 'data-index': _this3.visibleStart + i };
+
+ if (post) {
+ var time = post.time();
+ var PostComponent = app.postComponents[post.contentType()];
+ content = PostComponent ? PostComponent.component({ post: post }) : '';
+
+ attrs.key = 'post' + post.id();
+ attrs.config = fadeIn;
+ attrs['data-time'] = time.toISOString();
+ attrs['data-number'] = post.number();
+ attrs['data-id'] = post.id();
+ attrs['data-type'] = post.contentType();
+
+ // If the post before this one was more than 4 hours ago, we will
+ // display a 'time gap' indicating how long it has been in between
+ // the posts.
+ var dt = time - lastTime;
+
+ if (dt > 1000 * 60 * 60 * 24 * 4) {
+ content = [m(
+ 'div',
+ { className: 'PostStream-timeGap' },
+ m(
+ 'span',
+ null,
+ app.translator.trans('core.forum.post_stream.time_lapsed_text', { period: moment.duration(dt).humanize() })
+ )
+ ), content];
+ }
+
+ lastTime = time;
+ } else {
+ attrs.key = 'post' + postIds[_this3.visibleStart + i];
+
+ content = PostLoading.component();
+ }
+
+ return m(
+ 'div',
+ babelHelpers._extends({ className: 'PostStream-item' }, attrs),
+ content
+ );
+ });
+
+ if (!this.viewingEnd && posts[this.visibleEnd - this.visibleStart - 1]) {
+ items.push(m(
+ 'div',
+ { className: 'PostStream-loadMore', key: 'loadMore' },
+ m(
+ Button,
+ { className: 'Button', onclick: this.loadNext.bind(this) },
+ app.translator.trans('core.forum.post_stream.load_more_button')
+ )
+ ));
+ }
+
+ // If we're viewing the end of the discussion, the user can reply, and
+ // is not already doing so, then show a 'write a reply' placeholder.
+ if (this.viewingEnd && (!app.session.user || this.discussion.canReply())) {
+ items.push(m(
+ 'div',
+ { className: 'PostStream-item', key: 'reply' },
+ ReplyPlaceholder.component({ discussion: this.discussion })
+ ));
+ }
+
return m(
'div',
{ className: 'PostStream' },
- this.posts().map(function (post, i) {
- var content = undefined;
- var attrs = { 'data-index': _this3.visibleStart + i };
-
- if (post) {
- var time = post.time();
- var PostComponent = app.postComponents[post.contentType()];
- content = PostComponent ? PostComponent.component({ post: post }) : '';
-
- attrs.key = 'post' + post.id();
- attrs.config = fadeIn;
- attrs['data-time'] = time.toISOString();
- attrs['data-number'] = post.number();
- attrs['data-id'] = post.id();
-
- // If the post before this one was more than 4 hours ago, we will
- // display a 'time gap' indicating how long it has been in between
- // the posts.
- var dt = time - lastTime;
-
- if (dt > 1000 * 60 * 60 * 24 * 4) {
- content = [m(
- 'div',
- { className: 'PostStream-timeGap' },
- m(
- 'span',
- null,
- app.translator.trans('core.forum.post_stream.time_lapsed_text', { period: moment.duration(dt).humanize() })
- )
- ), content];
- }
-
- lastTime = time;
- } else {
- attrs.key = 'post' + postIds[_this3.visibleStart + i];
-
- content = PostLoading.component();
- }
-
- return m(
- 'div',
- babelHelpers._extends({ className: 'PostStream-item' }, attrs),
- content
- );
- }),
-
- // If we're viewing the end of the discussion, the user can reply, and
- // is not already doing so, then show a 'write a reply' placeholder.
- this.viewingEnd && (!app.session.user || this.discussion.canReply()) ? m(
- 'div',
- { className: 'PostStream-item', key: 'reply' },
- ReplyPlaceholder.component({ discussion: this.discussion })
- ) : ''
+ items
);
}
}, {
@@ -25777,6 +25989,13 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
*/
this.index = 0;
+ /**
+ * The index of the comment that is currently at the top of the viewport.
+ *
+ * @type {Number}
+ */
+ this.commentsIndex = 0;
+
/**
* The number of posts that are currently visible in the viewport.
*
@@ -25791,16 +26010,6 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
*/
this.description = '';
- /**
- * The integer index of the last item that is visible in the viewport. This
- * is displayed on the scrubber (i.e. X of 100 posts).
- *
- * @return {Integer}
- */
- this.visibleIndex = computed('index', 'visible', 'count', function (index, visible, count) {
- return Math.min(count, Math.ceil(Math.max(0, index) + visible));
- });
-
// When the post stream begins loading posts at a certain index, we want our
// scrubber scrollbar to jump to that position.
this.props.stream.on('unpaused', this.handlers.streamWasUnpaused = this.streamWasUnpaused.bind(this));
@@ -25829,12 +26038,12 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
index: m(
'span',
{ className: 'Scrubber-index' },
- retain || formatNumber(this.visibleIndex())
+ retain || formatNumber(this.commentsIndex)
),
count: m(
'span',
{ className: 'Scrubber-count' },
- formatNumber(count)
+ formatNumber(this.commentsCount())
)
});
@@ -25952,6 +26161,17 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
return this.props.stream.count();
}
+ /**
+ * Get the number of comments in the discussion.
+ *
+ * @return {Integer}
+ */
+ }, {
+ key: 'commentsCount',
+ value: function commentsCount() {
+ return this.props.stream.discussion.commentsCount();
+ }
+
/**
* When the stream is unpaused, update the scrubber to reflect its position.
*/
@@ -26005,6 +26225,7 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
var marginTop = stream.getMarginTop();
var viewportTop = scrollTop + marginTop;
var viewportHeight = $(window).height() - marginTop;
+ var viewportBottom = viewportTop + viewportHeight;
// Before looping through all of the posts, we reset the scrollbar
// properties to a 'default' state. These values reflect what would be
@@ -26012,6 +26233,7 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
// and the viewport had a height of 0.
var $items = stream.$('> .PostStream-item[data-index]');
var index = $items.first().data('index') || 0;
+ var commentsIndex = 0;
var visible = 0;
var period = '';
@@ -26023,33 +26245,60 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
var top = $this.offset().top;
var height = $this.outerHeight(true);
+ // If an item is comment and is above the top of the viewport,
+ // or within the viewport or more than 50% of it is visible,
+ // update the commentIndex
+ if ($this.data('type') == 'comment' && top < viewportBottom) {
+ commentsIndex++;
+ }
+
// If this item is above the top of the viewport, skip to the next
// post. If it's below the bottom of the viewport, break out of the
// loop.
if (top + height < viewportTop) {
- visible = (top + height - viewportTop) / height;
- index = parseFloat($this.data('index')) + 1 - visible;
return true;
}
if (top > viewportTop + viewportHeight) {
return false;
}
+ var visibleTop = Math.max(0, viewportTop - top);
+ var visibleBottom = Math.min(height, viewportTop + viewportHeight - top);
+ var visiblePost = visibleBottom - visibleTop;
+
+ if (visiblePost > 0) {
+ visible += visiblePost / height;
+ }
+
+ if (top <= viewportTop) {
+ index = parseFloat($this.data('index')) + visibleTop / height;
+ }
+
+ //if (top <= viewportTop) {
+ //
+ //}
+
// If the bottom half of this item is visible at the top of the
// viewport, then set the start of the visible proportion as our index.
- if (top <= viewportTop && top + height > viewportTop) {
- visible = (top + height - viewportTop) / height;
- index = parseFloat($this.data('index')) + 1 - visible;
- //
- // If the top half of this item is visible at the bottom of the
- // viewport, then add the visible proportion to the visible
- // counter.
- } else if (top + height >= viewportTop + viewportHeight) {
- visible += (viewportTop + viewportHeight - top) / height;
- //
- // If the whole item is visible in the viewport, then increment the
- // visible counter.
- } else visible++;
+ //if (top <= viewportTop) {
+ //
+ //
+ // if (top + height > viewportTop) {
+ // visible = (top + height - viewportTop) / height;
+ // }
+ //
+ // index = parseFloat($this.data('index')) + 1 - visible;
+ // //
+ //// If the top half of this item is visible at the bottom of the
+ //// viewport, then add the visible proportion to the visible
+ //// counter.
+ //}
+ //if (top + height >= viewportTop + viewportHeight) {
+ // visible += (viewportTop + viewportHeight - top) / height;
+ ////
+ //// If the whole item is visible in the viewport, then increment the
+ //// visible counter.
+ //}// else visible++;
// If this item has a time associated with it, then set the
// scrollbar's current period to a formatted version of this time.
@@ -26057,7 +26306,10 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
if (time) period = time;
});
+ console.log(index, visible);
+
this.index = index;
+ this.commentsIndex = commentsIndex;
this.visible = visible;
this.description = period ? moment(period).format('MMMM YYYY') : '';
}
@@ -26132,7 +26384,7 @@ System.register('flarum/components/PostStreamScrubber', ['flarum/Component', 'fl
var visible = this.visible || 1;
var $scrubber = this.$();
- $scrubber.find('.Scrubber-index').text(formatNumber(this.visibleIndex()));
+ $scrubber.find('.Scrubber-index').text(formatNumber(this.commentsIndex));
$scrubber.find('.Scrubber-description').text(this.description);
$scrubber.toggleClass('disabled', this.disabled());
@@ -26368,14 +26620,13 @@ System.register('flarum/components/PostsUserPage', ['flarum/components/UserPage'
m(
'div',
{ className: 'PostsUserPage-discussion' },
- 'In ',
- m(
- 'a',
- { href: app.route.post(post), config: m.route },
- post.discussion().title()
- )
+ app.translator.trans('core.forum.user.in_discussion_text', { discussion: m(
+ 'a',
+ { href: app.route.post(post), config: m.route },
+ post.discussion().title()
+ ) })
),
- CommentPost.component({ post: post, showDiscussionTitle: true })
+ CommentPost.component({ post: post })
);
})
),
@@ -26469,7 +26720,7 @@ System.register('flarum/components/PostsUserPage', ['flarum/components/UserPage'
}
};
});;
-System.register('flarum/components/PostUser', ['flarum/Component', 'flarum/components/UserCard', 'flarum/helpers/avatar', 'flarum/helpers/username', 'flarum/helpers/listItems'], function (_export) {
+System.register('flarum/components/PostUser', ['flarum/Component', 'flarum/components/UserCard', 'flarum/helpers/avatar', 'flarum/helpers/username', 'flarum/helpers/userOnline', 'flarum/helpers/listItems'], function (_export) {
/**
* The `PostUser` component shows the avatar and username of a post's author.
@@ -26480,7 +26731,7 @@ System.register('flarum/components/PostUser', ['flarum/Component', 'flarum/compo
*/
'use strict';
- var Component, UserCard, avatar, username, listItems, PostUser;
+ var Component, UserCard, avatar, username, userOnline, listItems, PostUser;
return {
setters: [function (_flarumComponent) {
Component = _flarumComponent['default'];
@@ -26490,6 +26741,8 @@ System.register('flarum/components/PostUser', ['flarum/Component', 'flarum/compo
avatar = _flarumHelpersAvatar['default'];
}, function (_flarumHelpersUsername) {
username = _flarumHelpersUsername['default'];
+ }, function (_flarumHelpersUserOnline) {
+ userOnline = _flarumHelpersUserOnline['default'];
}, function (_flarumHelpersListItems) {
listItems = _flarumHelpersListItems['default'];
}],
@@ -26545,6 +26798,7 @@ System.register('flarum/components/PostUser', ['flarum/Component', 'flarum/compo
return m(
'div',
{ className: 'PostUser' },
+ userOnline(user),
m(
'h3',
null,
@@ -26663,6 +26917,16 @@ System.register('flarum/components/ReplyComposer', ['flarum/components/ComposerB
babelHelpers.get(Object.getPrototypeOf(ReplyComposer.prototype), 'init', this).call(this);
this.editor.props.preview = function () {
+ // If the composer backdrop is visible, assume we're on mobile and need to
+ // minimize the composer in order to see the preview. We do this as a
+ // timeout so that it occurs after the click handler on the composer
+ // itself that shows the composer if minimized.
+ if (app.composer.isMobile()) {
+ setTimeout(function () {
+ return app.composer.minimize();
+ }, 0);
+ }
+
m.route(app.route.discussion(_this.props.discussion, 'reply'));
};
}
@@ -26985,7 +27249,7 @@ System.register('flarum/components/Search', ['flarum/Component', 'flarum/compone
*
* @type {Function}
*/
- this.value = m.prop();
+ this.value = m.prop('');
/**
* Whether or not the search input has focus.
@@ -27108,7 +27372,11 @@ System.register('flarum/components/Search', ['flarum/Component', 'flarum/compone
case 13:
// Return
- m.route(_this2.getItem(_this2.index).find('a').attr('href'));
+ if (_this2.value()) {
+ m.route(_this2.getItem(_this2.index).find('a').attr('href'));
+ } else {
+ _this2.clear();
+ }
_this2.$('input').blur();
break;
@@ -27700,7 +27968,7 @@ System.register('flarum/components/SettingsPage', ['flarum/components/UserPage',
items.add('notifications', FieldSet.component({
label: app.translator.trans('core.forum.settings.notifications_heading'),
className: 'Settings-notifications',
- children: [NotificationGrid.component({ user: this.user })]
+ children: this.notificationsItems().toArray()
}));
items.add('privacy', FieldSet.component({
@@ -27741,6 +28009,21 @@ System.register('flarum/components/SettingsPage', ['flarum/components/UserPage',
return items;
}
+ /**
+ * Build an item list for the user's notification settings.
+ *
+ * @return {ItemList}
+ */
+ }, {
+ key: 'notificationsItems',
+ value: function notificationsItems() {
+ var items = new ItemList();
+
+ items.add('notificationGrid', NotificationGrid.component({ user: this.user }));
+
+ return items;
+ }
+
/**
* Generate a callback that will save a value to the given preference.
*
@@ -27857,13 +28140,6 @@ System.register('flarum/components/SignUpModal', ['flarum/components/Modal', 'fl
* @type {Function}
*/
this.password = m.prop(this.props.password || '');
-
- /**
- * The user that has been signed up and that should be welcomed.
- *
- * @type {null|User}
- */
- this.welcomeUser = null;
}
}, {
key: 'className',
@@ -27891,13 +28167,13 @@ System.register('flarum/components/SignUpModal', ['flarum/components/Modal', 'fl
}, {
key: 'body',
value: function body() {
- var body = [this.props.token ? '' : m(LogInButtons, null), m(
+ return [this.props.token ? '' : m(LogInButtons, null), m(
'div',
{ className: 'Form Form--centered' },
m(
'div',
{ className: 'Form-group' },
- m('input', { className: 'FormControl', name: 'username', placeholder: extractText(app.translator.trans('core.forum.sign_up.username_placeholder')),
+ m('input', { className: 'FormControl', name: 'username', type: 'text', placeholder: extractText(app.translator.trans('core.forum.sign_up.username_placeholder')),
value: this.username(),
onchange: m.withAttr('value', this.username),
disabled: this.loading })
@@ -27931,54 +28207,6 @@ System.register('flarum/components/SignUpModal', ['flarum/components/Modal', 'fl
)
)
)];
-
- if (this.welcomeUser) {
- var user = this.welcomeUser;
-
- var fadeIn = function fadeIn(element, isInitialized) {
- if (isInitialized) return;
- $(element).hide().fadeIn();
- };
-
- body.push(m(
- 'div',
- { className: 'SignUpModal-welcome', style: { background: user.color() }, config: fadeIn },
- m(
- 'div',
- { className: 'darkenBackground' },
- m(
- 'div',
- { className: 'container' },
- avatar(user),
- m(
- 'h3',
- null,
- app.translator.trans('core.forum.sign_up.welcome_text', { user: user })
- ),
- m(
- 'p',
- null,
- app.translator.trans('core.forum.sign_up.confirmation_message', { email: m(
- 'strong',
- null,
- user.email()
- ) })
- ),
- m(
- 'p',
- null,
- m(
- Button,
- { className: 'Button Button--primary', onclick: this.hide.bind(this) },
- app.translator.trans('core.forum.sign_up.dismiss_button')
- )
- )
- )
- )
- ));
- }
-
- return body;
}
}, {
key: 'footer',
@@ -28018,8 +28246,6 @@ System.register('flarum/components/SignUpModal', ['flarum/components/Modal', 'fl
}, {
key: 'onsubmit',
value: function onsubmit(e) {
- var _this = this;
-
e.preventDefault();
this.loading = true;
@@ -28031,18 +28257,8 @@ System.register('flarum/components/SignUpModal', ['flarum/components/Modal', 'fl
method: 'POST',
data: data,
errorHandler: this.onerror.bind(this)
- }).then(function (payload) {
- var user = app.store.pushPayload(payload);
-
- // If the user's new account has been activated, then we can assume
- // that they have been logged in too. Thus, we will reload the page.
- // Otherwise, we will show a message asking them to check their email.
- if (user.isActivated()) {
- window.location.reload();
- } else {
- _this.welcomeUser = user;
- _this.loaded();
- }
+ }).then(function () {
+ return window.location.reload();
}, this.loaded.bind(this));
}
@@ -28066,6 +28282,10 @@ System.register('flarum/components/SignUpModal', ['flarum/components/Modal', 'fl
data.password = this.password();
}
+ if (this.props.avatarUrl) {
+ data.avatarUrl = this.props.avatarUrl;
+ }
+
return data;
}
}]);
@@ -28355,6 +28575,7 @@ System.register('flarum/components/TextEditor', ['flarum/Component', 'flarum/uti
children: this.props.submitLabel,
icon: 'check',
className: 'Button Button--primary',
+ itemClassName: 'App-primaryControl',
onclick: this.onsubmit.bind(this)
}));
@@ -28583,12 +28804,17 @@ System.register('flarum/components/UserBio', ['flarum/Component', 'flarum/compon
}, {
key: 'save',
value: function save(value) {
+ var _this = this;
+
var user = this.props.user;
if (user.bio() !== value) {
this.loading = true;
- user.save({ bio: value })['finally'](this.loaded.bind(this));
+ user.save({ bio: value })['finally'](function () {
+ _this.loading = false;
+ m.redraw();
+ });
}
this.editing = false;
@@ -28960,7 +29186,7 @@ System.register('flarum/components/UserPage', ['flarum/components/Page', 'flarum
}
};
});;
-System.register('flarum/components/UsersSearchSource', ['flarum/helpers/highlight', 'flarum/helpers/avatar'], function (_export) {
+System.register('flarum/components/UsersSearchSource', ['flarum/helpers/highlight', 'flarum/helpers/avatar', 'flarum/helpers/username'], function (_export) {
/**
* The `UsersSearchSource` finds and displays user search results in the search
@@ -28970,12 +29196,14 @@ System.register('flarum/components/UsersSearchSource', ['flarum/helpers/highligh
*/
'use strict';
- var highlight, avatar, UsersSearchResults;
+ var highlight, avatar, username, UsersSearchResults;
return {
setters: [function (_flarumHelpersHighlight) {
highlight = _flarumHelpersHighlight['default'];
}, function (_flarumHelpersAvatar) {
avatar = _flarumHelpersAvatar['default'];
+ }, function (_flarumHelpersUsername) {
+ username = _flarumHelpersUsername['default'];
}],
execute: function () {
UsersSearchResults = (function () {
@@ -29005,6 +29233,9 @@ System.register('flarum/components/UsersSearchSource', ['flarum/helpers/highligh
{ className: 'Dropdown-header' },
app.translator.trans('core.forum.search.users_heading')
), results.map(function (user) {
+ var name = username(user);
+ name.children[0] = highlight(name.children[0], query);
+
return m(
'li',
{ className: 'UserSearchResult', 'data-index': 'users' + user.id() },
@@ -29012,7 +29243,7 @@ System.register('flarum/components/UsersSearchSource', ['flarum/helpers/highligh
'a',
{ href: app.route.user(user), config: m.route },
avatar(user),
- highlight(user.username(), query)
+ name
)
);
})];
@@ -29571,7 +29802,8 @@ System.register('flarum/helpers/listItems', ['flarum/components/Separator', 'fla
return [isListItem ? item : m(
'li',
- { className: classList([item.itemName ? 'item-' + item.itemName : '', className, active ? 'active' : '']) },
+ { className: classList([item.itemName ? 'item-' + item.itemName : '', className, active ? 'active' : '']),
+ key: item.itemName },
item
), ' '];
});
@@ -29644,7 +29876,7 @@ System.register("flarum/helpers/username", [], function (_export) {
_export("default", username);
function username(user) {
- var name = user && user.username() || app.translator.trans('core.lib.deleted_user_text');
+ var name = user && user.username() || app.translator.trans('core.lib.username.deleted_text');
return m(
"span",
@@ -29658,6 +29890,37 @@ System.register("flarum/helpers/username", [], function (_export) {
execute: function () {}
};
});;
+System.register('flarum/helpers/userOnline', ['flarum/helpers/icon'], function (_export) {
+
+ /**
+ * The `useronline` helper displays a green circle if the user is online
+ *
+ * @param {User} user
+ * @return {Object}
+ */
+ 'use strict';
+
+ var icon;
+
+ _export('default', userOnline);
+
+ function userOnline(user) {
+ if (user.lastSeenTime() && user.isOnline()) {
+ return m(
+ 'span',
+ { className: 'UserOnline' },
+ icon('circle')
+ );
+ }
+ }
+
+ return {
+ setters: [function (_flarumHelpersIcon) {
+ icon = _flarumHelpersIcon['default'];
+ }],
+ execute: function () {}
+ };
+});;
System.register('flarum/initializers/boot', ['flarum/utils/ScrollListener', 'flarum/utils/Pane', 'flarum/utils/Drawer', 'flarum/utils/mapRoutes', 'flarum/helpers/icon', 'flarum/components/Navigation', 'flarum/components/HeaderPrimary', 'flarum/components/HeaderSecondary', 'flarum/components/Composer', 'flarum/components/ModalManager', 'flarum/components/AlertManager'], function (_export) {
/*global FastClick*/
@@ -29854,7 +30117,7 @@ System.register('flarum/initializers/preload', ['flarum/Session'], function (_ex
app.forum = app.store.getById('forums', 1);
- app.session = new Session(app.preload.session.token, app.store.getById('users', app.preload.session.userId));
+ app.session = new Session(app.store.getById('users', app.preload.session.userId), app.preload.session.csrfToken);
}
return {
@@ -30167,7 +30430,7 @@ System.register('flarum/Model', [], function (_export) {
// Before we update the model's data, we should make a copy of the model's
// old data so that we can revert back to it if something goes awry during
// persistence.
- var oldData = JSON.parse(JSON.stringify(this.data));
+ var oldData = this.copyData();
this.pushData(data);
@@ -30232,6 +30495,11 @@ System.register('flarum/Model', [], function (_export) {
value: function apiEndpoint() {
return '/' + this.data.type + (this.exists ? '/' + this.data.id : '');
}
+ }, {
+ key: 'copyData',
+ value: function copyData() {
+ return JSON.parse(JSON.stringify(this.data));
+ }
/**
* Generate a function which returns the value of the given attribute.
@@ -30701,7 +30969,7 @@ System.register('flarum/models/User', ['flarum/Model', 'flarum/utils/mixin', 'fl
avatarUrl: Model.attribute('avatarUrl'),
bio: Model.attribute('bio'),
bioHtml: computed('bio', function (bio) {
- return bio ? '' + $('
').text(bio).html().replace(/\n/g, '
').autoLink() + '' : '';
+ return bio ? '' + $('
').text(bio).html().replace(/\n/g, '
').autoLink({ rel: 'nofollow' }) + '' : '';
}),
preferences: Model.attribute('preferences'),
groups: Model.hasMany('groups'),
@@ -30812,7 +31080,7 @@ System.register('flarum/Session', [], function (_export) {
setters: [],
execute: function () {
Session = (function () {
- function Session(token, user) {
+ function Session(user, csrfToken) {
babelHelpers.classCallCheck(this, Session);
/**
@@ -30824,12 +31092,12 @@ System.register('flarum/Session', [], function (_export) {
this.user = user;
/**
- * The token that was used for authentication.
+ * The CSRF token.
*
* @type {String|null}
* @public
*/
- this.token = token;
+ this.csrfToken = csrfToken;
}
/**
@@ -30850,9 +31118,7 @@ System.register('flarum/Session', [], function (_export) {
method: 'POST',
url: app.forum.attribute('baseUrl') + '/login',
data: { identification: identification, password: password }
- }, options)).then(function () {
- return window.location.reload();
- });
+ }, options));
}
/**
@@ -30863,22 +31129,7 @@ System.register('flarum/Session', [], function (_export) {
}, {
key: 'logout',
value: function logout() {
- window.location = app.forum.attribute('baseUrl') + '/logout?token=' + this.token;
- }
-
- /**
- * Apply an authorization header with the current token to the given
- * XMLHttpRequest object.
- *
- * @param {XMLHttpRequest} xhr
- * @public
- */
- }, {
- key: 'authorize',
- value: function authorize(xhr) {
- if (this.token) {
- xhr.setRequestHeader('Authorization', 'Token ' + this.token);
- }
+ window.location = app.forum.attribute('baseUrl') + '/logout?token=' + this.csrfToken;
}
}]);
return Session;
@@ -31840,19 +32091,22 @@ System.register('flarum/utils/DiscussionControls', ['flarum/components/Discussio
* @return {Promise}
*/
deleteAction: function deleteAction() {
- if (confirm(extractText(app.translator.trans('core.forum.discussion_controls.delete_confirmation')))) {
- // If there is a discussion list in the cache, remove this discussion.
- if (app.cache.discussionList) {
- app.cache.discussionList.removeDiscussion(this);
- }
+ var _this3 = this;
+ if (confirm(extractText(app.translator.trans('core.forum.discussion_controls.delete_confirmation')))) {
// If we're currently viewing the discussion that was deleted, go back
// to the previous page.
if (app.viewingDiscussion(this)) {
app.history.back();
}
- return this['delete']();
+ return this['delete']().then(function () {
+ // If there is a discussion list in the cache, remove this discussion.
+ if (app.cache.discussionList) {
+ app.cache.discussionList.removeDiscussion(_this3);
+ m.redraw();
+ }
+ });
}
},
@@ -31862,7 +32116,7 @@ System.register('flarum/utils/DiscussionControls', ['flarum/components/Discussio
* @return {Promise}
*/
renameAction: function renameAction() {
- var _this3 = this;
+ var _this4 = this;
var currentTitle = this.title();
var title = prompt(extractText(app.translator.trans('core.forum.discussion_controls.rename_text')), currentTitle);
@@ -31872,7 +32126,7 @@ System.register('flarum/utils/DiscussionControls', ['flarum/components/Discussio
// indicating that the discussion was renamed.
if (title && title !== currentTitle) {
return this.save({ title: title }).then(function () {
- if (app.viewingDiscussion(_this3)) {
+ if (app.viewingDiscussion(_this4)) {
app.current.stream.update();
}
m.redraw();
@@ -32892,7 +33146,7 @@ System.register('flarum/utils/PostControls', ['flarum/components/EditPostCompose
* @return {ItemList}
* @protected
*/
- destructiveControls: function destructiveControls(post) {
+ destructiveControls: function destructiveControls(post, context) {
var items = new ItemList();
if (post.contentType() === 'comment' && !post.isHidden()) {
@@ -32915,7 +33169,7 @@ System.register('flarum/utils/PostControls', ['flarum/components/EditPostCompose
items.add('delete', Button.component({
icon: 'times',
children: app.translator.trans('core.forum.post_controls.delete_forever_button'),
- onclick: this.deleteAction.bind(post)
+ onclick: this.deleteAction.bind(post, context)
}));
}
}
@@ -32962,10 +33216,17 @@ System.register('flarum/utils/PostControls', ['flarum/components/EditPostCompose
*
* @return {Promise}
*/
- deleteAction: function deleteAction() {
- this.discussion().removePost(this.id());
+ deleteAction: function deleteAction(context) {
+ var _this2 = this;
- return this['delete']();
+ if (context) context.loading = true;
+
+ return this['delete']().then(function () {
+ _this2.discussion().removePost(_this2.id());
+ })['finally'](function () {
+ if (context) context.loading = false;
+ m.redraw();
+ });
}
});
}