WIP: Add notifications button to timeline

This commit is contained in:
Robin Ward 2016-05-25 15:40:53 -04:00
parent 1e3e4a95fd
commit 9e1021dfa3
No known key found for this signature in database
GPG Key ID: 0E091E2B4ED1B83D
5 changed files with 125 additions and 60 deletions

View File

@ -1,73 +1,49 @@
import DropdownButton from 'discourse/components/dropdown-button';
import NotificationLevels from 'discourse/lib/notification-levels';
import { all, buttonDetails } from 'discourse/lib/notification-levels';
import { iconHTML } from 'discourse/helpers/fa-icon';
import computed from 'ember-addons/ember-computed-decorators';
const NotificationsButton = DropdownButton.extend({
export default DropdownButton.extend({
classNames: ['notification-options'],
title: '',
buttonIncludesText: true,
activeItem: Em.computed.alias('notificationLevel'),
i18nPrefix: '',
i18nPostfix: '',
watchingClasses: 'fa fa-exclamation-circle watching',
trackingClasses: 'fa fa-circle tracking',
mutedClasses: 'fa fa-times-circle muted',
regularClasses: 'fa fa-circle-o regular',
options: function() {
return [['WATCHING', 'watching', this.watchingClasses],
['TRACKING', 'tracking', this.trackingClasses],
['REGULAR', 'regular', this.regularClasses],
['MUTED', 'muted', this.mutedClasses]];
}.property(),
@computed
dropDownContent() {
const prefix = this.get('i18nPrefix');
const postfix = this.get('i18nPostfix');
dropDownContent: function() {
const contents = [],
prefix = this.get('i18nPrefix'),
postfix = this.get('i18nPostfix');
_.each(this.get('options'), function(pair) {
if (postfix === '_pm' && pair[1] === 'regular') { return; }
contents.push({
id: NotificationLevels[pair[0]],
title: I18n.t(prefix + '.' + pair[1] + postfix + '.title'),
description: I18n.t(prefix + '.' + pair[1] + postfix + '.description'),
styleClasses: pair[2]
});
return all.map(l => {
const start = `${prefix}.${l.key}${postfix}`;
return {
id: l.id,
title: I18n.t(`${start}.title`),
description: I18n.t(`${start}.description`),
styleClasses: `${l.key} fa fa-${l.icon}`
};
});
},
return contents;
}.property(),
@computed('notificationLevel')
text(notificationLevel) {
const details = buttonDetails(notificationLevel);
const { key } = details;
const icon = iconHTML(details.icon, { class: key });
text: function() {
const self = this,
prefix = this.get('i18nPrefix'),
postfix = this.get('i18nPostfix');
const key = (function() {
switch (this.get('notificationLevel')) {
case NotificationLevels.WATCHING: return 'watching';
case NotificationLevels.TRACKING: return 'tracking';
case NotificationLevels.MUTED: return 'muted';
default: return 'regular';
}
}).call(this);
const icon = (function() {
switch (key) {
case 'watching': return '<i class="' + self.watchingClasses + '"></i>&nbsp;';
case 'tracking': return '<i class="' + self.trackingClasses + '"></i>&nbsp;';
case 'muted': return '<i class="' + self.mutedClasses + '"></i>&nbsp;';
default: return '<i class="' + self.regularClasses + '"></i>&nbsp;';
}
})();
return icon + ( this.get('buttonIncludesText') ? I18n.t(prefix + '.' + key + postfix + ".title") : '') + "<span class='caret'></span>";
}.property('notificationLevel'),
if (this.get('buttonIncludesText')) {
const prefix = this.get('i18nPrefix');
const postfix = this.get('i18nPostfix');
const text = I18n.t(`${prefix}.${key}${postfix}.title`);
return `${icon}&nbsp;${text}<span class='caret'></span>`;
} else {
return `${icon}&nbsp;<span class='caret'></span>`;
}
},
clicked(/* id */) {
// sub-class needs to implement this
}
});
export default NotificationsButton;
export { NotificationLevels };

View File

@ -1,6 +1,24 @@
export default {
const NotificationLevels = {
WATCHING: 3,
TRACKING: 2,
REGULAR: 1,
MUTED: 0
};
export default NotificationLevels;
export function buttonDetails(level) {
switch(level) {
case NotificationLevels.WATCHING:
return { id: NotificationLevels.WATCHING, key: 'watching', icon: 'exclamation-circle' };
case NotificationLevels.TRACKING:
return { id: NotificationLevels.TRACKING, key: 'tracking', icon: 'circle' };
case NotificationLevels.MUTED:
return { id: NotificationLevels.MUTED, key: 'muted', icon: 'times-circle' };
default:
return { id: NotificationLevels.REGULAR, key: 'regular', icon: 'circle-o' };
}
}
export const all = [ NotificationLevels.WATCHING,
NotificationLevels.TRACKING,
NotificationLevels.MUTED,
NotificationLevels.DEFAULT ].map(buttonDetails);

View File

@ -30,12 +30,11 @@ export default createWidget('button', {
html(attrs) {
const contents = [];
const left = !attrs.iconRight;
if (attrs.icon && left) { contents.push(iconNode(attrs.icon)); }
if (attrs.icon && left) { contents.push(iconNode(attrs.icon, { class: attrs.iconClass })); }
if (attrs.label) { contents.push(I18n.t(attrs.label, attrs.labelOptions)); }
if (attrs.contents) { contents.push(attrs.contents); }
if (attrs.icon && !left) { contents.push(iconNode(attrs.icon)); }
if (attrs.icon && !left) { contents.push(iconNode(attrs.icon, { class: attrs.iconClass })); }
return contents;
},

View File

@ -0,0 +1,69 @@
import { createWidget } from 'discourse/widgets/widget';
import { all, buttonDetails } from 'discourse/lib/notification-levels';
import { h } from 'virtual-dom';
createWidget('notification-option', {
buildKey: attrs => `topic-notifications-button-${attrs.id}`,
tagName: 'li',
html(attrs) {
return h('a', [
h('span.icon', { className: `fa fa-${attrs.icon} ${attrs.key}`}),
h('div', [
h('span.title', I18n.t(`topic.notifications.${attrs.key}.title`)),
h('span', I18n.t(`topic.notifications.${attrs.key}.description`)),
])
]);
},
click() {
this.sendWidgetAction('notificationLevelChanged', this.attrs.id);
}
});
export default createWidget('topic-notifications-button', {
tagName: 'span.btn-group.notification-options',
buildKey: () => `topic-notifications-button`,
defaultState() {
return { expanded: false };
},
buildClasses(attrs, state) {
if (state.expanded) { return "open"; }
},
buttonFor(level) {
const details = buttonDetails(level);
return this.attach('button', {
className: `btn no-text`,
icon: details.icon,
action: 'toggleDropdown',
iconClass: details.key
});
},
html(attrs, state) {
const result = [ this.buttonFor(attrs.topic.get('details.notification_level')) ];
if (state.expanded) {
result.push(h('ul.dropdown-menu', all.map(l => this.attach('notification-option', l))));
}
return result;
},
toggleDropdown() {
this.state.expanded = !this.state.expanded;
},
clickOutside() {
if (this.state.expanded) {
this.sendWidgetAction('toggleDropdown');
}
},
notificationLevelChanged(id) {
this.state.expanded = false;
return this.attrs.topic.get('details').updateNotifications(id);
}
});

View File

@ -225,7 +225,10 @@ export default createWidget('topic-timeline', {
const { currentUser } = this;
if (currentUser && currentUser.get('canManageTopic')) {
controls.push(this.attach('topic-admin-menu-button', { topic }));
if (currentUser.get('canManageTopic')) {
controls.push(this.attach('topic-admin-menu-button', { topic }));
}
controls.push(this.attach('topic-notifications-button', { topic }));
}
return [ h('div.timeline-controls', controls),