UNPKG

4.89 kBJavaScriptView Raw
1'use strict';
2
3var Base = require('base');
4var debug = require('debug')('base:templates:collection');
5var plugin = require('./plugins');
6var utils = require('./utils');
7
8/**
9 * Expose `Collection`
10 */
11
12module.exports = exports = Collection;
13
14/**
15 * Create an instance of `Collection` with the given `options`.
16 *
17 * ```js
18 * var collection = new Collection();
19 * collection.addItem('foo', {content: 'bar'});
20 * ```
21 * @param {Object} `options`
22 * @api public
23 */
24
25function Collection(options) {
26 if (!(this instanceof Collection)) {
27 return new Collection(options);
28 }
29
30 Base.call(this, {}, options);
31 this.is('Collection');
32 this.items = {};
33
34 this.use(utils.option());
35 this.use(utils.plugin());
36 this.init(options || {});
37}
38
39/**
40 * Inherit `Base`
41 */
42
43Base.extend(Collection);
44
45/**
46 * Mixin static methods
47 */
48
49plugin.is(Collection);
50
51/**
52 * Initialize `Collection` defaults
53 */
54
55Collection.prototype.init = function(opts) {
56 debug('initializing', __filename);
57
58 // add constructors to the instance
59 this.define('Item', opts.Item || Collection.Item);
60 this.define('View', opts.View || Collection.View);
61
62 this.use(plugin.renameKey());
63 this.use(plugin.item('item', 'Item', {emit: false}));
64
65 // if an instance of `List` or `Collection` is passed, load it now
66 if (Array.isArray(opts) || opts.isList) {
67 this.options = opts.options;
68 this.addList(opts.items);
69
70 } else if (opts.isCollection) {
71 this.options = opts.options;
72 this.addItems(opts.items);
73
74 } else {
75 this.options = opts;
76 }
77};
78
79/**
80 * Add an item to the collection.
81 *
82 * ```js
83 * collection.addItem('foo', {content: 'bar'});
84 * ```
85 * @emits `item` With the created `item` and `collection` instance as arguments.
86 * @param {String|Object} `key` Item name or object
87 * @param {Object} `val` Item object, when `key` is a string.
88 * @developer The `item` method is decorated onto the collection using the `item` plugin
89 * @return {Object} returns the `item` instance.
90 * @api public
91 */
92
93Collection.prototype.addItem = function(key, val) {
94 debug('adding item "%s"');
95 var item = this.item(key, val);
96 if (typeof item.use === 'function') {
97 this.run(item);
98 }
99 this.emit('item', item, this);
100 this.items[item.key] = item;
101 return item;
102};
103
104/**
105 * Identical to `.addItem`, except the collection instance is returned instead of
106 * the item, to allow chaining.
107 *
108 * ```js
109 * collection.setItem('foo', {content: 'bar'});
110 * ```
111 * @emits `item` With the created `item` and `collection` instance as arguments.
112 * @param {String|Object} `key` Item name or object
113 * @param {Object} `val` Item object, when `key` is a string.
114 * @return {Object} returns the `collection` instance.
115 * @api public
116 */
117
118Collection.prototype.setItem = function(/*key, value*/) {
119 this.addItem.apply(this, arguments);
120 return this;
121};
122
123/**
124 * Get an item from `collection.items`.
125 *
126 * ```js
127 * collection.getItem('a.html');
128 * ```
129 * @param {String} `key` Key of the item to get.
130 * @return {Object}
131 * @api public
132 */
133
134Collection.prototype.getItem = function(key) {
135 return this.items[key] || this.items[this.renameKey(key)];
136};
137
138/**
139 * Remove an item from `collection.items`.
140 *
141 * ```js
142 * items.deleteItem('abc');
143 * ```
144 * @param {String} `key`
145 * @return {Object} Returns the instance for chaining
146 * @api public
147 */
148
149Collection.prototype.deleteItem = function(item) {
150 if (typeof item === 'string') {
151 item = this.getItem(item);
152 }
153 delete this.items[item.key];
154 return this;
155};
156
157/**
158 * Load multiple items onto the collection.
159 *
160 * ```js
161 * collection.addItems({
162 * 'a.html': {content: '...'},
163 * 'b.html': {content: '...'},
164 * 'c.html': {content: '...'}
165 * });
166 * ```
167 * @param {Object|Array} `items`
168 * @return {Object} returns the instance for chaining
169 * @api public
170 */
171
172Collection.prototype.addItems = function(items) {
173 if (Array.isArray(items)) {
174 return this.addList.apply(this, arguments);
175 }
176 this.visit('addItem', items);
177 return this;
178};
179
180/**
181 * Load an array of items onto the collection.
182 *
183 * ```js
184 * collection.addList([
185 * {path: 'a.html', content: '...'},
186 * {path: 'b.html', content: '...'},
187 * {path: 'c.html', content: '...'}
188 * ]);
189 * ```
190 * @param {Array} `items` or an instance of `List`
191 * @param {Function} `fn` Optional sync callback function that is called on each item.
192 * @return {Object} returns the Collection instance for chaining
193 * @api public
194 */
195
196Collection.prototype.addList = function(list, fn) {
197 if (!Array.isArray(list)) {
198 throw new TypeError('expected list to be an array.');
199 }
200
201 if (typeof fn !== 'function') {
202 fn = utils.identity;
203 }
204 var len = list.length;
205 var idx = -1;
206
207 while (++idx < len) {
208 this.addItem(fn(list[idx]));
209 }
210 return this;
211};
212
213/**
214 * Expose static properties
215 */
216
217utils.define(Collection, 'Item', require('vinyl-item'));
218utils.define(Collection, 'View', require('vinyl-view'));