lib/collection/type/file-system.js
import _ from 'lodash';
import CollectionBase from '../base';
/**
* A collection that derives its content from the location of a file in the
* file system.
*/
export default class FileSystemCollection extends CollectionBase {
constructor(name, collectionConfig, config, renderer) {
super(name, collectionConfig, config, renderer);
/**
* Array of file id's that belong in this collection.
* @type {Object.<string, File>}
*/
this.files = {};
/**
* Array of paths to exclude from including in this collection.
* @type {Array.<string>}
*/
this.excludePaths = [];
}
/**
* Set what paths to exclude from including in this collection.
* @param {Object.<string, CollectionBase>} collections Array of Collections.
*/
_setExcludePaths(collections) {
this.excludePaths = _.reduce(
collections,
(allPaths, collection) => {
// Only include a collection path if it exists and isn't the app source,
// and isn't this collection's path.
if (
collection.path &&
collection.path !== this.path &&
collection.path !== this._config.get('path.source')
) {
allPaths.push(collection.path);
}
return allPaths;
},
[]
);
}
/**
* Is this file's path included in this collection's excludePaths.
* @param {File} file File object.
* @return {boolean} true if the file's path includes an exclude path.
* @private
*/
_isFileExcluded(file) {
return this.excludePaths.some(path => file.path.includes(path));
}
/**
* Checks to see if this file passes all requirements to be considered a part
* of this collection.
* @param {File} file File object.
* @return {boolean} true if the file meets all requirements.
*/
_isFileInCollection(file) {
return (
file.path.includes(this.path) &&
!this._isFileExcluded(file) &&
!this.isFiltered(file)
);
}
/**
* Add a file to the collection.
* @param {File} file File object.
* @return {boolean} True if the file was added to the collection.
*/
addFile(file) {
if (!this._isFileInCollection(file)) {
return false;
}
// Add file.
this.files[file.id] = file;
// Add data to template accessible object.
this.data.files.push(file.data);
return true;
}
/**
* Populate the Collection's files via file system path or metadata attribute.
* @param {Object.<string, Files>} files All Files.
* @param {?Object.<string, CollectionBase>} collections Object of all
* collections.
* @return {Collection}
*/
populate(files, collections) {
if (!_.isUndefined(collections)) {
this._setExcludePaths(collections);
}
// Add data to template accessible object.
this.data.files = [];
_.each(files, file => {
// Don't return value so we iterate over every file.
this.addFile(file);
});
this.createCollectionPages();
return this;
}
/**
* Create CollectionPage objects for our Collection.
* @return {boolean} True if we successfully created CollectionPages.
*/
createCollectionPages() {
// If no permalink paths are set then we don't render a CollectionPage.
if (!(this.permalink && this.permalink.index && this.permalink.page)) {
return false;
}
if (!_.isEmpty(this.files)) {
this.pages = [];
// Sort files according to config.
const files = CollectionBase.sortFiles(
_.values(this.files),
this.sort,
this._config.get('file.dateFormat')
);
// Break up our array of files into arrays that match our defined
// pagination size.
const pages = _.chunk(files, this.pageSize);
pages.forEach((pageFiles, index) => {
const collectionPage = this.createPage(index);
// Files in the page.
collectionPage.setFiles(pageFiles);
// Update CollectionPage template data.
collectionPage.setData({
// How many pages in the collection.
total_pages: pages.length,
// Posts displayed per page.
per_page: this.pageSize,
// Total number of posts.
total: files.length,
});
// Add to our array of pages.
this.pages.push(collectionPage);
});
}
this._linkPages(
// ShouldLinkPrevious
previous => previous,
// ShouldLinkNext
next => next
);
return true;
}
}