uki 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. data/.gitignore +7 -0
  2. data/.gitmodules +3 -0
  3. data/LICENSE +20 -0
  4. data/Rakefile +23 -0
  5. data/Readme.rdoc +9 -0
  6. data/VERSION +1 -0
  7. data/bin/uki +102 -0
  8. data/frameworks/jspec/lib/images/bg.png +0 -0
  9. data/frameworks/jspec/lib/images/hr.png +0 -0
  10. data/frameworks/jspec/lib/images/loading.gif +0 -0
  11. data/frameworks/jspec/lib/images/sprites.bg.png +0 -0
  12. data/frameworks/jspec/lib/images/sprites.png +0 -0
  13. data/frameworks/jspec/lib/images/vr.png +0 -0
  14. data/frameworks/jspec/lib/jspec.css +149 -0
  15. data/frameworks/jspec/lib/jspec.growl.js +115 -0
  16. data/frameworks/jspec/lib/jspec.jquery.js +72 -0
  17. data/frameworks/jspec/lib/jspec.js +1756 -0
  18. data/frameworks/jspec/lib/jspec.shell.js +39 -0
  19. data/frameworks/jspec/lib/jspec.timers.js +90 -0
  20. data/frameworks/jspec/lib/jspec.xhr.js +195 -0
  21. data/frameworks/uki/README.rdoc +179 -0
  22. data/frameworks/uki/compiler.jar +0 -0
  23. data/frameworks/uki/run.rb +2 -0
  24. data/frameworks/uki/spec/commands/example_command.rb +19 -0
  25. data/frameworks/uki/spec/dom.html +39 -0
  26. data/frameworks/uki/spec/support/images/bg.png +0 -0
  27. data/frameworks/uki/spec/support/images/hr.png +0 -0
  28. data/frameworks/uki/spec/support/images/loading.gif +0 -0
  29. data/frameworks/uki/spec/support/images/sprites.bg.png +0 -0
  30. data/frameworks/uki/spec/support/images/sprites.png +0 -0
  31. data/frameworks/uki/spec/support/images/vr.png +0 -0
  32. data/frameworks/uki/spec/support/jspec.css +149 -0
  33. data/frameworks/uki/spec/support/jspec.js +1773 -0
  34. data/frameworks/uki/spec/support/jspec.xhr.js +193 -0
  35. data/frameworks/uki/spec/support/spec.helper.js +1 -0
  36. data/frameworks/uki/spec/unit/background.spec.js +29 -0
  37. data/frameworks/uki/spec/unit/builder.spec.js +51 -0
  38. data/frameworks/uki/spec/unit/data/model.spec.js +29 -0
  39. data/frameworks/uki/spec/unit/dom/dnd.spec.js +71 -0
  40. data/frameworks/uki/spec/unit/dom/event.spec.js +78 -0
  41. data/frameworks/uki/spec/unit/dom.spec.js +28 -0
  42. data/frameworks/uki/spec/unit/geometry.spec.js +79 -0
  43. data/frameworks/uki/spec/unit/selector.spec.js +140 -0
  44. data/frameworks/uki/spec/unit/theme/template.spec.js +31 -0
  45. data/frameworks/uki/spec/unit/utils.spec.js +176 -0
  46. data/frameworks/uki/spec/unit/view/base.spec.js +86 -0
  47. data/frameworks/uki/spec/unit/view/container.spec.js +73 -0
  48. data/frameworks/uki/spec/unit/view.spec.js +13 -0
  49. data/frameworks/uki/src/airport.js +1 -0
  50. data/frameworks/uki/src/uki-core/attachment.js +175 -0
  51. data/frameworks/uki/src/uki-core/background/css.js +37 -0
  52. data/frameworks/uki/src/uki-core/background/cssBox.js +73 -0
  53. data/frameworks/uki/src/uki-core/background/multi.js +20 -0
  54. data/frameworks/uki/src/uki-core/background/null.js +10 -0
  55. data/frameworks/uki/src/uki-core/background/rows.js +77 -0
  56. data/frameworks/uki/src/uki-core/background/sliced9.js +206 -0
  57. data/frameworks/uki/src/uki-core/background.js +35 -0
  58. data/frameworks/uki/src/uki-core/builder.js +68 -0
  59. data/frameworks/uki/src/uki-core/collection.js +278 -0
  60. data/frameworks/uki/src/uki-core/const.js +17 -0
  61. data/frameworks/uki/src/uki-core/dom/dnd.js +93 -0
  62. data/frameworks/uki/src/uki-core/dom/event.js +194 -0
  63. data/frameworks/uki/src/uki-core/dom/nativeLayout.js +18 -0
  64. data/frameworks/uki/src/uki-core/dom/offset.js +130 -0
  65. data/frameworks/uki/src/uki-core/dom/w3cdnd.js +333 -0
  66. data/frameworks/uki/src/uki-core/dom.js +109 -0
  67. data/frameworks/uki/src/uki-core/geometry.js +658 -0
  68. data/frameworks/uki/src/uki-core/image.js +90 -0
  69. data/frameworks/uki/src/uki-core/selector.js +201 -0
  70. data/frameworks/uki/src/uki-core/theme/base.js +39 -0
  71. data/frameworks/uki/src/uki-core/theme/template.js +26 -0
  72. data/frameworks/uki/src/uki-core/theme.js +45 -0
  73. data/frameworks/uki/src/uki-core/uki.js +45 -0
  74. data/frameworks/uki/src/uki-core/utils.js +399 -0
  75. data/frameworks/uki/src/uki-core/view/base.js +480 -0
  76. data/frameworks/uki/src/uki-core/view/container.js +155 -0
  77. data/frameworks/uki/src/uki-core/view/focusable.js +93 -0
  78. data/frameworks/uki/src/uki-core/view/observable.js +66 -0
  79. data/frameworks/uki/src/uki-core/view/styleable.js +70 -0
  80. data/frameworks/uki/src/uki-core/view/utils.js +66 -0
  81. data/frameworks/uki/src/uki-core/view.js +21 -0
  82. data/frameworks/uki/src/uki-core.js +36 -0
  83. data/frameworks/uki/src/uki-data/data.js +1 -0
  84. data/frameworks/uki/src/uki-data/model.js +28 -0
  85. data/frameworks/uki/src/uki-data/observable.js +34 -0
  86. data/frameworks/uki/src/uki-data.js +1 -0
  87. data/frameworks/uki/src/uki-more/more/utils.js +20 -0
  88. data/frameworks/uki/src/uki-more/more/view/listContainer.js +4 -0
  89. data/frameworks/uki/src/uki-more/more/view/multiselectList.js +196 -0
  90. data/frameworks/uki/src/uki-more/more/view/radioButton.js +27 -0
  91. data/frameworks/uki/src/uki-more/more/view/splitTable.js +79 -0
  92. data/frameworks/uki/src/uki-more/more/view/toggleButton.js +24 -0
  93. data/frameworks/uki/src/uki-more/more/view/treeList/render.js +53 -0
  94. data/frameworks/uki/src/uki-more/more/view/treeList.js +110 -0
  95. data/frameworks/uki/src/uki-more/more/view.js +2 -0
  96. data/frameworks/uki/src/uki-more/more.js +1 -0
  97. data/frameworks/uki/src/uki-more.js +4 -0
  98. data/frameworks/uki/src/uki-theamless.js +15 -0
  99. data/frameworks/uki/src/uki-theme/airport/i/button/down-c.gif +0 -0
  100. data/frameworks/uki/src/uki-theme/airport/i/button/down-c.png +0 -0
  101. data/frameworks/uki/src/uki-theme/airport/i/button/down-h.gif +0 -0
  102. data/frameworks/uki/src/uki-theme/airport/i/button/down-h.png +0 -0
  103. data/frameworks/uki/src/uki-theme/airport/i/button/down-m.png +0 -0
  104. data/frameworks/uki/src/uki-theme/airport/i/button/down-v.png +0 -0
  105. data/frameworks/uki/src/uki-theme/airport/i/button/focusRing-c.png +0 -0
  106. data/frameworks/uki/src/uki-theme/airport/i/button/focusRing-h.png +0 -0
  107. data/frameworks/uki/src/uki-theme/airport/i/button/focusRing-m.png +0 -0
  108. data/frameworks/uki/src/uki-theme/airport/i/button/focusRing-v.png +0 -0
  109. data/frameworks/uki/src/uki-theme/airport/i/button/focusRing.png +0 -0
  110. data/frameworks/uki/src/uki-theme/airport/i/button/hover-c.gif +0 -0
  111. data/frameworks/uki/src/uki-theme/airport/i/button/hover-c.png +0 -0
  112. data/frameworks/uki/src/uki-theme/airport/i/button/hover-h.gif +0 -0
  113. data/frameworks/uki/src/uki-theme/airport/i/button/hover-h.png +0 -0
  114. data/frameworks/uki/src/uki-theme/airport/i/button/hover-m.png +0 -0
  115. data/frameworks/uki/src/uki-theme/airport/i/button/hover-v.png +0 -0
  116. data/frameworks/uki/src/uki-theme/airport/i/button/hover.png +0 -0
  117. data/frameworks/uki/src/uki-theme/airport/i/button/normal-c.gif +0 -0
  118. data/frameworks/uki/src/uki-theme/airport/i/button/normal-c.png +0 -0
  119. data/frameworks/uki/src/uki-theme/airport/i/button/normal-h.gif +0 -0
  120. data/frameworks/uki/src/uki-theme/airport/i/button/normal-h.png +0 -0
  121. data/frameworks/uki/src/uki-theme/airport/i/button/normal-m.png +0 -0
  122. data/frameworks/uki/src/uki-theme/airport/i/button/normal-v.png +0 -0
  123. data/frameworks/uki/src/uki-theme/airport/i/button/normal.png +0 -0
  124. data/frameworks/uki/src/uki-theme/airport/i/checkbox/checkbox.png +0 -0
  125. data/frameworks/uki/src/uki-theme/airport/i/checkbox/focus.png +0 -0
  126. data/frameworks/uki/src/uki-theme/airport/i/checkbox/normal.gif +0 -0
  127. data/frameworks/uki/src/uki-theme/airport/i/checkbox/normal.png +0 -0
  128. data/frameworks/uki/src/uki-theme/airport/i/panel/dark-h.gif +0 -0
  129. data/frameworks/uki/src/uki-theme/airport/i/panel/dark-h.png +0 -0
  130. data/frameworks/uki/src/uki-theme/airport/i/panel/dark-m.png +0 -0
  131. data/frameworks/uki/src/uki-theme/airport/i/panel/dark.png +0 -0
  132. data/frameworks/uki/src/uki-theme/airport/i/popup/normal.png +0 -0
  133. data/frameworks/uki/src/uki-theme/airport/i/radio/focus.png +0 -0
  134. data/frameworks/uki/src/uki-theme/airport/i/radio/normal.gif +0 -0
  135. data/frameworks/uki/src/uki-theme/airport/i/radio/normal.png +0 -0
  136. data/frameworks/uki/src/uki-theme/airport/i/radio/radio.png +0 -0
  137. data/frameworks/uki/src/uki-theme/airport/i/shadow/large-c.png +0 -0
  138. data/frameworks/uki/src/uki-theme/airport/i/shadow/large-h.png +0 -0
  139. data/frameworks/uki/src/uki-theme/airport/i/shadow/large-m.png +0 -0
  140. data/frameworks/uki/src/uki-theme/airport/i/shadow/large-v.png +0 -0
  141. data/frameworks/uki/src/uki-theme/airport/i/shadow/large.png +0 -0
  142. data/frameworks/uki/src/uki-theme/airport/i/slider/bar-m.gif +0 -0
  143. data/frameworks/uki/src/uki-theme/airport/i/slider/bar-m.png +0 -0
  144. data/frameworks/uki/src/uki-theme/airport/i/slider/bar-v.gif +0 -0
  145. data/frameworks/uki/src/uki-theme/airport/i/slider/bar-v.png +0 -0
  146. data/frameworks/uki/src/uki-theme/airport/i/slider/bar.png +0 -0
  147. data/frameworks/uki/src/uki-theme/airport/i/slider/focus.png +0 -0
  148. data/frameworks/uki/src/uki-theme/airport/i/slider/handle.gif +0 -0
  149. data/frameworks/uki/src/uki-theme/airport/i/splitPane/horizontal.gif +0 -0
  150. data/frameworks/uki/src/uki-theme/airport/i/splitPane/horizontal.png +0 -0
  151. data/frameworks/uki/src/uki-theme/airport/i/splitPane/vertical.gif +0 -0
  152. data/frameworks/uki/src/uki-theme/airport/i/x.gif +0 -0
  153. data/frameworks/uki/src/uki-theme/airport.js +322 -0
  154. data/frameworks/uki/src/uki-theme/aristo/i/button/down-c.gif +0 -0
  155. data/frameworks/uki/src/uki-theme/aristo/i/button/down-c.png +0 -0
  156. data/frameworks/uki/src/uki-theme/aristo/i/button/down-h.png +0 -0
  157. data/frameworks/uki/src/uki-theme/aristo/i/button/down-m.png +0 -0
  158. data/frameworks/uki/src/uki-theme/aristo/i/button/down-v.png +0 -0
  159. data/frameworks/uki/src/uki-theme/aristo/i/button/down.png +0 -0
  160. data/frameworks/uki/src/uki-theme/aristo/i/button/focusRing-c.png +0 -0
  161. data/frameworks/uki/src/uki-theme/aristo/i/button/focusRing-h.png +0 -0
  162. data/frameworks/uki/src/uki-theme/aristo/i/button/focusRing-m.png +0 -0
  163. data/frameworks/uki/src/uki-theme/aristo/i/button/focusRing-v.png +0 -0
  164. data/frameworks/uki/src/uki-theme/aristo/i/button/focusRing.png +0 -0
  165. data/frameworks/uki/src/uki-theme/aristo/i/button/normal-c.gif +0 -0
  166. data/frameworks/uki/src/uki-theme/aristo/i/button/normal-c.png +0 -0
  167. data/frameworks/uki/src/uki-theme/aristo/i/button/normal-h.png +0 -0
  168. data/frameworks/uki/src/uki-theme/aristo/i/button/normal-m.png +0 -0
  169. data/frameworks/uki/src/uki-theme/aristo/i/button/normal-v.png +0 -0
  170. data/frameworks/uki/src/uki-theme/aristo/i/button/normal.png +0 -0
  171. data/frameworks/uki/src/uki-theme/aristo/i/checkbox/focus.png +0 -0
  172. data/frameworks/uki/src/uki-theme/aristo/i/checkbox/normal.gif +0 -0
  173. data/frameworks/uki/src/uki-theme/aristo/i/checkbox/normal.png +0 -0
  174. data/frameworks/uki/src/uki-theme/aristo/i/panel/normal-h.png +0 -0
  175. data/frameworks/uki/src/uki-theme/aristo/i/panel/normal-m.png +0 -0
  176. data/frameworks/uki/src/uki-theme/aristo/i/panel/normal.png +0 -0
  177. data/frameworks/uki/src/uki-theme/aristo/i/popup/normal.png +0 -0
  178. data/frameworks/uki/src/uki-theme/aristo/i/radio/focus.png +0 -0
  179. data/frameworks/uki/src/uki-theme/aristo/i/radio/normal.gif +0 -0
  180. data/frameworks/uki/src/uki-theme/aristo/i/radio/normal.png +0 -0
  181. data/frameworks/uki/src/uki-theme/aristo/i/shadow/large-c.png +0 -0
  182. data/frameworks/uki/src/uki-theme/aristo/i/shadow/large-h.png +0 -0
  183. data/frameworks/uki/src/uki-theme/aristo/i/shadow/large-m.png +0 -0
  184. data/frameworks/uki/src/uki-theme/aristo/i/shadow/large-v.png +0 -0
  185. data/frameworks/uki/src/uki-theme/aristo/i/shadow/large.png +0 -0
  186. data/frameworks/uki/src/uki-theme/aristo/i/slider/bar-m.gif +0 -0
  187. data/frameworks/uki/src/uki-theme/aristo/i/slider/bar-m.png +0 -0
  188. data/frameworks/uki/src/uki-theme/aristo/i/slider/bar-v.gif +0 -0
  189. data/frameworks/uki/src/uki-theme/aristo/i/slider/bar-v.png +0 -0
  190. data/frameworks/uki/src/uki-theme/aristo/i/slider/bar.png +0 -0
  191. data/frameworks/uki/src/uki-theme/aristo/i/slider/handle.gif +0 -0
  192. data/frameworks/uki/src/uki-theme/aristo/i/slider/handle.png +0 -0
  193. data/frameworks/uki/src/uki-theme/aristo/i/splitPane/horizontal.gif +0 -0
  194. data/frameworks/uki/src/uki-theme/aristo/i/splitPane/horizontal.png +0 -0
  195. data/frameworks/uki/src/uki-theme/aristo/i/splitPane/vertical.gif +0 -0
  196. data/frameworks/uki/src/uki-theme/aristo/i/x.gif +0 -0
  197. data/frameworks/uki/src/uki-theme/aristo.js +217 -0
  198. data/frameworks/uki/src/uki-view/view/box.js +1 -0
  199. data/frameworks/uki/src/uki-view/view/button.js +126 -0
  200. data/frameworks/uki/src/uki-view/view/checkbox.js +36 -0
  201. data/frameworks/uki/src/uki-view/view/flow.js +48 -0
  202. data/frameworks/uki/src/uki-view/view/image.js +9 -0
  203. data/frameworks/uki/src/uki-view/view/label.js +123 -0
  204. data/frameworks/uki/src/uki-view/view/list/render.js +23 -0
  205. data/frameworks/uki/src/uki-view/view/list.js +442 -0
  206. data/frameworks/uki/src/uki-view/view/popup.js +113 -0
  207. data/frameworks/uki/src/uki-view/view/radio.js +57 -0
  208. data/frameworks/uki/src/uki-view/view/scrollPane.js +139 -0
  209. data/frameworks/uki/src/uki-view/view/slider.js +154 -0
  210. data/frameworks/uki/src/uki-view/view/splitPane.js +213 -0
  211. data/frameworks/uki/src/uki-view/view/table/column.js +96 -0
  212. data/frameworks/uki/src/uki-view/view/table/header.js +53 -0
  213. data/frameworks/uki/src/uki-view/view/table/render.js +25 -0
  214. data/frameworks/uki/src/uki-view/view/table.js +71 -0
  215. data/frameworks/uki/src/uki-view/view/textField.js +145 -0
  216. data/frameworks/uki/src/uki-view/view/toolbar.js +93 -0
  217. data/frameworks/uki/src/uki-view.js +15 -0
  218. data/frameworks/uki/src/uki.js +2 -0
  219. data/frameworks/uki/thin.yaml +11 -0
  220. data/frameworks/uki/uki.rb +38 -0
  221. data/frameworks/uki/uki.ru +2 -0
  222. data/lib/uki/include_js.rb +50 -0
  223. data/lib/uki/project.rb +207 -0
  224. data/lib/uki/routes.rb +20 -0
  225. data/lib/uki/server.rb +42 -0
  226. data/lib/uki.rb +9 -0
  227. data/templates/index.html.erb +10 -0
  228. data/templates/model.js.erb +5 -0
  229. data/templates/myapp.js.erb +44 -0
  230. data/templates/package.js.erb +3 -0
  231. data/templates/spec.html.erb +23 -0
  232. data/templates/spec.js.erb +6 -0
  233. data/templates/view.js.erb +10 -0
  234. data/uki.gemspec +281 -0
  235. metadata +317 -0
@@ -0,0 +1,442 @@
1
+ include('scrollPane.js');
2
+
3
+ uki.view.list = {};
4
+ uki.view.declare('uki.view.List', uki.view.Base, uki.view.Focusable, function(Base, Focusable) {
5
+
6
+ this._throttle = 5; // do not try to render more often than every 5ms
7
+ this._visibleRectExt = 300; // extend visible rect by 300 px overflow
8
+ this._defaultBackground = 'theme(list)';
9
+
10
+ this._setup = function() {
11
+ Base._setup.call(this);
12
+ uki.extend(this, {
13
+ _rowHeight: 30,
14
+ _render: new uki.view.list.Render(),
15
+ _data: [],
16
+ _lastClickIndex: -1,
17
+ _selectedIndexes: []
18
+ });
19
+ };
20
+
21
+ this.defaultBackground = function() {
22
+ return uki.theme.background('list', this._rowHeight);
23
+ };
24
+
25
+ uki.addProps(this, ['render', 'packSize', 'visibleRectExt', 'throttle', 'contentDraggable', 'lastClickIndex', 'multiselect']);
26
+
27
+ this.rowHeight = uki.newProp('_rowHeight', function(val) {
28
+ this._rowHeight = val;
29
+ if (this._background) this._background.detach();
30
+ this._background = null;
31
+ if (this.background()) this.background().attachTo(this);
32
+ });
33
+
34
+ this.data = function(d) {
35
+ if (d === undefined) return this._data;
36
+ this.clearSelection();
37
+ this._data = d;
38
+ this._packs[0].itemFrom = this._packs[0].itemTo = this._packs[1].itemFrom = this._packs[1].itemTo = 0;
39
+ this._updateRectOnDataChnage();
40
+ this._relayoutParent();
41
+ return this;
42
+ };
43
+
44
+ this.addRow = function(position, data) {
45
+ this.clearSelection();
46
+ this._data.splice(position, 0, data);
47
+ this.data(this._data);
48
+ };
49
+
50
+ this.removeRow = function(position, data) {
51
+ this.clearSelection();
52
+ this._data.splice(position, 1);
53
+ this.data(this._data);
54
+ };
55
+
56
+ this.selectedIndex = function(position) {
57
+ if (position === undefined) return this._selectedIndexes.length ? this._selectedIndexes[0] : -1;
58
+ this.selectedIndexes([position]);
59
+ this._scrollToPosition(position);
60
+ return this;
61
+ };
62
+
63
+ this.selectedIndexes = function(indexes) {
64
+ if (indexes === undefined) return this._selectedIndexes;
65
+ this.clearSelection(true);
66
+ this._selectedIndexes = indexes;
67
+ for (var i=0; i < this._selectedIndexes.length; i++) {
68
+ this._setSelected(this._selectedIndexes[i], true);
69
+ };
70
+ this.trigger('selection', {source: this});
71
+ return this;
72
+ };
73
+
74
+ this.selectedRows = function() {
75
+ return uki.map(this.selectedIndexes(), function(index) {
76
+ return this._data[index];
77
+ }, this)
78
+ };
79
+
80
+ this.clearSelection = function(skipClickIndex) {
81
+ for (var i=0; i < this._selectedIndexes.length; i++) {
82
+ this._setSelected(this._selectedIndexes[i], false);
83
+ };
84
+ this._selectedIndexes = [];
85
+ if (!skipClickIndex) this._lastClickIndex = -1;
86
+ };
87
+
88
+ this.isSelected = function(index) {
89
+ var found = uki.binarySearch(index, this._selectedIndexes);
90
+ return this._selectedIndexes[found] == index;
91
+ };
92
+
93
+ this.layout = function() {
94
+ this._layoutDom(this._rect);
95
+ this._needsLayout = false;
96
+ // send visibleRect with layout
97
+ this.trigger('layout', { rect: this._rect, source: this, visibleRect: this._visibleRect });
98
+ this._firstLayout = false;
99
+ };
100
+
101
+ function range (from, to) {
102
+ var result = new Array(to - from);
103
+ for (var idx = 0; from <= to; from++, idx++) {
104
+ result[idx] = from;
105
+ };
106
+ return result;
107
+ }
108
+
109
+ function removeRange (array, from, to) {
110
+ var p = uki.binarySearch(from, array),
111
+ initialP = p;
112
+ while (array[p] <= to) p++;
113
+ if (p > initialP) array.splice(initialP, p - initialP);
114
+ }
115
+
116
+ this._toggleSelection = function(p) {
117
+ var indexes = [].concat(this._selectedIndexes);
118
+ var addTo = uki.binarySearch(p, indexes);
119
+ if (indexes[addTo] == p) {
120
+ indexes.splice(addTo, 1);
121
+ } else {
122
+ indexes.splice(addTo, 0, p);
123
+ }
124
+ this.selectedIndexes(indexes);
125
+ };
126
+
127
+ this._scrollableParentScroll = function() {
128
+ if (this._throttle) {
129
+ if (this._throttleStarted) return;
130
+ this._throttleStarted = true;
131
+ setTimeout(uki.proxy(function() {
132
+ this._throttleStarted = false;
133
+ this.layout();
134
+ }, this), this._throttle);
135
+ } else {
136
+ this.layout();
137
+ }
138
+ };
139
+
140
+ this._relayoutParent = function() {
141
+ if (!this._scrollableParent) return;
142
+ var c = this;
143
+ while ( c && c != this._scrollableParent) {
144
+ c._needsLayout = true;
145
+ c = c.parent();
146
+ }
147
+ c.layout();
148
+ };
149
+
150
+
151
+ this._updateRectOnDataChnage = function() {
152
+ this.rect(this._parentRect);
153
+ };
154
+
155
+ this.keyPressEvent = function() {
156
+ var useKeyPress = /mozilla/i.test( ua ) && !(/(compatible|webkit)/i).test( ua );
157
+ return useKeyPress ? 'keypress' : 'keydown';
158
+ };
159
+
160
+ this._bindSelectionEvents = function() {
161
+ this.bind('mousedown', this._mousedown);
162
+ this.bind('mouseup', this._mouseup);
163
+ this.bind(this.keyPressEvent(), this._keypress);
164
+ };
165
+
166
+ this._mouseup = function(e) {
167
+ if (!this._multiselect) return;
168
+
169
+ var o = uki.dom.offset(this._dom),
170
+ y = e.pageY - o.y,
171
+ p = y / this._rowHeight << 0;
172
+
173
+ if (this._selectionInProcess && this._lastClickIndex == p && this.isSelected(p)) this.selectedIndexes([p]);
174
+ this._selectionInProcess = false;
175
+ };
176
+
177
+ this._mousedown = function(e) {
178
+ var o = uki.dom.offset(this._dom),
179
+ y = e.pageY - o.y,
180
+ p = y / this._rowHeight << 0,
181
+ indexes = this._selectedIndexes;
182
+
183
+ if (this._multiselect) {
184
+ this._selectionInProcess = false;
185
+ if (e.shiftKey && indexes.length > 0) {
186
+ if (this.isSelected(p)) {
187
+ indexes = [].concat(indexes);
188
+ removeRange(indexes, Math.min(p+1, this._lastClickIndex), Math.max(p-1, this._lastClickIndex));
189
+ this.selectedIndexes(indexes);
190
+ } else {
191
+ this.selectedIndexes(range(
192
+ Math.min(p, indexes[0]),
193
+ Math.max(p, indexes[indexes.length - 1])
194
+ ));
195
+ }
196
+ } else if (e.metaKey) {
197
+ this._toggleSelection(p);
198
+ } else {
199
+ if (!this.isSelected(p)) {
200
+ this.selectedIndexes([p]);
201
+ } else {
202
+ this._selectionInProcess = true;
203
+ }
204
+ }
205
+ } else {
206
+ this.selectedIndexes([p]);
207
+ }
208
+ this._lastClickIndex = p;
209
+ };
210
+
211
+ this._keypress = function(e) {
212
+ var indexes = this._selectedIndexes,
213
+ nextIndex = -1;
214
+ if (e.which == 38 || e.keyCode == 38) { // UP
215
+ nextIndex = Math.max(0, this._lastClickIndex - 1);
216
+ } else if (e.which == 40 || e.keyCode == 40) { // DOWN
217
+ nextIndex = Math.min(this._data.length-1, this._lastClickIndex + 1);
218
+ }
219
+ if (nextIndex > -1 && nextIndex != this._lastClickIndex) {
220
+ if (e.shiftKey) {
221
+ if (this.isSelected(nextIndex)) {
222
+ this._toggleSelection(this._lastClickIndex);
223
+ } else {
224
+ this._toggleSelection(nextIndex);
225
+ }
226
+ } else {
227
+ this.selectedIndex(nextIndex);
228
+ }
229
+ this._lastClickIndex = nextIndex;
230
+ e.preventDefault();
231
+ }
232
+ };
233
+
234
+ this._createDom = function() {
235
+ this._dom = uki.createElement('div', this.defaultCss + 'overflow:hidden');
236
+
237
+ var packDom = uki.createElement('div', 'position:absolute;left:0;top:0px;width:100%;overflow:hidden');
238
+ this._packs = [
239
+ {
240
+ dom: packDom,
241
+ itemTo: 0,
242
+ itemFrom: 0
243
+ },
244
+ {
245
+ dom: packDom.cloneNode(false),
246
+ itemTo: 0,
247
+ itemFrom: 0
248
+ }
249
+ ];
250
+ this._dom.appendChild(this._packs[0].dom);
251
+ this._dom.appendChild(this._packs[1].dom);
252
+
253
+ this._initFocusable();
254
+ this._bindSelectionEvents();
255
+ };
256
+
257
+ this._setSelected = function(position, state) {
258
+ var item = this._itemAt(position);
259
+ if (item) this._render.setSelected(item, this._data[position], state, this.hasFocus());
260
+ };
261
+
262
+ this._scrollToPosition = function(position) {
263
+ if (!this._visibleRect) return;
264
+ var maxY, minY;
265
+ maxY = (position+1)*this._rowHeight;
266
+ minY = position*this._rowHeight;
267
+ if (maxY >= this._visibleRect.maxY()) {
268
+ this._scrollableParent.scroll(0, maxY - this._visibleRect.maxY());
269
+ } else if (minY < this._visibleRect.y) {
270
+ this._scrollableParent.scroll(0, minY - this._visibleRect.y);
271
+ }
272
+ this.layout();
273
+ };
274
+
275
+ this._itemAt = function(position) {
276
+ if (position < this._packs[1].itemTo && position >= this._packs[1].itemFrom) {
277
+ return this._packs[1].dom.childNodes[position - this._packs[1].itemFrom];
278
+ } else if (position < this._packs[0].itemTo && position >= this._packs[0].itemFrom) {
279
+ return this._packs[0].dom.childNodes[position - this._packs[0].itemFrom];
280
+ }
281
+ return null;
282
+ };
283
+
284
+ this._rowTemplate = new uki.theme.Template('<div style="width:100%;height:${height}px;overflow:hidden;">${text}</div>')
285
+
286
+ this._renderPack = function(pack, itemFrom, itemTo) {
287
+ var html = [], position,
288
+ rect = new Rect(0, itemFrom*this._rowHeight, this.rect().width, this._rowHeight);
289
+ for (i=itemFrom; i < itemTo; i++) {
290
+ html[html.length] = this._rowTemplate.render({
291
+ height: this._rowHeight,
292
+ text: this._render.render(this._data[i], rect, i)
293
+ });
294
+ rect.y += this._rowHeight;
295
+ };
296
+ pack.dom.innerHTML = html.join('');
297
+ pack.itemFrom = itemFrom;
298
+ pack.itemTo = itemTo;
299
+ pack.dom.style.top = itemFrom*this._rowHeight + 'px';
300
+ this._restorePackSelection(pack, itemFrom, itemTo);
301
+ };
302
+
303
+ // xxxxx | xxxxx | xxxxxxxx | xxx
304
+ // yyyyy | yyyyy | yyyy | yyyyyyy
305
+ this._restorePackSelection = function(pack) {
306
+ var indexes = this._selectedIndexes;
307
+
308
+ if (
309
+ (indexes[0] <= pack.itemFrom && indexes[indexes.length - 1] >= pack.itemFrom) || // left index
310
+ (indexes[0] <= pack.itemTo && indexes[indexes.length - 1] >= pack.itemTo) || // right index
311
+ (indexes[0] >= pack.itemFrom && indexes[indexes.length - 1] <= pack.itemTo) // within
312
+ ) {
313
+ var currentSelection = uki.binarySearch(pack.itemFrom, indexes);
314
+ currentSelection = Math.max(currentSelection, 0);
315
+ while(indexes[currentSelection] !== null && indexes[currentSelection] < pack.itemTo) {
316
+ var position = indexes[currentSelection] - pack.itemFrom;
317
+ this._render.setSelected(pack.dom.childNodes[position], this._data[position], true, this.hasFocus());
318
+ currentSelection++;
319
+ }
320
+ }
321
+ };
322
+
323
+ this._swapPacks = function() {
324
+ var tmp = this._packs[0];
325
+ this._packs[0] = this._packs[1];
326
+ this._packs[1] = tmp;
327
+ };
328
+
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
+ this._layoutDom = function(rect) {
341
+ if (!this._scrollableParent) {
342
+ this._scrollableParent = uki.view.scrollableParent(this);
343
+ this._scrollableParent.bind('scroll', uki.proxy(this._scrollableParentScroll, this));
344
+ }
345
+
346
+ var totalHeight = this._rowHeight * this._data.length,
347
+ scrollableParent = this._scrollableParent;
348
+
349
+ this._visibleRect = uki.view.visibleRect(this, scrollableParent);
350
+
351
+ var prefferedPackSize = CEIL((this._visibleRect.height + this._visibleRectExt*2) / this._rowHeight),
352
+
353
+ minVisibleY = MAX(0, this._visibleRect.y - this._visibleRectExt),
354
+ maxVisibleY = MIN(totalHeight, this._visibleRect.maxY() + this._visibleRectExt),
355
+ minRenderedY = this._packs[0].itemFrom * this._rowHeight,
356
+ maxRenderedY = this._packs[1].itemTo * this._rowHeight,
357
+
358
+ itemFrom, itemTo, startAt, updated = true;
359
+
360
+ Base._layoutDom.call(this, rect);
361
+
362
+ if (
363
+ maxVisibleY <= minRenderedY || minVisibleY >= maxRenderedY || // both packs below/above visible area
364
+ (maxVisibleY > maxRenderedY && this._packs[1].itemFrom * this._rowHeight > this._visibleRect.y && this._packs[1].itemTo > this._packs[1].itemFrom) || // need to render below, and pack 2 is not enough to cover
365
+ (minVisibleY < minRenderedY && this._packs[0].itemTo * this._rowHeight < this._visibleRect.maxY()) // need to render above, and pack 1 is not enough to cover the area
366
+ // || prefferedPackSize is not enough to cover the area above/below, can this actually happen?
367
+ ) {
368
+ // this happens a) on first render b) on scroll jumps c) on container resize
369
+ // render both packs, move them to be at the center of visible area
370
+ // startAt = minVisibleY + (maxVisibleY - minVisibleY - prefferedPackSize*this._rowHeight*2) / 2;
371
+ startAt = minVisibleY - this._visibleRectExt / 2;
372
+ itemFrom = MAX(0, Math.round(startAt / this._rowHeight));
373
+ itemTo = MIN(this._data.length, itemFrom + prefferedPackSize);
374
+
375
+ this._renderPack(this._packs[0], itemFrom, itemTo);
376
+ this._renderPack(this._packs[1], itemTo, itemTo);
377
+ // this._renderPack(this._packs[1], itemTo, MIN(this._data.length, itemTo + prefferedPackSize));
378
+ } else if (maxVisibleY > maxRenderedY && this._packs[1].itemTo > this._packs[1].itemFrom) { // we need to render below current area
379
+ // this happens on normal scroll down
380
+ // re-render bottom, swap
381
+ itemFrom = this._packs[1].itemTo;
382
+ itemTo = MIN(this._data.length, this._packs[1].itemTo + prefferedPackSize);
383
+
384
+ this._renderPack(this._packs[0], itemFrom, itemTo);
385
+ this._swapPacks();
386
+ } else if (maxVisibleY > maxRenderedY) { // we need to render below current area
387
+ itemFrom = this._packs[0].itemTo;
388
+ itemTo = MIN(this._data.length, this._packs[1].itemTo + prefferedPackSize);
389
+
390
+ this._renderPack(this._packs[1], itemFrom, itemTo);
391
+ } else if (minVisibleY < minRenderedY) { // we need to render above current area
392
+ // this happens on normal scroll up
393
+ // re-render top, swap
394
+ itemFrom = MAX(this._packs[0].itemFrom - prefferedPackSize, 0);
395
+ itemTo = this._packs[0].itemFrom;
396
+
397
+ this._renderPack(this._packs[1], itemFrom, itemTo);
398
+ this._swapPacks();
399
+ } else {
400
+ updated = false;
401
+ }
402
+ if (updated && /MSIE 7/.test(ua)) this.dom().className += '';
403
+ };
404
+
405
+ this._bindToDom = function(name) {
406
+ return Focusable._bindToDom.call(this, name) || Base._bindToDom.call(this, name);
407
+ };
408
+
409
+ this._focus = function(e) {
410
+ Focusable._focus.call(this, e);
411
+ if (this._selectedIndexes.length == 0 && this._data.length > 0) {
412
+ this.selectedIndexes([0]);
413
+ } else {
414
+ this.selectedIndexes(this.selectedIndexes());
415
+ }
416
+ };
417
+
418
+ this._blur = function(e) {
419
+ Focusable._blur.call(this, e);
420
+ this.selectedIndexes(this.selectedIndexes());
421
+ };
422
+
423
+ });
424
+
425
+ uki.Collection.addAttrs(['data','selectedIndex']);
426
+
427
+ uki.view.declare('uki.view.ScrollableList', uki.view.ScrollPane, function(Base) {
428
+
429
+ this._createDom = function() {
430
+ Base._createDom.call(this);
431
+ this._list = uki({ view: 'List', rect: this.rect().clone().normalize(), anchors: 'left top right bottom' })[0];
432
+ this.appendChild(this._list);
433
+ };
434
+
435
+ uki.each('data rowHeight render packSize visibleRectExt throttle focusable selectedIndexes selectedIndex selectedIndexes selectedRows multiselect contentDraggable draggable textSelectable'.split(' '),
436
+ function(i, name) {
437
+ uki.delegateProp(this, name, '_list');
438
+ }, this);
439
+
440
+ });
441
+
442
+ include('list/render.js');
@@ -0,0 +1,113 @@
1
+ uki.view.declare('uki.view.Popup', uki.view.Container, function(Base) {
2
+
3
+ this._setup = function() {
4
+ Base._setup.call(this);
5
+ uki.extend(this, {
6
+ _offset: 2,
7
+ _relativeTo: null,
8
+ _horizontal: false,
9
+ _flipOnResize: true,
10
+ _defaultBackground: 'theme(popup-normal)'
11
+ });
12
+ };
13
+
14
+ this._createDom = function() {
15
+ Base._createDom.call(this);
16
+ this.hideOnClick(true);
17
+ };
18
+
19
+ uki.addProps(this, ['offset', 'relativeTo', 'horizontal', 'flipOnResize']);
20
+
21
+ this.hideOnClick = function(state) {
22
+ if (state === undefined) return this._clickHandler;
23
+ if (state != !!this._clickHandler) {
24
+ if (state) {
25
+ this._clickHandler = this._clickHandler || uki.proxy(function(e) {
26
+ if (uki.dom.contains(this._relativeTo.dom(), e.target)) return;
27
+ if (uki.dom.contains(this.dom(), e.target)) return;
28
+ this.hide();
29
+ }, this);
30
+ uki.dom.bind(doc.body, 'mousedown', this._clickHandler);
31
+ uki.dom.bind(root, 'resize', this._clickHandler);
32
+ } else {
33
+ uki.dom.unbind(doc.body, 'mousedown', this._clickHandler);
34
+ uki.dom.unbind(root, 'resize', this._clickHandler);
35
+ this._clickHandler = false;
36
+ }
37
+ }
38
+ return this;
39
+ };
40
+
41
+ this.toggle = function() {
42
+ if (this.parent() && this.visible()) {
43
+ this.hide();
44
+ } else {
45
+ this.show();
46
+ }
47
+ };
48
+
49
+ this.show = function() {
50
+ this.visible(true);
51
+ if (!this.parent()) {
52
+ new uki.Attachment( root, this );
53
+ } else {
54
+ this.rect(this._recalculateRect());
55
+ this.layout(this._rect);
56
+ }
57
+ this.trigger('toggle', { source: this });
58
+ };
59
+
60
+ this.hide = function() {
61
+ this.visible(false);
62
+ this.trigger('toggle', { source: this });
63
+ };
64
+
65
+ this.parentResized = function() {
66
+ this.rect(this._recalculateRect());
67
+ };
68
+
69
+ this._resizeSelf = function(newRect) {
70
+ this._rect = this._normalizeRect(newRect);
71
+ return true;
72
+ };
73
+
74
+ this._layoutDom = function(rect) {
75
+ return Base._layoutDom.call(this, rect);
76
+ };
77
+
78
+ this._recalculateRect = function() {
79
+ if (!this.visible()) return this._rect;
80
+ var relativeOffset = uki.dom.offset(this._relativeTo.dom()),
81
+ relativeRect = this._relativeTo.rect(),
82
+ rect = this.rect().clone(),
83
+ attachment = uki.view.top(this),
84
+ attachmentRect = attachment.rect(),
85
+ attachmentOffset = uki.dom.offset(attachment.dom()),
86
+ position = new Point(),
87
+ hOffset = this._horizontal ? this._offset : 0,
88
+ vOffset = this._horizontal ? 0 : this._offset;
89
+
90
+ relativeOffset.offset(-attachmentOffset.x, -attachmentOffset.y);
91
+
92
+ if (this._anchors & ANCHOR_RIGHT) {
93
+ position.x = relativeOffset.x + relativeRect.width - (this._horizontal ? 0 : rect.width) + hOffset;
94
+ } else {
95
+ position.x = relativeOffset.x - (this._horizontal ? rect.width : 0) - hOffset;
96
+ }
97
+
98
+ if (this._anchors & ANCHOR_BOTTOM) {
99
+ position.y = relativeOffset.y + (this._horizontal ? relativeRect.height : 0) - rect.height - vOffset;
100
+ } else {
101
+ position.y = relativeOffset.y + (this._horizontal ? 0 : relativeRect.height) + vOffset;
102
+ }
103
+
104
+ return new Rect(position.x, position.y, rect.width, rect.height);
105
+ };
106
+ });
107
+
108
+
109
+ uki.each(['show', 'hide', 'toggle'], function(i, name) {
110
+ uki.fn[name] = function() {
111
+ this.each(function() { this[name](); });
112
+ };
113
+ });
@@ -0,0 +1,57 @@
1
+ include('checkbox.js');
2
+
3
+ (function() {
4
+ var manager = uki.view.declare('uki.view.Radio', uki.view.Checkbox, function(base) {
5
+
6
+ this._backgroundPrefix = 'radio-';
7
+
8
+ this.group = uki.newProp('_group', function(g) {
9
+ manager.unregisterGroup(this);
10
+ this._group = g;
11
+ manager.registerGroup(this);
12
+ manager.clearGroup(this);
13
+ });
14
+
15
+ this.value = this.checked = uki.newProp('_checked', function(state) {
16
+ this._checked = !!state;
17
+ if (state) manager.clearGroup(this);
18
+ this._updateBg();
19
+ });
20
+
21
+ this._mouseup = function() {
22
+ if (!this._down) return;
23
+ this._down = false;
24
+ if (!this._checked && !this._disabled) {
25
+ this.checked(!this._checked);
26
+ this.trigger('change', {checked: this._checked, source: this});
27
+ }
28
+ }
29
+ });
30
+
31
+
32
+ manager.groups = {};
33
+
34
+ manager.registerGroup = function(radio) {
35
+ var group = radio.group();
36
+ if (!manager.groups[group]) {
37
+ manager.groups[group] = [radio];
38
+ } else {
39
+ manager.groups[group].push(radio);
40
+ }
41
+ };
42
+
43
+ manager.unregisterGroup = function(radio) {
44
+ var group = radio.group();
45
+ if (manager.groups[group]) manager.groups[group] = uki.grep(manager.groups[group], function(registered) {
46
+ return registered != radio;
47
+ });
48
+ };
49
+
50
+ manager.clearGroup = function(radio) {
51
+ uki.each(manager.groups[radio.group()] || [], function(i, registered) {
52
+ if (registered == radio) return;
53
+ if (registered.checked()) registered.checked(false);
54
+ });
55
+ };
56
+
57
+ })();