Massive JavaScript cleanup

- Use JSX for templates
- Docblock/comment everything
- Mostly passes ESLint (still some work to do)
- Lots of renaming, refactoring, etc.

CSS hasn't been updated yet.
This commit is contained in:
Toby Zerner
2015-07-15 14:00:11 +09:30
parent 4480e0a83f
commit ab6c03c0cc
220 changed files with 9785 additions and 5919 deletions

View File

@ -0,0 +1,190 @@
import Component from 'flarum/Component';
import Checkbox from 'flarum/components/Checkbox';
import icon from 'flarum/helpers/icon';
import ItemList from 'flarum/utils/ItemList';
/**
* The `NotificationGrid` component displays a table of notification types and
* methods, allowing the user to toggle each combination.
*
* ### Props
*
* - `user`
*/
export default class NotificationGrid extends Component {
constructor(...args) {
super(...args);
/**
* Information about the available notification methods.
*
* @type {Array}
*/
this.methods = [
{name: 'alert', icon: 'bell', label: 'Alert'},
{name: 'email', icon: 'envelope-o', label: 'Email'}
];
/**
* A map of notification type-method combinations to the checkbox instances
* that represent them.
*
* @type {Object}
*/
this.inputs = {};
/**
* Information about the available notification types.
*
* @type {Object}
*/
this.types = this.notificationTypes().toArray();
// For each of the notification type-method combinations, create and store a
// new checkbox component instance, which we will render in the view.
this.types.forEach(type => {
this.methods.forEach(method => {
const key = this.preferenceKey(type.name, method.name);
const preference = this.props.user.preferences()[key];
this.inputs[key] = new Checkbox({
state: !!preference,
disabled: typeof preference === 'undefined',
onchange: () => this.toggle([key])
});
});
});
}
view() {
return (
<table className="notification-grid">
<thead>
<tr>
<td/>
{this.methods.map(method => (
<th className="toggle-group" onclick={this.toggleMethod.bind(this, method.name)}>
{icon(method.icon)} {method.label}
</th>
))}
</tr>
</thead>
<tbody>
{this.types.map(type => (
<tr>
<td className="toggle-group" onclick={this.toggleType.bind(this, type.name)}>
{type.label}
</td>
{this.methods.map(method => (
<td className="checkbox-cell">
{this.inputs[this.preferenceKey(type.name, method.name)].render()}
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
config(isInitialized) {
if (isInitialized) return;
var self = this;
this.$('thead .toggle-group').bind('mouseenter mouseleave', function(e) {
var i = parseInt($(this).index()) + 1;
self.$('table').find('td:nth-child('+i+')').toggleClass('highlighted', e.type === 'mouseenter');
});
this.$('tbody .toggle-group').bind('mouseenter mouseleave', function(e) {
$(this).parent().find('td').toggleClass('highlighted', e.type === 'mouseenter');
});
}
/**
* Toggle the state of the given preferences, based on the value of the first
* one.
*
* @param {Array} keys
*/
toggle(keys) {
const user = this.props.user;
const preferences = user.preferences();
const enabled = !preferences[keys[0]];
keys.forEach(key => {
const control = this.inputs[key];
control.loading = true;
preferences[key] = control.props.state = enabled;
});
m.redraw();
user.save({preferences}).then(() => {
keys.forEach(key => this.inputs[key].loading = false);
m.redraw();
});
}
/**
* Toggle all notification types for the given method.
*
* @param {String} method
*/
toggleMethod(method) {
const keys = this.types
.map(type => this.preferenceKey(type.name, method))
.filter(key => !this.inputs[key].props.disabled);
this.toggle(keys);
}
/**
* Toggle all notification methods for the given type.
*
* @param {String} type
*/
toggleType(type) {
const keys = this.methods
.map(method => this.preferenceKey(type, method.name))
.filter(key => !this.inputs[key].props.disabled);
this.toggle(keys);
}
/**
* Get the name of the preference key for the given notification type-method
* combination.
*
* @param {String} type
* @param {String} method
* @return {String}
*/
preferenceKey(type, method) {
return 'notify_' + type + '_' + method;
}
/**
* Build an item list for the notification types to display in the grid.
*
* Each notification type is an object which has the following properties:
*
* - `name` The name of the notification type.
* - `label` The label to display in the notification grid row.
*
* @return {ItemList}
*/
notificationTypes() {
const items = new ItemList();
items.add('discussionRenamed', {
name: 'discussionRenamed',
label: [icon('pencil'), ' Someone renames a discussion I started']
});
return items;
}
}