blob: 455312ddda7ea1d629bec699e8450d265a12be31 [file] [log] [blame]
Nils Diewald19ccee92014-12-08 11:30:08 +00001/**
Nils Diewald5c5a7472015-04-02 22:13:38 +00002 * Hint menu for Kalamar.
Nils Diewald47f366b2015-04-15 20:06:35 +00003 * Based on menu object.
Nils Diewald19ccee92014-12-08 11:30:08 +00004 *
5 * @author Nils Diewald
6 */
Akron308db382016-05-30 22:34:07 +02007/*
8 * TODO: List can be shown when prefix is like 'base/s=pcorenlp/'
9 * TODO: Sometimes the drop-down box down vanish when list is shown
10 * TODO: Create should expect an input text field
11 * TODO: Embed only one single menu (not multiple)
12 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000013define([
14 'hint/input',
15 'hint/menu',
16 'hint/contextanalyzer',
Akron00cd4d12016-05-31 21:01:11 +020017 'hint/alert',
Nils Diewald0e6992a2015-04-14 20:13:52 +000018 'util'
19], function (inputClass,
Akron00cd4d12016-05-31 21:01:11 +020020 menuClass,
21 analyzerClass,
22 alertClass) {
Nils Diewald19ccee92014-12-08 11:30:08 +000023 "use strict";
24
Nils Diewald19ccee92014-12-08 11:30:08 +000025 /**
26 * @define {regex} Regular expression for context
27 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000028 KorAP.context = KorAP.context ||
Nils Diewald19ccee92014-12-08 11:30:08 +000029 "(?:^|[^-_a-zA-Z0-9])" + // Anchor
30 "((?:[-_a-zA-Z0-9]+?)\/" + // Foundry
31 "(?:" +
32 "(?:[-_a-zA-Z0-9]+?)=" + // Layer
Akron113cc1a2016-01-22 21:17:57 +010033 "(?:"+
34 "(?:[^:=\/ ]+?):|" + // Key
Akron308db382016-05-30 22:34:07 +020035 "(?:[^-=\/ ]+?)-" + // Node
Akron113cc1a2016-01-22 21:17:57 +010036 ")?" +
Nils Diewald19ccee92014-12-08 11:30:08 +000037 ")?" +
38 ")$";
Nils Diewald19ccee92014-12-08 11:30:08 +000039 KorAP.hintArray = KorAP.hintArray || {};
40
Nils Diewald0e6992a2015-04-14 20:13:52 +000041 /**
42 * Return keycode based on event
43 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000044
45 // Initialize hint array
Nils Diewald5c5a7472015-04-02 22:13:38 +000046
47 /**
48 * KorAP.Hint.create({
49 * inputField : node,
50 * context : context regex
51 * });
52 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000053 return {
Nils Diewald5c5a7472015-04-02 22:13:38 +000054
55 // Some variables
56 // _firstTry : true,
Akron00cd4d12016-05-31 21:01:11 +020057 // active : false,
Nils Diewald5c5a7472015-04-02 22:13:38 +000058
Nils Diewald0e6992a2015-04-14 20:13:52 +000059 /**
60 * Create new hint helper.
61 */
Nils Diewald5c5a7472015-04-02 22:13:38 +000062 create : function (param) {
Nils Diewald0e6992a2015-04-14 20:13:52 +000063 return Object.create(this)._init(param);
Nils Diewald5c5a7472015-04-02 22:13:38 +000064 },
65
Nils Diewald0e6992a2015-04-14 20:13:52 +000066 // Initialize hint helper
Nils Diewald5c5a7472015-04-02 22:13:38 +000067 _init : function (param) {
68 param = param || {};
69
70 // Holds all menus per prefix context
Akron00cd4d12016-05-31 21:01:11 +020071 this._menu = {};
72 this._alert = alertClass.create();
73 this._active = false;
Nils Diewald5c5a7472015-04-02 22:13:38 +000074
75 // Get input field
Nils Diewald0e6992a2015-04-14 20:13:52 +000076 var qfield = param["inputField"] || document.getElementById("q-field");
77 if (!qfield)
78 return null;
79
Akron00cd4d12016-05-31 21:01:11 +020080 // Create input field
Nils Diewald0e6992a2015-04-14 20:13:52 +000081 this._inputField = inputClass.create(qfield);
Nils Diewald5c5a7472015-04-02 22:13:38 +000082
83 var inputFieldElement = this._inputField.element();
84
Akron00cd4d12016-05-31 21:01:11 +020085 var c = this._inputField.container();
Nils Diewald5c5a7472015-04-02 22:13:38 +000086
Akron00cd4d12016-05-31 21:01:11 +020087 // create alert
88 c.appendChild(this._alert.element());
89
90
91 var that = this;
Nils Diewald5c5a7472015-04-02 22:13:38 +000092
Nils Diewald47f366b2015-04-15 20:06:35 +000093 this._inputField.container().addEventListener('click', function (e) {
94 if (!this.classList.contains('active')) {
95 that.show(false);
96 };
97 });
98
Akron00cd4d12016-05-31 21:01:11 +020099 var _down = function (e) {
100 var code = _codeFromEvent(e);
101 if (code === 40) {
102 this.show(false);
103 e.halt();
104 };
Nils Diewald47f366b2015-04-15 20:06:35 +0000105 };
106
107 // Move infobox
Akron00cd4d12016-05-31 21:01:11 +0200108 inputFieldElement.addEventListener("keyup", this.update.bind(this));
109 inputFieldElement.addEventListener("click", this.update.bind(this));
110
111 // Add event listener for key pressed down
112 inputFieldElement.addEventListener(
113 "keydown", _down.bind(this), false
114 );
Nils Diewald5c5a7472015-04-02 22:13:38 +0000115
116 // Set Analyzer for context
Nils Diewald0e6992a2015-04-14 20:13:52 +0000117 this._analyzer = analyzerClass.create(
Nils Diewald5c5a7472015-04-02 22:13:38 +0000118 param["context"] || KorAP.context
119 );
Nils Diewald19ccee92014-12-08 11:30:08 +0000120 return this;
121 },
122
Akron308db382016-05-30 22:34:07 +0200123
124 /**
125 * Return the input field attached to the hint helper.
126 */
Nils Diewald5c5a7472015-04-02 22:13:38 +0000127 inputField : function () {
128 return this._inputField;
129 },
Nils Diewald19ccee92014-12-08 11:30:08 +0000130
Akron308db382016-05-30 22:34:07 +0200131
132 /**
133 * Altert at a specific character position.
134 */
Akron00cd4d12016-05-31 21:01:11 +0200135 alert : function (charPos, msg) {
136
137 if (arguments.length === 0)
138 return this._alert;
139
140 // Do not alert if already alerted!
141 if (this._alert.active)
142 return false;
143
144 // Move to the correct position
Akron308db382016-05-30 22:34:07 +0200145 this._inputField.moveto(charPos);
Akron00cd4d12016-05-31 21:01:11 +0200146
147 // Set container to active (aka hide the hint helper button)
148
149 this._alert.show(msg);
150 this.active(true);
151 return true;
Akron308db382016-05-30 22:34:07 +0200152 },
153
Akron00cd4d12016-05-31 21:01:11 +0200154 _unshowAlert : function () {
155 this._alert.unshow();
156 this.active(false);
157 },
158
159 update : function () {
160 this._inputField.update();
161 if (this._alert.unshow())
162 this.active(false);
163 },
164
165
Nils Diewald5c5a7472015-04-02 22:13:38 +0000166 /**
Nils Diewald5c5a7472015-04-02 22:13:38 +0000167 * Return hint menu and probably init based on an action
168 */
169 menu : function (action) {
170
171 if (this._menu[action] === undefined) {
172
173 // No matching hint menu
174 if (KorAP.hintArray[action] === undefined)
175 return;
176
177 // Create matching hint menu
Nils Diewald0e6992a2015-04-14 20:13:52 +0000178 this._menu[action] = menuClass.create(
Nils Diewald5c5a7472015-04-02 22:13:38 +0000179 this, action, KorAP.hintArray[action]
Nils Diewald19ccee92014-12-08 11:30:08 +0000180 );
Nils Diewald5c5a7472015-04-02 22:13:38 +0000181 };
182
183 // Return matching hint menu
184 return this._menu[action];
185 },
186
187 /**
188 * Get the correct menu based on the context
189 */
190 contextMenu : function (ifContext) {
191 var context = this._inputField.context();
192 if (context === undefined || context.length == 0)
193 return ifContext ? undefined : this.menu("-");
194
195 context = this._analyzer.test(context);
196 if (context === undefined || context.length == 0)
197 return ifContext ? undefined : this.menu("-");
198
199 return this.menu(context);
200 },
201
Akron00cd4d12016-05-31 21:01:11 +0200202 active : function (bool) {
203 if (arguments.length === 1) {
204 var c = this._inputField.container();
205 if (bool && !this._active) {
206 c.classList.add('active');
207 this._active = true;
208 }
209 else {
210 c.classList.remove('active');
211 this._active = false;
212 }
213 };
214 return this._active;
215 },
216
Nils Diewald5c5a7472015-04-02 22:13:38 +0000217
218 /**
Akron308db382016-05-30 22:34:07 +0200219 * Show the menu.
220 * Currently this means that multiple menus may be loaded
221 * but not shown.
Nils Diewald5c5a7472015-04-02 22:13:38 +0000222 */
223 show : function (ifContext) {
224
225 // Menu is already active
Akron00cd4d12016-05-31 21:01:11 +0200226 if (this.active()) {
227
228 // Alert is not active
229 if (!this._alert.unshow())
230 return;
231 };
Nils Diewald5c5a7472015-04-02 22:13:38 +0000232
Nils Diewald5c5a7472015-04-02 22:13:38 +0000233 // Get the menu
234 var menu;
235 if (menu = this.contextMenu(ifContext)) {
Nils Diewald2488d052015-04-09 21:46:02 +0000236 var c = this._inputField.container();
Akron00cd4d12016-05-31 21:01:11 +0200237 this.active(true);
238 // c.classList.add('active');
Nils Diewald2488d052015-04-09 21:46:02 +0000239 c.appendChild(menu.element());
Akron6ed13992016-05-23 18:06:05 +0200240 menu.show();
Nils Diewald5c5a7472015-04-02 22:13:38 +0000241 menu.focus();
Akron308db382016-05-30 22:34:07 +0200242 // Focus on input field
243 // this.inputField.element.focus();
Nils Diewald19ccee92014-12-08 11:30:08 +0000244 };
Akron00cd4d12016-05-31 21:01:11 +0200245 },
246
247 unshow : function () {
248 this.active(false);
249 this.inputField().element().focus();
Nils Diewald19ccee92014-12-08 11:30:08 +0000250 }
251 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000252});