uki 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,84 @@
1
+ uki.more.view.splitTable = {};
1
2
 
2
-
3
- uki.view.declare('uki.more.view.SplitTable', uki.view.Table, function(base) {
4
- var Rect = uki.geometry.Rect;
3
+ uki.view.declare('uki.more.view.SplitTable', uki.view.Container, function(Base) {
4
+ var Rect = uki.geometry.Rect,
5
+ Size = uki.geometry.Size;
6
+
7
+ var propertiesToDelegate = 'rowHeight data packSize visibleRectExt render selectedIndex focusable textSelectable multiselect'.split(' ');
5
8
 
6
9
 
7
10
  this._defaultHandlePosition = 200;
11
+ this._headerHeight = 17;
12
+
13
+ this._style = function(name, value) {
14
+ this._leftHeader.style(name, value);
15
+ this._rightHeader.style(name, value);
16
+ return Base._style.call(this, name, value);
17
+ };
18
+
19
+ this.columns = uki.newProp('_columns', function(c) {
20
+ this._columns = uki.build(c);
21
+ this._totalWidth = 0;
22
+ this._leftHeader.columns([this._columns[0]]);
23
+
24
+ this._columns[0].bind('beforeResize', uki.proxy(this._syncHandlePosition, this, this._columns[0]));
25
+
26
+ for (var i = 1; i < this._columns.length; i++) {
27
+ this._columns[i].position(i - 1);
28
+ this._columns[i].bind('beforeResize', uki.proxy(this._rightColumnResized, this, this._columns[i]));
29
+ };
30
+ this._updateTotalWidth();
31
+ this._rightHeader.columns(Array.prototype.slice.call(this._columns, 1));
32
+ this._splitPane.leftMin(this._columns[0].minWidth() - 1)
33
+ // this._splitPane.handlePosition(this._columns[0].width());
34
+ this._syncHandlePosition(this._splitPane);
35
+ });
36
+
37
+ uki.each(propertiesToDelegate, function(i, name) {
38
+ this[name] = function(v) {
39
+ if (v === undefined) return this._leftList[name]();
40
+ this._leftList[name](v);
41
+ this._rightList[name](v);
42
+ return this;
43
+ };
44
+ }, this);
45
+
46
+ this.hasFocus = function() {
47
+ return this._leftList.hasFocus() || this._rightList.hasFocus();
48
+ };
49
+
50
+ this.rightColumns = function() {
51
+ return this._rightHeader.columns();
52
+ };
53
+
54
+ this._rightColumnResized = function(column) {
55
+ this._updateTotalWidth();
56
+ this._horizontalScroll.layout();
57
+ };
58
+
59
+ this.rowHeight = function(value) {
60
+ if (value === undefined) return this._leftList.rowHeight();
61
+ this._leftList.rowHeight(value);
62
+ this._rightList.rowHeight(value);
63
+ return this;
64
+ };
65
+
66
+ this.data = function(d) {
67
+ if (d === undefined) return uki.map(this._leftList.data(), function(value, i) {
68
+ return [value].concat(this._rightList.data()[i]);
69
+ }, this);
70
+
71
+ this._leftList.data(uki.map(d, function(value) {
72
+ return [value[0]];
73
+ }));
74
+
75
+ this._rightList.data(uki.map(d, function(value) {
76
+ return value.slice(1);
77
+ }));
78
+
79
+ this._splitPane.minSize(new Size(0, this._leftList.minSize().height));
80
+ this._verticalScroll.layout();
81
+ };
8
82
 
9
83
  this._createDom = function() {
10
84
  Base._createDom.call(this);
@@ -14,20 +88,34 @@ uki.view.declare('uki.more.view.SplitTable', uki.view.Table, function(base) {
14
88
  [
15
89
  {
16
90
  view: 'table.Header',
17
- rect: new Rect(0, 0, this.rect().width, this._headerHeight),
18
- anchors: 'top left right',
19
- className: 'table-header'
91
+ rect: new Rect(this._defaultHandlePosition, this._headerHeight),
92
+ anchors: 'left top'
93
+ },
94
+ {
95
+ view: 'Box',
96
+ className: 'table-header-container',
97
+ style: { overflow: 'hidden' },
98
+ rect: new Rect(this._defaultHandlePosition, 0, this.rect().width - this._defaultHandlePosition - 1, this._headerHeight),
99
+ anchors: 'left top right',
100
+ childViews: {
101
+ view: 'table.Header',
102
+ rect: new Rect(this.rect().width - this._defaultHandlePosition - 1, this._headerHeight),
103
+ anchors: 'top left right',
104
+ className: 'table-header'
105
+ }
20
106
  },
21
107
  {
22
108
  view: 'ScrollPane',
23
109
  rect: new Rect(0, this._headerHeight, this.rect().width, bodyHeight),
24
110
  anchors: 'left top right bottom',
25
111
  className: 'table-v-scroll',
112
+ scrollV: true,
26
113
  childViews: [
27
114
  {
28
- view: 'SplitPane',
115
+ view: 'HSplitPane',
29
116
  rect: new Rect(this.rect().width, bodyHeight),
30
- anchors: 'left top',
117
+ anchors: 'left top right bottom',
118
+ className: 'table-horizontal-split-pane',
31
119
  handlePosition: this._defaultHandlePosition,
32
120
  handleWidth: 1,
33
121
  leftChildViews: [
@@ -40,19 +128,27 @@ uki.view.declare('uki.more.view.SplitTable', uki.view.Table, function(base) {
40
128
  ],
41
129
  rightChildViews: [
42
130
  {
43
- view: 'ScrollPane',
44
- rect: new Rect(this.rect().width - this._defaultHandlePosition - 1, bodyHeight + scrollWidth),
45
- scrollableV: false,
46
- scrollableH: true,
131
+ view: 'Box',
132
+ rect: '0 0 100 100',
47
133
  anchors: 'left top right bottom',
48
- className: 'table-h-scroll',
49
- childViews: [
50
- {
51
- view: 'List',
52
- rect: new Rect(this.rect().width - this._defaultHandlePosition - 1, bodyHeight + scrollWidth),
53
- anchors: 'left top rect bottom'
54
- }
55
- ]
134
+ style: { overflow: 'hidden' },
135
+ rect: new Rect(this.rect().width - this._defaultHandlePosition - 1, bodyHeight),
136
+ childViews: {
137
+ view: 'ScrollPane',
138
+ rect: new Rect(this.rect().width - this._defaultHandlePosition - 1, bodyHeight + scrollWidth),
139
+ scrollableV: false,
140
+ scrollableH: true,
141
+ anchors: 'left top right bottom',
142
+ className: 'table-h-scroll',
143
+ childViews: [
144
+ {
145
+ view: 'List',
146
+ rect: new Rect(this.rect().width - this._defaultHandlePosition - 1, bodyHeight + scrollWidth),
147
+ anchors: 'left top right bottom'
148
+ }
149
+ ]
150
+ }
151
+
56
152
  }
57
153
  ]
58
154
  }
@@ -65,7 +161,8 @@ uki.view.declare('uki.more.view.SplitTable', uki.view.Table, function(base) {
65
161
  scrollableH: true,
66
162
  scrollableV: false,
67
163
  scrollH: true,
68
- className: 'table-h-scroll-bar'
164
+ className: 'table-h-scroll-bar',
165
+ childViews: { view: 'Box', rect: '1 1', anchors: 'left top' }
69
166
  }
70
167
  ]).appendTo(this);
71
168
 
@@ -74,6 +171,88 @@ uki.view.declare('uki.more.view.SplitTable', uki.view.Table, function(base) {
74
171
  this._horizontalScrollBar = uki('ScrollPane[className=table-h-scroll-bar]', this)[0];
75
172
  this._leftList = uki('List:eq(0)', this)[0];
76
173
  this._rightList = uki('List:eq(1)', this)[0];
77
- this._splitPane = uki('SplitPane', this)[0];
174
+ this._splitPane = uki('HSplitPane', this)[0];
175
+ this._leftHeader = uki('table.Header:eq(0)', this)[0];
176
+ this._rightHeader = uki('table.Header:eq(1)', this)[0];
177
+ this._rightHeaderContainer = uki('[className=table-header-container]', this)[0];
178
+ this._dummyScrollContents = uki('Box', this._horizontalScrollBar);
179
+
180
+ this._leftList._scrollableParent = this._verticalScroll;
181
+ this._rightList._scrollableParent = this._verticalScroll;
182
+ this._verticalScroll.bind('scroll', uki.proxy(this._leftList._scrollableParentScroll, this._leftList));
183
+ this._verticalScroll.bind('scroll', uki.proxy(this._rightList._scrollableParentScroll, this._rightList));
184
+
185
+ this._leftList.render(new uki.more.view.splitTable.Render(this._leftHeader));
186
+ this._rightList.render(new uki.more.view.splitTable.Render(this._rightHeader));
187
+ this._bindEvents();
188
+ };
189
+
190
+ this._bindEvents = function() {
191
+ this._splitPane.bind('handleMove', uki.proxy(this._syncHandlePosition, this, this._splitPane));
192
+ this._horizontalScroll.bind('scroll', uki.proxy(this._syncHScroll, this, this._horizontalScroll));
193
+ this._horizontalScrollBar.bind('scroll', uki.proxy(this._syncHScroll, this, this._horizontalScrollBar));
194
+ this._leftList.bind('selection', uki.proxy(this._syncSelection, this, this._leftList));
195
+ this._rightList.bind('selection', uki.proxy(this._syncSelection, this, this._rightList));
196
+ };
197
+
198
+ var updatingHandlePosition = false;
199
+ this._syncHandlePosition = function(source) {
200
+ if (updatingHandlePosition) return;
201
+ updatingHandlePosition = true;
202
+ var w, rect;
203
+ if (source == this._splitPane) {
204
+ w = this._splitPane.handlePosition() + 1;
205
+ this.columns()[0].width(w);
206
+ } else {
207
+ var w = this.columns()[0].width();
208
+ this._splitPane.handlePosition(w - 1).layout();
209
+ }
210
+
211
+ this._leftHeader.rect(new Rect(w, this._headerHeight)).layout();
212
+
213
+ rect = this._rightHeaderContainer.rect().clone();
214
+ rect.x = w;
215
+ rect.width = this._rect.width - w - uki.view.ScrollPane.initScrollWidth();
216
+ this._rightHeaderContainer.rect(rect).layout();
217
+ rect = this._horizontalScrollBar.rect().clone();
218
+ rect.x = w;
219
+ rect.width = this._rect.width - w - uki.view.ScrollPane.initScrollWidth();
220
+ this._horizontalScrollBar.rect(rect).layout();
221
+ updatingHandlePosition = false;
222
+ };
223
+
224
+ var updatingHScroll = false;
225
+ this._syncHScroll = function(source) {
226
+ if (updatingHScroll) return;
227
+ updatingHScroll = true;
228
+ var scroll, target = source == this._horizontalScroll ? this._horizontalScrollBar : this._horizontalScroll;
229
+ scroll = source.scrollLeft();
230
+ target.scrollLeft(scroll);
231
+ this._rightHeader.dom().style.marginLeft = -scroll + 'px';
232
+ updatingHScroll = false;
233
+ };
234
+
235
+ var updatingSelection = false;
236
+ this._syncSelection = function(source) {
237
+ if (updatingSelection) return;
238
+ updatingSelection = true;
239
+ var target = source == this._leftList ? this._rightList : this._leftList;
240
+ target.selectedIndexes(source.selectedIndexes());
241
+ updatingSelection = false;
78
242
  };
79
- });
243
+
244
+ this._updateTotalWidth = function() {
245
+ this._totalWidth = 0;
246
+ for (var i=1; i < this._columns.length; i++) {
247
+ this._totalWidth += this._columns[i].width();
248
+ };
249
+ this._rightHeader.minSize(new Size(this._totalWidth, 0));
250
+ this._rightList.minSize(new Size(this._totalWidth, this._rightList.minSize().height));
251
+ this._dummyScrollContents.rect(new Rect(this._totalWidth, 1)).parent().layout();
252
+ this._rightHeader.minSize(new Size(this._totalWidth, 0));
253
+ this._horizontalScroll.layout();
254
+ };
255
+
256
+ });
257
+
258
+ include('splitTable/render.js');
@@ -11,7 +11,7 @@ uki.more.view.treeList.Render = uki.newClass(uki.view.list.Render, new function(
11
11
  );
12
12
 
13
13
  this.initStyles = function() {
14
- uki.more.view.treeList.Render.prototype.classPrefix = 'treeList-' + uki.dom.guid++;
14
+ this.classPrefix = 'treeList-' + uki.dom.guid++;
15
15
  var style = new uki.theme.Template(
16
16
  '.${classPrefix}-row { color: #333; position:relative; padding-top:3px; } ' +
17
17
  '.${classPrefix}-toggle { overflow: hidden; position:absolute; left:-15px; top:5px; width: 10px; height:9px; } ' +
@@ -3,25 +3,20 @@ include('../view.js');
3
3
  // really basic tree list implementation
4
4
  uki.more.view.treeList = {};
5
5
 
6
- uki.more.view.TreeList = uki.newClass(uki.view.List, new function() {
7
- var Base = uki.view.List.prototype,
8
- proto = this;
9
-
10
- proto.typeName = function() { return 'uki.more.view.TreeList'; };
11
-
12
- proto._setup = function() {
6
+ uki.view.declare('uki.more.view.TreeList', uki.view.List, function(Base) {
7
+ this._setup = function() {
13
8
  Base._setup.call(this);
14
9
  this._render = new uki.more.view.treeList.Render();
15
10
  };
16
11
 
17
- proto.listData = Base.data;
12
+ this.listData = Base.data;
18
13
 
19
- proto.data = uki.newProp('_treeData', function(v) {
14
+ this.data = uki.newProp('_treeData', function(v) {
20
15
  this._treeData = v;
21
16
  this.listData(this._treeNodeToListData(v));
22
17
  });
23
18
 
24
- proto._treeNodeToListData = function(node, indent) {
19
+ this._treeNodeToListData = function(node, indent) {
25
20
  indent = indent || 0;
26
21
  return uki.map(node, function(row) {
27
22
  row.__indent = indent;
@@ -29,62 +24,94 @@ uki.more.view.TreeList = uki.newClass(uki.view.List, new function() {
29
24
  });
30
25
  };
31
26
 
32
- proto.toggle = function(index) {
27
+ this.toggle = function(index) {
33
28
  this._data[index].__opened ? this.close(index) : this.open(index);
34
29
  };
35
30
 
31
+ function offsetFrom (array, from, offset) {
32
+ for (var i = from; i < array.length; i++) {
33
+ array[i] += offset;
34
+ };
35
+ }
36
+
36
37
  function recursiveLength (item) {
37
38
  var children = item.children,
38
- length = children.length;
39
-
39
+ length = children.length;
40
+
40
41
  for (var i=0; i < children.length; i++) {
41
42
  if (children[i].__opened) length += recursiveLength(children[i]);
42
43
  };
43
44
  return length;
44
- }
45
-
46
- proto.open = function(index, _skipUpdate) {
47
- var selectedIndex = this._selectedIndex,
48
- item = this._data[index],
45
+ }
46
+
47
+ this._openSubElement = function(index) {
48
+ var item = this._data[index],
49
49
  children = item.children;
50
50
 
51
- if (!children || !children.length || (item.__opened && !_skipUpdate)) return 0;
51
+ if (!children || !children.length) return 0;
52
52
  var length = children.length;
53
-
53
+
54
54
  item.__opened = true;
55
55
  this._data.splice.apply(this._data, [index+1, 0].concat( this._treeNodeToListData(children, item.__indent + 1) ));
56
56
 
57
57
  for (var i=children.length - 1; i >= 0 ; i--) {
58
58
  if (this._data[index+1+i].__opened) {
59
- length += this.open(index+1+i, true);
59
+ length += this._openSubElement(index+1+i);
60
60
  }
61
61
  };
62
- if (!_skipUpdate) {
63
- this.listData(this._data);
64
- this.selectedIndex(selectedIndex <= index ? selectedIndex : selectedIndex + length);
65
- }
66
62
  return length;
67
63
  };
68
64
 
69
- proto.close = function(index) {
70
- var selectedIndex = this._selectedIndex,
71
- item = this._data[index],
72
- children = item.children;
65
+ this.open = function(index) {
66
+ if (this._data[index].__opened) return this;
67
+
68
+ var length = this._openSubElement(index),
69
+ positionInSelection = uki.binarySearch(index, this._selectedIndexes),
70
+ clickIndex = this._lastClickIndex,
71
+ indexes = this._selectedIndexes;
73
72
 
73
+ this.clearSelection(true);
74
+ offsetFrom(
75
+ indexes,
76
+ positionInSelection + (indexes[positionInSelection] == index ? 1 : 0),
77
+ length
78
+ );
79
+
80
+ this.listData(this._data);
81
+ this.selectedIndexes(indexes);
82
+ this._lastClickIndex = clickIndex > index ? clickIndex + length : clickIndex;
83
+ return this;
84
+ };
85
+
86
+ this.close = function(index) {
87
+ var item = this._data[index],
88
+ indexes = this._selectedIndexes,
89
+ children = item.children;
74
90
  if (!children || !children.length || !item.__opened) return;
91
+
75
92
  var length = recursiveLength(item);
76
-
93
+
77
94
  item.__opened = false;
78
95
  this._data.splice(index+1, length);
96
+
97
+ var positionInSelection = uki.binarySearch(index, indexes),
98
+ removeFrom = positionInSelection + (indexes[positionInSelection] == index ? 1 : 0),
99
+ toRemove = 0,
100
+ clickIndex = this._lastClickIndex;
101
+ while (indexes[removeFrom + toRemove] && indexes[removeFrom + toRemove] <= index + length) toRemove++;
102
+
103
+ this.clearSelection(true);
104
+ offsetFrom(indexes, removeFrom, -length);
105
+ if (toRemove > 0) {
106
+ indexes.splice(positionInSelection, toRemove);
107
+ }
108
+
79
109
  this.listData(this._data);
80
- this.selectedIndex(
81
- selectedIndex <= index ? selectedIndex :
82
- selectedIndex >= index + length ? index - length :
83
- index
84
- );
110
+ this.selectedIndexes(indexes);
111
+ this._lastClickIndex = clickIndex > index ? clickIndex - length : clickIndex;
85
112
  };
86
-
87
- proto._mousedown = function(e) {
113
+
114
+ this._mousedown = function(e) {
88
115
  if (e.domEvent.target.className.indexOf('toggle-tree') > -1) {
89
116
  var o = uki.dom.offset(this._dom),
90
117
  y = e.domEvent.pageY - o.y,
@@ -95,13 +122,13 @@ uki.more.view.TreeList = uki.newClass(uki.view.List, new function() {
95
122
  }
96
123
  };
97
124
 
98
- proto._keypress = function(e) {
125
+ this._keypress = function(e) {
99
126
  Base._keypress.call(this, e);
100
127
  e = e.domEvent;
101
128
  if (e.which == 39 || e.keyCode == 39) { // RIGHT
102
- this.open(this._selectedIndex);
129
+ this.open(this._lastClickIndex);
103
130
  } else if (e.which == 37 || e.keyCode == 37) { // LEFT
104
- this.close(this._selectedIndex);
131
+ this.close(this._lastClickIndex);
105
132
  }
106
133
  };
107
134
 
@@ -1,4 +1,4 @@
1
1
  include('uki-more/more/view/treeList.js');
2
- include('uki-more/more/view/multiselectList.js');
3
2
  include('uki-more/more/view/toggleButton.js');
4
3
  include('uki-more/more/view/radioButton.js');
4
+ include('uki-more/more/view/splitTable.js');
@@ -141,8 +141,16 @@
141
141
  return new uki.background.Css('#CCC');
142
142
  },
143
143
 
144
+ 'toolbar-popup-button-normal': function() {
145
+ return new uki.background.Css({ textAlign: 'left' });
146
+ },
147
+
148
+ 'toolbar-popup-button-down': function() {
149
+ return new uki.background.Css({ background: '#AAA', textAlign: 'left' });
150
+ },
151
+
144
152
  'toolbar-popup-button-hover': function() {
145
- return new uki.background.Css({ background: '#4086FF', color: '#FFF' });
153
+ return new uki.background.Css({ background: '#4086FF', color: '#FFF', textAlign: 'left' });
146
154
  },
147
155
 
148
156
 
@@ -240,10 +248,24 @@
240
248
  }
241
249
  },
242
250
 
251
+ templates: {
252
+ 'table-header-cell': function() {
253
+ return new uki.theme.Template(
254
+ '<div style="position:relative;border:1px solid #CCC;border-top:none;border-left:none;'+
255
+ '${style}" class="${className}">${data}</div>');
256
+ },
257
+
258
+ 'table-cell': function() {
259
+ return new uki.theme.Template(
260
+ '<div style="position:relative;border-right:1px solid #CCC;height:100%;'+
261
+ '${style}" class="${className}">${data}</div>');
262
+ }
263
+ },
264
+
243
265
  doms: {
244
- 'resizer': function(params) {
245
- var template = new uki.theme.Template('position:absolute;width:5px;top:0;height:${height}px;cursor:col-resize;cursor:ew-resize;z-index:101;background:url(' + uki.theme.imageSrc('x') + ')'),
246
- node = uki.createElement('div', template.render(params));
266
+ 'resizer': function(height) {
267
+ var template = new uki.theme.Template('position:absolute;width:5px;top:0;right:-3px;height:${height}px;cursor:col-resize;cursor:ew-resize;z-index:101;background:url(' + uki.theme.imageSrc('x') + ')'),
268
+ node = uki.createElement('div', template.render({height:height}));
247
269
 
248
270
  if (!node.style.cursor || window.opera) node.style.cursor = 'e-resize';
249
271
  return node;
@@ -317,6 +339,7 @@
317
339
 
318
340
  uki.theme.airport.backgrounds['input-focus'] = uki.theme.airport.backgrounds['button-focus'];
319
341
  uki.theme.airport.backgrounds['toolbar-popup'] = uki.theme.airport.backgrounds['popup-normal'];
342
+ uki.theme.airport.backgrounds['toolbar-popup-button-disabled'] = uki.theme.airport.backgrounds['toolbar-popup-button-normal'];
320
343
 
321
344
  uki.theme.register(uki.theme.airport);
322
345
  })();
@@ -12,7 +12,7 @@ uki.view.declare('uki.view.Label', uki.view.Base, function(Base) {
12
12
  };
13
13
 
14
14
  this._style = function(name, value) {
15
- if (value !== undefined && 'fontWeight fontSize textDecoration color'.indexOf(name) != -1) {
15
+ if (value !== undefined && 'font fontFamily fontWeight fontSize textDecoration color'.indexOf(name) != -1) {
16
16
  this._label.style[name] = value;
17
17
  }
18
18
  return Base._style.call(this, name, value);
@@ -36,11 +36,18 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
36
36
  this.clearSelection();
37
37
  this._data = d;
38
38
  this._packs[0].itemFrom = this._packs[0].itemTo = this._packs[1].itemFrom = this._packs[1].itemTo = 0;
39
- this._updateRectOnDataChnage();
39
+
40
+ var minWidth = this._minSize ? this._minSize.width : 0;
41
+ this.minSize(new Size(minWidth, this._rowHeight * this._data.length));
40
42
  this._relayoutParent();
41
43
  return this;
42
44
  };
43
45
 
46
+ this.relayout = function() {
47
+ this._packs[0].itemFrom = this._packs[0].itemTo = this._packs[1].itemFrom = this._packs[1].itemTo = 0;
48
+ this.layout();
49
+ };
50
+
44
51
  this.addRow = function(position, data) {
45
52
  this.clearSelection();
46
53
  this._data.splice(position, 0, data);
@@ -124,7 +131,9 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
124
131
  this.selectedIndexes(indexes);
125
132
  };
126
133
 
134
+ var updatingScroll = false;
127
135
  this._scrollableParentScroll = function() {
136
+ if (updatingScroll) return;
128
137
  if (this._throttle) {
129
138
  if (this._throttleStarted) return;
130
139
  this._throttleStarted = true;
@@ -148,12 +157,8 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
148
157
  };
149
158
 
150
159
 
151
- this._updateRectOnDataChnage = function() {
152
- this.rect(this._parentRect);
153
- };
154
-
155
160
  this.keyPressEvent = function() {
156
- var useKeyPress = /mozilla/i.test( ua ) && !(/(compatible|webkit)/i).test( ua );
161
+ var useKeyPress = root.opera || (/mozilla/i.test( ua ) && !(/(compatible|webkit)/i).test( ua ));
157
162
  return useKeyPress ? 'keypress' : 'keydown';
158
163
  };
159
164
 
@@ -213,11 +218,13 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
213
218
  nextIndex = -1;
214
219
  if (e.which == 38 || e.keyCode == 38) { // UP
215
220
  nextIndex = Math.max(0, this._lastClickIndex - 1);
221
+ e.preventDefault();
216
222
  } else if (e.which == 40 || e.keyCode == 40) { // DOWN
217
223
  nextIndex = Math.min(this._data.length-1, this._lastClickIndex + 1);
224
+ e.preventDefault();
218
225
  }
219
226
  if (nextIndex > -1 && nextIndex != this._lastClickIndex) {
220
- if (e.shiftKey) {
227
+ if (e.shiftKey && this._multiselect) {
221
228
  if (this.isSelected(nextIndex)) {
222
229
  this._toggleSelection(this._lastClickIndex);
223
230
  } else {
@@ -227,7 +234,6 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
227
234
  this.selectedIndex(nextIndex);
228
235
  }
229
236
  this._lastClickIndex = nextIndex;
230
- e.preventDefault();
231
237
  }
232
238
  };
233
239
 
@@ -264,11 +270,13 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
264
270
  var maxY, minY;
265
271
  maxY = (position+1)*this._rowHeight;
266
272
  minY = position*this._rowHeight;
273
+ updatingScroll = true;
267
274
  if (maxY >= this._visibleRect.maxY()) {
268
275
  this._scrollableParent.scroll(0, maxY - this._visibleRect.maxY());
269
276
  } else if (minY < this._visibleRect.y) {
270
277
  this._scrollableParent.scroll(0, minY - this._visibleRect.y);
271
278
  }
279
+ updatingScroll = false;
272
280
  this.layout();
273
281
  };
274
282
 
@@ -326,17 +334,6 @@ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Ba
326
334
  this._packs[1] = tmp;
327
335
  };
328
336
 
329
- this._normalizeRect = function(rect) {
330
- rect = Base._normalizeRect.call(this, rect);
331
- // if (rect.height != this._rowHeight * this._data.length) {
332
- // rect = new Rect(rect.x, rect.y, rect.width, this._rowHeight * this._data.length);
333
- // }
334
- if (rect.height < this._rowHeight * this._data.length) {
335
- rect = new Rect(rect.x, rect.y, rect.width, this._rowHeight * this._data.length);
336
- }
337
- return rect;
338
- };
339
-
340
337
  this._layoutDom = function(rect) {
341
338
  if (!this._scrollableParent) {
342
339
  this._scrollableParent = uki.view.scrollableParent(this);