5708b508e7b40fe5915987da60d847d8348c9bee
[WebKit-https.git] / Websites / test-results / public / js / autocompleter.js
1 function Autocompleter(inputElement, list) {
2     this._inputElement = inputElement;
3     this._currentSelection = undefined;
4     this._list = list;
5     this._candidates = [];
6     this._currentFilter = null;
7     this._candidateWindow = null;
8
9     inputElement.addEventListener('focus', this.show.bind(this));
10     inputElement.addEventListener('blur', this.hide.bind(this));
11     inputElement.addEventListener('keyup', this.update.bind(this));
12     inputElement.addEventListener('keydown', this.navigate.bind(this));
13 }
14
15 Autocompleter.prototype._ensureCandidateWindow = function () {
16     if (this._candidateWindow)
17         return;
18
19     var container = element('ul');
20     container.className = 'candidateWindow';
21     container.style.position = 'absolute';
22     container.style.display = 'none';
23     this._inputElement.parentNode.appendChild(container);
24     this._candidateWindow = container;
25 }
26
27 Autocompleter.prototype._updateCandidates = function (filter) {
28     if (this._currentFilter == filter)
29         return false;
30
31     var candidates = this._list.filter(function (testName) { return testName.indexOf(filter) >= 0; });
32     if (candidates.length > 50 || candidates.length == 1)
33         candidates = [];
34     this._candidates = candidates;
35     this._currentFilter = filter;
36     this._currentSelection = undefined;
37     return true;
38 }
39
40 Autocompleter.prototype._showCandidateWindow = function () {
41     if (!this._candidateWindow)
42         return;
43     var style = this._candidateWindow.style;
44     style.display = 'block';
45     style.top = this._inputElement.offsetTop + this._inputElement.offsetHeight + 'px';
46     style.left = this._inputElement.offsetLeft + 'px';
47 }
48
49 Autocompleter.prototype._createItem = function (candidate) {
50     var tokens = candidate.split(this._currentFilter);
51     var children = [];
52     for (var i = 0; i < tokens.length; i++) {
53         children.push(text(tokens[i]));
54         if (i + 1 < tokens.length)
55             children.push(element('em', [this._currentFilter]));
56     }
57     return element('li', children);
58 }
59
60 Autocompleter.prototype.show = function () {
61     this.hide();
62     this._ensureCandidateWindow();
63
64     for (var i = 0; i < this._candidates.length; i++)
65         this._candidateWindow.appendChild(this._createItem(this._candidates[i]));
66     this._selectItem(this._currentSelection);
67
68     if (this._candidates.length)
69         this._showCandidateWindow();
70 }
71
72 Autocompleter.prototype.update = function () {
73     if (this._updateCandidates(this._inputElement.value))
74         this.show();
75 }
76
77 Autocompleter.prototype.hide = function () {
78     if (!this._candidateWindow)
79         return;
80     this._candidateWindow.style.display = 'none';
81     this._candidateWindow.innerHTML = '';
82 }
83
84 Autocompleter.prototype._selectItem = function (index) {
85     if (!this._candidateWindow || this._currentSelection == index)
86         return;
87
88     var item = this._candidateWindow.childNodes[index];
89     if (!item)
90         return;
91     item.classList.add('selected');
92
93     var oldItem = this._candidateWindow.childNodes[this._currentSelection];
94     if (oldItem)
95         oldItem.classList.remove('selected');
96
97     this._currentSelection = index;
98 }
99
100 Autocompleter.prototype.navigate = function (event) {
101     if (event.keyCode == 0x28 /* DOM_VK_DOWN */) {
102         this._selectItem(this._currentSelection === undefined ? 0 : Math.min(this._currentSelection + 1, this._candidates.length - 1));
103         event.preventDefault();
104     } else if (event.keyCode == 0x26 /* DOM_VK_UP */) {
105         this._selectItem(this._currentSelection === undefined ? this._candidates.length - 1 : Math.max(this._currentSelection - 1, 0));
106         event.preventDefault();
107     } else if (event.keyCode == 0x0D /* VK_RETURN */) {
108         if (this._currentSelection === undefined)
109             return;
110         this._inputElement.value = this._candidates[this._currentSelection];
111     } else if (event.keyCode == 0x1B /* DOM_VK_ESCAPE */) {
112         this.hide();
113     }
114 }