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,480 @@
1
+ include('../view.js');
2
+ include('../geometry.js');
3
+ include('../utils.js');
4
+ include('../builder.js');
5
+ include('../dom.js');
6
+ include('../dom/nativeLayout.js');
7
+ include('observable.js');
8
+ include('styleable.js');
9
+
10
+ var ANCHOR_TOP = 1,
11
+ ANCHOR_RIGHT = 2,
12
+ ANCHOR_BOTTOM = 4,
13
+ ANCHOR_LEFT = 8,
14
+ ANCHOR_WIDTH = 16,
15
+ ANCHOR_HEIGHT = 32;
16
+
17
+ uki.view.declare('uki.view.Base', uki.view.Observable, uki.view.Styleable, function(Observable, Styleable) {
18
+
19
+ var layoutId = 1;
20
+
21
+ this.defaultCss = 'position:absolute;z-index:100;-moz-user-focus:none;'
22
+ + 'font-family:Arial,Helvetica,sans-serif;';
23
+
24
+ /**
25
+ * Base class for all uki views.
26
+ *
27
+ * <p>View creates and layouts dom nodes. uki.view.Base defines basic API for other views.
28
+ * It also defines common layout algorithms.</p>
29
+ *
30
+ * Layout
31
+ *
32
+ * <p>View layout is defined by rectangle and anchors.
33
+ * Rectangle is passed to constructor, anchors are set through the #anchors attribute.</p>
34
+ *
35
+ * <p>Rectangle defines initial position and size. Anchors specify how view will move and
36
+ * resize when its parent is resized.</p>
37
+ *
38
+ * 2 phases of layout
39
+ *
40
+ * <p>Layout process has 2 phases.
41
+ * First views rectangles are recalculated. This may happen several times before dom
42
+ * is touched. This is done either explicitly through #rect attribute or through
43
+ * #parentResized callbacks.
44
+ * After rectangles are set #layout is called. This actually updates dom styles.</p>
45
+ *
46
+ * @example
47
+ * uki({ view: 'Base', rect: '10 20 100 50', anchors: 'left top right' })
48
+ * // Creates Base view with initial x = 10px, y = 20px, width = 100px, height = 50px.
49
+ * // When parent resizes x, y and height will stay the same. Width will resize with parent.
50
+ *
51
+ *
52
+ * @see uki.view.Base#anchors
53
+ * @constructor
54
+ * @augments uki.view.Observable
55
+ * @augments uki.view.Styleable
56
+ *
57
+ * @name uki.view.Base
58
+ * @implements uki.view.Observable
59
+ * @param {uki.geometry.Rect} rect initial position and size
60
+ */
61
+ this.init = function(rect) {
62
+ this._parentRect = this._rect = Rect.create(rect);
63
+ this._setup();
64
+ uki.initNativeLayout();
65
+ this._createDom();
66
+ };
67
+
68
+ /**#@+ @memberOf uki.view.Base# */
69
+
70
+ /** @private */
71
+ this._setup = function() {
72
+ uki.extend(this, {
73
+ _anchors: 0,
74
+ _parent: null,
75
+ _visible: true,
76
+ _needsLayout: true,
77
+ _textSelectable: false,
78
+ _styleH: 'left',
79
+ _styleV: 'top',
80
+ _firstLayout: true
81
+ });
82
+ };
83
+
84
+ /**
85
+ * Get views container dom node.
86
+ * @returns {Element} dom
87
+ */
88
+ this.dom = function() {
89
+ return this._dom;
90
+ };
91
+
92
+ /* ------------------------------- Common settings --------------------------------*/
93
+ /**
94
+ * Used for fast (on hash lookup) view searches: uki('#view_id');
95
+ *
96
+ * @param {string=} id New id value
97
+ * @returns {string|uki.view.Base} current id or self
98
+ */
99
+ this.id = function(id) {
100
+ if (id === undefined) return this._dom.id;
101
+ if (this._dom.id) uki.unregisterId(this);
102
+ this._dom.id = id;
103
+ uki.registerId(this);
104
+ return this;
105
+ };
106
+
107
+ /**
108
+ * Accessor for dom().className
109
+ * @param {string=} className
110
+ *
111
+ * @returns {string|uki.view.Base} className or self
112
+ */
113
+ uki.delegateProp(this, 'className', '_dom');
114
+
115
+ /**
116
+ * Accessor for view visibility.
117
+ *
118
+ * @param {boolean=} state
119
+ * @returns {boolean|uki.view.Base} current visibility state of self
120
+ */
121
+ this.visible = function(state) {
122
+ if (state === undefined) return this._dom.style.display != 'none';
123
+
124
+ this._dom.style.display = state ? 'block' : 'none';
125
+ return this;
126
+ };
127
+
128
+ /**
129
+ * Accessor for background attribute.
130
+ * @param {string|uki.background.Base=} background
131
+ * @returns {uki.background.Base|uki.view.Base} current background or self
132
+ */
133
+ this.background = function(val) {
134
+ if (val === undefined && !this._background && this.defaultBackground) this._background = this.defaultBackground();
135
+ if (val === undefined) return this._background;
136
+ val = uki.background(val);
137
+
138
+ if (val == this._background) return this;
139
+ if (this._background) this._background.detach(this);
140
+ val.attachTo(this);
141
+
142
+ this._background = val;
143
+ return this;
144
+ };
145
+
146
+ /**
147
+ * Accessor for default background attribute.
148
+ * @name defaultBackground
149
+ * @function
150
+ * @returns {uki.background.Base} default background if not overridden through attribute
151
+ */
152
+ this.defaultBackground = function() {
153
+ return this._defaultBackground && uki.background(this._defaultBackground);
154
+ };
155
+
156
+ /* ----------------------------- Container api ------------------------------*/
157
+
158
+ /**
159
+ * Accessor attribute for parent view. When parent is set view appends its #dom
160
+ * to parents #domForChild
161
+ *
162
+ * @param {?uki.view.Base=} parent
163
+ * @returns {uki.view.Base} parent or self
164
+ */
165
+ this.parent = function(parent) {
166
+ if (parent === undefined) return this._parent;
167
+
168
+ // if (this._parent) this._dom.parentNode.removeChild(this._dom);
169
+ this._parent = parent;
170
+ // if (this._parent) this._parent.domForChild(this).appendChild(this._dom);
171
+ return this;
172
+ };
173
+
174
+ /**
175
+ * Accessor for childViews. @see uki.view.Container for implementation
176
+ * @returns {Array.<uki.view.Base>}
177
+ */
178
+ this.childViews = function() {
179
+ return [];
180
+ };
181
+
182
+ /**
183
+ * Reader for previous view
184
+ * @returns {uki.view.Base}
185
+ */
186
+ this.prevView = function() {
187
+ if (!this.parent()) return null;
188
+ return this.parent().childViews()[this._viewIndex - 1] || null;
189
+ };
190
+
191
+ /**
192
+ * Reader for next view
193
+ * @returns {uki.view.Base}
194
+ */
195
+ this.nextView = function() {
196
+ if (!this.parent()) return null;
197
+ return this.parent().childViews()[this._viewIndex + 1] || null;
198
+ };
199
+
200
+
201
+ /* ----------------------------- Layout ------------------------------*/
202
+
203
+ /**
204
+ * Sets or retrieves view's position and size.
205
+ *
206
+ * @param {string|uki.geometry.Rect} newRect
207
+ * @returns {uki.view.Base} self
208
+ */
209
+ this.rect = function(newRect) {
210
+ if (newRect === undefined) return this._rect;
211
+
212
+ newRect = Rect.create(newRect);
213
+ this._parentRect = newRect;
214
+ this._rect = this._normalizeRect(newRect);
215
+ this._needsLayout = this._needsLayout || layoutId++;
216
+ return this;
217
+ };
218
+
219
+ /**
220
+ * Set or get sides which the view should be attached to.
221
+ * When a view is attached to a side the distance between this side and views border
222
+ * will remain constant on resize. Anchor can be any combination of
223
+ * "top", "right", "bottom", "left", "width" and "height".
224
+ * If you set both "right" and "left" than "width" is assumed.
225
+ *
226
+ * Anchors are stored as a bit mask. Though its easier to set them using strings
227
+ *
228
+ * @function
229
+ * @param {string|number} anchors
230
+ * @returns {number|uki.view.Base} anchors or self
231
+ */
232
+ this.anchors = uki.newProp('_anchors', function(anchors) {
233
+ if (anchors.indexOf) {
234
+ var tmp = 0;
235
+ if (anchors.indexOf('right' ) > -1) tmp |= ANCHOR_RIGHT;
236
+ if (anchors.indexOf('bottom' ) > -1) tmp |= ANCHOR_BOTTOM;
237
+ if (anchors.indexOf('top' ) > -1) tmp |= ANCHOR_TOP;
238
+ if (anchors.indexOf('left' ) > -1) tmp |= ANCHOR_LEFT;
239
+ if (anchors.indexOf('width' ) > -1 || (tmp & ANCHOR_LEFT && tmp & ANCHOR_RIGHT)) tmp |= ANCHOR_WIDTH;
240
+ if (anchors.indexOf('height' ) > -1 || (tmp & ANCHOR_BOTTOM && tmp & ANCHOR_TOP)) tmp |= ANCHOR_HEIGHT;
241
+ anchors = tmp;
242
+ }
243
+ this._anchors = anchors;
244
+ this._styleH = anchors & ANCHOR_LEFT ? 'left' : 'right';
245
+ this._styleV = anchors & ANCHOR_TOP ? 'top' : 'bottom';
246
+ });
247
+
248
+ /**
249
+ * Returns rectangle for child layout. Usually equals to #rect. Though in some cases,
250
+ * client rectangle my differ from #rect. Example uki.view.ScrollPane.
251
+ *
252
+ * @param {uki.view.Base} child
253
+ * @returns {uki.geometry.Rect}
254
+ */
255
+ this.rectForChild = function(child) {
256
+ return this.rect();
257
+ };
258
+
259
+ /**
260
+ * Updates dom to match #rect property.
261
+ *
262
+ * Layout is designed to minimize dom writes. If view is anchored to the right then
263
+ * style.right is used, style.left for left anchor, etc. If browser supports this
264
+ * both style.right and style.left are used. Otherwise style.width will be updated
265
+ * manually on each resize.
266
+ *
267
+ * @fires event:layout
268
+ * @see uki.dom.initNativeLayout
269
+ */
270
+ this.layout = function() {
271
+ this._layoutDom(this._rect);
272
+ this._needsLayout = false;
273
+ this.trigger('layout', {rect: this._rect, source: this});
274
+ this._firstLayout = false;
275
+ };
276
+
277
+ /**
278
+ * @function
279
+ */
280
+ this.minSize = uki.newProp('_minSize', function(s) {
281
+ this._minSize = Size.create(s);
282
+ this.rect(this._parentRect);
283
+ if (this._minSize.width) this._dom.style.minWidth = this._minSize.width + PX;
284
+ if (this._minSize.height) this._dom.style.minHeight = this._minSize.height + PX;
285
+ });
286
+
287
+ /**
288
+ * @function
289
+ */
290
+ this.maxSize = uki.newProp('_maxSize', function(s) {
291
+ this._maxSize = Size.create(s);
292
+ this.rect(this._parentRect);
293
+ if (this._maxSize.width) this._dom.style.maxWidth = this._maxSize.width + PX;
294
+ if (this._maxSize.height) this._dom.style.maxHeight = this._maxSize.height + PX;
295
+ });
296
+
297
+ /**
298
+ * Resizes view when parent changes size according to anchors.
299
+ * Called from parent view. Usually after parent's #rect is called.
300
+ *
301
+ * @param {uki.geometry.Rect} oldSize
302
+ * @param {uki.geometry.Rect} newSize
303
+ */
304
+ this.parentResized = function(oldSize, newSize) {
305
+ var newRect = this._parentRect.clone(),
306
+ dX = (newSize.width - oldSize.width) /
307
+ ((this._anchors & ANCHOR_LEFT ^ ANCHOR_LEFT ? 1 : 0) + // flexible left
308
+ (this._anchors & ANCHOR_WIDTH ? 1 : 0) +
309
+ (this._anchors & ANCHOR_RIGHT ^ ANCHOR_RIGHT ? 1 : 0)), // flexible right
310
+ dY = (newSize.height - oldSize.height) /
311
+ ((this._anchors & ANCHOR_TOP ^ ANCHOR_TOP ? 1 : 0) + // flexible top
312
+ (this._anchors & ANCHOR_HEIGHT ? 1 : 0) +
313
+ (this._anchors & ANCHOR_BOTTOM ^ ANCHOR_BOTTOM ? 1 : 0)); // flexible right
314
+
315
+ if (this._anchors & ANCHOR_LEFT ^ ANCHOR_LEFT) newRect.x += dX;
316
+ if (this._anchors & ANCHOR_WIDTH) newRect.width += dX;
317
+
318
+ if (this._anchors & ANCHOR_TOP ^ ANCHOR_TOP) newRect.y += dY;
319
+ if (this._anchors & ANCHOR_HEIGHT) newRect.height += dY;
320
+ this.rect(newRect);
321
+ };
322
+
323
+ /**
324
+ * Resizes view to its contents. Contents size is determined by view.
325
+ * View can be resized by width, height or both. This is specified through
326
+ * autosizeStr param.
327
+ * View will grow shrink according to its #anchors.
328
+ *
329
+ * @param {autosizeStr} autosize
330
+ * @returns {uki.view.Base} self
331
+ */
332
+ this.resizeToContents = function(autosizeStr) {
333
+ var autosize = decodeAutosize(autosizeStr);
334
+ if (0 == autosize) return this;
335
+
336
+ var oldRect = this.rect(),
337
+ newRect = this._calcRectOnContentResize(autosize);
338
+ // if (newRect.eq(oldRect)) return this;
339
+ // this.rect(newRect);
340
+ this._rect = this._parentRect = newRect;
341
+ this._needsLayout = true;
342
+ return this;
343
+ };
344
+
345
+ /**
346
+ * Calculates view's contents size. Redefined in subclasses.
347
+ *
348
+ * @param {number} autosize Bitmask
349
+ * @returns {uki.geometry.Rect}
350
+ */
351
+ this.contentsSize = function(autosize) {
352
+ return this.rect();
353
+ };
354
+
355
+ /** @private */
356
+ this._normalizeRect = function(rect) {
357
+ if (this._minSize) {
358
+ rect = new Rect(rect.x, rect.y, MAX(this._minSize.width, rect.width), MAX(this._minSize.height, rect.height));
359
+ }
360
+ if (this._maxSize) {
361
+ rect = new Rect(rect.x, rect.y, MIN(this._maxSize.width, rect.width), MIN(this._maxSize.height, rect.height));
362
+ }
363
+ return rect;
364
+ };
365
+
366
+
367
+
368
+ /** @ignore */
369
+ function decodeAutosize (autosizeStr) {
370
+ if (!autosizeStr) return 0;
371
+ var autosize = 0;
372
+ if (autosizeStr.indexOf('width' ) > -1) autosize = autosize | ANCHOR_WIDTH;
373
+ if (autosizeStr.indexOf('height') > -1) autosize = autosize | ANCHOR_HEIGHT;
374
+ return autosize;
375
+ }
376
+
377
+
378
+ /** @private */
379
+ this._initBackgrounds = function() {
380
+ if (this.background()) this.background().attachTo(this);
381
+ };
382
+
383
+ /** @private */
384
+ this._calcRectOnContentResize = function(autosize) {
385
+ var newSize = this.contentsSize( autosize ),
386
+ oldSize = this.rect();
387
+
388
+ if (newSize.eq(oldSize)) return oldSize; // nothing changed
389
+
390
+ // calculate where to resize
391
+ var newRect = this.rect().clone(),
392
+ dX = newSize.width - oldSize.width,
393
+ dY = newSize.height - oldSize.height;
394
+
395
+ if (autosize & ANCHOR_WIDTH) {
396
+ if (this._anchors & ANCHOR_LEFT ^ ANCHOR_LEFT && this._anchors & ANCHOR_RIGHT ^ ANCHOR_RIGHT) {
397
+ newRect.x -= dX/2;
398
+ } else if (this._anchors & ANCHOR_LEFT ^ ANCHOR_LEFT) {
399
+ newRect.x -= dX;
400
+ }
401
+ newRect.width += dX;
402
+ }
403
+
404
+ if (autosize & ANCHOR_HEIGHT) {
405
+ if (this._anchors & ANCHOR_TOP ^ ANCHOR_TOP && this._anchors & ANCHOR_BOTTOM ^ ANCHOR_BOTTOM) {
406
+ newRect.y -= dY/2;
407
+ } else if (this._anchors & ANCHOR_TOP ^ ANCHOR_TOP) {
408
+ newRect.y -= dY;
409
+ }
410
+ newRect.height += dY;
411
+ }
412
+
413
+ return newRect;
414
+ };
415
+
416
+ /** @function
417
+ @name uki.view.Base#width */
418
+ /** @function
419
+ @name uki.view.Base#height */
420
+ /** @function
421
+ @name uki.view.Base#minX */
422
+ /** @function
423
+ @name uki.view.Base#maxX */
424
+ /** @function
425
+ @name uki.view.Base#minY */
426
+ /** @function
427
+ @name uki.view.Base#maxY */
428
+ /** @function
429
+ @name uki.view.Base#left */
430
+ /** @function
431
+ @name uki.view.Base#top */
432
+ uki.each(['width', 'height', 'minX', 'maxX', 'minY', 'maxY', 'left', 'top'], function(index, attr) {
433
+ this[attr] = function(value) {
434
+ return uki.attr(this.rect(), attr, value);
435
+ };
436
+ }, this);
437
+
438
+ /* ---------------------------------- Dom --------------------------------*/
439
+ /**
440
+ * Called through a second layout pass when _dom should be created
441
+ * @private
442
+ */
443
+ this._createDom = function() {
444
+ this._dom = uki.createElement('div', this.defaultCss);
445
+ };
446
+
447
+ /**
448
+ * Called through a second layout pass when _dom is already created
449
+ * @private
450
+ */
451
+ this._layoutDom = function(rect) {
452
+ var l = {}, s = uki.supportNativeLayout, relativeRect = this.parent().rectForChild(this);
453
+ if (s && this._anchors & ANCHOR_LEFT && this._anchors & ANCHOR_RIGHT) {
454
+ l.left = rect.x;
455
+ l.right = relativeRect.width - rect.x - rect.width;
456
+ } else {
457
+ l.width = rect.width;
458
+ l[this._styleH] = this._styleH == 'left' ? rect.x : relativeRect.width - rect.x - rect.width;
459
+ }
460
+
461
+ if (s && this._anchors & ANCHOR_TOP && this._anchors & ANCHOR_BOTTOM) {
462
+ l.top = rect.y;
463
+ l.bottom = relativeRect.height - rect.y - rect.height;
464
+ } else {
465
+ l.height = rect.height;
466
+ l[this._styleV] = this._styleV == 'top' ? rect.y : relativeRect.height - rect.y - rect.height;
467
+ }
468
+ this._lastLayout = uki.dom.layout(this._dom.style, l, this._lastLayout);
469
+ if (this._firstLayout) this._initBackgrounds();
470
+ return true;
471
+ };
472
+
473
+ /** @private */
474
+ this._bindToDom = function(name) {
475
+ if ('resize layout'.indexOf(name) > -1) return true;
476
+ return uki.view.Observable._bindToDom.call(this, name);
477
+ };
478
+
479
+ /**#@-*/
480
+ });
@@ -0,0 +1,155 @@
1
+ include('base.js');
2
+
3
+ /**
4
+ * @class
5
+ * @augments uki.view.Base
6
+ * @name uki.view.Container
7
+ */
8
+ uki.view.declare('uki.view.Container', uki.view.Base, function(Base) {
9
+ /**#@+ @memberOf uki.view.Container# */
10
+
11
+ /** @private */
12
+ this._setup = function() {
13
+ this._childViews = [];
14
+ Base._setup.call(this);
15
+ };
16
+
17
+ /** @ignore */
18
+ function maxProp (c, prop) {
19
+ var val = 0, i, l;
20
+ for (i = c._childViews.length - 1; i >= 0; i--){
21
+ if (!c._childViews[i].visible()) continue;
22
+ val = MAX(val, c._childViews[i].rect()[prop]());
23
+ };
24
+ return val;
25
+ }
26
+
27
+ this.contentsWidth = function() {
28
+ return maxProp(this, 'maxX');
29
+ };
30
+
31
+ this.contentsHeight = function() {
32
+ return maxProp(this, 'maxY');
33
+ };
34
+
35
+ this.contentsSize = function() {
36
+ return new Size(this.contentsWidth(), this.contentsHeight());
37
+ };
38
+
39
+ /**
40
+ * Sets or retrieves view child view.
41
+ * @param anything uki.build can parse
42
+ *
43
+ * Note: if setting on view with child views, all child view will be removed
44
+ */
45
+ this.childViews = function(val) {
46
+ if (val === undefined) return this._childViews;
47
+ uki.each(this._childViews, function(i, child) {
48
+ this.removeChild(child);
49
+ }, this);
50
+ uki.each(uki.build(val), function(tmp, child) {
51
+ this.appendChild(child);
52
+ }, this);
53
+ return this;
54
+ };
55
+
56
+ /**
57
+ * Remove particular child
58
+ */
59
+ this.removeChild = function(child) {
60
+ child.parent(null);
61
+ this.domForChild(child).removeChild(child.dom());
62
+ var index = child._viewIndex,
63
+ i, l;
64
+ for (i=index+1, l = this._childViews.length; i < l; i++) {
65
+ this._childViews[i]._viewIndex--;
66
+ };
67
+ this._childViews = uki.grep(this._childViews, function(elem) { return elem != child; });
68
+ };
69
+
70
+ /**
71
+ * Adds a child.
72
+ */
73
+ this.appendChild = function(child) {
74
+ child._viewIndex = this._childViews.length;
75
+ this._childViews.push(child);
76
+ child.parent(this);
77
+ this.domForChild(child).appendChild(child.dom());
78
+ };
79
+
80
+ /**
81
+ * Insert child before target beforeChild
82
+ * @param {uki.view.Base} child Child to insert
83
+ * @param {uki.view.Base} beforeChild Existent child before which we should insert
84
+ */
85
+ this.insertBefore = function(child, beforeChild) {
86
+ var i, l;
87
+ child._viewIndex = beforeChild._viewIndex;
88
+ for (i=beforeChild._viewIndex, l = this._childViews.length; i < l; i++) {
89
+ this._childViews[i]._viewIndex++;
90
+ };
91
+ this._childViews.splice(beforeChild._viewIndex-1, 0, child);
92
+ child.parent(this);
93
+ this.domForChild(child).insertBefore(child.dom(), beforeChild.dom());
94
+ };
95
+
96
+ /**
97
+ * Should return a dom node for a child.
98
+ * Child should append itself to this dom node
99
+ */
100
+ this.domForChild = function(child) {
101
+ return this._dom;
102
+ };
103
+
104
+
105
+ /** @private */
106
+ this._layoutDom = function(rect) {
107
+ Base._layoutDom.call(this, rect);
108
+ this._layoutChildViews(rect);
109
+ };
110
+
111
+ /** @private */
112
+ this._layoutChildViews = function() {
113
+ for (var i=0, childViews = this.childViews(); i < childViews.length; i++) {
114
+ if (childViews[i]._needsLayout && childViews[i].visible()) {
115
+ childViews[i].layout(this._rect);
116
+ }
117
+ };
118
+ };
119
+
120
+ /**
121
+ * @fires event:resize
122
+ */
123
+ this.rect = function(newRect) {
124
+ if (newRect === undefined) return this._rect;
125
+
126
+ newRect = Rect.create(newRect);
127
+ this._parentRect = newRect;
128
+ var oldRect = this._rect;
129
+ if (!this._resizeSelf(newRect)) return this;
130
+ this._needsLayout = true;
131
+
132
+ if (oldRect.width != newRect.width || oldRect.height != newRect.height) this._resizeChildViews(oldRect);
133
+ this.trigger('resize', {oldRect: oldRect, newRect: this._rect, source: this});
134
+ return this;
135
+ };
136
+
137
+ /** @private */
138
+ this._resizeSelf = function(newRect) {
139
+ // if (newRect.eq(this._rect)) return false;
140
+ this._rect = this._normalizeRect(newRect);
141
+ return true;
142
+ };
143
+
144
+ /**
145
+ * Called to notify all interested parties: childViews and observers
146
+ * @private
147
+ */
148
+ this._resizeChildViews = function(oldRect) {
149
+ for (var i=0, childViews = this.childViews(); i < childViews.length; i++) {
150
+ childViews[i].parentResized(oldRect, this._rect);
151
+ };
152
+ };
153
+
154
+ /**#@-*/
155
+ });