api-list.js (6770B)
1 YUI.add('api-list', function (Y) { 2 3 var Lang = Y.Lang, 4 YArray = Y.Array, 5 6 APIList = Y.namespace('APIList'), 7 8 classesNode = Y.one('#api-classes'), 9 elementsNode = Y.one('#api-elements'), 10 inputNode = Y.one('#api-filter'), 11 modulesNode = Y.one('#api-modules'), 12 tabviewNode = Y.one('#api-tabview'), 13 14 tabs = APIList.tabs = {}, 15 16 filter = APIList.filter = new Y.APIFilter({ 17 inputNode : inputNode, 18 maxResults: 1000, 19 20 on: { 21 results: onFilterResults 22 } 23 }), 24 25 search = APIList.search = new Y.APISearch({ 26 inputNode : inputNode, 27 maxResults: 100, 28 29 on: { 30 clear : onSearchClear, 31 results: onSearchResults 32 } 33 }), 34 35 tabview = APIList.tabview = new Y.TabView({ 36 srcNode : tabviewNode, 37 panelNode: '#api-tabview-panel', 38 render : true, 39 40 on: { 41 selectionChange: onTabSelectionChange 42 } 43 }), 44 45 focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, { 46 circular : true, 47 descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a', 48 keys : {next: 'down:40', previous: 'down:38'} 49 }).focusManager, 50 51 LIST_ITEM_TEMPLATE = 52 '<li class="api-list-item {typeSingular}">' + 53 '<a href="{rootPath}{typePlural}/{name}.html">{displayName}</a>' + 54 '</li>'; 55 56 // -- Init --------------------------------------------------------------------- 57 58 // Duckpunch FocusManager's key event handling to prevent it from handling key 59 // events when a modifier is pressed. 60 Y.before(function (e, activeDescendant) { 61 if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 62 return new Y.Do.Prevent(); 63 } 64 }, focusManager, '_focusPrevious', focusManager); 65 66 Y.before(function (e, activeDescendant) { 67 if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 68 return new Y.Do.Prevent(); 69 } 70 }, focusManager, '_focusNext', focusManager); 71 72 // Create a mapping of tabs in the tabview so we can refer to them easily later. 73 tabview.each(function (tab, index) { 74 var name = tab.get('label').toLowerCase(); 75 76 tabs[name] = { 77 index: index, 78 name : name, 79 tab : tab 80 }; 81 }); 82 83 // Switch tabs on Ctrl/Cmd-Left/Right arrows. 84 tabviewNode.on('key', onTabSwitchKey, 'down:37,39'); 85 86 // Focus the filter input when the `/` key is pressed. 87 Y.one(Y.config.doc).on('key', onSearchKey, 'down:83'); 88 89 // Keep the Focus Manager up to date. 90 inputNode.on('focus', function () { 91 focusManager.set('activeDescendant', inputNode); 92 }); 93 94 // Update all tabview links to resolved URLs. 95 tabview.get('panelNode').all('a').each(function (link) { 96 link.setAttribute('href', link.get('href')); 97 }); 98 99 // -- Private Functions -------------------------------------------------------- 100 function getFilterResultNode() { 101 var queryType = filter.get('queryType'); 102 return queryType === 'classes' ? classesNode 103 : queryType === 'elements' ? elementsNode : modulesNode; 104 } 105 106 // -- Event Handlers ----------------------------------------------------------- 107 function onFilterResults(e) { 108 var frag = Y.one(Y.config.doc.createDocumentFragment()), 109 resultNode = getFilterResultNode(), 110 typePlural = filter.get('queryType'), 111 typeSingular = typePlural === 'classes' ? 'class' : typePlural === 'elements' ? 'element' : 'module'; 112 113 if (e.results.length) { 114 YArray.each(e.results, function (result) { 115 frag.append(Lang.sub(LIST_ITEM_TEMPLATE, { 116 rootPath : APIList.rootPath, 117 displayName : filter.getDisplayName(result.highlighted), 118 name : result.text, 119 typePlural : typePlural, 120 typeSingular: typeSingular 121 })); 122 }); 123 } else { 124 frag.append( 125 '<li class="message">' + 126 'No ' + typePlural + ' found.' + 127 '</li>' 128 ); 129 } 130 131 resultNode.empty(true); 132 resultNode.append(frag); 133 134 focusManager.refresh(); 135 } 136 137 function onSearchClear(e) { 138 139 focusManager.refresh(); 140 } 141 142 function onSearchKey(e) { 143 var target = e.target; 144 145 if (target.test('input,select,textarea') 146 || target.get('isContentEditable')) { 147 return; 148 } 149 150 e.preventDefault(); 151 152 inputNode.focus(); 153 focusManager.refresh(); 154 } 155 156 function onSearchResults(e) { 157 var frag = Y.one(Y.config.doc.createDocumentFragment()); 158 159 if (e.results.length) { 160 YArray.each(e.results, function (result) { 161 frag.append(result.display); 162 }); 163 } else { 164 frag.append( 165 '<li class="message">' + 166 'No results found. Maybe you\'ll have better luck with a ' + 167 'different query?' + 168 '</li>' 169 ); 170 } 171 172 173 focusManager.refresh(); 174 } 175 176 function onTabSelectionChange(e) { 177 var tab = e.newVal, 178 name = tab.get('label').toLowerCase(); 179 180 tabs.selected = { 181 index: tab.get('index'), 182 name : name, 183 tab : tab 184 }; 185 186 switch (name) { 187 case 'elements':// fallthru 188 case 'classes': // fallthru 189 case 'modules': 190 filter.setAttrs({ 191 minQueryLength: 0, 192 queryType : name 193 }); 194 195 search.set('minQueryLength', -1); 196 197 // Only send a request if this isn't the initially-selected tab. 198 if (e.prevVal) { 199 filter.sendRequest(filter.get('value')); 200 } 201 break; 202 203 case 'everything': 204 filter.set('minQueryLength', -1); 205 search.set('minQueryLength', 1); 206 207 if (search.get('value')) { 208 search.sendRequest(search.get('value')); 209 } else { 210 inputNode.focus(); 211 } 212 break; 213 214 default: 215 // WTF? We shouldn't be here! 216 filter.set('minQueryLength', -1); 217 search.set('minQueryLength', -1); 218 } 219 220 if (focusManager) { 221 setTimeout(function () { 222 focusManager.refresh(); 223 }, 1); 224 } 225 } 226 227 function onTabSwitchKey(e) { 228 var currentTabIndex = tabs.selected.index; 229 230 if (!(e.ctrlKey || e.metaKey)) { 231 return; 232 } 233 234 e.preventDefault(); 235 236 switch (e.keyCode) { 237 case 37: // left arrow 238 if (currentTabIndex > 0) { 239 tabview.selectChild(currentTabIndex - 1); 240 inputNode.focus(); 241 } 242 break; 243 244 case 39: // right arrow 245 if (currentTabIndex < (Y.Object.size(tabs) - 2)) { 246 tabview.selectChild(currentTabIndex + 1); 247 inputNode.focus(); 248 } 249 break; 250 } 251 } 252 253 }, '3.4.0', {requires: [ 254 'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview' 255 ]});