decorate categories with active and expanded properties; adapt Categories.getParents to work with store; add category parent resolver; improve mongo-redux; remove duplicate unflatten; add level property to items in unflatten

This commit is contained in:
SachaG 2017-02-06 10:50:48 +09:00
parent 8bc6aacf85
commit 435cc3555d
7 changed files with 52 additions and 66 deletions

View file

@ -5,19 +5,37 @@ import { Button, DropdownButton, MenuItem } from 'react-bootstrap';
import { withRouter } from 'react-router'
import { LinkContainer } from 'react-router-bootstrap';
import Categories from 'meteor/nova:categories';
import { withApollo } from 'react-apollo';
class CategoriesList extends Component {
render() {
getNestedCategories() {
const categories = this.props.results;
const currentQuery = _.clone(this.props.router.location.query);
delete currentQuery.cat;
// check if a category is currently active in the route
const currentCategorySlug = this.props.router.location.query && this.props.router.location.query.cat;
const currentCategory = Categories.findOneInStore(this.props.client.store, {slug: currentCategorySlug});
const parentCategories = Categories.getParents(currentCategory, this.props.client.store);
// decorate categories with active and expanded properties
const categoriesClone = _.map(categories, category => {
return {
...category, // we don't want to modify the objects we got from props
active: currentCategory && category.slug === currentCategory.slug,
expanded: parentCategories && _.contains(_.pluck(parentCategories, 'slug'), category.slug)
};
});
const categoriesClone = _.map(categories, _.clone); // we don't want to modify the objects we got from props
const nestedCategories = Utils.unflatten(categoriesClone, '_id', 'parentId');
return nestedCategories;
}
render() {
const currentQuery = _.clone(this.props.router.location.query);
const nestedCategories = this.getNestedCategories();
return (
<div>
<DropdownButton
@ -26,8 +44,8 @@ class CategoriesList extends Component {
title={<FormattedMessage id="categories"/>}
id="categories-dropdown"
>
<div className="category-menu-item dropdown-item">
<LinkContainer to={{pathname:"/", query: currentQuery}}>
<div className="category-menu-item category-menu-item-all dropdown-item">
<LinkContainer className="category-menu-item-title" to={{pathname:"/", query: currentQuery}}>
<MenuItem eventKey={0}>
<FormattedMessage id="categories.all"/>
</MenuItem>
@ -72,4 +90,4 @@ const options = {
pollInterval: 0,
};
registerComponent('CategoriesList', CategoriesList, withRouter, [withList, options]);
registerComponent('CategoriesList', CategoriesList, withRouter, withApollo, [withList, options]);

View file

@ -47,9 +47,9 @@ function categoriesNewGenerateSlug (category) {
}
addCallback("categories.new.sync", categoriesNewGenerateSlug);
function categoriesEditGenerateSlug (modifier) {
function categoriesEditGenerateSlug (modifier, document) {
// if slug is changing
if (modifier.$set && modifier.$set.slug) {
if (modifier.$set && modifier.$set.slug && modifier.$set.slug !== document.slug) {
const slug = modifier.$set.slug;
modifier.$set.slug = Utils.getUnusedSlug(Categories, slug);
}

View file

@ -6,14 +6,15 @@ import { Utils } from 'meteor/nova:core';
* @summary Get all of a category's parents
* @param {Object} category
*/
Categories.getParents = function (category) {
Categories.getParents = function (category, store) {
const categoriesArray = [];
const getParents = function recurse (category) {
const parent = Categories.findOne(category.parentId);
if (parent) {
categoriesArray.push(parent);
recurse(parent);
if (category && category.parentId) {
const parent = store ? Categories.findOneInStore(store, category.parentId) : Categories.findOne(category.parentId);
if (parent) {
categoriesArray.push(parent);
recurse(parent);
}
}
};
getParents(category);

View file

@ -7,12 +7,11 @@ const specificResolvers = {
return post.categories ? context.Categories.find({_id: {$in: post.categories}}, { fields: context.getViewableFields(context.currentUser, context.Categories) }).fetch() : [];
},
},
// TODO: fix this
// Category: {
// parent(category, args, context) {
// return category.parent ? context.Categories.findOne({_id: category.parent }, { fields: context.getViewableFields(context.currentUser, context.Categories) }) : null;
// }
// },
Category: {
parent(category, args, context) {
return category.parentId ? context.Categories.findOne({_id: category.parentId }, { fields: context.getViewableFields(context.currentUser, context.Categories) }) : null;
}
},
};
GraphQLSchema.addResolvers(specificResolvers);

View file

@ -5,6 +5,6 @@ Mongo.Collection.prototype.findRedux = function (selector = {}, options = {}) {
return this.findInStore(store, selector, options);
}
Mongo.Collection.prototype.findOneRedux = function (_id) {
return this.findRedux({_id});
Mongo.Collection.prototype.findOneRedux = function (_idOrObject) {
return this.findOneInStore(store, _idOrObject);
}

View file

@ -20,6 +20,7 @@ Mongo.Collection.prototype.findInStore = function (store, selector = {}, options
return {fetch: () => sortedDocs};
}
Mongo.Collection.prototype.findOneInStore = function (store, _id) {
return this.findInStore(store, {_id}).fetch();
Mongo.Collection.prototype.findOneInStore = function (store, _idOrObject) {
const docs = typeof _idOrObject === 'string' ? this.findInStore(store, {_id: _idOrObject}).fetch() : this.findInStore(store, _idOrObject).fetch();
return docs.length === 0 ? undefined: docs[0];
}

View file

@ -266,42 +266,6 @@ _.mixin({
}
});
// adapted from http://stackoverflow.com/a/22072374/649299
Utils.unflatten = function( array, idProperty, parentIdProperty, parent, tree ){
tree = typeof tree !== "undefined" ? tree : [];
let children = [];
if (typeof parent === "undefined") {
// if there is no parent, we're at the root level
// so we return all root nodes (i.e. nodes with no parent)
children = _.filter( array, node => !node[parentIdProperty]);
} else {
// if there *is* a parent, we return all its child nodes
// (i.e. nodes whose parentId is equal to the parent's id.)
children = _.filter( array, node => node[parentIdProperty] === parent[idProperty]);
}
// if we found children, we keep on iterating
if (!!children.length) {
if (typeof parent === "undefined") {
// if we're at the root, then the tree consist of all root nodes
tree = children;
} else {
// else, we add the children to the parent as the "childrenResults" property
parent.childrenResults = children;
}
// we call the function on each child
children.forEach(child => {
Utils.unflatten(array, idProperty, parentIdProperty, child);
});
}
return tree;
}
Utils.getFieldLabel = (fieldName, collection) => {
const label = collection.simpleSchema()._schema[fieldName].label;
@ -344,7 +308,9 @@ Utils.findIndex = (array, predicate) => {
}
// adapted from http://stackoverflow.com/a/22072374/649299
Utils.unflatten = function( array, idProperty, parentIdProperty, parent, tree ){
Utils.unflatten = function(array, idProperty, parentIdProperty, parent, level=0, tree){
level++;
tree = typeof tree !== "undefined" ? tree : [];
@ -353,11 +319,11 @@ Utils.unflatten = function( array, idProperty, parentIdProperty, parent, tree ){
if (typeof parent === "undefined") {
// if there is no parent, we're at the root level
// so we return all root nodes (i.e. nodes with no parent)
children = _.filter( array, node => !node[parentIdProperty]);
children = _.filter(array, node => !node[parentIdProperty]);
} else {
// if there *is* a parent, we return all its child nodes
// (i.e. nodes whose parentId is equal to the parent's id.)
children = _.filter( array, node => node[parentIdProperty] === parent[idProperty]);
children = _.filter(array, node => node[parentIdProperty] === parent[idProperty]);
}
// if we found children, we keep on iterating
@ -373,7 +339,8 @@ Utils.unflatten = function( array, idProperty, parentIdProperty, parent, tree ){
// we call the function on each child
children.forEach(child => {
Utils.unflatten(array, idProperty, parentIdProperty, child);
child.level = level;
Utils.unflatten(array, idProperty, parentIdProperty, child, level);
});
}