mirror of
https://github.com/flarum/framework.git
synced 2025-05-31 20:43:36 +08:00
Finish admin permissions page and clean up everything
This commit is contained in:
@ -189,9 +189,10 @@ export default class Model {
|
||||
method: 'DELETE',
|
||||
url: app.forum.attribute('apiUrl') + this.apiEndpoint(),
|
||||
data
|
||||
}).then(
|
||||
() => this.exists = false
|
||||
);
|
||||
}).then(() => {
|
||||
this.exists = false;
|
||||
this.store.remove(this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,7 +215,7 @@ export default class Model {
|
||||
*/
|
||||
static attribute(name, transform) {
|
||||
return function() {
|
||||
const value = this.data.attributes[name];
|
||||
const value = this.data.attributes && this.data.attributes[name];
|
||||
|
||||
return transform ? transform(value) : value;
|
||||
};
|
||||
|
@ -139,6 +139,15 @@ export default class Store {
|
||||
return records ? Object.keys(records).map(id => records[id]) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given model from the store.
|
||||
*
|
||||
* @param {Model} model
|
||||
*/
|
||||
remove(model) {
|
||||
delete this.data[model.data.type][model.id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new record of the given type.
|
||||
*
|
||||
|
@ -20,17 +20,17 @@ export default class Badge extends Component {
|
||||
const type = extract(attrs, 'type');
|
||||
const iconName = extract(attrs, 'icon');
|
||||
|
||||
attrs.className = 'Badge Badge--' + type + ' ' + (attrs.className || '');
|
||||
attrs.title = extract(attrs, 'label');
|
||||
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.className;
|
||||
attrs.key = attrs.type;
|
||||
|
||||
return (
|
||||
<span {...attrs}>
|
||||
{iconName ? icon(iconName, {className: 'Badge-icon'}) : ''}
|
||||
{iconName ? icon(iconName, {className: 'Badge-icon'}) : m.trust(' ')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export default class Button extends Component {
|
||||
const iconName = this.props.icon;
|
||||
|
||||
return [
|
||||
iconName ? icon(iconName, {className: 'Button-icon'}) : '', ' ',
|
||||
iconName && iconName !== true ? icon(iconName, {className: 'Button-icon'}) : '',
|
||||
this.props.children ? <span className="Button-label">{this.props.children}</span> : '',
|
||||
this.props.loading ? LoadingIndicator.component({size: 'tiny', className: 'LoadingIndicator--inline'}) : ''
|
||||
];
|
||||
|
@ -10,9 +10,10 @@ import listItems from 'flarum/helpers/listItems';
|
||||
*
|
||||
* - `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. Defaults
|
||||
* to 'ellipsis-v'.
|
||||
* - `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`
|
||||
*
|
||||
* The children will be displayed as a list inside of the dropdown menu.
|
||||
*/
|
||||
@ -23,8 +24,8 @@ export default class Dropdown extends Component {
|
||||
props.className = props.className || '';
|
||||
props.buttonClassName = props.buttonClassName || '';
|
||||
props.contentClassName = props.contentClassName || '';
|
||||
props.icon = props.icon || 'ellipsis-v';
|
||||
props.label = props.label || app.trans('core.controls');
|
||||
props.caretIcon = typeof props.caretIcon !== 'undefined' ? props.caretIcon : 'caret-down';
|
||||
}
|
||||
|
||||
view() {
|
||||
@ -40,6 +41,29 @@ export default class Dropdown extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
config(isInitialized) {
|
||||
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', () => {
|
||||
const $menu = this.$('.Dropdown-menu').removeClass('Dropdown-menu--top');
|
||||
|
||||
$menu.toggleClass(
|
||||
'Dropdown-menu--top',
|
||||
$menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height()
|
||||
);
|
||||
});
|
||||
|
||||
this.$().on('hide.bs.dropdown', () => {
|
||||
if (this.props.onhide) {
|
||||
this.props.onhide();
|
||||
m.redraw();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template for the button.
|
||||
*
|
||||
@ -65,9 +89,9 @@ export default class Dropdown extends Component {
|
||||
*/
|
||||
getButtonContent() {
|
||||
return [
|
||||
icon(this.props.icon, {className: 'Button-icon'}),
|
||||
this.props.icon ? icon(this.props.icon, {className: 'Button-icon'}) : '',
|
||||
<span className="Button-label">{this.props.label}</span>, ' ',
|
||||
icon('caret-down', {className: 'Button-caret'})
|
||||
this.props.caretIcon ? icon(this.props.caretIcon, {className: 'Button-caret'}) : ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
16
js/lib/components/GroupBadge.js
Normal file
16
js/lib/components/GroupBadge.js
Normal file
@ -0,0 +1,16 @@
|
||||
import Badge from 'flarum/components/Badge';
|
||||
|
||||
export default class GroupBadge extends Badge {
|
||||
static initProps(props) {
|
||||
super.initProps(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;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,23 +5,29 @@ import icon from 'flarum/helpers/icon';
|
||||
* The `SelectDropdown` component is the same as a `Dropdown`, except the toggle
|
||||
* button's label is set as the label of the first child which has a truthy
|
||||
* `active` prop.
|
||||
*
|
||||
* ### Props
|
||||
*
|
||||
* - `caretIcon`
|
||||
* - `defaultLabel`
|
||||
*/
|
||||
export default class SelectDropdown extends Dropdown {
|
||||
static initProps(props) {
|
||||
super.initProps(props);
|
||||
|
||||
props.className += ' Dropdown--select';
|
||||
props.caretIcon = props.caretIcon || 'sort';
|
||||
}
|
||||
|
||||
getButtonContent() {
|
||||
const activeChild = this.props.children.filter(child => child.props.active)[0];
|
||||
let label = activeChild && activeChild.props.children;
|
||||
let label = activeChild && activeChild.props.children || this.props.defaultLabel;
|
||||
|
||||
if (label instanceof Array) label = label[0];
|
||||
|
||||
return [
|
||||
<span className="Button-label">{label}</span>, ' ',
|
||||
icon('sort', {className: 'Button-caret'})
|
||||
icon(this.props.caretIcon, {className: 'Button-caret'})
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ class Group extends mixin(Model, {
|
||||
icon: Model.attribute('icon')
|
||||
}) {}
|
||||
|
||||
Group.ADMINISTRATOR_ID = 1;
|
||||
Group.GUEST_ID = 2;
|
||||
Group.MEMBER_ID = 3;
|
||||
Group.ADMINISTRATOR_ID = '1';
|
||||
Group.GUEST_ID = '2';
|
||||
Group.MEMBER_ID = '3';
|
||||
|
||||
export default Group;
|
||||
|
Reference in New Issue
Block a user