blob: 89003ee6b7cdb5344acefa6e3240d982757a1517 [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
Akron00cd4d12016-05-31 21:01:11 +020090 var that = this;
Nils Diewald5c5a7472015-04-02 22:13:38 +000091
Nils Diewald47f366b2015-04-15 20:06:35 +000092 this._inputField.container().addEventListener('click', function (e) {
93 if (!this.classList.contains('active')) {
94 that.show(false);
95 };
96 });
97
Akron00cd4d12016-05-31 21:01:11 +020098 var _down = function (e) {
99 var code = _codeFromEvent(e);
100 if (code === 40) {
101 this.show(false);
102 e.halt();
103 };
Nils Diewald47f366b2015-04-15 20:06:35 +0000104 };
105
106 // Move infobox
Akron00cd4d12016-05-31 21:01:11 +0200107 inputFieldElement.addEventListener("keyup", this.update.bind(this));
108 inputFieldElement.addEventListener("click", this.update.bind(this));
109
110 // Add event listener for key pressed down
111 inputFieldElement.addEventListener(
112 "keydown", _down.bind(this), false
113 );
Nils Diewald5c5a7472015-04-02 22:13:38 +0000114
115 // Set Analyzer for context
Nils Diewald0e6992a2015-04-14 20:13:52 +0000116 this._analyzer = analyzerClass.create(
Nils Diewald5c5a7472015-04-02 22:13:38 +0000117 param["context"] || KorAP.context
118 );
Nils Diewald19ccee92014-12-08 11:30:08 +0000119 return this;
120 },
121
Akron308db382016-05-30 22:34:07 +0200122
123 /**
124 * Return the input field attached to the hint helper.
125 */
Nils Diewald5c5a7472015-04-02 22:13:38 +0000126 inputField : function () {
127 return this._inputField;
128 },
Nils Diewald19ccee92014-12-08 11:30:08 +0000129
Akron308db382016-05-30 22:34:07 +0200130
131 /**
132 * Altert at a specific character position.
133 */
Akron00cd4d12016-05-31 21:01:11 +0200134 alert : function (charPos, msg) {
135
136 if (arguments.length === 0)
137 return this._alert;
138
139 // Do not alert if already alerted!
140 if (this._alert.active)
141 return false;
142
143 // Move to the correct position
Akron308db382016-05-30 22:34:07 +0200144 this._inputField.moveto(charPos);
Akron00cd4d12016-05-31 21:01:11 +0200145
146 // Set container to active (aka hide the hint helper button)
147
148 this._alert.show(msg);
149 this.active(true);
150 return true;
Akron308db382016-05-30 22:34:07 +0200151 },
152
Akron00cd4d12016-05-31 21:01:11 +0200153 _unshowAlert : function () {
154 this._alert.unshow();
155 this.active(false);
156 },
157
158 update : function () {
159 this._inputField.update();
160 if (this._alert.unshow())
161 this.active(false);
162 },
163
164
Nils Diewald5c5a7472015-04-02 22:13:38 +0000165 /**
Nils Diewald5c5a7472015-04-02 22:13:38 +0000166 * Return hint menu and probably init based on an action
167 */
168 menu : function (action) {
Nils Diewald5c5a7472015-04-02 22:13:38 +0000169 if (this._menu[action] === undefined) {
170
171 // No matching hint menu
172 if (KorAP.hintArray[action] === undefined)
173 return;
174
175 // Create matching hint menu
Nils Diewald0e6992a2015-04-14 20:13:52 +0000176 this._menu[action] = menuClass.create(
Nils Diewald5c5a7472015-04-02 22:13:38 +0000177 this, action, KorAP.hintArray[action]
Nils Diewald19ccee92014-12-08 11:30:08 +0000178 );
Nils Diewald5c5a7472015-04-02 22:13:38 +0000179 };
180
181 // Return matching hint menu
182 return this._menu[action];
183 },
184
185 /**
186 * Get the correct menu based on the context
187 */
188 contextMenu : function (ifContext) {
189 var context = this._inputField.context();
Akronee9ef4a2016-06-03 12:50:08 +0200190
Nils Diewald5c5a7472015-04-02 22:13:38 +0000191 if (context === undefined || context.length == 0)
192 return ifContext ? undefined : this.menu("-");
193
194 context = this._analyzer.test(context);
Akronee9ef4a2016-06-03 12:50:08 +0200195
Nils Diewald5c5a7472015-04-02 22:13:38 +0000196 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});