blob: 16b3f8b6498e9fe710aa5b39e0b19d0323d6081d [file] [log] [blame]
/**
* Hint menu for Kalamar.
* Based on menu object.
*
* @author Nils Diewald
*/
/*
* TODO: List can be shown when prefix is like 'base/s=pcorenlp/'
* TODO: Sometimes the drop-down box down vanish when list is shown
* TODO: Create should expect an input text field
* TODO: Embed only one single menu (not multiple)
* By holding the current menu in _active
* TODO: show() should accept a context field (especially for no-context fields,
* like fragments)
* TODO: Improve context analyzer from hint!
* TODO: Marked annotations should be addable to "fragments"
*/
define([
'hint/input',
'hint/menu',
'hint/contextanalyzer',
'hint/alert',
'util'
], function (inputClass,
menuClass,
analyzerClass,
alertClass) {
"use strict";
/**
* @define {regex} Regular expression for context
*/
KorAP.context = KorAP.context ||
"(?:^|[^-_a-zA-Z0-9])" + // Anchor
"((?:[-_a-zA-Z0-9]+?)\/" + // Foundry
"(?:" +
"(?:[-_a-zA-Z0-9]+?)=" + // Layer
"(?:"+
"(?:[^:=\/ ]+?):|" + // Key
"(?:[^-=\/ ]+?)-" + // Node
")?" +
")?" +
")$";
KorAP.hintArray = KorAP.hintArray || {};
/**
* Return keycode based on event
*/
// Initialize hint array
/**
* KorAP.Hint.create({
* inputField : node,
* context : context regex
* });
*/
return {
// Some variables
// _firstTry : true,
// active : false,
/**
* Create new hint helper.
*/
create : function (param) {
return Object.create(this)._init(param);
},
// Initialize hint helper
_init : function (param) {
param = param || {};
// Holds all menus per prefix context
this._menu = {};
this._alert = alertClass.create();
this._active = null;
// Get input field
var qfield = param["inputField"] || document.getElementById("q-field");
if (!qfield)
return null;
// Create input field
this._inputField = inputClass.create(qfield);
var inputFieldElement = this._inputField.element();
var c = this._inputField.container();
// create alert
c.appendChild(this._alert.element());
var that = this;
this._inputField.container().addEventListener('click', function (e) {
if (!this.classList.contains('active')) {
that.show(false);
};
});
var _down = function (e) {
var code = _codeFromEvent(e);
if (code === 40) {
this.show(false);
e.halt();
};
};
// Move infobox
inputFieldElement.addEventListener("keyup", this.update.bind(this));
inputFieldElement.addEventListener("click", this.update.bind(this));
// Add event listener for key pressed down
inputFieldElement.addEventListener(
"keydown", _down.bind(this), false
);
// Set Analyzer for context
this._analyzer = analyzerClass.create(
param["context"] || KorAP.context
);
return this;
},
/**
* Return the input field attached to the hint helper.
*/
inputField : function () {
return this._inputField;
},
/**
* Altert at a specific character position.
*/
alert : function (charPos, msg) {
if (arguments.length === 0)
return this._alert;
// Do not alert if already alerted!
if (this._alert.active)
return false;
// Move to the correct position
this._inputField.moveto(charPos);
// Set container to active (aka hide the hint helper button)
this._alert.show(msg);
this.active(this._alert);
return true;
},
_unshowAlert : function () {
this._alert.hide();
this.active(null);
},
update : function () {
this._inputField.update();
if (this._alert.hide())
this.active(null);
},
/**
* Return hint menu and probably init based on an action
*/
menu : function (action) {
if (this._menu[action] === undefined) {
// No matching hint menu
if (KorAP.hintArray[action] === undefined)
return;
// Create matching hint menu
this._menu[action] = menuClass.create(
this, action, KorAP.hintArray[action]
);
};
// Return matching hint menu
return this._menu[action];
},
/**
* Get the correct menu based on the context
*/
contextMenu : function (ifContext) {
// Get context (aka left text)
var context = this._inputField.context();
if (context === undefined || context.length === 0)
return ifContext ? undefined : this.menu("-");
// Get context (aka left text matching regex)
context = this._analyzer.test(context);
if (context === undefined || context.length == 0)
return ifContext ? undefined : this.menu("-");
return this.menu(context) || this.menu('-');
},
active : function (obj) {
if (arguments.length === 1) {
var c = this._inputField.container();
if (obj !== null) {
c.classList.add('active');
this._active = obj;
}
else {
c.classList.remove('active');
this._active = null;
}
};
return this._active;
},
/**
* Show the menu.
* Currently this means that multiple menus may be loaded
* but not shown.
*
* @param {boolean} Boolean value to indicate if context
* is necessary (true) or if the main context should
* be shown if context fails.
*
*/
show : function (ifContext) {
var c = this._inputField.container();
// Menu is already active
if (this.active() !== null) {
// This does not work for alert currently!
if (this._active._type !== 'alert') {
c.removeChild(this._active.element());
};
// This may already be hidden!
this._active.hide();
this.active(null);
// Alert is not active
/*
if (!this._alert.unshow())
return;
*/
};
// Get the menu
var menu;
if (menu = this.contextMenu(ifContext)) {
// TODO: Remove old element!
this.active(menu);
c.appendChild(menu.element());
menu.show();
menu.focus();
// Focus on input field
// this.inputField.element.focus();
};
},
// Show an object in the containerField
// This will hide all other objects
// Accepts menus as well as alerts
show2 : function (obj) {},
// This will get the context of the field
getContext : function () {},
unshow : function () {
this.active(null);
this.inputField().element().focus();
}
};
});