From 64a182ae1dbe33bc02f828e3040b5e5e3ea5acd5 Mon Sep 17 00:00:00 2001 From: rolux Date: Fri, 29 Jun 2012 14:19:34 +0200 Subject: [PATCH] lists: implement select-as-you-type --- source/Ox.UI/js/List/IconList.js | 3 + source/Ox.UI/js/List/InfoList.js | 2 + source/Ox.UI/js/List/List.js | 119 +++++++++++++++++++----------- source/Ox.UI/js/List/TableList.js | 22 +----- 4 files changed, 85 insertions(+), 61 deletions(-) diff --git a/source/Ox.UI/js/List/IconList.js b/source/Ox.UI/js/List/IconList.js index 5740fbc7..bae58c4f 100644 --- a/source/Ox.UI/js/List/IconList.js +++ b/source/Ox.UI/js/List/IconList.js @@ -19,6 +19,7 @@ Ox.IconList IconList Object orientation orientation ("horizontal", "vertical" or "both") pageLength Number of items per page (if orientation != "both") query Query + selectAsYouType If set to a key, enables select-as-you-type selected array of selected items size list size sort sort keys @@ -46,6 +47,7 @@ Ox.IconList = function(options, self) { orientation: 'both', pageLength: 100, query: {conditions: [], operator: '&'}, + selectAsYouType: '', selected: [], size: 128, sort: [], @@ -95,6 +97,7 @@ Ox.IconList = function(options, self) { orientation: self.options.orientation, pageLength: self.options.pageLength, query: self.options.query, + selectAsYouType: self.options.selectAsYouType, selected: self.options.selected, sort: self.options.sort, type: 'icon', diff --git a/source/Ox.UI/js/List/InfoList.js b/source/Ox.UI/js/List/InfoList.js index 40bc527b..93ac7eed 100644 --- a/source/Ox.UI/js/List/InfoList.js +++ b/source/Ox.UI/js/List/InfoList.js @@ -21,6 +21,7 @@ Ox.InfoList = function(options, self) { max: -1, min: 0, query: {conditions: [], operator: '&'}, + selectAsYouType: '', selected: [], size: 192, sort: [], @@ -71,6 +72,7 @@ Ox.InfoList = function(options, self) { orientation: 'vertical', pageLength: 10, query: self.options.query, + selectAsYouType: self.options.selectAsYouType, selected: self.options.selected, sort: self.options.sort, type: 'info', diff --git a/source/Ox.UI/js/List/List.js b/source/Ox.UI/js/List/List.js index 95863fc7..ddcd20f7 100644 --- a/source/Ox.UI/js/List/List.js +++ b/source/Ox.UI/js/List/List.js @@ -24,6 +24,7 @@ Ox.List List constructor prefixed with `'!'` (not) value <*> Value operator Operator (`'&'` or `'|'`) + selectAsYouType If set to a key, enables select-as-you-type selected ids of the selected elements sort sort order sortable If true, items can be re-ordered @@ -107,12 +108,12 @@ Ox.List = function(options, self) { that.reloadList(); }, selected: function() { - var previousSelected = self.selected; + var previousSelected = Ox.clone(self.selected); setSelected(self.options.selected); // fixme: the following was added in order // to make table list find-as-you-type work, // 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); } }, @@ -227,10 +228,16 @@ Ox.List = function(options, self) { ] = selectNext; if (self.options.max == -1) { self.keyboardEvents[ - 'key_' + (self.options.orientation == 'vertical' ? 'shift_up' : 'shift_left') + 'key_' + ( + self.options.orientation == 'vertical' + ? 'shift_up' : 'shift_left' + ) ] = addPreviousToSelection; self.keyboardEvents[ - 'key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right') + 'key_' + ( + self.options.orientation == 'vertical' + ? 'shift_down' : 'shift_right' + ) ] = addNextToSelection; } if (self.options.orientation == 'vertical') { @@ -258,10 +265,14 @@ Ox.List = function(options, self) { 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(); - that.bindEvent(self.keyboardEvents); //Ox.UI.$window.resize(that.size); // fixme: this is not the widget's job function addAboveToSelection() { @@ -309,9 +320,7 @@ Ox.List = function(options, self) { } function addItem(keys) { - that.triggerEvent('add', { - keys: keys - }); + that.triggerEvent('add', {keys: keys}); } function addNextToSelection() { @@ -335,8 +344,9 @@ Ox.List = function(options, self) { Ox.makeArray(pos).forEach(function(pos) { if (!isSelected(pos)) { self.selected.push(pos); - !Ox.isUndefined(self.$items[pos]) - && self.$items[pos].addClass('OxSelected'); + if (!Ox.isUndefined(self.$items[pos])) { + self.$items[pos].addClass('OxSelected'); + } triggerEvent = true; } else { // allow for 'cursor navigation' if orientation == 'both' @@ -410,6 +420,10 @@ Ox.List = function(options, self) { triggerEvent && triggerSelectEvent(); } + function doubleclick(data) { + open(isSpecialTarget(data)); + } + function dragstart(data) { var $target = $(data.target), $parent = $target.parent(); @@ -971,36 +985,6 @@ Ox.List = function(options, self) { 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) { var $item = self.$items[startPos], insert = startPos < stopPos ? 'insertAfter' : 'insertBefore'; @@ -1158,6 +1142,29 @@ Ox.List = function(options, self) { 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() { var pos = getBelow(); if (pos > -1) { @@ -1209,8 +1216,9 @@ Ox.List = function(options, self) { self.$items.forEach(function($item, pos) { if (isSelected(pos)) { self.selected.splice(self.selected.indexOf(pos), 1); - !Ox.isUndefined(self.$items[pos]) && + if (!Ox.isUndefined(self.$items[pos])) { self.$items[pos].removeClass('OxSelected'); + } } }); ids.forEach(function(id, i) { @@ -1231,13 +1239,40 @@ Ox.List = function(options, self) { }); function select(pos, i) { self.selected.push(pos); - !Ox.isUndefined(self.$items[pos]) && + if (!Ox.isUndefined(self.$items[pos])) { self.$items[pos].addClass('OxSelected'); + } i == 0 && scrollToPosition(pos); ++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) { // FIXME: unused if (!isSelected(pos)) { diff --git a/source/Ox.UI/js/List/TableList.js b/source/Ox.UI/js/List/TableList.js index 02765cbb..3dd799b3 100644 --- a/source/Ox.UI/js/List/TableList.js +++ b/source/Ox.UI/js/List/TableList.js @@ -32,6 +32,7 @@ Ox.TableList TableList Widget pageLength Number of items per page query Query scrollbarVisible If true, the scrollbar is always visible + selectAsYouType If set to a key, enables select-as-you-type selected <[s]|[]> Array of selected ids sort <[o]|[s]|[]> ['+foo', ...] or [{key: 'foo', operator: '+'}, ...] sortable If true, elements can be re-ordered @@ -104,8 +105,7 @@ Ox.TableList = function(options, self) { var $element = that.$body.$element, scrollLeft = $element[0].scrollLeft + $element.width(); $element.animate({scrollLeft: scrollLeft}, 250); - }, - keys: find + } }); 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, paste: self.options.paste, query: self.options.query, + selectAsYouType: self.options.selectAsYouType, selected: self.options.selected, sort: self.options.sort, 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) { // fixme: this may be obscure... // since the format of a value may depend on another value,