]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/dojo/openils/widget/AutoSuggest.js
AutoSuggest: more UI tweaks regarding typing after selecting
[Evergreen.git] / Open-ILS / web / js / dojo / openils / widget / AutoSuggest.js
1 if (!dojo._hasResource["openils.widget.AutoSuggest"]) {
2     dojo.provide("openils.widget.AutoSuggest");
3     dojo._hasResource["openils.widget.AutoSuggest"] = true;
4
5     dojo.require("dijit.form.ComboBox");
6     dojo.require("openils.AutoSuggestStore");
7
8     /* Do some monkey-patching on dijit.form._ComboBoxMenu to make AutoSuggest
9      * widget behavior more Google-like, and do it within a function to prevent
10      * namespace pollution. */
11
12     (function() {
13         var victim = dijit.form._ComboBoxMenu;
14
15         /* Assist in making clicking on a suggestion lead directly to search.
16          * Relies on overridden _startSearch() in the widget below. */
17         var _orig_onMouseUp = victim.prototype._onMouseUp;
18         victim.prototype._onMouseUp = function(evt) {
19             if (this.parent_widget)
20                 this.parent_widget.mouse_used_most_recently = true;
21             dojo.hitch(this, _orig_onMouseUp)(evt);
22         };
23
24         /* These next two, taken together, prevent the user from having to
25          * type space twice after selecting (with arrow keys) an item from
26          * the autosuggestions. */
27         var _orig_handleKey = victim.prototype.handleKey;
28         victim.prototype.handleKey = function(key) {
29             /* Testing for this.parent_widget's existence allows our patch
30              * not to be intrusive if /other/ widgets (besides
31              * openils.widget.AutoSuggest) are using d.f._ComboBoxMenu on the
32              * same page. */
33             if (this.parent_widget && key == " ") {
34                 this.just_had_space = true;
35             } else {
36                 this.just_had_space = false;
37                 return dojo.hitch(this, _orig_handleKey)(key);
38             }
39         }
40
41         var _orig_getHighlightedOption = victim.prototype.getHighlightedOption;
42         victim.prototype.getHighlightedOption = function() {
43             if (this.just_had_space) {
44                 this.just_had_space = false;
45                 return null;
46             } else {
47                 return dojo.hitch(this, _orig_getHighlightedOption)();
48             }
49         }
50     })();
51
52     dojo.declare(
53         "openils.widget.AutoSuggest", [dijit.form.ComboBox], {
54
55             "labelAttr": "match",
56             "labelType": "html",
57             "searchAttr": "term",
58             "hasDownArrow": false,
59             "autoComplete": false,
60             "searchDelay": 200,
61
62             /* Don't forget to these two parameters when instantiating. */
63             "submitter": function() { console.log("No submitter connected"); },
64             "type_selector": null,  /* see openils.AutoSuggestStore for docs */
65
66             "store_args": {},
67
68             "mouse_used_most_recently": false,
69
70             "_update_search_type_selector": function(id) {  /* cmf id */
71                 if (!this.store.cm_cache.is_done) {
72                     console.warn(
73                         "can't update search type selector; " +
74                         "store doesn't have config.metabib_* caches available"
75                     );
76                     return;
77                 }
78
79                 var f = this.store.cm_cache.cmf[id];
80                 var selector = this.type_selector;
81                 var search_class = f.field_class + "|" + f.name;
82                 var exact = dojo.indexOf(
83                     dojo.map(selector.options, function(o) { return o.value; }),
84                     search_class
85                 );
86
87                 if (exact > 0) {
88                     selector.selectedIndex = exact;
89                 } else {    /* settle for class match if we can get it */
90                     for (var i = 0; i < selector.options.length; i++) {
91                         if (selector.options[i].value.split("|")[0] ==
92                                 f.field_class) {
93                             selector.selectedIndex = i;
94                             break;
95                         }
96                     }
97                 }
98             },
99
100             "_startSearch": function() {
101                 this.inherited(arguments);
102                 this._popupWidget.parent_widget = this;
103             },
104
105             "_setCaretPos": function(element, loc) {
106                 /* selects nothing, puts cursor at the end of the string */
107                 dijit.selectInputText(element, element.value.length);
108             },
109
110             "_autoCompleteText": function() {
111                 var orig = dijit.selectInputText;
112                 dijit.selectInputText = function() { };
113
114                 this.inherited(arguments);
115
116                 dijit.selectInputText = orig;
117             },
118
119             "onChange": function(value) {
120                 if (typeof value.field == "number") {
121                     this._update_search_type_selector(value.field);
122
123                     /* If onChange fires and the following condition is true,
124                      * it must mean that the user clicked on an actual
125                      * suggestion with the mouse.  We also perform our search
126                      * when the user presses enter (handled elsewhere), but not
127                      * when the user selects something and keeps typing. */
128                     if (this.mouse_used_most_recently)
129                         this.submitter();
130                 }
131             },
132
133             "postMixInProperties": function() {
134                 this.inherited(arguments);
135
136                 if (typeof this.submitter == "string")
137                     this.submitter = dojo.hitch(this, this.submitter);
138
139                 if (typeof this.type_selector == "string")
140                     this.type_selector = dojo.byId(this.type_selector);
141
142                 /* Save the instantiator from needing to specify same thing
143                  * twice, even though we need it and the store needs it too. */
144                 if (this.type_selector && !this.store_args.type_selector)
145                     this.store_args.type_selector = this.type_selector;
146
147                 this.store = new openils.AutoSuggestStore(this.store_args);
148             },
149
150             "postCreate": function() {
151                 this.inherited(arguments);
152
153                 dojo.connect(
154                     this, "onKeyPress", this, function(evt) {
155                         this.mouse_used_most_recently = false;
156                         if (evt.keyCode == dojo.keys.ENTER)
157                             this.submitter();
158                     }
159                 );
160             }
161         }
162     );
163 }