Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / app / controller / Search.js
1 /**
2  * Controller for search.
3  */
4 Ext.define('Docs.controller.Search', {
5     extend: 'Ext.app.Controller',
6
7     views: [
8         'search.Dropdown'
9     ],
10
11     stores: ['Search'],
12
13     init: function() {
14         this.control({
15             '#search-dropdown': {
16                 itemclick: function(dropdown, record) {
17                     this.loadRecord(record);
18                 }
19             },
20             '#search-field': {
21                 keyup: function(el, ev) {
22                     var dropdown = this.getDropdown();
23
24                     el.setHideTrigger(el.getValue().length === 0);
25
26                     if (ev.keyCode === Ext.EventObject.ESC || !el.value) {
27                         dropdown.hide();
28                         el.setValue("");
29                         return;
30                     }
31                     else {
32                         dropdown.show();
33                     }
34
35                     var selModel = dropdown.getSelectionModel();
36                     var record = selModel.getLastSelected();
37                     var curIndex = dropdown.store.indexOf(record);
38                     var lastIndex = dropdown.store.getCount() - 1;
39
40                     if (ev.keyCode === Ext.EventObject.UP) {
41                         if (curIndex === undefined) {
42                             selModel.select(0);
43                         } else {
44                             selModel.select(curIndex === 0 ? lastIndex : (curIndex - 1));
45                         }
46                     }
47                     else if (ev.keyCode === Ext.EventObject.DOWN) {
48                         if (curIndex === undefined) {
49                             selModel.select(0);
50                         } else {
51                             selModel.select(curIndex === lastIndex ? 0 : curIndex + 1);
52                         }
53                     }
54                     else if (ev.keyCode === Ext.EventObject.ENTER) {
55                         ev.preventDefault();
56                         record && this.loadRecord(record);
57                     }
58                     else {
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);
67                         }, 50, this);
68                     }
69                 },
70                 focus: function(el) {
71                     if (el.value && this.getDropdown().store.getCount() > 0) {
72                         this.getDropdown().show();
73                     }
74                 },
75                 blur: function() {
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
82                     // dropdown item.
83                     var dropdown = this.getDropdown();
84                     Ext.Function.defer(dropdown.hide, 500, dropdown);
85                 }
86             }
87         });
88     },
89
90     getDropdown: function() {
91         return this.dropdown || (this.dropdown = Ext.getCmp('search-dropdown'));
92     },
93
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");
99         }
100         Docs.App.getController('Classes').loadClass(name);
101         this.getDropdown().hide();
102     },
103
104     search: function(term) {
105         // perform search and load results to store
106         var limit = 10;
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();
115         }
116         else {
117             // auto-select first result
118             this.getDropdown().getSelectionModel().select(0);
119         }
120     },
121
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");
130
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;
135
136             if (r.xtypes && Ext.Array.some(r.xtypes, function(x) {return reFull.test(x);})) {
137                 results[xFull].push(r);
138             }
139             else if (r.xtypes && Ext.Array.some(r.xtypes, function(x) {return reBeg.test(x);})) {
140                 results[xBeg].push(r);
141             }
142             else if (reFull.test(name)) {
143                 results[nFull].push(r);
144             }
145             else if (reBeg.test(name)) {
146                 results[nBeg].push(r);
147             }
148             else if (reMid.test(name)) {
149                 results[nMid].push(r);
150             }
151         });
152
153         return Ext.Array.flatten(results);
154     }
155
156 });