-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbasic-keyboard-prefix-selection.html
More file actions
168 lines (136 loc) · 4.28 KB
/
basic-keyboard-prefix-selection.html
File metadata and controls
168 lines (136 loc) · 4.28 KB
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
<!--
Handle list box-style prefix typing, in which the user can type a string to
select the first item that begins with that string.
@element basic-keyboard-prefix-selection
-->
<!--
TODO: If the selection is changed by some other means (e.g., arrow keys) other
than prefix typing, then that act should reset the prefix.
-->
<link rel="import" href="../basic-aspect/basic-aspect.html">
<link rel="import" href="../basic-shared/basic-shared.html">
<script>
window.Basic = window.Basic || {};
window.Basic.KeyboardPrefixSelection = {
contribute: {
itemsChanged: function() {
this._itemTextContents = null;
this._resetTypedPrefix();
},
keydown: function(event) {
var handled = false;
var resetPrefix = true;
switch (event.keyCode) {
case 8: // Backspace
this._handleBackspace();
handled = true;
resetPrefix = false;
break;
case 27: // Escape
handled = true;
break;
default:
if (!event.ctrlKey && !event.metaKey && !event.altKey
&& event.which !== 32 /* Space */) {
this._handlePlainCharacter(String.fromCharCode(event.which));
}
resetPrefix = false;
}
if (resetPrefix) {
this._resetTypedPrefix();
}
if (handled) {
event.preventDefault();
event.stopPropagation();
}
},
/**
* Select the first item whose text content begins with the given prefix.
*
* @method selectItemWithTextPrefix
* @param prefix [String] The string to search for
*/
selectItemWithTextPrefix: function(prefix) {
if (prefix == null || prefix.length === 0) {
return;
}
var index = this._getIndexOfItemWithTextPrefix(prefix);
if (index >= 0) {
this.collective.selectedIndex = index;
}
}
},
name: 'KeyboardPrefixSelection',
// Return the index of the first item with the given prefix, else -1.
_getIndexOfItemWithTextPrefix: function(prefix) {
var itemTextContents = this._getItemTextContents();
var prefixLength = prefix.length;
for (var i = 0; i < itemTextContents.length; i++) {
var itemTextContent = itemTextContents[i];
if (itemTextContent.substr(0, prefixLength) === prefix) {
return i;
}
}
return -1;
},
// Return an array of the text content (in lowercase) of all items.
// Cache these results.
_getItemTextContents: function() {
if (!this._itemTextContents) {
var items = this.collective.items;
this._itemTextContents = items.map(function(child) {
var text = child.textContent || child.alt;
return text.toLowerCase();
});
}
return this._itemTextContents;
},
_handleBackspace: function() {
var length = this._typedPrefix.length;
if (length > 0) {
this._typedPrefix = this._typedPrefix.substr(0, length - 1);
}
this.collective.selectItemWithTextPrefix(this._typedPrefix);
this._setPrefixTimeout();
},
_handlePlainCharacter: function(char) {
this._typedPrefix += char.toLowerCase();
this.collective.selectItemWithTextPrefix(this._typedPrefix);
this._setPrefixTimeout();
},
_resetPrefixTimeout: function() {
if (this._prefixTimeout) {
clearTimeout(this._prefixTimeout);
this._prefixTimeout = false;
}
},
_resetTypedPrefix: function() {
this._typedPrefix = '';
this._resetPrefixTimeout();
},
_setPrefixTimeout: function() {
this._resetPrefixTimeout();
this._prefixTimeout = setTimeout(function() {
this._resetTypedPrefix();
}.bind(this), this._prefixTimeoutDuration);
},
// The text content of the items. This is only populated if the user tries to
// navigate with typed prefix matching.
_itemTextContents: null,
// Times out when the user has not typed anything for a bit.
_prefixTimeout: null,
// Time in milliseconds after which the user is considered to have stopped
// typing.
_prefixTimeoutDuration: 1000,
// The string the user has typed to navigate by prefix.
_typedPrefix: ''
};
Polymer({
aspects: [Basic.KeyboardPrefixSelection],
behaviors: [Basic.Aspect],
is: 'basic-keyboard-prefix-selection',
selectItemWithTextPrefix: function(prefix) {
this.collective.selectItemWithTextPrefix(prefix);
}
});
</script>