blob: 4324c1edc1588cd00e4fc08adc937c548e663061 [file] [log] [blame]
Nils Diewald44a72782014-06-20 16:03:21 +00001/*
2TODO:
3 - Limit the size to a certain number of elements
4 - addEventListener("click", ... , false);
5 - addEventListener("paste", ... , false);
6*/
7
8var Hint = function (param) {
9 var foundryRegex = new RegExp("(?:^|[^a-zA-Z0-9])([-a-zA-Z0-9]+?)\/(?:([^=]+?)=)?$");
10
Nils Diewald465c4252014-06-20 21:51:58 +000011 var search = document.getElementById(param["ref"]);
12 var qlField = document.getElementById(param["qlRef"]);
13 var mirror = document.createElement("div");
14 var hint = document.createElement("ul");
Nils Diewald44a72782014-06-20 16:03:21 +000015 var hintSize = param["hintSize"] ? param["hintSize"] : 10;
Nils Diewald465c4252014-06-20 21:51:58 +000016 var hints = param["hints"];
Nils Diewald44a72782014-06-20 16:03:21 +000017 var that = this;
Nils Diewald465c4252014-06-20 21:51:58 +000018 var ql;
Nils Diewald44a72782014-06-20 16:03:21 +000019
20 // Build the mirror element
21 // <div id="searchMirror"><span></span><ul></ul></div>
22 mirror.setAttribute("id", "searchMirror");
23 mirror.appendChild(document.createElement("span"));
24 mirror.appendChild(hint);
Nils Diewald7cad8402014-07-08 17:06:56 +000025 document.getElementsByTagName("body")[0].appendChild(mirror);
Nils Diewald44a72782014-06-20 16:03:21 +000026 // Default active state
27 this.active = -2;
28
29 // Show hint table
30 this.show = function (topic) {
31 if (!hints[topic])
32 return;
Nils Diewald3b5c4632014-06-20 22:06:02 +000033 this.hide();
Nils Diewald44a72782014-06-20 16:03:21 +000034 this.active = -1;
35 this.list(hints[topic]);
36 var searchRight = search.getBoundingClientRect().right;
37 var infoRight = hint.getBoundingClientRect().right;
38 if (infoRight > searchRight) {
39 hint.style.marginLeft = '-' + (infoRight - searchRight) + 'px';
40 };
41 hint.style.opacity = 1;
42 };
43
44 // Initialize the mirror element
45 function init () {
46 // Copy input style
47 var searchRect = search.getBoundingClientRect();
48 var searchStyle = window.getComputedStyle(search, null);
49
50 with (mirror.style) {
51 left = searchRect.left + "px";
52 top = searchRect.bottom + "px";
53 borderLeftColor = "transparent";
54 paddingLeft = searchStyle.getPropertyValue("padding-left");
55 marginLeft = searchStyle.getPropertyValue("margin-left");
56 borderLeftWidth = searchStyle.getPropertyValue("border-left-width");
57 borderLeftStyle = searchStyle.getPropertyValue("border-left-style");
58 fontSize = searchStyle.getPropertyValue("font-size");
59 fontFamily = searchStyle.getPropertyValue("font-family");
60 };
Nils Diewald465c4252014-06-20 21:51:58 +000061
62 qlSelect();
Nils Diewald44a72782014-06-20 16:03:21 +000063 };
64
65 // Hide hint table
66 this.hide = function () {
Nils Diewald3b5c4632014-06-20 22:06:02 +000067 if (this.active === -2)
68 return;
Nils Diewald44a72782014-06-20 16:03:21 +000069 this.active = -2;
70 hint.style.opacity = 0;
71 hint.style.marginLeft = 0;
72
73 // Remove all children
74 var lis = hint.childNodes;
75 for (var li = lis.length - 1; li >= 0; li--) {
76 hint.removeChild(lis[li])
77 };
78 };
79
80 // List elements in the hint table
81 this.list = function (hintList) {
82 var li, title;
83 var arrayType = hintList instanceof Array;
84 for (var i in hintList) {
85 // Create list items
86 li = document.createElement("li");
87 li.setAttribute("data-action", arrayType ? hintList[i] : hintList[i][0]);
88 title = document.createElement("strong");
89 title.appendChild(document.createTextNode(arrayType ? hintList[i] : i));
90 li.appendChild(title);
91 hint.appendChild(li);
92
93 // Include descriptions
94 if (!arrayType && hintList[i][1]) {
95 var desc = document.createElement("span");
96 desc.appendChild(document.createTextNode(hintList[i][1]));
97 li.appendChild(desc);
98 };
99 };
100 };
101
102 // Choose next item in list
103 this.next = function () {
104 if (this.active === -2)
Nils Diewald7cad8402014-07-08 17:06:56 +0000105 return false;
106
Nils Diewald44a72782014-06-20 16:03:21 +0000107 var lis = hint.getElementsByTagName("li");
108 if (this.active === -1) {
109 lis[0].setAttribute("class", "active");
110 this.active = 0;
111 }
112 else if (this.active === lis.length - 1) {
113 lis[this.active].removeAttribute("class");
114 lis[0].setAttribute("class", "active");
115 this.active = 0;
116 }
117 else {
118 lis[this.active].removeAttribute("class");
119 lis[++this.active].setAttribute("class", "active");
120 };
Nils Diewald7cad8402014-07-08 17:06:56 +0000121
122 return true;
Nils Diewald44a72782014-06-20 16:03:21 +0000123 };
124
125 // Choose previous item in list
126 this.previous = function () {
127 if (this.active === -2)
128 return;
129
130 var lis = hint.getElementsByTagName("li");
131 if (this.active === -1) {
132 this.active = lis.length - 1;
133 lis[this.active].setAttribute("class", "active");
134 }
135 else if (this.active === 0) {
136 lis[0].removeAttribute("class");
137 this.active = lis.length - 1;
138 lis[this.active].setAttribute("class", "active");
139 }
140 else {
141 lis[this.active].removeAttribute("class");
142 lis[--this.active].setAttribute("class", "active");
143 };
144 };
145
146 // Choose item from list
147 this.choose = function () {
148 if (this.active < 0)
149 return;
150
151 var action = hint.getElementsByTagName("li")[this.active].getAttribute("data-action");
152
153 var value = search.value;
154 var start = search.selectionStart;
155 var begin = value.substring(0, start);
156 var end = value.substring(start, value.length);
157 search.value = begin + action + end;
Nils Diewald465c4252014-06-20 21:51:58 +0000158 search.selectionStart = (begin + action).length
159 search.selectionEnd = search.selectionStart;
Nils Diewald44a72782014-06-20 16:03:21 +0000160
161 this.hide();
162
163 // Check for new changes
Nils Diewald465c4252014-06-20 21:51:58 +0000164 mirror.firstChild.textContent = begin + action;
165
Nils Diewald44a72782014-06-20 16:03:21 +0000166 if (foundryRegex.exec(begin + action))
167 this.show(RegExp.$1 + (RegExp.$2 ? '/' + RegExp.$2 : ''));
Nils Diewald7cad8402014-07-08 17:06:56 +0000168
169 return true;
Nils Diewald44a72782014-06-20 16:03:21 +0000170 };
171
172 function changed (e) {
173 var el = e.target;
174
175 if (e.key === '/' || e.key === '=') {
176 var start = el.selectionStart;
Nils Diewald465c4252014-06-20 21:51:58 +0000177 mirror.firstChild.textContent = el.value.substring(0, start);
Nils Diewald44a72782014-06-20 16:03:21 +0000178 var sub = el.value.substring(start - 128 >= 0 ? start - 128 : 0, start);
179
180 if (foundryRegex.exec(sub))
181 that.show(RegExp.$1 + (RegExp.$2 ? '/' + RegExp.$2 : ''));
182 }
Nils Diewald3b5c4632014-06-20 22:06:02 +0000183 else if (e.key === '>') {
184 that.hide();
185 }
186 else if (ql === 'poliqarp' && (e.key === '[' || e.key === '<')) {
Nils Diewald465c4252014-06-20 21:51:58 +0000187 mirror.firstChild.textContent = el.value.substring(0, el.selectionStart);
188 that.show("-foundries");
189 }
Nils Diewald44a72782014-06-20 16:03:21 +0000190 else if (e.key !== 'Shift' &&
191 e.key !== 'Up' &&
192 e.key !== 'Down' &&
Nils Diewald465c4252014-06-20 21:51:58 +0000193 e.key !== 'Enter' &&
194 e.key !== 'Alt' &&
195 e.key !== 'AltGraph' &&
196 e.key !== 'CapsLock') {
Nils Diewald44a72782014-06-20 16:03:21 +0000197 that.hide();
198 };
199 };
200
201 // Select item from suggestion list
202 function select (e) {
203 if (that.active === -2)
204 return;
205 if (e.key === 'Down') {
Nils Diewald7cad8402014-07-08 17:06:56 +0000206 return that.next();
Nils Diewald44a72782014-06-20 16:03:21 +0000207 }
208 else if (e.key === 'Up') {
Nils Diewald7cad8402014-07-08 17:06:56 +0000209 return that.previous();
Nils Diewald44a72782014-06-20 16:03:21 +0000210 }
Nils Diewald7cad8402014-07-08 17:06:56 +0000211 else if (e.key === 'Enter' && that.choose()) {
Nils Diewald44a72782014-06-20 16:03:21 +0000212 e.stopPropagation();
213 e.preventDefault();
214 return false;
Nils Diewald7cad8402014-07-08 17:06:56 +0000215 };
216 that.hide();
Nils Diewald44a72782014-06-20 16:03:21 +0000217 };
218
Nils Diewald465c4252014-06-20 21:51:58 +0000219 function qlSelect () {
220 var nodes = qlField.childNodes;
221 for (var i = 0; i < nodes.length; i++) {
222 if (nodes[i].selected) {
223 ql = nodes[i].value;
224 break;
225 };
226 };
227 };
228
Nils Diewald44a72782014-06-20 16:03:21 +0000229 // Initialize style
230 init();
Nils Diewalddb03fa92014-06-23 13:36:55 +0000231 window.onresize = init;
Nils Diewald002e8fb2014-06-22 14:27:01 +0000232 search.addEventListener("keyup", changed, false);
Nils Diewald3b5c4632014-06-20 22:06:02 +0000233 search.addEventListener("keydown", select, false);
Nils Diewald002e8fb2014-06-22 14:27:01 +0000234 qlField.addEventListener('change', qlSelect, false);
Nils Diewald44a72782014-06-20 16:03:21 +0000235};