mirror of
https://github.com/flarum/framework.git
synced 2025-02-17 02:02:47 +08:00
JS cleanup/refactor
This commit is contained in:
parent
f873fd0600
commit
14dbd5381c
254
extensions/tags/js/bootstrap.js
vendored
254
extensions/tags/js/bootstrap.js
vendored
|
@ -1,69 +1,59 @@
|
||||||
import { extend, override } from 'flarum/extension-utils';
|
import { extend, override } from 'flarum/extension-utils';
|
||||||
import Model from 'flarum/model';
|
import Model from 'flarum/model';
|
||||||
import Component from 'flarum/component';
|
|
||||||
import Discussion from 'flarum/models/discussion';
|
import Discussion from 'flarum/models/discussion';
|
||||||
import IndexPage from 'flarum/components/index-page';
|
import IndexPage from 'flarum/components/index-page';
|
||||||
import DiscussionPage from 'flarum/components/discussion-page';
|
import DiscussionPage from 'flarum/components/discussion-page';
|
||||||
import DiscussionList from 'flarum/components/discussion-list';
|
import DiscussionList from 'flarum/components/discussion-list';
|
||||||
import DiscussionHero from 'flarum/components/discussion-hero';
|
import DiscussionHero from 'flarum/components/discussion-hero';
|
||||||
import Separator from 'flarum/components/separator';
|
import Separator from 'flarum/components/separator';
|
||||||
import NavItem from 'flarum/components/nav-item';
|
|
||||||
import ActionButton from 'flarum/components/action-button';
|
import ActionButton from 'flarum/components/action-button';
|
||||||
|
import NavItem from 'flarum/components/nav-item';
|
||||||
import ComposerDiscussion from 'flarum/components/composer-discussion';
|
import ComposerDiscussion from 'flarum/components/composer-discussion';
|
||||||
import ActivityPost from 'flarum/components/activity-post';
|
import ActivityPost from 'flarum/components/activity-post';
|
||||||
import icon from 'flarum/helpers/icon';
|
import icon from 'flarum/helpers/icon';
|
||||||
|
|
||||||
import CategoriesPage from 'categories/components/categories-page';
|
|
||||||
import Category from 'categories/category';
|
|
||||||
import PostDiscussionMoved from 'categories/components/post-discussion-moved';
|
|
||||||
import NotificationDiscussionMoved from 'categories/components/notification-discussion-moved';
|
|
||||||
|
|
||||||
import app from 'flarum/app';
|
import app from 'flarum/app';
|
||||||
|
|
||||||
Discussion.prototype.category = Model.one('category');
|
import Category from 'categories/models/category';
|
||||||
|
import CategoriesPage from 'categories/components/categories-page';
|
||||||
|
import CategoryHero from 'categories/components/category-hero';
|
||||||
|
import CategoryNavItem from 'categories/components/category-nav-item';
|
||||||
|
import MoveDiscussionModal from 'categories/components/move-discussion-modal';
|
||||||
|
import NotificationDiscussionMoved from 'categories/components/notification-discussion-moved';
|
||||||
|
import PostDiscussionMoved from 'categories/components/post-discussion-moved';
|
||||||
|
import categoryLabel from 'categories/helpers/category-label';
|
||||||
|
import categoryIcon from 'categories/helpers/category-icon';
|
||||||
|
|
||||||
app.initializers.add('categories', function() {
|
app.initializers.add('categories', function() {
|
||||||
|
|
||||||
|
// Register routes.
|
||||||
app.routes['categories'] = ['/categories', CategoriesPage.component()];
|
app.routes['categories'] = ['/categories', CategoriesPage.component()];
|
||||||
|
app.routes['category'] = ['/c/:categories', IndexPage.component()];
|
||||||
app.routes['category'] = ['/c/:categories', IndexPage.component({category: true})];
|
|
||||||
|
|
||||||
|
|
||||||
// @todo support combination with filters
|
// @todo support combination with filters
|
||||||
// app.routes['category.filter'] = ['/c/:slug/:filter', IndexPage.component({category: true})];
|
// app.routes['category.filter'] = ['/c/:slug/:filter', IndexPage.component({category: true})];
|
||||||
|
|
||||||
|
// Register models.
|
||||||
|
app.store.models['categories'] = Category;
|
||||||
|
Discussion.prototype.category = Model.one('category');
|
||||||
|
|
||||||
|
// Register components.
|
||||||
app.postComponentRegistry['discussionMoved'] = PostDiscussionMoved;
|
app.postComponentRegistry['discussionMoved'] = PostDiscussionMoved;
|
||||||
app.notificationComponentRegistry['discussionMoved'] = NotificationDiscussionMoved;
|
app.notificationComponentRegistry['discussionMoved'] = NotificationDiscussionMoved;
|
||||||
app.store.model('categories', Category);
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// INDEX PAGE
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Add a category label to each discussion in the discussion list.
|
||||||
extend(DiscussionList.prototype, 'infoItems', function(items, discussion) {
|
extend(DiscussionList.prototype, 'infoItems', function(items, discussion) {
|
||||||
var category = discussion.category();
|
var category = discussion.category();
|
||||||
if (category && category.slug() !== this.props.params.categories) {
|
if (category && category.slug() !== this.props.params.categories) {
|
||||||
items.add('category', m('span.category', {style: 'color: '+category.color()}, category.title()), {first: true});
|
items.add('category', categoryLabel(category), {first: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
class CategoryNavItem extends NavItem {
|
// Add a link to the categories page, as well as a list of all the categories,
|
||||||
view() {
|
// to the index page's sidebar.
|
||||||
var category = this.props.category;
|
|
||||||
var active = this.constructor.active(this.props);
|
|
||||||
return m('li'+(active ? '.active' : ''), m('a', {href: this.props.href, config: m.route, onclick: () => {app.cache.discussionList = null; m.redraw.strategy('none')}, style: active ? 'color: '+category.color() : ''}, [
|
|
||||||
m('span.icon.category-icon', {style: 'background-color: '+category.color()}),
|
|
||||||
category.title()
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static props(props) {
|
|
||||||
var category = props.category;
|
|
||||||
props.params.categories = category.slug();
|
|
||||||
props.href = app.route('category', props.params);
|
|
||||||
props.label = category.title();
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extend(IndexPage.prototype, 'navItems', function(items) {
|
extend(IndexPage.prototype, 'navItems', function(items) {
|
||||||
items.add('categories', NavItem.component({
|
items.add('categories', NavItem.component({
|
||||||
icon: 'reorder',
|
icon: 'reorder',
|
||||||
|
@ -77,200 +67,156 @@ app.initializers.add('categories', function() {
|
||||||
app.store.all('categories').forEach(category => {
|
app.store.all('categories').forEach(category => {
|
||||||
items.add('category'+category.id(), CategoryNavItem.component({category, params: this.stickyParams()}), {last: true});
|
items.add('category'+category.id(), CategoryNavItem.component({category, params: this.stickyParams()}), {last: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
return items;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
extend(IndexPage.prototype, 'params', function(params) {
|
IndexPage.prototype.currentCategory = function() {
|
||||||
params.categories = this.props.category ? m.route.param('categories') : undefined;
|
var slug = this.params().categories;
|
||||||
return params;
|
if (slug) {
|
||||||
});
|
return app.store.getBy('categories', 'slug', slug);
|
||||||
|
|
||||||
class CategoryHero extends Component {
|
|
||||||
view() {
|
|
||||||
var category = this.props.category;
|
|
||||||
|
|
||||||
return m('header.hero.category-hero', {style: 'background-color: '+category.color()}, [
|
|
||||||
m('div.container', [
|
|
||||||
m('div.container-narrow', [
|
|
||||||
m('h2', category.title()),
|
|
||||||
m('div.subtitle', category.description())
|
|
||||||
])
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// If currently viewing a category, insert a category hero at the top of the
|
||||||
|
// view.
|
||||||
extend(IndexPage.prototype, 'view', function(view) {
|
extend(IndexPage.prototype, 'view', function(view) {
|
||||||
if (this.props.category) {
|
var category = this.currentCategory();
|
||||||
var slug = this.params().categories;
|
if (category) {
|
||||||
var category = app.store.all('categories').filter(category => category.slug() == slug)[0];
|
|
||||||
view.children[0] = CategoryHero.component({category});
|
view.children[0] = CategoryHero.component({category});
|
||||||
}
|
}
|
||||||
return view;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If currently viewing a category, restyle the 'new discussion' button to use
|
||||||
|
// the category's color.
|
||||||
extend(IndexPage.prototype, 'sidebarItems', function(items) {
|
extend(IndexPage.prototype, 'sidebarItems', function(items) {
|
||||||
var slug = this.params().categories;
|
var category = this.currentCategory();
|
||||||
var category = app.store.all('categories').filter(category => category.slug() == slug)[0];
|
|
||||||
if (category) {
|
if (category) {
|
||||||
items.newDiscussion.content.props.style = 'background-color: '+category.color();
|
items.newDiscussion.content.props.style = 'background-color: '+category.color();
|
||||||
}
|
}
|
||||||
return items;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add a parameter for the IndexPage to pass on to the DiscussionList that
|
||||||
|
// will let us filter discussions by category.
|
||||||
|
extend(IndexPage.prototype, 'params', function(params) {
|
||||||
|
params.categories = m.route.param('categories');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Translate that parameter into a gambit appended to the search query.
|
||||||
extend(DiscussionList.prototype, 'params', function(params) {
|
extend(DiscussionList.prototype, 'params', function(params) {
|
||||||
if (params.categories) {
|
if (params.categories) {
|
||||||
params.q = (params.q || '')+' category:'+params.categories;
|
params.q = (params.q || '')+' category:'+params.categories;
|
||||||
delete params.categories;
|
delete params.categories;
|
||||||
}
|
}
|
||||||
return params;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// DISCUSSION PAGE
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Include a discussion's category when fetching it.
|
||||||
extend(DiscussionPage.prototype, 'params', function(params) {
|
extend(DiscussionPage.prototype, 'params', function(params) {
|
||||||
params.include += ',category';
|
params.include += ',category';
|
||||||
return params;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Restyle a discussion's hero to use its category color.
|
||||||
extend(DiscussionHero.prototype, 'view', function(view) {
|
extend(DiscussionHero.prototype, 'view', function(view) {
|
||||||
var category = this.props.discussion.category();
|
var category = this.props.discussion.category();
|
||||||
if (category) {
|
if (category) {
|
||||||
view.attrs.style = 'background-color: '+category.color();
|
view.attrs.style = 'background-color: '+category.color();
|
||||||
}
|
}
|
||||||
return view;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add the name of a discussion's category to the discussion hero, displayed
|
||||||
|
// before the title. Put the title on its own line.
|
||||||
extend(DiscussionHero.prototype, 'items', function(items) {
|
extend(DiscussionHero.prototype, 'items', function(items) {
|
||||||
var category = this.props.discussion.category();
|
var category = this.props.discussion.category();
|
||||||
if (category) {
|
if (category) {
|
||||||
items.add('category', m('span.category', category.title()), {before: 'title'});
|
items.add('category', m('span.category-label', category.title()), {before: 'title'});
|
||||||
items.title.content.wrapperClass = 'block-item';
|
items.title.content.wrapperClass = 'block-item';
|
||||||
}
|
}
|
||||||
return items;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
class MoveDiscussionModal extends Component {
|
// Add a control allowing the discussion to be moved to another category.
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.categories = m.prop(app.store.all('categories'));
|
|
||||||
}
|
|
||||||
|
|
||||||
view() {
|
|
||||||
var discussion = this.props.discussion;
|
|
||||||
|
|
||||||
return m('div.modal-dialog.modal-move-discussion', [
|
|
||||||
m('div.modal-content', [
|
|
||||||
m('button.btn.btn-icon.btn-link.close.back-control', {onclick: app.modal.close.bind(app.modal)}, icon('times')),
|
|
||||||
m('div.modal-header', m('h3.title-control', discussion
|
|
||||||
? ['Move ', m('em', discussion.title()), ' from ', m('span.category', {style: 'color: '+discussion.category().color()}, discussion.category().title()), ' to...']
|
|
||||||
: ['Start a Discussion In...'])),
|
|
||||||
m('div', [
|
|
||||||
m('ul.category-list', [
|
|
||||||
this.categories().map(category =>
|
|
||||||
(discussion && category.id() === discussion.category().id()) ? '' : m('li.category-tile', {style: 'background-color: '+category.color()}, [
|
|
||||||
m('a[href=javascript:;]', {onclick: this.save.bind(this, category)}, [
|
|
||||||
m('h3.title', category.title()),
|
|
||||||
m('p.description', category.description()),
|
|
||||||
m('span.count', category.discussionsCount()+' discussions'),
|
|
||||||
])
|
|
||||||
])
|
|
||||||
)
|
|
||||||
])
|
|
||||||
])
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(category) {
|
|
||||||
var discussion = this.props.discussion;
|
|
||||||
|
|
||||||
if (discussion) {
|
|
||||||
discussion.save({links: {category}}).then(discussion => {
|
|
||||||
if (app.current instanceof DiscussionPage) {
|
|
||||||
app.current.stream().sync();
|
|
||||||
}
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onchange && this.props.onchange(category);
|
|
||||||
|
|
||||||
app.modal.close();
|
|
||||||
|
|
||||||
m.redraw.strategy('none');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function move() {
|
|
||||||
app.modal.show(new MoveDiscussionModal({discussion: this}));
|
|
||||||
}
|
|
||||||
|
|
||||||
extend(Discussion.prototype, 'controls', function(items) {
|
extend(Discussion.prototype, 'controls', function(items) {
|
||||||
if (this.canEdit()) {
|
if (this.canEdit()) {
|
||||||
items.add('move', ActionButton.component({
|
items.add('move', ActionButton.component({
|
||||||
label: 'Move',
|
label: 'Move',
|
||||||
icon: 'arrow-right',
|
icon: 'arrow-right',
|
||||||
onclick: move.bind(this)
|
onclick: () => app.modal.show(new MoveDiscussionModal({discussion: this}))
|
||||||
}), {after: 'rename'});
|
}), {after: 'rename'});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
override(IndexPage.prototype, 'newDiscussion', function(parent) {
|
// ---------------------------------------------------------------------------
|
||||||
var categories = app.store.all('categories');
|
// COMPOSER
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// When the 'new discussion' button is clicked...
|
||||||
|
override(IndexPage.prototype, 'newDiscussion', function(original) {
|
||||||
var slug = this.params().categories;
|
var slug = this.params().categories;
|
||||||
var category;
|
|
||||||
|
// If we're currently viewing a specific category, or if the user isn't
|
||||||
|
// logged in, then we'll let the core code proceed. If that results in the
|
||||||
|
// composer appearing, we'll set the composer's current category to the one
|
||||||
|
// we're viewing.
|
||||||
if (slug || !app.session.user()) {
|
if (slug || !app.session.user()) {
|
||||||
parent();
|
if (original()) {
|
||||||
if (app.composer.component) {
|
var category = app.store.getBy('categories', 'slug', slug);
|
||||||
category = categories.filter(category => category.slug() == slug)[0];
|
|
||||||
app.composer.component.category(category);
|
app.composer.component.category(category);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var modal = new MoveDiscussionModal({onchange: category => {
|
// If we're logged in and we're viewing All Discussions, we'll present the
|
||||||
parent();
|
// user with a category selection dialog before proceeding to show the
|
||||||
app.composer.component.category(category);
|
// composer.
|
||||||
}});
|
var modal = new MoveDiscussionModal({
|
||||||
|
onchange: category => {
|
||||||
|
original();
|
||||||
|
app.composer.component.category(category);
|
||||||
|
}
|
||||||
|
});
|
||||||
app.modal.show(modal);
|
app.modal.show(modal);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add category-selection abilities to the discussion composer.
|
||||||
|
ComposerDiscussion.prototype.category = m.prop();
|
||||||
ComposerDiscussion.prototype.chooseCategory = function() {
|
ComposerDiscussion.prototype.chooseCategory = function() {
|
||||||
var modal = new MoveDiscussionModal({onchange: category => {
|
var modal = new MoveDiscussionModal({
|
||||||
this.category(category);
|
onchange: category => {
|
||||||
this.$('textarea').focus();
|
this.category(category);
|
||||||
}});
|
this.$('textarea').focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
app.modal.show(modal);
|
app.modal.show(modal);
|
||||||
};
|
};
|
||||||
|
|
||||||
ComposerDiscussion.prototype.category = m.prop();
|
// Add a category-selection menu to the discussion composer's header, after
|
||||||
|
// the title.
|
||||||
extend(ComposerDiscussion.prototype, 'headerItems', function(items) {
|
extend(ComposerDiscussion.prototype, 'headerItems', function(items) {
|
||||||
var category = this.category();
|
var category = this.category();
|
||||||
|
|
||||||
items.add('category', m('a[href=javascript:;][tabindex=-1].btn.btn-link.control-change-category', {
|
items.add('category', m('a[href=javascript:;][tabindex=-1].btn.btn-link.control-change-category', {onclick: this.chooseCategory.bind(this)}, [
|
||||||
onclick: this.chooseCategory.bind(this)
|
categoryIcon(category), ' ',
|
||||||
}, [
|
|
||||||
category ? m('span.category-icon', {style: 'background-color: '+category.color()}) : '', ' ',
|
|
||||||
m('span.label', category ? category.title() : 'Uncategorized'),
|
m('span.label', category ? category.title() : 'Uncategorized'),
|
||||||
icon('sort')
|
icon('sort')
|
||||||
]));
|
]));
|
||||||
|
|
||||||
return items;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add the selected category as data to submit to the server.
|
||||||
extend(ComposerDiscussion.prototype, 'data', function(data) {
|
extend(ComposerDiscussion.prototype, 'data', function(data) {
|
||||||
data.links = data.links || {};
|
data.links = data.links || {};
|
||||||
data.links.category = this.category();
|
data.links.category = this.category();
|
||||||
return data;
|
});
|
||||||
})
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ACTIVITY PAGE
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Add a category label next to the discussion title in post activity items.
|
||||||
extend(ActivityPost.prototype, 'headerItems', function(items) {
|
extend(ActivityPost.prototype, 'headerItems', function(items) {
|
||||||
var category = this.props.activity.post().discussion().category();
|
var category = this.props.activity.post().discussion().category();
|
||||||
if (category) {
|
if (category) {
|
||||||
items.add('category', m('span.category', {style: {color: category.color()}}, category.title()));
|
items.add('category', categoryLabel(category));
|
||||||
}
|
}
|
||||||
return items;
|
});
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
16
extensions/tags/js/src/components/category-hero.js
Normal file
16
extensions/tags/js/src/components/category-hero.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import Component from 'flarum/component';
|
||||||
|
|
||||||
|
export default class CategoryHero extends Component {
|
||||||
|
view() {
|
||||||
|
var category = this.props.category;
|
||||||
|
|
||||||
|
return m('header.hero.category-hero', {style: 'background-color: '+category.color()}, [
|
||||||
|
m('div.container', [
|
||||||
|
m('div.container-narrow', [
|
||||||
|
m('h2', category.title()),
|
||||||
|
m('div.subtitle', category.description())
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
22
extensions/tags/js/src/components/category-nav-item.js
Normal file
22
extensions/tags/js/src/components/category-nav-item.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import NavItem from 'flarum/components/nav-item';
|
||||||
|
import categoryIcon from 'categories/helpers/category-icon';
|
||||||
|
|
||||||
|
export default class CategoryNavItem extends NavItem {
|
||||||
|
view() {
|
||||||
|
var category = this.props.category;
|
||||||
|
var active = this.constructor.active(this.props);
|
||||||
|
return m('li'+(active ? '.active' : ''), m('a', {href: this.props.href, config: m.route, onclick: () => {app.cache.discussionList = null; m.redraw.strategy('none')}, style: active ? 'color: '+category.color() : ''}, [
|
||||||
|
categoryIcon(category, {className: 'icon'}),
|
||||||
|
category.title()
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static props(props) {
|
||||||
|
var category = props.category;
|
||||||
|
props.params.categories = category.slug();
|
||||||
|
props.href = app.route('category', props.params);
|
||||||
|
props.label = category.title();
|
||||||
|
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
}
|
56
extensions/tags/js/src/components/move-discussion-modal.js
Normal file
56
extensions/tags/js/src/components/move-discussion-modal.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import Component from 'flarum/component';
|
||||||
|
import DiscussionPage from 'flarum/components/discussion-page';
|
||||||
|
import icon from 'flarum/helpers/icon';
|
||||||
|
|
||||||
|
export default class MoveDiscussionModal extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.categories = m.prop(app.store.all('categories'));
|
||||||
|
}
|
||||||
|
|
||||||
|
view() {
|
||||||
|
var discussion = this.props.discussion;
|
||||||
|
|
||||||
|
return m('div.modal-dialog.modal-move-discussion', [
|
||||||
|
m('div.modal-content', [
|
||||||
|
m('button.btn.btn-icon.btn-link.close.back-control', {onclick: app.modal.close.bind(app.modal)}, icon('times')),
|
||||||
|
m('div.modal-header', m('h3.title-control', discussion
|
||||||
|
? ['Move ', m('em', discussion.title()), ' from ', m('span.category', {style: 'color: '+discussion.category().color()}, discussion.category().title()), ' to...']
|
||||||
|
: ['Start a Discussion In...'])),
|
||||||
|
m('div', [
|
||||||
|
m('ul.category-list', [
|
||||||
|
this.categories().map(category =>
|
||||||
|
(discussion && category.id() === discussion.category().id()) ? '' : m('li.category-tile', {style: 'background-color: '+category.color()}, [
|
||||||
|
m('a[href=javascript:;]', {onclick: this.save.bind(this, category)}, [
|
||||||
|
m('h3.title', category.title()),
|
||||||
|
m('p.description', category.description()),
|
||||||
|
m('span.count', category.discussionsCount()+' discussions'),
|
||||||
|
])
|
||||||
|
])
|
||||||
|
)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
save(category) {
|
||||||
|
var discussion = this.props.discussion;
|
||||||
|
|
||||||
|
if (discussion) {
|
||||||
|
discussion.save({links: {category}}).then(discussion => {
|
||||||
|
if (app.current instanceof DiscussionPage) {
|
||||||
|
app.current.stream().sync();
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onchange && this.props.onchange(category);
|
||||||
|
|
||||||
|
app.modal.close();
|
||||||
|
|
||||||
|
m.redraw.strategy('none');
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import avatar from 'flarum/helpers/avatar';
|
||||||
import icon from 'flarum/helpers/icon';
|
import icon from 'flarum/helpers/icon';
|
||||||
import username from 'flarum/helpers/username';
|
import username from 'flarum/helpers/username';
|
||||||
import humanTime from 'flarum/helpers/human-time';
|
import humanTime from 'flarum/helpers/human-time';
|
||||||
|
import categoryLabel from 'categories/helpers/category-label';
|
||||||
|
|
||||||
export default class NotificationDiscussionMoved extends Notification {
|
export default class NotificationDiscussionMoved extends Notification {
|
||||||
content() {
|
content() {
|
||||||
|
@ -19,7 +20,7 @@ export default class NotificationDiscussionMoved extends Notification {
|
||||||
m('h3.notification-title', discussion.title()),
|
m('h3.notification-title', discussion.title()),
|
||||||
m('div.notification-info', [
|
m('div.notification-info', [
|
||||||
icon('arrow-right'),
|
icon('arrow-right'),
|
||||||
' Moved to ', m('span.category', {style: 'color: '+category.color()}, category.title()), ' by ', username(notification.sender()),
|
' Moved to ', categoryLabel(category), ' by ', username(notification.sender()),
|
||||||
' ', humanTime(notification.time())
|
' ', humanTime(notification.time())
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -1,59 +1,15 @@
|
||||||
import Component from 'flarum/component';
|
import PostActivity from 'flarum/components/post-activity';
|
||||||
import icon from 'flarum/helpers/icon';
|
import categoryLabel from 'categories/helpers/category-label';
|
||||||
import username from 'flarum/helpers/username';
|
|
||||||
import humanTime from 'flarum/utils/human-time';
|
|
||||||
import SubtreeRetainer from 'flarum/utils/subtree-retainer';
|
|
||||||
import ItemList from 'flarum/utils/item-list';
|
|
||||||
import ActionButton from 'flarum/components/action-button';
|
|
||||||
import DropdownButton from 'flarum/components/dropdown-button';
|
|
||||||
|
|
||||||
export default class PostDiscussionMoved extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.subtree = new SubtreeRetainer(
|
|
||||||
() => this.props.post.freshness,
|
|
||||||
() => this.props.post.user().freshness
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
view(ctrl) {
|
|
||||||
var controls = this.controlItems().toArray();
|
|
||||||
|
|
||||||
|
export default class PostDiscussionMoved extends PostActivity {
|
||||||
|
view() {
|
||||||
var post = this.props.post;
|
var post = this.props.post;
|
||||||
var oldCategory = app.store.getById('categories', post.content()[0]);
|
var oldCategory = app.store.getById('categories', post.content()[0]);
|
||||||
var newCategory = app.store.getById('categories', post.content()[1]);
|
var newCategory = app.store.getById('categories', post.content()[1]);
|
||||||
|
|
||||||
return m('article.post.post-activity.post-discussion-moved', this.subtree.retain() || m('div', [
|
return super.view(['moved the discussion from ', categoryLabel(oldCategory), ' to ', categoryLabel(newCategory), '.'], {
|
||||||
controls.length ? DropdownButton.component({
|
className: 'post-discussion-moved',
|
||||||
items: controls,
|
icon: 'arrow-right'
|
||||||
className: 'contextual-controls',
|
});
|
||||||
buttonClass: 'btn btn-default btn-icon btn-sm btn-naked',
|
|
||||||
menuClass: 'pull-right'
|
|
||||||
}) : '',
|
|
||||||
icon('arrow-right post-icon'),
|
|
||||||
m('div.post-activity-info', [
|
|
||||||
m('a.post-user', {href: app.route('user', {username: post.user().username()}), config: m.route}, username(post.user())),
|
|
||||||
' moved the discussion from ', m('span.category', {style: {color: oldCategory.color()}}, oldCategory.title()), ' to ', m('span.category', {style: {color: newCategory.color()}}, newCategory.title()), '.'
|
|
||||||
]),
|
|
||||||
m('div.post-activity-time', humanTime(post.time()))
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
controlItems() {
|
|
||||||
var items = new ItemList();
|
|
||||||
var post = this.props.post;
|
|
||||||
|
|
||||||
if (post.canDelete()) {
|
|
||||||
items.add('delete', ActionButton.component({ icon: 'times', label: 'Delete', onclick: this.delete.bind(this) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete() {
|
|
||||||
var post = this.props.post;
|
|
||||||
post.delete();
|
|
||||||
this.props.ondelete && this.props.ondelete(post);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
extensions/tags/js/src/helpers/category-icon.js
Normal file
12
extensions/tags/js/src/helpers/category-icon.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
export default function categoryIcon(category, attrs) {
|
||||||
|
attrs = attrs || {};
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
attrs.style = attrs.style || {};
|
||||||
|
attrs.style.backgroundColor = category.color();
|
||||||
|
} else {
|
||||||
|
attrs.className = (attrs.className || '')+' uncategorized';
|
||||||
|
}
|
||||||
|
|
||||||
|
return m('span.icon.category-icon', attrs);
|
||||||
|
}
|
3
extensions/tags/js/src/helpers/category-label.js
Normal file
3
extensions/tags/js/src/helpers/category-label.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function categoryLabel(category) {
|
||||||
|
return m('span.category-label', {style: {color: category.color()}}, category.title());
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
.category {
|
.category-label {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user