2 * Controller for search.
4 Ext.define('Docs.controller.Search', {
5 extend: 'Ext.app.Controller',
16 itemclick: function(dropdown, record) {
17 this.loadRecord(record);
21 keyup: function(el, ev) {
22 var dropdown = this.getDropdown();
24 el.setHideTrigger(el.getValue().length === 0);
26 if (ev.keyCode === Ext.EventObject.ESC || !el.value) {
35 var selModel = dropdown.getSelectionModel();
36 var record = selModel.getLastSelected();
37 var curIndex = dropdown.store.indexOf(record);
38 var lastIndex = dropdown.store.getCount() - 1;
40 if (ev.keyCode === Ext.EventObject.UP) {
41 if (curIndex === undefined) {
44 selModel.select(curIndex === 0 ? lastIndex : (curIndex - 1));
47 else if (ev.keyCode === Ext.EventObject.DOWN) {
48 if (curIndex === undefined) {
51 selModel.select(curIndex === lastIndex ? 0 : curIndex + 1);
54 else if (ev.keyCode === Ext.EventObject.ENTER) {
56 record && this.loadRecord(record);
59 // Wait a bit before actually performing the search.
60 // When user is typing fast, the value of el.value
61 // might not right away be the final value. For example
62 // user might type "tre" but we will get three keyup events
63 // where el.value === "t".
64 clearTimeout(this.searchTimeout);
65 this.searchTimeout = Ext.Function.defer(function() {
66 this.search(el.value);
71 if (el.value && this.getDropdown().store.getCount() > 0) {
72 this.getDropdown().show();
76 // Don't hide the dropdown right away, otherwise
77 // we don't receive the itemclick event when focus
78 // was lost because we clicked on dropdown item.
79 // Not really a good solution, but I can't
80 // currently think of anything better. Behaves
81 // badly when you make a long mouse press on
83 var dropdown = this.getDropdown();
84 Ext.Function.defer(dropdown.hide, 500, dropdown);
90 getDropdown: function() {
91 return this.dropdown || (this.dropdown = Ext.getCmp('search-dropdown'));
94 // loads class/method corrseponding to the record
95 loadRecord: function(record) {
96 var name = record.get("cls");
97 if (record.get("type") !== 'cls') {
98 name += '-' + record.get("type") + '-' + record.get("member");
100 Docs.App.getController('Classes').loadClass(name);
101 this.getDropdown().hide();
104 search: function(term) {
105 // perform search and load results to store
107 var results = this.filterMembers(term);
108 this.getDropdown().setTotal(results.length);
109 this.getDropdown().getStore().loadData(results.slice(0, limit));
110 // position dropdown below search box
111 this.getDropdown().alignTo('search-field', 'bl', [-23, 2]);
112 // hide dropdown when nothing found
113 if (results.length === 0) {
114 this.getDropdown().hide();
117 // auto-select first result
118 this.getDropdown().getSelectionModel().select(0);
122 filterMembers: function(text) {
123 var results = [[], [], [], [], []];
124 var xFull=0, nFull=1, xBeg=2, nBeg=3, nMid=4;
125 var hasDot = /\./.test(text);
126 var safeText = Ext.escapeRe(text);
127 var reFull = new RegExp("^" + safeText + "$", "i");
128 var reBeg = new RegExp("^" + safeText, "i");
129 var reMid = new RegExp(safeText, "i");
131 Ext.Array.forEach(Docs.membersData.data, function(r) {
132 // when search text has "." in it, search from the full name (e.g. "Ext.Component.focus")
133 // Otherwise search from just the member name (e.g. "focus" or "Component")
134 var name = hasDot ? r.cls + (r.type === "cls" ? "" : "." + r.member) : r.member;
136 if (r.xtypes && Ext.Array.some(r.xtypes, function(x) {return reFull.test(x);})) {
137 results[xFull].push(r);
139 else if (r.xtypes && Ext.Array.some(r.xtypes, function(x) {return reBeg.test(x);})) {
140 results[xBeg].push(r);
142 else if (reFull.test(name)) {
143 results[nFull].push(r);
145 else if (reBeg.test(name)) {
146 results[nBeg].push(r);
148 else if (reMid.test(name)) {
149 results[nMid].push(r);
153 return Ext.Array.flatten(results);