blob: eed45f3b8c5bd2cd2d29f67d75b638275cf73923 [file] [log] [blame]
Nils Diewaldeca30442014-11-18 20:33:54 +00001"use strict";
Nils Diewald44a72782014-06-20 16:03:21 +00002
Nils Diewaldeca30442014-11-18 20:33:54 +00003// Don't let events bubble up
4Event.prototype.halt = function () {
5 this.stopPropagation();
6 this.preventDefault();
7};
Nils Diewald44a72782014-06-20 16:03:21 +00008
Nils Diewaldeca30442014-11-18 20:33:54 +00009// http://www.nlpado.de/~sebastian/software/ner_german.shtml
10// http://www.cnts.ua.ac.be/conll2003/ner/
11var namedEntities = [
12 ["I-LOC", "I-LOC", "Location"],
13 ["I-MISC", "I-MISC", "Miscellaneous"],
14 ["I-ORG", "I-ORG", "Organization"],
15 ["I-PER", "I-PER", "Person"]
16];
Nils Diewald44a72782014-06-20 16:03:21 +000017
Nils Diewaldeca30442014-11-18 20:33:54 +000018// http://www.ids-mannheim.de/cosmas2/projekt/referenz/stts/morph.html
19// http://nachhalt.sfb632.uni-potsdam.de/owl-docu/stts.html
20var sttsArray = [
21 // "$.", "$(", "$,"
22 ["ADJA","ADJA", "Attributive Adjective"],
23 ["ADJD","ADJD", "Predicative Adjective"],
24 ["ADV","ADV", "Adverb"],
25 ["APPO","APPO", "Postposition"],
26 ["APPR","APPR", "Preposition"],
27 ["APPRART","APPRART", "Preposition with Determiner"],
28 ["APZR","APZR","Right Circumposition"],
29 ["ART","ART", "Determiner"],
30 ["CARD","CARD", "Cardinal Number"],
31 ["FM","FM", "Foreign Material"],
32 ["ITJ","ITJ", "Interjection"],
33 ["KOKOM","KOKOM", "Comparison Particle"],
34 ["KON","KON", "Coordinating Conjuncion"],
35 ["KOUI","KOUI", "Subordinating Conjunction with 'zu'"],
36 ["KOUS","KOUS", "Subordinating Conjunction with Sentence"],
37 ["NE","NE", "Named Entity"],
38 ["NN","NN", "Normal Nomina"],
39 ["PAV", "PAV", "Pronominal Adverb"],
40 ["PDAT","PDAT","Attributive Demonstrative Pronoun"],
41 ["PDS","PDS", "Substitutive Demonstrative Pronoun"],
42 ["PIAT","PIAT", "Attributive Indefinite Pronoun without Determiner"],
43 ["PIDAT","PIDAT", "Attributive Indefinite Pronoun with Determiner"],
44 ["PIS","PIS", "Substitutive Indefinite Pronoun"],
45 ["PPER","PPER", "Personal Pronoun"],
46 ["PPOSAT","PPOSAT", "Attributive Possessive Pronoun"],
47 ["PPOSS","PPOSS", "Substitutive Possessive Pronoun"],
48 ["PRELAT","PRELAT", "Attributive Relative Pronoun"],
49 ["PRELS","PRELS", "Substitutive Relative Pronoun"],
50 ["PRF","PRF", "Reflexive Pronoun"],
51 ["PROAV","PROAV", "Pronominal Adverb"],
52 ["PTKA","PTKA","Particle with Adjective"],
53 ["PTKANT","PTKANT", "Answering Particle"],
54 ["PTKNEG","PTKNEG", "Negation Particle"],
55 ["PTKVZ","PTKVZ", "Separated Verbal Particle"],
56 ["PTKZU","PTKZU", "'zu' Particle"],
57 ["PWAT","PWAT", "Attributive Interrogative Pronoun"],
58 ["PWAV","PWAV", "Adverbial Interrogative Pronoun"],
59 ["PWS","PWS", "Substitutive Interrogative Pronoun"],
60 ["TRUNC","TRUNC","Truncated"],
61 ["VAFIN","VAFIN", "Auxiliary Finite Verb"],
62 ["VAINF","VAINF", "Auxiliary Infinite Verb"],
63 ["VAIMP","VAIMP", "Auxiliary Finite Imperative Verb"],
64 ["VAPP","VAPP", "Auxiliary Perfect Participle"],
65 ["VMFIN","VMFIN", "Modal Finite Verb"],
66 ["VMINF","VMINF", "Modal Infinite Verb"],
67 ["VMPP","VMPP", "Modal Perfect Participle"],
68 ["VVFIN","VVFIN","Finite Verb"],
69 ["VVIMP","VVIMP", "Finite Imperative Verb"],
70 ["VVINF","VVINF", "Infinite Verb"],
71 ["VVIZU","VVIZU", "Infinite Verb with 'zu'"],
72 ["VVPP","VVPP", "Perfect Participle"],
73 ["XY", "XY", "Non-Word"]
74];
Nils Diewald44a72782014-06-20 16:03:21 +000075
Nils Diewaldeca30442014-11-18 20:33:54 +000076var mateSttsArray = sttsArray.slice(0);
77mateSttsArray.push(
78 ["<root-POS>","<root-POS>","Root Part of Speech"]
79);
Nils Diewald44a72782014-06-20 16:03:21 +000080
Nils Diewald44a72782014-06-20 16:03:21 +000081
Nils Diewaldeca30442014-11-18 20:33:54 +000082var hintArray = {
83 "-" : [
84 ["Connexor", "cnx/"],
85 ["CoreNLP", "corenlp/"],
86 ["Mate", "mate/"],
87 ["OpenNLP", "opennlp/"],
88 ["TreeTagger", "tt/"],
89 ["Xerox Parser", "xip/"]
90 ],
91 "corenlp/" : [
92 ["Named Entity", "ne=" , "Combined"],
93 ["Named Entity", "ne_dewac_175m_600=" , "ne_dewac_175m_600"],
94 ["Named Entity", "ne_hgc_175m_600=", "ne_hgc_175m_600"]
95 ],
96 "corenlp/ne=" : namedEntities,
97 "corenlp/ne_dewac_175m_600=" : namedEntities,
98 "corenlp/ne_hgc_175m_600=" : namedEntities,
99 "cnx/" : [
100 ["Constituency", "c="],
101 ["Lemma", "l="],
102 ["Morphology", "m="],
103 ["Part-of-Speech", "p="],
104 ["Syntax", "syn="]
105 ],
106 "cnx/c=" : [
107 ["np", "np", "Nominal Phrase"]
108 ],
109 // http://www.ids-mannheim.de/cosmas2/projekt/referenz/connexor/morph.html
110 "cnx/m=" : [
111 ["Abbr","Abbr", "Nouns: Abbreviation"],
112 ["CMP","CMP", "Adjective: Comparative"],
113 ["IMP", "IMP", "Mood: Imperative"],
114 ["IND", "IND", "Mood: Indicative"],
115 ["INF", "INF", "Infinitive"],
116 ["ORD","ORD", "Numeral: Ordinal"],
117 ["PAST", "PAST", "Tense: past"],
118 ["PCP", "PCP", "Participle"],
119 ["PERF", "PERF", "Perfective Participle"],
120 ["PL","PL", "Nouns: Plural"],
121 ["PRES", "PRES", "Tense: present"],
122 ["PROG", "PROG", "Progressive Participle"],
123 ["Prop","Prop", "Nouns: Proper Noun"],
124 ["SUB", "SUB", "Mood: Subjunctive"],
125 ["SUP","SUP", "Adjective: Superlative"]
126 ],
127 // http://www.ids-mannheim.de/cosmas2/projekt/referenz/connexor/morph.html
128 "cnx/p=" : [
129 ["A", "A", "Adjective"],
130 ["ADV", "ADV", "Adverb"],
131 ["CC", "CC", "Coordination Marker"],
132 ["CS", "CS", "Clause Marker"],
133 ["DET", "DET", "Determiner"],
134 ["INTERJ", "INTERJ", "Interjection"],
135 ["N", "N", "Noun"],
136 ["NUM", "NUM", "Numeral"],
137 ["PREP", "PREP", "Preposition"],
138 ["PRON", "PRON", "Pro-Nominal"],
139 ["V", "V", "Verb"]
140 ],
141 // http://www.ids-mannheim.de/cosmas2/projekt/referenz/connexor/syntax.html
142 "cnx/syn=" : [
143 ["@ADVL", "@ADVL", "Adverbial Head"],
144 ["@AUX", "@AUX", "Auxiliary Verb"],
145 ["@CC", "@CC", "Coordination"]
146 ["@MAIN", "@MAIN", "Main Verb"],
147 ["@NH", "@NH", "Nominal Head"],
148 ["@POSTMOD", "@POSTMOD", "Postmodifier"],
149 ["@PREMARK", "@PREMARK", "Preposed Marker"],
150 ["@PREMOD", "@POSTMOD", "Premodifier"]
151 ],
152 "opennlp/" : [
153 ["Part-of-Speech", "p="]
154 ],
155 "opennlp/p=" : sttsArray,
156 "xip/" : [
157 ["Constituency", "c="],
158 // Inactive: ["Dependency", "d="],
159 ["Lemma", "l="],
160 ["Part-of-Speech", "p="],
161 ],
162 // "xip/c=" : [],
163 // Inactive: "xip/d=" : [],
164 // "xip/p=" : [],
165 "tt/" : [
166 ["Lemma", "l="],
167 ["Part-of-Speech", "p="]
168 ],
169 "tt/p=" : sttsArray,
170 "mate/" : [
171 // Inactive: "d" : ["d=", "Dependency"],
172 ["Lemma", "l="],
173 ["Morphology", "m="],
174 ["Part-of-Speech", "p="]
175 ],
176 // Inactive: mate/d=
177 "mate/p=" : mateSttsArray,
178 "mate/m=" : [
179 ["Case", "case:"],
180 ["Degree", "degree:"],
181 ["Gender", "gender:"],
182 ["Mood", "mood:"],
183 ["Number", "number:"],
184 ["Person", "person:"],
185 ["Tense","tense:"],
186 ["No type", "<no-type>"]
187 ],
188 "mate/m=case:" : [
189 ["acc", "acc", "Accusative"],
190 ["dat","dat", "Dative"],
191 ["gen", "gen","Genitive"],
192 ["nom","nom", "Nominative"],
193 ["*","*", "Undefined"]
194 ],
195 "mate/m=degree:" : [
196 ["comp","comp", "Comparative"],
197 ["pos","pos", "Positive"],
198 ["sup","sup", "Superative"]
199 ],
200 "mate/m=gender:" : [
201 ["fem", "fem", "Feminium"],
202 ["masc", "masc", "Masculinum"],
203 ["neut","neut", "Neuter"],
204 ["*","*","Undefined"]
205 ],
206 "mate/m=mood:" : [
207 ["imp","imp", "Imperative"],
208 ["ind","ind", "Indicative"],
209 ["subj","subj", "Subjunctive"]
210 ],
211 "mate/m=number:" : [
212 ["pl","pl","Plural"],
213 ["sg","sg","Singular"],
214 ["*","*","Undefined"]
215 ],
216 "mate/m=person:" : [
217 ["1","1", "First Person"],
218 ["2","2", "Second Person"],
219 ["3","3", "Third Person"]
220 ],
221 "mate/m=tense:" : [
222 ["past","past", "Past"],
223 ["pres","pres", "Present"]
224 ]
225};
226
227
228/**
229 * Analyze strings for prefixes
230 */
231var PrefixAnalyzer = {
232 _regex : new RegExp(
233 "(?:^|[^a-zA-Z0-9])" + // Anchor
234 "((?:[-a-zA-Z0-9]+?)\/" + // Foundry
235 "(?:" +
236 "(?:[^=:]+?)=" + // Layer
237 "(?:(?:[^:]+?):)?" + // Key
238 ")?" +
239 ")$"),
240 analyze : function (text) {
241 if (!this._regex.exec(text))
242 return undefined;
243 return RegExp.$1
244 }
245};
246
247/**
248 * Event handling after a key pressed
249 */
250function updateKey (that, e) {
251 var menu = that.menu();
252 switch (e.key) {
253 case 'Esc':
254 // Hide menu
255 menu.hide();
256 break;
257 case 'Down':
258 e.halt(); // No event propagation
259
260 // Menu is not active
261 if (!menu.active) {
262 that.popUp()
263 }
264 // Menu is active
265 else {
266 that.removePrefix();
267 menu.next();
Nils Diewald44a72782014-06-20 16:03:21 +0000268 };
Nils Diewald465c4252014-06-20 21:51:58 +0000269
Nils Diewaldeca30442014-11-18 20:33:54 +0000270 break;
271 case "Up":
272 if (!menu.active)
273 break;
274 e.halt(); // No event propagation
275 that.removePrefix();
276 menu.prev();
277 break;
278 case "Enter":
279 if (!menu.active)
280 break;
281 e.halt(); // No event propagation
282 that.insertText(menu.getActiveItem().getAction());
283 that.removePrefix();
Nils Diewald44a72782014-06-20 16:03:21 +0000284
Nils Diewaldeca30442014-11-18 20:33:54 +0000285 // Remove menu
286 menu.hide();
Nils Diewald44a72782014-06-20 16:03:21 +0000287
Nils Diewaldeca30442014-11-18 20:33:54 +0000288 // Fill this with the correct value
289 // Todo: This is redundant with click function
290 var show;
291 if ((show = that.analyzeContext()) !== "-") {
292 menu.show(show);
293 menu.update(
294 e.target.getBoundingClientRect().right
295 );
Nils Diewald44a72782014-06-20 16:03:21 +0000296 };
Nils Diewald44a72782014-06-20 16:03:21 +0000297
Nils Diewaldeca30442014-11-18 20:33:54 +0000298 break;
299 default:
300 if (!menu.active)
301 break;
Nils Diewald44a72782014-06-20 16:03:21 +0000302
Nils Diewaldeca30442014-11-18 20:33:54 +0000303 // key stroke is not a character
304 if (e.key.length != 1) {
305
306 // Key stroke is not a text modifying key
307 if (e.key !== 'Shift' &&
308 e.key !== 'Up' &&
309 e.key !== 'Down' &&
310 e.key !== 'Enter' &&
311 e.key !== 'Alt' &&
312 e.key !== 'AltGraph' &&
313 e.key !== 'CapsLock') {
314 that.insertPrefix();
315 menu.hide();
Nils Diewald44a72782014-06-20 16:03:21 +0000316 };
Nils Diewaldeca30442014-11-18 20:33:54 +0000317 break;
Nils Diewald44a72782014-06-20 16:03:21 +0000318 };
Nils Diewald7cad8402014-07-08 17:06:56 +0000319
Nils Diewaldeca30442014-11-18 20:33:54 +0000320 e.halt(); // No event propagation
321
322 // Try to identify prefix
323 if (menu.skipToPrefix(e.key))
324 break;
Nils Diewald44a72782014-06-20 16:03:21 +0000325
Nils Diewaldeca30442014-11-18 20:33:54 +0000326 // Prefix not found
327 that.insertPrefix();
328 menu.hide();
329 };
330};
331
332// new hint object
333var Hint = {
334 _search : undefined, // Return the search element
335 _mirror : undefined, // Return the mirror element
336 _menu : undefined,
337 _analyzer : undefined,
338 firstTry : true,
339 menu : function () {
340 // In case this wasn't defined yet
341 if (this._menu === undefined) {
342 this._menu = Object.create(Menu).init();
343 this._mirror.appendChild(this._menu.getElement());
344 };
345 return this._menu;
346 },
347
348 // Initialize the object
349 init : function () {
350 this._search = document.getElementById("q-field");
351 this._mirror = document.createElement("div");
352 this._mirror.setAttribute("id", "searchMirror");
353 this._mirror.appendChild(document.createElement("span"));
354 document.getElementsByTagName("body")[0].appendChild(this._mirror);
355
356 this._analyzer = Object.create(PrefixAnalyzer);
357
358 // Update positional information, in case the windows size changes
359 var that = this;
360 window.onresize = function () { that.reposition() };
361
362 // Add event listener for key pressed down
363 this._search.addEventListener(
364 "keydown",
365 function (e) {
366 updateKey(that, e)
367 },
368 false
369 );
370
371 // Reposition the mirror
372 this.reposition();
373
374 // Return object for chaining
375 return this;
376 },
377
378 // Popup method
379 popUp : function () {
380 if (this.active)
Nils Diewald44a72782014-06-20 16:03:21 +0000381 return;
382
Nils Diewaldeca30442014-11-18 20:33:54 +0000383 // Reposition hint list on first try
384 if (this.firstTry)
385 this.reposition().firstTry = false;
Nils Diewald44a72782014-06-20 16:03:21 +0000386
Nils Diewaldeca30442014-11-18 20:33:54 +0000387 // Update view
388 this.update();
Nils Diewald44a72782014-06-20 16:03:21 +0000389
Nils Diewaldeca30442014-11-18 20:33:54 +0000390 // Fill this with the correct value
391 if (this.menu().show(this.analyzeContext()))
392 this.update(
393 this._search.getBoundingClientRect().right
394 );
395 else
396 this.hide();
Nils Diewald44a72782014-06-20 16:03:21 +0000397
Nils Diewaldeca30442014-11-18 20:33:54 +0000398 this._search.focus();
399 },
400
401 // Reposition the mirror object
402 reposition : function () {
403
404 // Update style properties
405 var searchRect = this._search.getBoundingClientRect();
406 var searchStyle = window.getComputedStyle(this._search, null);
407 var mStyle = this._mirror.style;
408 mStyle.left = searchRect.left + "px";
409 mStyle.top = searchRect.bottom + "px";
410 mStyle.borderLeftColor = "transparent";
411 mStyle.height = "1px";
412 mStyle.paddingLeft = searchStyle.getPropertyValue("padding-left");
413 mStyle.marginLeft = searchStyle.getPropertyValue("margin-left");
414 mStyle.borderLeftWidth = searchStyle.getPropertyValue("border-left-width");
415 mStyle.borderLeftStyle = searchStyle.getPropertyValue("border-left-style");
416 mStyle.fontSize = searchStyle.getPropertyValue("font-size");
417 mStyle.fontFamily = searchStyle.getPropertyValue("font-family");
418 return this;
419 },
420
421 // Reposition the menu object
422 update : function () {
423 var s = this._search;
424 var start = s.selectionStart;
425 this._mirror.firstChild.textContent = s.value.substring(0, start);
426 },
427
428 analyzeContext : function () {
429 var context = this._splitInputText()[0];
430 if (context === undefined || context.length === 0)
431 return "-";
432 context = this._analyzer.analyze(context);
433 if (context === undefined || context.length === 0)
434 return "-";
435
436 return context;
437 },
438
439 _splitInputText : function () {
440 var s = this._search;
441 var value = s.value;
442 var start = s.selectionStart;
Nils Diewald44a72782014-06-20 16:03:21 +0000443 var begin = value.substring(0, start);
Nils Diewaldeca30442014-11-18 20:33:54 +0000444 var end = value.substring(start, value.length);
445 return new Array(begin, end);
446 },
Nils Diewald44a72782014-06-20 16:03:21 +0000447
Nils Diewaldeca30442014-11-18 20:33:54 +0000448 // Insert text at the current cursor position
449 insertText : function (text) {
450 var s = this._search;
451 var splitText = this._splitInputText();
452 s.value = splitText[0] + text + splitText[1];
453 s.selectionStart = (splitText[0] + text).length
454 s.selectionEnd = s.selectionStart;
455 this._mirror.firstChild.textContent = splitText[0] + text;
456 },
Nils Diewald44a72782014-06-20 16:03:21 +0000457
Nils Diewaldeca30442014-11-18 20:33:54 +0000458 // Remove stored prefix
459 removePrefix : function () {
460 this.menu()._prefix = undefined;
461 },
Nils Diewald465c4252014-06-20 21:51:58 +0000462
Nils Diewaldeca30442014-11-18 20:33:54 +0000463 // Insert stored prefix at current cursor position
464 insertPrefix : function () {
465 if (this.menu()._prefix === undefined)
Nils Diewald44a72782014-06-20 16:03:21 +0000466 return;
Nils Diewaldeca30442014-11-18 20:33:54 +0000467 this.insertText(this.menu()._prefix);
468 }
469};
Nils Diewald44a72782014-06-20 16:03:21 +0000470
Nils Diewaldeca30442014-11-18 20:33:54 +0000471
472/**
473* Menu list
474*/
475var Menu = {
476 active : false,
477 _element : undefined,
478 _position : 0, // Position of menu item
479 _offset : 0, // Visual offset for chosen highlight
480 _size : 8, // Number of items to be shown
481 _items : [], // Items for menu
482 _name : undefined,
483 _prefix : undefined,
484 getElement : function () {
485 return this._element;
486 },
487 init : function () {
488 this._element = document.createElement("ul");
489
490 // Add onclick event
491 this._element.addEventListener("click", chooseHint, false);
492
493 this._element.style.opacity = 0;
494 this.active = false;
495 this._setDefaults();
496 return this;
497 },
498 update : function (searchRightPosition) {
499 var infoRightPosition = this._element.getBoundingClientRect().right;
500 if (infoRightPosition > searchRightPosition) {
501 this._element.style.marginLeft = '-' + (infoRightPosition - searchRightPosition) + 'px';
502 };
503 return this;
504 },
505 next : function () {
506 if (!this.active)
507 return;
508 this._clearView();
509 this._position++;
510
511 // In case the list is bigger than the view
512 if (this._items.length > this._size) {
513 if (this._position >= this._items.length) {
514 // Roll to top
515 this._offset = 0;
516 this._position = 0;
517 this._showItems(0);
518 }
519 else if (this._position >= (this._size + this._offset)) {
520 // Roll down
521 this._element.removeChild(this._element.firstChild);
522 this._offset++;
523 this._element.appendChild(this.getItem(this._position).getElement());
524 };
525 }
526 else if (this._position >= this._items.length) {
527 this._position = 0;
528 };
529 this._updateView();
530 },
531 prev : function () {
532 if (!this.active)
533 return;
534 this._clearView();
535 this._position--;
536
537 // In case the list is bigger than the view
538 if (this._items.length > this._size) {
539 if (this._position < 0) {
540 // roll to bottom
541 this._setToLast();
542 this._offset = (this._position - this._size) + 1;
543 this._showLastItems();
544 }
545 else if (this._position < this._offset) {
546 // roll up
547 this._element.removeChild(this._element.lastChild);
548 this._offset--;
549 this._element.insertBefore(
550 this.getItem(this._position).getElement(),
551 this._element.firstChild
552 );
553 };
554 }
555 else if (this._position < 0) {
556 this._setToLast();
557 };
558 this._updateView();
559 },
560 skipToPrefix : function (prefix) {
561 if (this._prefix === undefined)
562 this._prefix = prefix.toLocaleLowerCase();
563 else
564 this._prefix += prefix.toLocaleLowerCase();
565
566 var pos = 0;
567 var found = false;
568 var good = -1;
569 var test;
570 for (; pos < this._items.length; pos++) {
571 if ((test = this.getItem(pos).getLCName().indexOf(this._prefix)) !== -1) {
572 if (test === 0) {
573 found = true;
574 break;
575 };
576 good = pos;
Nils Diewald465c4252014-06-20 21:51:58 +0000577 };
578 };
Nils Diewaldeca30442014-11-18 20:33:54 +0000579
580 // Perfect prefix
581 if (found)
582 return this.skipToPos(pos);
583 // At least infix
584 else if (good !== -1)
585 return this.skipToPos(good);
586 // No
587 return false;
588 },
589 skipToPos : function (index) {
590 if (!this.active)
591 return false;
592 if (index < 0 || index >= this._items.length)
593 return false;
594
595 this._clearView();
596 this._position = index;
597
598 if (index < this._offset || index >= (this._offset + this._size)) {
599
600 // Index is in the final frame
601 if (index >= (this._items.length - this._size)) {
602 this._offset = this._items.length - this._size;
603 this._showLastItems();
604 }
605
606 // Index is in the final frame
607 else {
608 this._offset = index;
609 this._showItems(index);
610 };
611 };
612
613 // Activate new position
614 this._updateView();
615 return true;
616 },
617 show : function (name) {
618 // The element is already given
619 if (this._name !== name) {
620
621 // Todo: store hints in hash
622
623 // Delete items
624 this._items.length = 0;
625
626 var items = hintArray[name];
627
628 // Hints not found
629 if (items === undefined)
630 return false;
631
632 var i;
633 for (i in items) {
634 var item = Object.create(MenuItem).init(items[i]);
635 this._items.push(item);
636 };
637
638 // Add classes for rolling menus
639 this.getItem(0).getElement().classList.add("no-more");
640 this.getItem(i).getElement().classList.add("no-more");
641
642 this._name = name;
643 };
644 this._showItems(0);
645 this._element.style.opacity = 1;
646 this._setDefaults();
647 this.active = true;
648 this._updateView();
649 return true;
650 },
651 hide : function () {
652 this._element.style.opacity = 0;
653 if (this.active)
654 this.getActiveItem().deactivate();
655 this._setDefaults();
656 this.active = false;
657 },
658 getActiveItem : function () {
659 return this._items[this._position];
660 },
661 getItem : function (index) {
662 return this._items[index];
663 },
664 getPrefix : function () {
665 return this._prefix;
666 },
667 _setDefaults : function () {
668 this._offset = 0;
669 this._position = 0;
670 this._prefix = undefined;
671 },
672 // Remove all visible list items
673 _deleteMenu : function () {
674 var child;
675 while (child = this._element.firstChild)
676 this._element.removeChild(child);
677 },
678 _clearView : function () {
679 var active = this.getActiveItem();
680 if (active !== undefined)
681 active.deactivate();
682 },
683 _updateView : function () {
684 var active = this.getActiveItem();
685 if (active !== undefined)
686 active.activate();
687 },
688
689 // Make all list items visible starting at a certain offset
690 _showItems : function (offset) {
691 this._deleteMenu();
692 for (var i = offset; i < this._size + offset; i++) {
693 if (i >= this._items.length)
694 break;
695 this._element.appendChild(
696 this._items[i].getElement()
697 )
698 };
699 },
700
701 // Make all final list items visible
702 _showLastItems : function () {
703 this._deleteMenu();
704 for (var i = (this._items.length - 1); i >= (this._items.length - this._size); i--) {
705 if (i < 0)
706 break;
707 if (!this._element.firstChild)
708 this._element.appendChild(this._items[i].getElement());
709 else
710 this._element.insertBefore(
711 this._items[i].getElement(),
712 this._element.firstChild
713 );
714 };
715 },
716 _setToLast : function () {
717 this._position = this._items.length - 1;
718 }
719};
720
721function chooseHint (e) {
722 var element = e.target;
723 while (element.nodeName == "STRONG" || element.nodeName == "SPAN") {
724 element = element.parentNode;
Nils Diewald465c4252014-06-20 21:51:58 +0000725 };
726
Nils Diewaldeca30442014-11-18 20:33:54 +0000727 if (element === undefined || element.nodeName != "LI")
728 return;
729
730 var action = element.getAttribute('data-action');
731 hint.insertText(action);
732 var menu = hint.menu();
733 menu.hide();
734
735 // Fill this with the correct value
736 var show;
737 if ((show = hint.analyzeContext()) !== "-") {
738 menu.show(show);
739 menu.update(
740 hint._search.getBoundingClientRect().right
741 );
742 };
743
744 hint._search.focus();
745};
746
747var MenuItem = {
748 _name : undefined,
749 _lcname : undefined,
750 _desc : undefined,
751 _element : undefined,
752 _action : "",
753 activate : function () {
754 this._element.classList.add("active");
755 },
756 deactivate : function () {
757 this._element.classList.remove("active");
758 },
759 // Initialize this item
760 init : function (param) {
761 this._name = param[0];
762 this._action = param[1];
763 this._lcname = this._name.toLocaleLowerCase();
764
765 if (param.length > 2) {
766 this._desc = param[2];
767 this._lcname += " " + this._desc.toLocaleLowerCase();
768 };
769
770 return this;
771 },
772
773 // Created element of this item
774 getElement : function () {
775 if (this._element !== undefined)
776 return this._element;
777
778 var li = document.createElement("li");
779
780 li.setAttribute("data-action", this._action);
781
782 var name = document.createElement("strong");
783
784 name.appendChild(document.createTextNode(this._name));
785 li.appendChild(name);
786 if (this._desc !== undefined) {
787 var desc = document.createElement("span");
788 desc.appendChild(document.createTextNode(this._desc));
789 li.appendChild(desc);
790 };
791 this._element = li;
792 return this._element;
793 },
794
795 // Name of this item
796 getName : function () {
797 return this._name;
798 },
799
800 getLCName : function () {
801 return this._lcname;
802 },
803
804 // Description of this item
805 getDesc : function () {
806 return this._desc;
807 },
808
809
810 getAction : function () {
811 return this._action;
812 }
Nils Diewald44a72782014-06-20 16:03:21 +0000813};