352 lines
5.9 KiB
JavaScript
352 lines
5.9 KiB
JavaScript
|
|
var ColumnText = require ('../column/text');
|
|
|
|
module.exports = new Class
|
|
({
|
|
Extends: Htk.Field
|
|
,Implements: Vn.Iterator
|
|
,Tag: 'htk-combo'
|
|
,Properties:
|
|
{
|
|
/**
|
|
* The model associated to this form.
|
|
*/
|
|
model:
|
|
{
|
|
type: Db.Model
|
|
,set: function (x)
|
|
{
|
|
this.link ({_model: x}, {'status-changed-after': this._onModelChange});
|
|
this._onModelChange ();
|
|
}
|
|
,get: function ()
|
|
{
|
|
return this._model;
|
|
}
|
|
},
|
|
/**
|
|
* The row where the form positioned, has -1 if the row is unselected.
|
|
*/
|
|
row:
|
|
{
|
|
type: Number
|
|
,set: function (x)
|
|
{
|
|
if (!this._model || this._model.numRows <= x || x < -1)
|
|
x = -1;
|
|
if (x == this._row)
|
|
return;
|
|
|
|
this._row = x;
|
|
this.rowChanged ();
|
|
}
|
|
,get: function ()
|
|
{
|
|
return this._row;
|
|
}
|
|
},
|
|
/**
|
|
* The number of rows in the form.
|
|
*/
|
|
numRows:
|
|
{
|
|
type: Number
|
|
,get: function ()
|
|
{
|
|
if (this._model)
|
|
return this._model.numRows;
|
|
|
|
return 0;
|
|
}
|
|
},
|
|
/**
|
|
* Checks if the form data is ready.
|
|
*/
|
|
ready:
|
|
{
|
|
type: Boolean
|
|
,get: function ()
|
|
{
|
|
return this._model && this._model.ready;
|
|
}
|
|
},
|
|
/**
|
|
* Checks if the form data is ready.
|
|
*/
|
|
placeholder:
|
|
{
|
|
type: String
|
|
,set: function (x)
|
|
{
|
|
this._placeholder = x;
|
|
this._refreshShowText (x);
|
|
}
|
|
,get: function ()
|
|
{
|
|
return this._placeholder;
|
|
}
|
|
},
|
|
/**
|
|
* Wether to allow null values.
|
|
*/
|
|
notNull:
|
|
{
|
|
type: Boolean
|
|
,set: function (x)
|
|
{
|
|
this._notNull = x;
|
|
}
|
|
,get: function ()
|
|
{
|
|
return this._notNull;
|
|
}
|
|
},
|
|
/**
|
|
* The field to use for internal value.
|
|
*/
|
|
valueField:
|
|
{
|
|
type: String,
|
|
value: 'id'
|
|
},
|
|
/**
|
|
* The field to display.
|
|
*/
|
|
showField:
|
|
{
|
|
type: String,
|
|
value: 'name'
|
|
},
|
|
params:
|
|
{
|
|
type: Object
|
|
,set: function (x)
|
|
{
|
|
this.setAll (x);
|
|
}
|
|
,get: function ()
|
|
{
|
|
return this._params;
|
|
}
|
|
}
|
|
,$:
|
|
{
|
|
type: Object
|
|
,set: function (x)
|
|
{
|
|
this.setAll (x);
|
|
}
|
|
,get: function ()
|
|
{
|
|
return this._params;
|
|
}
|
|
}
|
|
}
|
|
|
|
,_row: -1
|
|
,_model: null
|
|
,_notNull: false
|
|
,_selected: false
|
|
|
|
,render: function ()
|
|
{
|
|
var node = this.createRoot ('div');
|
|
Vn.Node.addClass (node, 'input clickable');
|
|
node.tabIndex = 0;
|
|
node.addEventListener ('mousedown',
|
|
this._onMouseDown.bind (this));
|
|
|
|
var icons = this.createElement ('div');
|
|
icons.className = 'icons';
|
|
node.appendChild (icons);
|
|
|
|
var clearButton = this.createElement ('htk-icon');
|
|
clearButton.className = 'clear button';
|
|
clearButton.icon = 'close';
|
|
clearButton.node.title = _('Clear');
|
|
clearButton.on ('click', this._onClearClick, this);
|
|
clearButton.on ('mousedown', this._onClearMouseDown, this);
|
|
icons.appendChild (clearButton.node);
|
|
|
|
var downIcon = this.createElement ('htk-icon');
|
|
downIcon.className = 'down';
|
|
downIcon.icon = 'down';
|
|
icons.appendChild (downIcon.node);
|
|
|
|
var text = this.createElement ('div');
|
|
text.className = 'text';
|
|
node.appendChild (text);
|
|
|
|
this.text = text;
|
|
this.clearButton = clearButton;
|
|
this._refreshShowText ();
|
|
}
|
|
|
|
,_onClearClick: function ()
|
|
{
|
|
this.value = null;
|
|
}
|
|
|
|
,_onClearMouseDown: function (_, event)
|
|
{
|
|
event.preventDefault ();
|
|
}
|
|
|
|
,_onMouseDown: function (e)
|
|
{
|
|
if (e.defaultPrevented)
|
|
return;
|
|
|
|
if (this._popup)
|
|
{
|
|
this._popup.hide ();
|
|
return;
|
|
}
|
|
|
|
var model = this._model;
|
|
|
|
if (model.status === Db.Model.Status.CLEAN)
|
|
model.refresh ();
|
|
|
|
var menu = this.createElement ('div');
|
|
menu.className = 'htk-combo-menu';
|
|
|
|
var grid = new Htk.Grid ({showHeader: false});
|
|
menu.appendChild (grid.node);
|
|
|
|
var gridNode = grid.node;
|
|
gridNode.addEventListener ('click',
|
|
this._onGridClicked.bind (this, grid));
|
|
|
|
var column = new ColumnText ({column: this.showField});
|
|
grid.appendColumn (column);
|
|
grid.model = model;
|
|
|
|
var popup = this._popup = new Htk.Popup ({childNode: menu});
|
|
popup.on ('closed', this._onPopupClose.bind (this));
|
|
popup.show (this.node, true, e);
|
|
|
|
this.emit ('menu-show');
|
|
}
|
|
|
|
,_onGridClicked: function (grid, e)
|
|
{
|
|
e.stopPropagation ();
|
|
var target = e.target;
|
|
var parentNode = target.parentNode;
|
|
|
|
while (parentNode !== grid.tbody)
|
|
{
|
|
target = parentNode;
|
|
parentNode = parentNode.parentNode;
|
|
}
|
|
|
|
var value;
|
|
var row = target.rowIndex - 1;
|
|
|
|
if (row >= 0)
|
|
value = this._model.get (row, this.valueField);
|
|
else
|
|
value = null;
|
|
|
|
this._popup.hide ();
|
|
|
|
var changed = this._putValue (value);
|
|
|
|
this._selected = false;
|
|
this._setRow (row, true);
|
|
|
|
if (changed)
|
|
{
|
|
if (this.conditionalFunc)
|
|
this.conditionalFunc (this, newValue);
|
|
|
|
this._notifyChanges ();
|
|
}
|
|
}
|
|
|
|
,_onPopupClose: function ()
|
|
{
|
|
this._popup = null;
|
|
this.emit ('menu-hide');
|
|
}
|
|
|
|
,_setRow: function (row)
|
|
{
|
|
this._row = row;
|
|
|
|
if (!this._selected)
|
|
{
|
|
if (row != -1)
|
|
this._selected = true;
|
|
|
|
this.rowChanged ();
|
|
this._refreshShowText ();
|
|
}
|
|
}
|
|
|
|
,_onModelChange: function ()
|
|
{
|
|
var model = this._model;
|
|
this.emit ('status-changed');
|
|
|
|
if (this._popup)
|
|
this._popup.reset ();
|
|
|
|
this._selectOption ();
|
|
|
|
if (model && model.ready)
|
|
this.emit ('ready');
|
|
}
|
|
|
|
,_selectOption: function ()
|
|
{
|
|
var row;
|
|
|
|
if (this._model && this._model.ready)
|
|
row = this._model.search (this.valueField, this._value);
|
|
else
|
|
row = -1;
|
|
|
|
this._setRow (row);
|
|
}
|
|
|
|
,_putFieldValue: function ()
|
|
{
|
|
this._selected = false;
|
|
this._selectOption ();
|
|
}
|
|
|
|
,_refreshShowText: function ()
|
|
{
|
|
var model = this._model;
|
|
|
|
if (this._value != null)
|
|
var showText = this.$[this.showField];
|
|
else if (model && model.status === Db.Model.Status.LOADING)
|
|
var showText = _('Loading...');
|
|
else if (this._placeholder)
|
|
var showText = this._placeholder;
|
|
else
|
|
var showText = '';
|
|
|
|
if (this.node)
|
|
{
|
|
var display;
|
|
|
|
if (this._value && !this._notNull)
|
|
display = '';
|
|
else
|
|
display = 'none';
|
|
|
|
this.clearButton.node.style.display = display;
|
|
Vn.Node.setText (this.text, showText);
|
|
}
|
|
}
|
|
|
|
,setEditable: function (editable)
|
|
{
|
|
this.node.disabled = !editable;
|
|
}
|
|
});
|