-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
246 lines (211 loc) · 6.14 KB
/
index.js
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
'use strict';
/**
* Assemble Navigation main function
*/
var Menu = require('./lib/menu');
var MenuItem = require('./lib/menuitem');
var _ = require('lodash');
var merge = require('mixin-deep');
var File = require('vinyl');
/**
* create a Navigation instance
* ```js
* var navigation = new Navigation([config]);
* ```
* @param {object} config [optional config]
*/
function Navigation(config) {
if (!(this instanceof Navigation)) {
return new Navigation(config);
}
config = config || {};
// create properties
this.menus = {};
// set properties
this.setMenus(config.menus || ['main']);
this.default = config.default || 'main';
}
/**
* setMenus adds new menus to the menu list
* @param {Array} menus [menu names]
*/
Navigation.prototype.setMenus = function (menus) {
for (var i = 0; i < menus.length; i++) {
var menu = this.createMenuOption(menus[i]);
var menuName = _.isString(menu) ? menu : menu['menu-name'];
this.menus[menuName] = new Menu(menu);
}
};
/**
* defaultMenu() get's or sets the default menu for the navigation scheme
* @param {string} menu (optional) menu to set as default
* @return {string} name of default menu
*/
Navigation.prototype.defaultMenu = function (menu) {
if (menu && this.menuExists(menu)) {
this.default = menu;
}
return this.default;
};
/**
* sees if a given menu name exists
* @param {string} menu [menu name]
* @return {boolean} [true if menu exists]
*/
Navigation.prototype.menuExists = function (menu) {
return _.has(this.menus, menu);
};
/**
* getAssignedMenus parses a view and returns any designated
* menus for the file or the default menu.
* Only returns existing menus
* @param {object} view [Assemble view]
* @return {array} [array of strings]
*/
Navigation.prototype.getAssignedMenus = function (view) {
var pageData = view.data;
var menus = _(pageData).has('menu') ? pageData.menu:this.default;
// is menu a sting? then turn it into an array
if (_.isString(menus)) {
menus = [menus];
}
// normalize menu options
menus = menus.map(function (menu) {
return this.createMenuOption(menu)
}, this);
// filter out non-existing menus
menus = menus.filter(function (m) {
return this.menuExists(m['menu-name']);
}, this);
return menus;
};
/**
* Enables views to have per/menu settings
* If menu is just a string, it will wrap it in an object
* otherwise it just passes back an object
* @param {String|Object} menu settings
* @return {Object} Menu settings object
*/
Navigation.prototype.createMenuOption = function (menu) {
var options = {};
if (_.isString(menu)) {
options['menu-name'] = menu;
}else{
options = menu;
}
return options;
};
/**
* Creates a custom menu item from the config object passed to it. Used to create menutItems
* for pages that are not Assemble views, like outside links and links to PDFs or other downloadables.
*
* Object should at least have a `url` attribute, a `menuPath` and preferably a `title`. But it can use any attribute
* any of the valid frontmatter values.
*
* ```js
* nav.customMenuItem({
* title: 'Click Me',
* url: 'http://sample.com',
* menu: 'footer',
* menuPath: '.'
* });
* ```
* Menu item is added to menu(s)
*
* @param {Object} config hash
* @return {[type]} [description]
*/
Navigation.prototype.customMenuItem = function (config) {
if (!config['menuPath'] && !config.data['menu-path']) {
throw new TypeError('Custom Menu Items require a `menuPath` or `data[\'menu-path\']` variable.');
}
var menuItem = new MenuItem(config);
var menus = this.getAssignedMenus(menuItem);
menus.forEach(function (menu) {
var name = menu['menu-name'];
this.menus[name].addItem(menuItem);
}, this);
return menuItem;
}
/**
* examines an Assemble view object. THen creates
* a menuItem object for each menu it belongs in
* @param {object} view [assemble view]
*/
Navigation.prototype.parseView = function (view) {
var menus = this.getAssignedMenus(view);
menus.forEach(function (options) {
var name = options['menu-name'];
var menuItem = new MenuItem(view, options);
this.menus[name].addItem(menuItem);
}, this);
};
/**
* adds a localized copy of the navigation object to view
* @param {object} view [assemble view]
*/
Navigation.prototype.inject = function (view) {
var navLocal = _.cloneDeep(this.menus);
// localize the menus
// create menuItem based on view
// set isCurrentPage to true
// add revised menuItem to relevant menus in navLocal
var menus = this.getAssignedMenus(view);
menus.forEach(function (menu) {
var name = menu['menu-name'];
var menuItem = new MenuItem(view);
menuItem.isCurrentPage = true
navLocal[name].addItem(menuItem);
});
view.data = merge({}, {'navigation': navLocal}, view.data);
};
Navigation.prototype.getLocalMenu = function (view) {
var navLocal = _.cloneDeep(this.menus);
// localize the menus
// create menuItem based on view
// set isCurrentPage to true
// add revised menuItem to relevant menus in navLocal
var menus = this.getAssignedMenus(view);
menus.forEach(function (menu) {
var name = menu['menu-name'];
var menuItem = new MenuItem(view);
menuItem.isCurrentPage = true
navLocal[name].addItem(menuItem);
});
return navLocal;
};
/**
* Loops through each menu and delete's it items. This
* prepares the menu for fresh data.
* @return {[type]} [description]
*/
Navigation.prototype.clearMenus = function () {
_.forEach(this.menus, function (menu) {
menu.clearMenu();
});
};
/**
* Onload middleware for Assemble
*
* @return {function} [a middleware function]
*/
Navigation.prototype.onLoad = function () {
var self = this;
return function (view, next) {
self.parseView(view);
next();
};
};
Navigation.prototype.preRender = function () {
var self = this;
return function (view, next) {
if (typeof next !== 'function') {
throw new TypeError('expected a callback function');
}
var navLocal = self.getLocalMenu(view);
view.data = merge({}, {'navigation': navLocal}, view.data);
// console.log('view.data', view.data);
next(null, view);
};
};
module.exports = Navigation;