lists: implement select-as-you-type
This commit is contained in:
parent
c211b55d3b
commit
64a182ae1d
4 changed files with 85 additions and 61 deletions
|
|
@ -19,6 +19,7 @@ Ox.IconList <f> IconList Object
|
||||||
orientation <s|both> orientation ("horizontal", "vertical" or "both")
|
orientation <s|both> orientation ("horizontal", "vertical" or "both")
|
||||||
pageLength <n|100> Number of items per page (if orientation != "both")
|
pageLength <n|100> Number of items per page (if orientation != "both")
|
||||||
query <o> Query
|
query <o> Query
|
||||||
|
selectAsYouType <s|''> If set to a key, enables select-as-you-type
|
||||||
selected <a|[]> array of selected items
|
selected <a|[]> array of selected items
|
||||||
size <n|128> list size
|
size <n|128> list size
|
||||||
sort <a|[]> sort keys
|
sort <a|[]> sort keys
|
||||||
|
|
@ -46,6 +47,7 @@ Ox.IconList = function(options, self) {
|
||||||
orientation: 'both',
|
orientation: 'both',
|
||||||
pageLength: 100,
|
pageLength: 100,
|
||||||
query: {conditions: [], operator: '&'},
|
query: {conditions: [], operator: '&'},
|
||||||
|
selectAsYouType: '',
|
||||||
selected: [],
|
selected: [],
|
||||||
size: 128,
|
size: 128,
|
||||||
sort: [],
|
sort: [],
|
||||||
|
|
@ -95,6 +97,7 @@ Ox.IconList = function(options, self) {
|
||||||
orientation: self.options.orientation,
|
orientation: self.options.orientation,
|
||||||
pageLength: self.options.pageLength,
|
pageLength: self.options.pageLength,
|
||||||
query: self.options.query,
|
query: self.options.query,
|
||||||
|
selectAsYouType: self.options.selectAsYouType,
|
||||||
selected: self.options.selected,
|
selected: self.options.selected,
|
||||||
sort: self.options.sort,
|
sort: self.options.sort,
|
||||||
type: 'icon',
|
type: 'icon',
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ Ox.InfoList = function(options, self) {
|
||||||
max: -1,
|
max: -1,
|
||||||
min: 0,
|
min: 0,
|
||||||
query: {conditions: [], operator: '&'},
|
query: {conditions: [], operator: '&'},
|
||||||
|
selectAsYouType: '',
|
||||||
selected: [],
|
selected: [],
|
||||||
size: 192,
|
size: 192,
|
||||||
sort: [],
|
sort: [],
|
||||||
|
|
@ -71,6 +72,7 @@ Ox.InfoList = function(options, self) {
|
||||||
orientation: 'vertical',
|
orientation: 'vertical',
|
||||||
pageLength: 10,
|
pageLength: 10,
|
||||||
query: self.options.query,
|
query: self.options.query,
|
||||||
|
selectAsYouType: self.options.selectAsYouType,
|
||||||
selected: self.options.selected,
|
selected: self.options.selected,
|
||||||
sort: self.options.sort,
|
sort: self.options.sort,
|
||||||
type: 'info',
|
type: 'info',
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ Ox.List <f> List constructor
|
||||||
prefixed with `'!'` (not)
|
prefixed with `'!'` (not)
|
||||||
value <*> Value
|
value <*> Value
|
||||||
operator <s> Operator (`'&'` or `'|'`)
|
operator <s> Operator (`'&'` or `'|'`)
|
||||||
|
selectAsYouType <s|''> If set to a key, enables select-as-you-type
|
||||||
selected <a|[]> ids of the selected elements
|
selected <a|[]> ids of the selected elements
|
||||||
sort <a|[]> sort order
|
sort <a|[]> sort order
|
||||||
sortable <b|false> If true, items can be re-ordered
|
sortable <b|false> If true, items can be re-ordered
|
||||||
|
|
@ -107,12 +108,12 @@ Ox.List = function(options, self) {
|
||||||
that.reloadList();
|
that.reloadList();
|
||||||
},
|
},
|
||||||
selected: function() {
|
selected: function() {
|
||||||
var previousSelected = self.selected;
|
var previousSelected = Ox.clone(self.selected);
|
||||||
setSelected(self.options.selected);
|
setSelected(self.options.selected);
|
||||||
// fixme: the following was added in order
|
// fixme: the following was added in order
|
||||||
// to make table list find-as-you-type work,
|
// to make table list find-as-you-type work,
|
||||||
// this may break other things
|
// this may break other things
|
||||||
if (!self.isAsync && !Ox.isEqual(self.selected, previousSelected)) {
|
if (/*!self.isAsync && */!Ox.isEqual(self.selected, previousSelected)) {
|
||||||
triggerSelectEvent(self.options.selected);
|
triggerSelectEvent(self.options.selected);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -227,10 +228,16 @@ Ox.List = function(options, self) {
|
||||||
] = selectNext;
|
] = selectNext;
|
||||||
if (self.options.max == -1) {
|
if (self.options.max == -1) {
|
||||||
self.keyboardEvents[
|
self.keyboardEvents[
|
||||||
'key_' + (self.options.orientation == 'vertical' ? 'shift_up' : 'shift_left')
|
'key_' + (
|
||||||
|
self.options.orientation == 'vertical'
|
||||||
|
? 'shift_up' : 'shift_left'
|
||||||
|
)
|
||||||
] = addPreviousToSelection;
|
] = addPreviousToSelection;
|
||||||
self.keyboardEvents[
|
self.keyboardEvents[
|
||||||
'key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right')
|
'key_' + (
|
||||||
|
self.options.orientation == 'vertical'
|
||||||
|
? 'shift_down' : 'shift_right'
|
||||||
|
)
|
||||||
] = addNextToSelection;
|
] = addNextToSelection;
|
||||||
}
|
}
|
||||||
if (self.options.orientation == 'vertical') {
|
if (self.options.orientation == 'vertical') {
|
||||||
|
|
@ -258,10 +265,14 @@ Ox.List = function(options, self) {
|
||||||
66, 60, 65, 70, 60, 64, 68, 72, 76, 60
|
66, 60, 65, 70, 60, 64, 68, 72, 76, 60
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
if (self.options.selectAsYouType) {
|
||||||
|
Ox.extend(self.keyboardEvents, {keys: selectAsYouType});
|
||||||
|
}
|
||||||
|
|
||||||
|
that.bindEvent(self.keyboardEvents);
|
||||||
|
|
||||||
!self.isAsync ? updateItems() : updateQuery();
|
!self.isAsync ? updateItems() : updateQuery();
|
||||||
|
|
||||||
that.bindEvent(self.keyboardEvents);
|
|
||||||
//Ox.UI.$window.resize(that.size); // fixme: this is not the widget's job
|
//Ox.UI.$window.resize(that.size); // fixme: this is not the widget's job
|
||||||
|
|
||||||
function addAboveToSelection() {
|
function addAboveToSelection() {
|
||||||
|
|
@ -309,9 +320,7 @@ Ox.List = function(options, self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addItem(keys) {
|
function addItem(keys) {
|
||||||
that.triggerEvent('add', {
|
that.triggerEvent('add', {keys: keys});
|
||||||
keys: keys
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNextToSelection() {
|
function addNextToSelection() {
|
||||||
|
|
@ -335,8 +344,9 @@ Ox.List = function(options, self) {
|
||||||
Ox.makeArray(pos).forEach(function(pos) {
|
Ox.makeArray(pos).forEach(function(pos) {
|
||||||
if (!isSelected(pos)) {
|
if (!isSelected(pos)) {
|
||||||
self.selected.push(pos);
|
self.selected.push(pos);
|
||||||
!Ox.isUndefined(self.$items[pos])
|
if (!Ox.isUndefined(self.$items[pos])) {
|
||||||
&& self.$items[pos].addClass('OxSelected');
|
self.$items[pos].addClass('OxSelected');
|
||||||
|
}
|
||||||
triggerEvent = true;
|
triggerEvent = true;
|
||||||
} else {
|
} else {
|
||||||
// allow for 'cursor navigation' if orientation == 'both'
|
// allow for 'cursor navigation' if orientation == 'both'
|
||||||
|
|
@ -410,6 +420,10 @@ Ox.List = function(options, self) {
|
||||||
triggerEvent && triggerSelectEvent();
|
triggerEvent && triggerSelectEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doubleclick(data) {
|
||||||
|
open(isSpecialTarget(data));
|
||||||
|
}
|
||||||
|
|
||||||
function dragstart(data) {
|
function dragstart(data) {
|
||||||
var $target = $(data.target),
|
var $target = $(data.target),
|
||||||
$parent = $target.parent();
|
$parent = $target.parent();
|
||||||
|
|
@ -971,36 +985,6 @@ Ox.List = function(options, self) {
|
||||||
delete self.drag;
|
delete self.drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
function singleclick(data) {
|
|
||||||
// these can't trigger on mousedown, since the mousedown
|
|
||||||
// could still be the start of a doubleclick or drag
|
|
||||||
var pos = findItemPosition(data),
|
|
||||||
$cell, clickable, editable;
|
|
||||||
if (pos > -1) {
|
|
||||||
if (
|
|
||||||
!data.metaKey && !data.shiftKey
|
|
||||||
&& isSelected(pos) && self.selected.length > 1
|
|
||||||
) {
|
|
||||||
// click on one of multiple selected items
|
|
||||||
select(pos);
|
|
||||||
} else if (self.mousedownOnSelectedCell) {
|
|
||||||
$cell = findCell(data);
|
|
||||||
if ($cell) {
|
|
||||||
clickable = $cell.is('.OxClickable');
|
|
||||||
editable = $cell.is('.OxEditable') && !$cell.is('.OxEdit');
|
|
||||||
if (clickable || editable) {
|
|
||||||
// click on a clickable or editable cell
|
|
||||||
triggerClickEvent(clickable ? 'click' : 'edit', self.$items[pos], $cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function doubleclick(data) {
|
|
||||||
open(isSpecialTarget(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveItem(startPos, stopPos) {
|
function moveItem(startPos, stopPos) {
|
||||||
var $item = self.$items[startPos],
|
var $item = self.$items[startPos],
|
||||||
insert = startPos < stopPos ? 'insertAfter' : 'insertBefore';
|
insert = startPos < stopPos ? 'insertAfter' : 'insertBefore';
|
||||||
|
|
@ -1158,6 +1142,29 @@ Ox.List = function(options, self) {
|
||||||
addToSelection(Ox.range(self.listLength));
|
addToSelection(Ox.range(self.listLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectAsYouType(data) {
|
||||||
|
self.options.items({
|
||||||
|
keys: [self.options.unique],
|
||||||
|
query: {
|
||||||
|
conditions: [
|
||||||
|
self.options.query,
|
||||||
|
{
|
||||||
|
key: self.options.selectAsYouType,
|
||||||
|
operator: '^',
|
||||||
|
value: data.keys
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operator: '&'
|
||||||
|
},
|
||||||
|
range: [0, 1],
|
||||||
|
sort: [{key: self.options.selectAsYouType, operator: '+'}]
|
||||||
|
}, function(result) {
|
||||||
|
result.data.items.length && that.options({
|
||||||
|
selected: [result.data.items[0][self.options.unique]]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function selectBelow() {
|
function selectBelow() {
|
||||||
var pos = getBelow();
|
var pos = getBelow();
|
||||||
if (pos > -1) {
|
if (pos > -1) {
|
||||||
|
|
@ -1209,8 +1216,9 @@ Ox.List = function(options, self) {
|
||||||
self.$items.forEach(function($item, pos) {
|
self.$items.forEach(function($item, pos) {
|
||||||
if (isSelected(pos)) {
|
if (isSelected(pos)) {
|
||||||
self.selected.splice(self.selected.indexOf(pos), 1);
|
self.selected.splice(self.selected.indexOf(pos), 1);
|
||||||
!Ox.isUndefined(self.$items[pos]) &&
|
if (!Ox.isUndefined(self.$items[pos])) {
|
||||||
self.$items[pos].removeClass('OxSelected');
|
self.$items[pos].removeClass('OxSelected');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ids.forEach(function(id, i) {
|
ids.forEach(function(id, i) {
|
||||||
|
|
@ -1231,13 +1239,40 @@ Ox.List = function(options, self) {
|
||||||
});
|
});
|
||||||
function select(pos, i) {
|
function select(pos, i) {
|
||||||
self.selected.push(pos);
|
self.selected.push(pos);
|
||||||
!Ox.isUndefined(self.$items[pos]) &&
|
if (!Ox.isUndefined(self.$items[pos])) {
|
||||||
self.$items[pos].addClass('OxSelected');
|
self.$items[pos].addClass('OxSelected');
|
||||||
|
}
|
||||||
i == 0 && scrollToPosition(pos);
|
i == 0 && scrollToPosition(pos);
|
||||||
++counter == ids.length && callback && callback();
|
++counter == ids.length && callback && callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function singleclick(data) {
|
||||||
|
// these can't trigger on mousedown, since the mousedown
|
||||||
|
// could still be the start of a doubleclick or drag
|
||||||
|
var pos = findItemPosition(data),
|
||||||
|
$cell, clickable, editable;
|
||||||
|
if (pos > -1) {
|
||||||
|
if (
|
||||||
|
!data.metaKey && !data.shiftKey
|
||||||
|
&& isSelected(pos) && self.selected.length > 1
|
||||||
|
) {
|
||||||
|
// click on one of multiple selected items
|
||||||
|
select(pos);
|
||||||
|
} else if (self.mousedownOnSelectedCell) {
|
||||||
|
$cell = findCell(data);
|
||||||
|
if ($cell) {
|
||||||
|
clickable = $cell.is('.OxClickable');
|
||||||
|
editable = $cell.is('.OxEditable') && !$cell.is('.OxEdit');
|
||||||
|
if (clickable || editable) {
|
||||||
|
// click on a clickable or editable cell
|
||||||
|
triggerClickEvent(clickable ? 'click' : 'edit', self.$items[pos], $cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function toggleSelection(pos) {
|
function toggleSelection(pos) {
|
||||||
// FIXME: unused
|
// FIXME: unused
|
||||||
if (!isSelected(pos)) {
|
if (!isSelected(pos)) {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ Ox.TableList <f> TableList Widget
|
||||||
pageLength <n|100> Number of items per page
|
pageLength <n|100> Number of items per page
|
||||||
query <o> Query
|
query <o> Query
|
||||||
scrollbarVisible <b|false> If true, the scrollbar is always visible
|
scrollbarVisible <b|false> If true, the scrollbar is always visible
|
||||||
|
selectAsYouType <s|''> If set to a key, enables select-as-you-type
|
||||||
selected <[s]|[]> Array of selected ids
|
selected <[s]|[]> Array of selected ids
|
||||||
sort <[o]|[s]|[]> ['+foo', ...] or [{key: 'foo', operator: '+'}, ...]
|
sort <[o]|[s]|[]> ['+foo', ...] or [{key: 'foo', operator: '+'}, ...]
|
||||||
sortable <b|false> If true, elements can be re-ordered
|
sortable <b|false> If true, elements can be re-ordered
|
||||||
|
|
@ -104,8 +105,7 @@ Ox.TableList = function(options, self) {
|
||||||
var $element = that.$body.$element,
|
var $element = that.$body.$element,
|
||||||
scrollLeft = $element[0].scrollLeft + $element.width();
|
scrollLeft = $element[0].scrollLeft + $element.width();
|
||||||
$element.animate({scrollLeft: scrollLeft}, 250);
|
$element.animate({scrollLeft: scrollLeft}, 250);
|
||||||
},
|
}
|
||||||
keys: find
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.options.columns.forEach(function(column) { // fixme: can this go into a generic ox.js function?
|
self.options.columns.forEach(function(column) { // fixme: can this go into a generic ox.js function?
|
||||||
|
|
@ -246,6 +246,7 @@ Ox.TableList = function(options, self) {
|
||||||
pageLength: self.options.pageLength,
|
pageLength: self.options.pageLength,
|
||||||
paste: self.options.paste,
|
paste: self.options.paste,
|
||||||
query: self.options.query,
|
query: self.options.query,
|
||||||
|
selectAsYouType: self.options.selectAsYouType,
|
||||||
selected: self.options.selected,
|
selected: self.options.selected,
|
||||||
sort: self.options.sort,
|
sort: self.options.sort,
|
||||||
sortable: self.options.sortable,
|
sortable: self.options.sortable,
|
||||||
|
|
@ -596,23 +597,6 @@ Ox.TableList = function(options, self) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function find(data) {
|
|
||||||
// fixme: works only if items are an array
|
|
||||||
var query = data.keys,
|
|
||||||
sort = self.options.sort[0];
|
|
||||||
Ox.Log('List', 'QUERY', query)
|
|
||||||
Ox.forEach(self.options.items, function(item, i) {
|
|
||||||
var value = (
|
|
||||||
sort.map ? sort.map(item[sort.key]) : item[sort.key]
|
|
||||||
).toString().toLowerCase();
|
|
||||||
if (Ox.startsWith(value, query)) {
|
|
||||||
that.$body.options({selected: [item[self.options.unique]]});
|
|
||||||
Ox.Log('List', 'QUERY', query, 'VALUE', value)
|
|
||||||
Ox.Break();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatValue(key, value, data) {
|
function formatValue(key, value, data) {
|
||||||
// fixme: this may be obscure...
|
// fixme: this may be obscure...
|
||||||
// since the format of a value may depend on another value,
|
// since the format of a value may depend on another value,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue