sproutcore 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. data/History.txt +233 -0
  2. data/Manifest.txt +67 -34
  3. data/bin/sc-build +12 -1
  4. data/bin/sc-gen +1 -1
  5. data/bin/sproutcore +14 -0
  6. data/clients/sc_docs/controllers/docs.js +38 -8
  7. data/clients/sc_docs/english.lproj/body.css +80 -127
  8. data/clients/sc_docs/english.lproj/body.rhtml +43 -23
  9. data/clients/sc_docs/english.lproj/no_docs.rhtml +2 -1
  10. data/clients/sc_docs/english.lproj/tabs.rhtml +16 -0
  11. data/clients/sc_docs/main.js +14 -9
  12. data/clients/sc_docs/models/doc.js +1 -1
  13. data/clients/sc_docs/tests/controllers/docs.rhtml +1 -2
  14. data/clients/sc_docs/tests/models/doc.rhtml +1 -2
  15. data/clients/sc_docs/tests/views/doc_frame.rhtml +1 -2
  16. data/clients/sc_docs/tests/views/doc_label_view.rhtml +1 -2
  17. data/clients/sc_docs/views/doc_frame.js +1 -1
  18. data/clients/sc_test_runner/controllers/runner.js +31 -8
  19. data/clients/sc_test_runner/english.lproj/body.css +62 -122
  20. data/clients/sc_test_runner/english.lproj/body.rhtml +62 -26
  21. data/clients/sc_test_runner/main.js +1 -6
  22. data/clients/sc_test_runner/models/test.js +14 -1
  23. data/clients/sc_test_runner/views/runner_frame.js +4 -2
  24. data/clients/view_builder/builders/builder.js +339 -0
  25. data/clients/view_builder/builders/button.js +81 -0
  26. data/clients/view_builder/controllers/document.js +21 -0
  27. data/clients/view_builder/core.js +19 -0
  28. data/clients/view_builder/english.lproj/body.css +77 -0
  29. data/clients/view_builder/english.lproj/body.rhtml +41 -0
  30. data/clients/{sc_docs → view_builder}/english.lproj/controls.css +0 -0
  31. data/clients/view_builder/english.lproj/strings.js +14 -0
  32. data/clients/view_builder/main.js +38 -0
  33. data/clients/view_builder/tests/controllers/document.rhtml +20 -0
  34. data/clients/view_builder/tests/views/builder.rhtml +20 -0
  35. data/clients/view_builder/views/builder.js +23 -0
  36. data/frameworks/prototype/prototype.js +1 -1
  37. data/frameworks/sproutcore/Core.js +32 -7
  38. data/frameworks/sproutcore/README +1 -1
  39. data/frameworks/sproutcore/animation/animation.js +411 -0
  40. data/frameworks/sproutcore/controllers/array.js +17 -9
  41. data/frameworks/sproutcore/controllers/collection.js +9 -110
  42. data/frameworks/sproutcore/controllers/controller.js +1 -1
  43. data/frameworks/sproutcore/controllers/object.js +2 -1
  44. data/frameworks/sproutcore/drag/drag.js +267 -56
  45. data/frameworks/sproutcore/drag/drag_data_source.js +24 -16
  46. data/frameworks/sproutcore/drag/drag_source.js +53 -42
  47. data/frameworks/sproutcore/drag/drop_target.js +2 -2
  48. data/frameworks/sproutcore/english.lproj/buttons.css +337 -236
  49. data/frameworks/sproutcore/english.lproj/core.css +115 -0
  50. data/frameworks/sproutcore/english.lproj/icons.css +227 -0
  51. data/{clients/sc_docs → frameworks/sproutcore}/english.lproj/images/indicator.gif +0 -0
  52. data/frameworks/sproutcore/english.lproj/images/sc-theme-sprite.png +0 -0
  53. data/frameworks/sproutcore/english.lproj/images/sc-theme-ysprite.png +0 -0
  54. data/frameworks/sproutcore/english.lproj/images/shared-icons.png +0 -0
  55. data/frameworks/sproutcore/english.lproj/menu.css +1 -1
  56. data/frameworks/sproutcore/english.lproj/strings.js +1 -1
  57. data/frameworks/sproutcore/english.lproj/theme.css +405 -31
  58. data/frameworks/sproutcore/foundation/application.js +15 -11
  59. data/frameworks/sproutcore/foundation/benchmark.js +1 -1
  60. data/frameworks/sproutcore/foundation/binding.js +2 -2
  61. data/frameworks/sproutcore/foundation/date.js +1 -1
  62. data/frameworks/sproutcore/foundation/error.js +1 -1
  63. data/frameworks/sproutcore/foundation/input_manager.js +32 -21
  64. data/frameworks/sproutcore/foundation/mock.js +1 -1
  65. data/frameworks/sproutcore/foundation/node_descriptor.js +9 -6
  66. data/frameworks/sproutcore/foundation/object.js +249 -177
  67. data/frameworks/sproutcore/foundation/page.js +5 -2
  68. data/frameworks/sproutcore/foundation/path_module.js +11 -10
  69. data/frameworks/sproutcore/foundation/responder.js +5 -2
  70. data/frameworks/sproutcore/foundation/routes.js +17 -13
  71. data/frameworks/sproutcore/foundation/run_loop.js +249 -11
  72. data/frameworks/sproutcore/foundation/server.js +1 -1
  73. data/frameworks/sproutcore/foundation/set.js +3 -3
  74. data/frameworks/sproutcore/foundation/string.js +5 -3
  75. data/frameworks/sproutcore/foundation/timer.js +371 -0
  76. data/frameworks/sproutcore/foundation/undo_manager.js +1 -1
  77. data/frameworks/sproutcore/foundation/unittest.js +3 -3
  78. data/frameworks/sproutcore/foundation/utils.js +161 -2
  79. data/frameworks/sproutcore/globals/panels.js +1 -1
  80. data/frameworks/sproutcore/globals/popups.js +4 -3
  81. data/frameworks/sproutcore/globals/window.js +44 -4
  82. data/frameworks/sproutcore/lib/button_views.rb +328 -0
  83. data/frameworks/sproutcore/lib/collection_view.rb +80 -0
  84. data/frameworks/sproutcore/lib/core_views.rb +281 -0
  85. data/frameworks/sproutcore/lib/form_views.rb +253 -0
  86. data/frameworks/sproutcore/lib/index.rhtml +2 -0
  87. data/frameworks/sproutcore/lib/menu_views.rb +88 -0
  88. data/frameworks/sproutcore/{foundation → mixins}/array.js +60 -29
  89. data/frameworks/sproutcore/mixins/control.js +265 -0
  90. data/frameworks/sproutcore/mixins/delegate_support.js +66 -0
  91. data/frameworks/sproutcore/{foundation → mixins}/observable.js +176 -6
  92. data/frameworks/sproutcore/mixins/scrollable.js +245 -0
  93. data/frameworks/sproutcore/mixins/selection_support.js +148 -0
  94. data/frameworks/sproutcore/mixins/validatable.js +152 -0
  95. data/frameworks/sproutcore/models/collection.js +5 -5
  96. data/frameworks/sproutcore/models/record.js +1 -1
  97. data/frameworks/sproutcore/models/store.js +1 -1
  98. data/frameworks/sproutcore/panes/dialog.js +1 -1
  99. data/frameworks/sproutcore/panes/manager.js +1 -1
  100. data/frameworks/sproutcore/panes/menu.js +1 -1
  101. data/frameworks/sproutcore/panes/overlay.js +2 -2
  102. data/frameworks/sproutcore/panes/panel.js +1 -1
  103. data/frameworks/sproutcore/panes/picker.js +1 -1
  104. data/frameworks/sproutcore/tests/controllers/array.rhtml +44 -4
  105. data/frameworks/sproutcore/tests/foundation/timer/invalidate.rhtml +33 -0
  106. data/frameworks/sproutcore/tests/foundation/timer/invokeLater.rhtml +145 -0
  107. data/frameworks/sproutcore/tests/foundation/timer/isPaused.rhtml +70 -0
  108. data/frameworks/sproutcore/tests/foundation/timer/schedule.rhtml +145 -0
  109. data/frameworks/sproutcore/tests/views/{scroll.rhtml → checkbox.rhtml} +3 -3
  110. data/frameworks/sproutcore/tests/views/{collection.rhtml → collection/base.rhtml} +33 -32
  111. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +260 -0
  112. data/frameworks/sproutcore/tests/views/image_cell.rhtml +19 -0
  113. data/frameworks/sproutcore/tests/views/label_item.rhtml +2 -4
  114. data/frameworks/sproutcore/tests/views/list.rhtml +2 -3
  115. data/frameworks/sproutcore/tests/views/list_item.rhtml +20 -0
  116. data/frameworks/sproutcore/tests/views/slider.rhtml +20 -0
  117. data/frameworks/sproutcore/tests/views/text_cell.rhtml +19 -0
  118. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +395 -0
  119. data/frameworks/sproutcore/tests/views/view/frame.rhtml +353 -0
  120. data/frameworks/sproutcore/tests/views/view/innerFrame.rhtml +347 -0
  121. data/frameworks/sproutcore/tests/views/view/isVisibleInWindow.rhtml +148 -0
  122. data/frameworks/sproutcore/tests/views/view/scrollFrame.rhtml +468 -0
  123. data/frameworks/sproutcore/validators/credit_card.js +33 -13
  124. data/frameworks/sproutcore/validators/date.js +26 -6
  125. data/frameworks/sproutcore/validators/email.js +21 -3
  126. data/frameworks/sproutcore/validators/not_empty.js +11 -1
  127. data/frameworks/sproutcore/validators/number.js +18 -4
  128. data/frameworks/sproutcore/validators/password.js +12 -1
  129. data/frameworks/sproutcore/validators/validator.js +204 -194
  130. data/frameworks/sproutcore/views/{button.js → button/button.js} +96 -94
  131. data/frameworks/sproutcore/views/button/checkbox.js +29 -0
  132. data/frameworks/sproutcore/views/button/disclosure.js +42 -0
  133. data/frameworks/sproutcore/views/button/radio.js +29 -0
  134. data/frameworks/sproutcore/views/{collection.js → collection/collection.js} +1373 -1024
  135. data/frameworks/sproutcore/views/collection/grid.js +124 -46
  136. data/frameworks/sproutcore/views/collection/image_cell.js +17 -46
  137. data/frameworks/sproutcore/views/collection/list.js +45 -35
  138. data/frameworks/sproutcore/views/collection/source_list.js +386 -0
  139. data/frameworks/sproutcore/views/collection/table.js +118 -0
  140. data/frameworks/sproutcore/views/container.js +7 -2
  141. data/frameworks/sproutcore/views/error_explanation.js +23 -10
  142. data/frameworks/sproutcore/views/{checkbox_field.js → field/checkbox_field.js} +16 -6
  143. data/frameworks/sproutcore/views/field/field.js +219 -0
  144. data/frameworks/sproutcore/views/{radio_field.js → field/radio_field.js} +27 -12
  145. data/frameworks/sproutcore/views/{select_field.js → field/select_field.js} +116 -90
  146. data/frameworks/sproutcore/views/{text_field.js → field/text_field.js} +57 -8
  147. data/frameworks/sproutcore/views/{textarea_field.js → field/textarea_field.js} +13 -3
  148. data/frameworks/sproutcore/views/filter_button.js +2 -2
  149. data/frameworks/sproutcore/views/form.js +3 -3
  150. data/frameworks/sproutcore/views/image.js +128 -21
  151. data/frameworks/sproutcore/views/inline_text_editor.js +1 -1
  152. data/frameworks/sproutcore/views/label.js +149 -92
  153. data/frameworks/sproutcore/views/list_item.js +225 -0
  154. data/frameworks/sproutcore/views/menu_item.js +10 -4
  155. data/frameworks/sproutcore/views/pagination.js +11 -4
  156. data/frameworks/sproutcore/views/popup_button.js +25 -21
  157. data/frameworks/sproutcore/views/popup_menu.js +10 -4
  158. data/frameworks/sproutcore/views/progress.js +29 -16
  159. data/frameworks/sproutcore/views/radio_group.js +1 -1
  160. data/frameworks/sproutcore/views/scroll.js +60 -20
  161. data/frameworks/sproutcore/views/segmented.js +1 -1
  162. data/frameworks/sproutcore/views/slider.js +132 -0
  163. data/frameworks/sproutcore/views/source_list_group.js +130 -0
  164. data/frameworks/sproutcore/views/spinner.js +1 -1
  165. data/frameworks/sproutcore/views/split.js +292 -0
  166. data/frameworks/sproutcore/views/split_divider.js +109 -0
  167. data/frameworks/sproutcore/views/tab.js +1 -1
  168. data/frameworks/sproutcore/views/toolbar.js +1 -1
  169. data/frameworks/sproutcore/views/view.js +1272 -591
  170. data/generators/client/templates/english.lproj/body.css +1 -1
  171. data/generators/controller/controller_generator.rb +1 -1
  172. data/generators/controller/templates/test.rhtml +2 -1
  173. data/generators/model/templates/test.rhtml +1 -1
  174. data/generators/test/templates/test.rhtml +1 -1
  175. data/generators/view/templates/test.rhtml +1 -1
  176. data/jsdoc/templates/sproutcore/class.tmpl +241 -338
  177. data/jsdoc/templates/sproutcore/default.css +105 -155
  178. data/jsdoc/templates/sproutcore/index.tmpl +43 -8
  179. data/jsdoc/templates/sproutcore/publish.js +9 -4
  180. data/lib/sproutcore/build_tools/html_builder.rb +29 -13
  181. data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
  182. data/lib/sproutcore/bundle.rb +86 -25
  183. data/lib/sproutcore/jsdoc.rb +2 -0
  184. data/lib/sproutcore/version.rb +1 -1
  185. data/lib/sproutcore/view_helpers.rb +36 -3
  186. data/tasks/deployment.rake +1 -1
  187. metadata +69 -36
  188. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  189. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  190. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  191. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  192. data/clients/sc_docs/english.lproj/warning.rhtml +0 -6
  193. data/clients/sc_test_runner/english.lproj/warning.rhtml +0 -6
  194. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  195. data/frameworks/sproutcore/english.lproj/collections.css +0 -82
  196. data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
  197. data/frameworks/sproutcore/views/collection/collection_item.js +0 -36
  198. data/frameworks/sproutcore/views/collection/text_cell.js +0 -128
  199. data/frameworks/sproutcore/views/field.js +0 -214
  200. data/frameworks/sproutcore/views/workspace.js +0 -170
  201. data/generators/client/templates/english.lproj/controls.css +0 -0
  202. data/generators/framework/templates/english.lproj/body.css +0 -0
  203. data/generators/framework/templates/english.lproj/body.rhtml +0 -3
  204. data/generators/framework/templates/english.lproj/controls.css +0 -0
  205. data/lib/sproutcore/view_helpers/button_views.rb +0 -302
  206. data/lib/sproutcore/view_helpers/core_views.rb +0 -292
  207. data/lib/sproutcore/view_helpers/form_views.rb +0 -258
  208. data/lib/sproutcore/view_helpers/menu_views.rb +0 -94
@@ -12,15 +12,10 @@ function main() {
12
12
  var clientName = indexRoot.match(/([^\/]+)\/-tests/)[1];
13
13
  var urlRoot = indexRoot.replace(new RegExp("^%@/?".fmt(window.indexPrefix)), window.urlPrefix + '/');
14
14
  console.log('indexRoot: %@ clientName: %@ urlRoot: %@'.fmt( indexRoot, clientName, urlRoot));
15
- TestRunner.hidePanels() ;
15
+
16
16
  TestRunner.runnerController.set('selection',[]) ;
17
17
  TestRunner.runnerController.set('urlRoot', urlRoot) ;
18
18
  TestRunner.runnerController.set('indexRoot', indexRoot) ;
19
19
  TestRunner.runnerController.set('clientName', clientName) ;
20
20
  TestRunner.runnerController.reloadTests() ;
21
21
  } ;
22
-
23
- TestRunner.hidePanels = function() {
24
- SC.page.get('warningPanel').set('isVisible', false) ;
25
- SC.page.get('noTestsPanel').set('isVisible',false) ;
26
- } ;
@@ -8,7 +8,20 @@ TestRunner.Test = SC.Record.extend({
8
8
 
9
9
  // TODO: Add your own code here.
10
10
  title: function() {
11
- return this.get('name').replace(/\.rhtml$/,'');
11
+ if (!this._title) {
12
+ var parts = (this.get('name') || '').split('/') ;
13
+ var ret = parts.pop() || '' ;
14
+ this._title = ret.replace(/\.rhtml$/,'').replace(/_/g,' ');
15
+ }
16
+ return this._title ;
17
+ }.property('name'),
18
+
19
+ group: function() {
20
+ if (!this._group) {
21
+ var parts = (this.get('name') || '').split('/') ;
22
+ this._group = parts.slice(0,parts.length-1).join('/').toLowerCase() ;
23
+ }
24
+ return this._group;
12
25
  }.property('name')
13
26
 
14
27
  }) ;
@@ -29,7 +29,9 @@ TestRunner.RunnerFrameView = SC.View.extend({
29
29
 
30
30
  // if the document URL is already loaded, then reload it...
31
31
  if (url == this.rootElement.src) {
32
- if (doc && doc.location) doc.location.reload() ;
32
+ this.rootElement.src = 'javascript:;' ;
33
+ this.rootElement.src = url ;
34
+ // if (doc && doc.location) doc.location.reload() ;
33
35
 
34
36
  // otherwise set to the new URL.
35
37
  } else {
@@ -65,7 +67,7 @@ TestRunner.RunnerFrameView = SC.View.extend({
65
67
  }
66
68
 
67
69
  if (this.get('state') != status) this.set('state', status) ;
68
- if (reschedule) setTimeout(this.checkState.bind(this),100) ;
70
+ if (reschedule) this.invokeLater(this.checkState,100) ;
69
71
 
70
72
  }
71
73
 
@@ -0,0 +1,339 @@
1
+ // ==========================================================================
2
+ // Basic View Builder
3
+ // ==========================================================================
4
+
5
+ /**
6
+ A Builder can generate HTML, JavaScript and CSS based on a set of input
7
+ attributes. It expects to have the following attributes defined:
8
+
9
+ - targetClass: The name of the output class for JavaScript purposes.
10
+ - name: the human readable name
11
+ - guid: an internally unique id used to identify the resource.
12
+
13
+ - htmlTemplate: the html template to render.
14
+ - tagName: the tag name
15
+ - htmlId: ID used for tag
16
+ - cssClassNames: class names to add to tag.
17
+ - attributes: { src: "item" } -- HTML attrs to include.
18
+
19
+ - targetClass: name of output class.
20
+ - key: name of object when added to parent.
21
+ - properties: properties to place on JS object.
22
+ - bind: named bindings. each binding is like:
23
+ { to: path, kind: 'SC.Binding.Kind', isEnabled: YES }
24
+
25
+ - children: Array of child view builder records, in order. If any.
26
+ - parent: parent builder or null if top level.
27
+ - inPage: YES if should be added to SC.page.
28
+
29
+ You can add any other properties as well. Use them when your callbacks are
30
+ invoked to enhance these properties before they are generated.
31
+ */
32
+ SC.Builder = SC.Record.extend({
33
+
34
+ _targetClass: 'SC.Object',
35
+
36
+ /**
37
+ Defined by subclasses. If this is true, then the content of the view
38
+ is the HTML generated by children.
39
+ */
40
+ isContainer: NO,
41
+
42
+ /**
43
+ Defined by subclasses. If true, then views will be generated with an
44
+ outletFor() attached to them.
45
+ */
46
+ isOutletView: YES,
47
+
48
+ childrenType: 'SC.Builder',
49
+
50
+ parentType: 'SC.Builder',
51
+
52
+ /**
53
+ The default profile. New records will inherit a cloned set of these
54
+ attributes.
55
+ */
56
+ defaultAttributes: {
57
+ propertySettings: {},
58
+ bindSettings: {},
59
+ attributeSettings: {},
60
+ htmlTemplate: '<{%TagName%}{%Attributes%}>{%Content%}</{%TagName%}>',
61
+ cssClassNames: [],
62
+ innerHtml: '',
63
+ lazyOutlet: NO
64
+ },
65
+
66
+ init: function() {
67
+ arguments.callee.base.apply(this) ;
68
+ if (this.get('newRecord')) {
69
+ var attrs = this._deepClone(this.get('defaultAttributes'));
70
+ attrs.name = attrs.targetClass = this._targetClass ;
71
+ attrs.guid = attrs.htmlId = 'id%@'.fmt(Date.now().toString());
72
+ this.updateAttributes(attrs, YES, YES);
73
+ }
74
+ },
75
+
76
+ /**
77
+ Invoked just before the attributes are written out. You can add anything
78
+ you want here.
79
+ */
80
+ prepareAttributes: function(attrs) {
81
+ return attrs ;
82
+ },
83
+
84
+ /**
85
+ Invoked just before the class name is set. Add anything you want here.
86
+ */
87
+ prepareClassNames: function(classNames) {
88
+ return classNames ;
89
+ },
90
+
91
+ /**
92
+ Invoked just before outlets are added and the final JS is generated. Add
93
+ anything here you might pull from specialized preferences.
94
+ */
95
+ prepareProperties: function(props) { return props; },
96
+
97
+ /**
98
+ Invoked just before bindings are blended into properties. Add your own.
99
+ */
100
+ prepareBindings: function(binds) { return binds; },
101
+
102
+ // ..........................................
103
+ // HTML RENDERING
104
+ //
105
+
106
+ /**
107
+ Computes the HTML for this builder. HTML is built by interpolating the
108
+ htmlTemplate. Any variables must match a corresponding property on the
109
+ record with 'html' added to the beginning.
110
+ */
111
+ htmlPart: function() {
112
+ var template = this.get('htmlTemplate') ;
113
+ if (!template) return null ;
114
+
115
+ var that = this;
116
+ return template.replace(/{%(.+?)%}/g,function(m,p) {
117
+ return (p[0] == '%') ? p.slice(1,p.length) : that.get('html' + p) ;
118
+ }) ;
119
+ }.property('htmlTemplate', 'htmlContent', 'htmlTagName', 'htmlAttributes'),
120
+
121
+ /**
122
+ The tag name for the HTML. Usually specified by tagName in the
123
+ attributes.
124
+ */
125
+ htmlTagName: function() {
126
+ return this.get('tagName') || 'div';
127
+ }.property('tagName'),
128
+
129
+ /**
130
+ The attributes for the HTML. Combines attributes hash, css classes,
131
+ and id. It then calls prepareAttributes() so you can do any extra
132
+ processing you need.
133
+ */
134
+ htmlAttributes: function() {
135
+ // start with attributeSettings.
136
+ var attrs = this._deepClone(this.get('attributeSettings')) || {} ;
137
+
138
+ // add id
139
+ attrs.id = this.get('htmlId') ;
140
+
141
+ // merge in CSS class names
142
+ var cssClassNames = this.get('cssClassNames') || [] ;
143
+ if ($type(cssClassNames) === T_STRING) {
144
+ cssClassNames = cssClassNames.split(' ') ;
145
+ }
146
+
147
+ var cur = attrs['class'] || [] ;
148
+ if ($type(cur) === T_STRING) {
149
+ cur = cur.split(' ') ;
150
+ }
151
+
152
+ cur = cur.concat(cssClassNames).uniq().compact().sort() ;
153
+ cur.push(attrs.id) ;
154
+ cur = this.prepareClassNames(cur) || cur;
155
+ if (cur.length > 0) {
156
+ attrs['class'] = cur.join(' ') ;
157
+ } else delete attrs['class'] ;
158
+
159
+ attrs = this.prepareAttributes(attrs) || attrs ;
160
+
161
+ // now convert to a string.
162
+ var ret = [''];
163
+ for(var key in attrs) {
164
+ if (!attrs.hasOwnProperty(key)) continue ;
165
+ ret.push('%@="%@"'.fmt(key, attrs[key])) ;
166
+ }
167
+
168
+ return (ret.length > 1) ? ret.join(' ') : '';
169
+ }.property('cssClassNames', 'attributeSettings', 'htmlId'),
170
+
171
+ /**
172
+ The inner content for the HTML. If isContainer is true, then we get
173
+ the children for this view and use their HTML, otherwise get the
174
+ innerHtml property.
175
+ */
176
+ htmlContent: function() {
177
+ if (this.get('isContainer')) {
178
+ var children = this.get('children') || [] ;
179
+ var ret = [];
180
+ for(var idx=0;idx<children.length;idx++) {
181
+ var child = children.objectAt(idx) ;
182
+ ret.push(child.get('htmlPart')) ;
183
+ }
184
+
185
+ return ret.join('') ;
186
+ } else return this.get('innerHtml') ;
187
+ }.property('innerHtml', 'isContainer', 'children'),
188
+
189
+ // ..........................................
190
+ // JAVASCRIPT RENDERING
191
+ //
192
+
193
+ /**
194
+ Generates the JavaScript for this part.
195
+
196
+ This works by merging the propertySettings and bindSettings. Then it
197
+ calls your prepareProperties and finally merges in any outlets. With the
198
+ properties combined, it then generates the code to build a view.
199
+ */
200
+ javascriptPart: function() {
201
+ var props = this.get('javascriptProperties') ;
202
+
203
+ var outlets = this.get('javascriptOutlets') ;
204
+ for(var key in outlets) {
205
+ if (!outlets.hasOwnProperty(key)) continue ;
206
+ props[key] = outlets[key] ;
207
+ }
208
+
209
+ var outletDeclaration = '' ;
210
+ var verb = 'create' ;
211
+ if (this.get('isOutletView')) {
212
+ verb = 'extend' ;
213
+ outletDeclaration = '.outletFor(".%@?")'.fmt(this.get('htmlId'));
214
+ }
215
+
216
+ return '%@.%@(%@)%@'.fmt(this.get('targetClass'), verb, this._stringify(props), outletDeclaration) ;
217
+ }.property(),
218
+
219
+ /**
220
+ Generates the properties for the JavaScript sans any outlets.
221
+ */
222
+ javascriptProperties: function() {
223
+ var props = this._deepClone(this.get('propertySettings')) ;
224
+ props = this.prepareProperties(props) || props ;
225
+
226
+ var binds = this._deepClone(this.get('bindSettings')) ;
227
+ binds = this.prepareBindings(binds) || binds ;
228
+ for(var key in binds) {
229
+ if (!binds.hasOwnProperty(key)) continue ;
230
+
231
+ var bind = binds[key] ;
232
+ if (!bind.isEnabled) continue ;
233
+ bind = (bind.kind) ? "%@('%@')".fmt(bind.kind, bind.to) : "'%@'".fmt(bind.to) ;
234
+ props[key + 'Binding'] = bind ;
235
+ }
236
+
237
+ return props ;
238
+ }.property(),
239
+
240
+ /**
241
+ Generates the outlet properties for the JavaScript.
242
+ */
243
+ javascriptOutlets: function() {
244
+ var ret = {} ;
245
+ var outlets = [] ;
246
+
247
+ // loop through children.
248
+ var children = this.get('children') || [];
249
+ var idx = children.length ;
250
+ if (idx <= 0) return {} ;
251
+ while(--idx >= 0) {
252
+ var child = children.objectAt(idx) ;
253
+ var outletName = child.get('outletName') ;
254
+ var js = child.get('javascriptPart') ;
255
+ ret[outletName] = js ;
256
+ if (!child.get('lazyOutlet')) outlets.push(outletName) ;
257
+ }
258
+
259
+ ret.outlets = outletName ;
260
+ return ret ;
261
+ }.property(),
262
+
263
+ outletName: function(key, value) {
264
+ if (value !== undefined) this.writeAttribute('outletName', value) ;
265
+ return this.readAttribute('outletName') || this.get('htmlId') ;
266
+ }.property(),
267
+
268
+ // ..........................................
269
+ // INTERNAL METHODS
270
+ //
271
+
272
+ // deep clones a hash of properties. expects only Hash, Array or
273
+ // primitives.
274
+ _deepClone: function(obj) {
275
+ var ret = obj ;
276
+
277
+ switch($type(obj)) {
278
+ case T_HASH:
279
+ ret = {} ;
280
+ for(var key in obj) {
281
+ if (!obj.hasOwnProperty(key)) continue ;
282
+ ret[key] = this._deepClone(obj[key]) ;
283
+ }
284
+ break ;
285
+ case T_ARRAY:
286
+ ret = [] ;
287
+ for(var idx=0;idx < obj.length; idx++) {
288
+ ret.push(this._deepClone(obj[idx])) ;
289
+ }
290
+ break ;
291
+ }
292
+ return ret ;
293
+ },
294
+
295
+ // converts the input object into a eval-able string
296
+ _stringify: function(obj) {
297
+ var ret = obj ;
298
+ switch($type(obj)) {
299
+ case T_HASH:
300
+ ret = [] ;
301
+ for(var key in obj) {
302
+ if (!obj.hasOwnProperty(key)) continue ;
303
+ ret.push([key, this._stringify(obj[key])].join(': ')) ;
304
+ }
305
+ ret = "{ %@ }".fmt(ret.join(",\n ")) ;
306
+ break ;
307
+
308
+ case T_ARRAY:
309
+ ret = [] ;
310
+ for(var idx=0; idx < obj.length; idx++) {
311
+ ret.push(this._stringify(obj[idx])) ;
312
+ }
313
+ ret = '[%@]'.fmt(ret.join(', ')) ;
314
+ break ;
315
+
316
+ case T_NULL:
317
+ ret = 'null' ;
318
+ break ;
319
+
320
+ // Strings can be either property paths or quoted strings. They are
321
+ // quoted strings if they are in "quotes". If they are strings they
322
+ // should be already quoted, etc.
323
+ case T_STRING:
324
+ ret = obj ;
325
+ break ;
326
+
327
+ default:
328
+ ret = (obj.toString) ? obj.toString() : obj ;
329
+ }
330
+ return ret ;
331
+ }
332
+
333
+ }) ;
334
+
335
+ SC.Builder.newBuilder = function(attrs) {
336
+ if (!attrs) attrs = {} ;
337
+ attrs.newRecord = YES ;
338
+ return this.create(attrs) ;
339
+ } ;
@@ -0,0 +1,81 @@
1
+ // ==========================================================================
2
+ // Button View Builder
3
+ // ==========================================================================
4
+
5
+ require('builders/builder') ;
6
+
7
+ /**
8
+ */
9
+ SC.ButtonView.Builder = SC.Builder.extend({
10
+
11
+ _targetClass: 'SC.ButtonView',
12
+
13
+ /**
14
+ Defined by subclasses. If this is true, then the content of the view
15
+ is the HTML generated by children.
16
+ */
17
+ isContainer: NO,
18
+
19
+ /**
20
+ Defined by subclasses. If true, then views will be generated with an
21
+ outletFor() attached to them.
22
+ */
23
+ isOutletView: YES,
24
+
25
+ /**
26
+ The default profile. New records will inherit a cloned set of these
27
+ attributes.
28
+ */
29
+ defaultAttributes: {
30
+ propertySettings: {},
31
+ bindSettings: {},
32
+ attributeSettings: {},
33
+ htmlTemplate: '<{%TagName%}{%Attributes%}><span class="button-inner"><span class="label">{%Content%}</span></span></{%TagName%}>',
34
+ cssClassNames: ['sc-button-view', 'regular', 'normal'],
35
+ lazyOutlet: NO,
36
+ tagName: 'a',
37
+
38
+ title: 'Hello!'
39
+ },
40
+
41
+ init: function() {
42
+ arguments.callee.base.apply(this) ;
43
+ if (this.get('newRecord')) {
44
+ var attrs = this._deepClone(this.get('defaultAttributes'));
45
+ attrs.name = attrs.targetClass = this._targetClass ;
46
+ attrs.guid = attrs.htmlId = 'id%@'.fmt(Date.now().toString());
47
+ this.updateAttributes(attrs, YES, YES);
48
+ }
49
+ },
50
+
51
+ /**
52
+ Invoked just before the attributes are written out. You can add anything
53
+ you want here.
54
+ */
55
+ prepareAttributes: function(attrs) {
56
+ return attrs ;
57
+ },
58
+
59
+ /**
60
+ Invoked just before the class name is set. Add anything you want here.
61
+ */
62
+ prepareClassNames: function(classNames) {
63
+ return classNames ;
64
+ },
65
+
66
+ /**
67
+ Invoked just before outlets are added and the final JS is generated. Add
68
+ anything here you might pull from specialized preferences.
69
+ */
70
+ prepareProperties: function(props) { return props; },
71
+
72
+ /**
73
+ Invoked just before bindings are blended into properties. Add your own.
74
+ */
75
+ prepareBindings: function(binds) { return binds; },
76
+
77
+ innerHtml: function() {
78
+ return this.get('title') ;
79
+ }.property('title')
80
+
81
+ }) ;