uki 1.0.0

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.
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
+ });