all files / lib/collection/type/ file-system.js

98.81% Statements 83/84
92% Branches 23/25
100% Functions 17/17
97.73% Lines 43/44
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200               31×             31×                           18×     84×     43×     84×                     88×                   92×                                                     45× 90× 45×                             45×                   18× 18× 16×           18×   88×     18×   18×                 22×   11×     11× 11×     11×       11×   13× 13×                                           11×     13×       13×       11×      
import isUndefined from 'lodash/isUndefined';
import isEmpty from 'lodash/isEmpty';
import values from 'lodash/values';
import reduce from 'lodash/reduce';
import each from 'lodash/each';
import chunk from 'lodash/chunk';
 
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, getConfig) {
    super(name, collectionConfig, getConfig);
 
    /**
     * 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._getConfig().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);
  }
 
  /**
   * Removes a file from the collection.
   * @param {File} file File object.
   * @return {boolean} True if the file was removed from the collection.
   */
  removeFile(file) {
    Iif (!this._isFileInCollection(file)) {
      return false;
    }
 
    // Remove file.
    delete this.files[file.id];
 
    let dataIndex = this.data.files.indexOf(file.data);
 
    // Remove data from template accessible object.
    this.data.files.splice(dataIndex, 1);
 
    return true;
  }
 
  /**
   * 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;
 
    // Set what permalink the file should use.
    file.setPermalink(this.permalink);
 
    // Add collection names.
    file.collectionIds.add(this.id);
 
    // 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.pagination &&
          this.pagination.permalinkIndex && this.pagination.permalinkPage)) {
      return false;
    }
 
    Eif (!isEmpty(this.files)) {
      this.pages = [];
 
      // Sort files according to config.
      let files = CollectionBase.sortFiles(values(this.files), this.sort);
 
      // Break up our array of files into arrays that match our defined
      // pagination size.
      let pages = chunk(files, this.pagination.size);
 
      pages.forEach((pageFiles, index) => {
        let 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.pagination.size,
 
          // Total number of posts.
          total: files.length
        });
 
        // Add to our array of pages.
        this.pages.push(collectionPage);
      });
    }
 
    this._linkPages(
      // ShouldLinkPrevious
      (previous) => {
        return previous;
      },
      // ShouldLinkNext
      (next) => {
        return next;
      }
    );
 
    return true;
  }
}