sproutcore 0.9.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 (270) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +269 -0
  4. data/README.txt +67 -0
  5. data/Rakefile +4 -0
  6. data/app_generators/sproutcore/USAGE +5 -0
  7. data/app_generators/sproutcore/sproutcore_generator.rb +66 -0
  8. data/app_generators/sproutcore/templates/README +77 -0
  9. data/app_generators/sproutcore/templates/environment.yml +4 -0
  10. data/bin/sc-build +145 -0
  11. data/bin/sc-gen +24 -0
  12. data/bin/sc-server +63 -0
  13. data/bin/sproutcore +21 -0
  14. data/clients/sc_docs/controllers/docs.js +118 -0
  15. data/clients/sc_docs/core.js +19 -0
  16. data/clients/sc_docs/english.lproj/body.css +159 -0
  17. data/clients/sc_docs/english.lproj/body.rhtml +33 -0
  18. data/clients/sc_docs/english.lproj/controls.css +0 -0
  19. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  20. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  21. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  22. data/clients/sc_docs/english.lproj/images/indicator.gif +0 -0
  23. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  24. data/clients/sc_docs/english.lproj/no_docs.rhtml +7 -0
  25. data/clients/sc_docs/english.lproj/strings.js +14 -0
  26. data/clients/sc_docs/english.lproj/warning.rhtml +6 -0
  27. data/clients/sc_docs/fixtures/doc.js +11 -0
  28. data/clients/sc_docs/main.js +21 -0
  29. data/clients/sc_docs/models/doc.js +9 -0
  30. data/clients/sc_docs/tests/controllers/docs.rhtml +21 -0
  31. data/clients/sc_docs/tests/models/doc.rhtml +21 -0
  32. data/clients/sc_docs/tests/views/doc_frame.rhtml +21 -0
  33. data/clients/sc_docs/tests/views/doc_label_view.rhtml +21 -0
  34. data/clients/sc_docs/views/doc_frame.js +33 -0
  35. data/clients/sc_docs/views/doc_label.js +20 -0
  36. data/clients/sc_test_runner/controllers/runner.js +175 -0
  37. data/clients/sc_test_runner/core.js +19 -0
  38. data/clients/sc_test_runner/english.lproj/body.css +151 -0
  39. data/clients/sc_test_runner/english.lproj/body.rhtml +35 -0
  40. data/clients/sc_test_runner/english.lproj/controls.css +0 -0
  41. data/clients/sc_test_runner/english.lproj/icons/small/next.png +0 -0
  42. data/clients/sc_test_runner/english.lproj/icons/small/reset.png +0 -0
  43. data/clients/sc_test_runner/english.lproj/images/gradients.png +0 -0
  44. data/clients/sc_test_runner/english.lproj/images/indicator.gif +0 -0
  45. data/clients/sc_test_runner/english.lproj/images/toolbar.png +0 -0
  46. data/clients/sc_test_runner/english.lproj/no_tests.rhtml +6 -0
  47. data/clients/sc_test_runner/english.lproj/strings.js +14 -0
  48. data/clients/sc_test_runner/english.lproj/warning.rhtml +6 -0
  49. data/clients/sc_test_runner/fixtures/test.js +12 -0
  50. data/clients/sc_test_runner/main.js +26 -0
  51. data/clients/sc_test_runner/models/test.js +11 -0
  52. data/clients/sc_test_runner/views/runner_frame.js +72 -0
  53. data/clients/sc_test_runner/views/test_label.js +20 -0
  54. data/config/hoe.rb +70 -0
  55. data/config/requirements.rb +17 -0
  56. data/environment.yml +9 -0
  57. data/frameworks/prototype/prototype.js +4186 -0
  58. data/frameworks/sproutcore/Core.js +378 -0
  59. data/frameworks/sproutcore/README +3 -0
  60. data/frameworks/sproutcore/controllers/array.js +236 -0
  61. data/frameworks/sproutcore/controllers/collection.js +305 -0
  62. data/frameworks/sproutcore/controllers/controller.js +323 -0
  63. data/frameworks/sproutcore/controllers/object.js +372 -0
  64. data/frameworks/sproutcore/drag/drag.js +549 -0
  65. data/frameworks/sproutcore/drag/drag_data_source.js +32 -0
  66. data/frameworks/sproutcore/drag/drag_source.js +64 -0
  67. data/frameworks/sproutcore/drag/drop_target.js +153 -0
  68. data/frameworks/sproutcore/english.lproj/blank.gif +0 -0
  69. data/frameworks/sproutcore/english.lproj/buttons.css +589 -0
  70. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  71. data/frameworks/sproutcore/english.lproj/inline_text_editor.css +21 -0
  72. data/frameworks/sproutcore/english.lproj/menu.css +121 -0
  73. data/frameworks/sproutcore/english.lproj/panels/background-fat.jpg +0 -0
  74. data/frameworks/sproutcore/english.lproj/panels/background-thin.jpg +0 -0
  75. data/frameworks/sproutcore/english.lproj/panels/bottom-edge.png +0 -0
  76. data/frameworks/sproutcore/english.lproj/panels/bottom-left-corner.png +0 -0
  77. data/frameworks/sproutcore/english.lproj/panels/bottom-right-corner.png +0 -0
  78. data/frameworks/sproutcore/english.lproj/panels/left-edge.png +0 -0
  79. data/frameworks/sproutcore/english.lproj/panels/overlay.png +0 -0
  80. data/frameworks/sproutcore/english.lproj/panels/right-edge.png +0 -0
  81. data/frameworks/sproutcore/english.lproj/panels/top-edge.png +0 -0
  82. data/frameworks/sproutcore/english.lproj/panels/top-left-corner.png +0 -0
  83. data/frameworks/sproutcore/english.lproj/panels/top-right-corner.png +0 -0
  84. data/frameworks/sproutcore/english.lproj/panes.css +155 -0
  85. data/frameworks/sproutcore/english.lproj/picker.css +22 -0
  86. data/frameworks/sproutcore/english.lproj/strings.js +15 -0
  87. data/frameworks/sproutcore/english.lproj/tab.css +23 -0
  88. data/frameworks/sproutcore/english.lproj/tests.css +67 -0
  89. data/frameworks/sproutcore/english.lproj/theme.css +77 -0
  90. data/frameworks/sproutcore/foundation/animator.js +670 -0
  91. data/frameworks/sproutcore/foundation/application.js +199 -0
  92. data/frameworks/sproutcore/foundation/array.js +348 -0
  93. data/frameworks/sproutcore/foundation/benchmark.js +211 -0
  94. data/frameworks/sproutcore/foundation/binding.js +384 -0
  95. data/frameworks/sproutcore/foundation/date.js +357 -0
  96. data/frameworks/sproutcore/foundation/error.js +39 -0
  97. data/frameworks/sproutcore/foundation/input_manager.js +153 -0
  98. data/frameworks/sproutcore/foundation/json.js +296 -0
  99. data/frameworks/sproutcore/foundation/mock.js +42 -0
  100. data/frameworks/sproutcore/foundation/node_descriptor.js +56 -0
  101. data/frameworks/sproutcore/foundation/object.js +777 -0
  102. data/frameworks/sproutcore/foundation/observable.js +451 -0
  103. data/frameworks/sproutcore/foundation/page.js +63 -0
  104. data/frameworks/sproutcore/foundation/path_module.js +413 -0
  105. data/frameworks/sproutcore/foundation/responder.js +310 -0
  106. data/frameworks/sproutcore/foundation/routes.js +371 -0
  107. data/frameworks/sproutcore/foundation/run_loop.js +21 -0
  108. data/frameworks/sproutcore/foundation/server.js +491 -0
  109. data/frameworks/sproutcore/foundation/set.js +96 -0
  110. data/frameworks/sproutcore/foundation/string.js +149 -0
  111. data/frameworks/sproutcore/foundation/undo_manager.js +186 -0
  112. data/frameworks/sproutcore/foundation/unittest.js +622 -0
  113. data/frameworks/sproutcore/foundation/utils.js +61 -0
  114. data/frameworks/sproutcore/globals/panels.js +182 -0
  115. data/frameworks/sproutcore/globals/popups.js +60 -0
  116. data/frameworks/sproutcore/globals/window.js +381 -0
  117. data/frameworks/sproutcore/lib/index.rhtml +66 -0
  118. data/frameworks/sproutcore/models/collection.js +395 -0
  119. data/frameworks/sproutcore/models/record.js +622 -0
  120. data/frameworks/sproutcore/models/store.js +295 -0
  121. data/frameworks/sproutcore/panes/dialog.js +16 -0
  122. data/frameworks/sproutcore/panes/manager.js +164 -0
  123. data/frameworks/sproutcore/panes/menu.js +45 -0
  124. data/frameworks/sproutcore/panes/overlay.js +231 -0
  125. data/frameworks/sproutcore/panes/pane.js +90 -0
  126. data/frameworks/sproutcore/panes/panel.js +19 -0
  127. data/frameworks/sproutcore/panes/picker.js +45 -0
  128. data/frameworks/sproutcore/tests/controllers/array.rhtml +86 -0
  129. data/frameworks/sproutcore/tests/controllers/controller.rhtml +273 -0
  130. data/frameworks/sproutcore/tests/controllers/object.rhtml +327 -0
  131. data/frameworks/sproutcore/tests/foundation/application.rhtml +125 -0
  132. data/frameworks/sproutcore/tests/foundation/array.rhtml +221 -0
  133. data/frameworks/sproutcore/tests/foundation/object.rhtml +69 -0
  134. data/frameworks/sproutcore/tests/globals/window.rhtml +45 -0
  135. data/frameworks/sproutcore/tests/panes/pane.rhtml +88 -0
  136. data/frameworks/sproutcore/tests/views/collection.rhtml +137 -0
  137. data/frameworks/sproutcore/tests/views/popup_button.rhtml +115 -0
  138. data/frameworks/sproutcore/tests/views/text_field.rhtml +37 -0
  139. data/frameworks/sproutcore/validators/credit_card.js +92 -0
  140. data/frameworks/sproutcore/validators/date.js +36 -0
  141. data/frameworks/sproutcore/validators/email.js +29 -0
  142. data/frameworks/sproutcore/validators/not_empty.js +24 -0
  143. data/frameworks/sproutcore/validators/number.js +55 -0
  144. data/frameworks/sproutcore/validators/password.js +78 -0
  145. data/frameworks/sproutcore/validators/validator.js +304 -0
  146. data/frameworks/sproutcore/views/button.js +425 -0
  147. data/frameworks/sproutcore/views/checkbox_field.js +30 -0
  148. data/frameworks/sproutcore/views/collection.js +1521 -0
  149. data/frameworks/sproutcore/views/container.js +62 -0
  150. data/frameworks/sproutcore/views/error_explanation.js +45 -0
  151. data/frameworks/sproutcore/views/field.js +214 -0
  152. data/frameworks/sproutcore/views/filter_button.js +29 -0
  153. data/frameworks/sproutcore/views/form.js +591 -0
  154. data/frameworks/sproutcore/views/image.js +141 -0
  155. data/frameworks/sproutcore/views/inline_text_editor.js +96 -0
  156. data/frameworks/sproutcore/views/label.js +176 -0
  157. data/frameworks/sproutcore/views/menu_item.js +90 -0
  158. data/frameworks/sproutcore/views/pagination.js +54 -0
  159. data/frameworks/sproutcore/views/popup_button.js +86 -0
  160. data/frameworks/sproutcore/views/popup_menu.js +137 -0
  161. data/frameworks/sproutcore/views/progress.js +100 -0
  162. data/frameworks/sproutcore/views/radio_field.js +107 -0
  163. data/frameworks/sproutcore/views/radio_group.js +48 -0
  164. data/frameworks/sproutcore/views/segmented.js +80 -0
  165. data/frameworks/sproutcore/views/select_field.js +272 -0
  166. data/frameworks/sproutcore/views/spinner.js +11 -0
  167. data/frameworks/sproutcore/views/tab.js +126 -0
  168. data/frameworks/sproutcore/views/text_field.js +179 -0
  169. data/frameworks/sproutcore/views/textarea_field.js +14 -0
  170. data/frameworks/sproutcore/views/toolbar.js +29 -0
  171. data/frameworks/sproutcore/views/view.js +1389 -0
  172. data/frameworks/sproutcore/views/workspace.js +170 -0
  173. data/generators/client/README +3 -0
  174. data/generators/client/USAGE +12 -0
  175. data/generators/client/client_generator.rb +53 -0
  176. data/generators/client/templates/core.js +19 -0
  177. data/generators/client/templates/english.lproj/body.css +0 -0
  178. data/generators/client/templates/english.lproj/body.rhtml +3 -0
  179. data/generators/client/templates/english.lproj/controls.css +0 -0
  180. data/generators/client/templates/english.lproj/strings.js +14 -0
  181. data/generators/client/templates/main.js +37 -0
  182. data/generators/controller/USAGE +16 -0
  183. data/generators/controller/controller_generator.rb +51 -0
  184. data/generators/controller/templates/controller.js +21 -0
  185. data/generators/controller/templates/test.rhtml +21 -0
  186. data/generators/framework/README +7 -0
  187. data/generators/framework/USAGE +12 -0
  188. data/generators/framework/framework_generator.rb +53 -0
  189. data/generators/framework/templates/core.js +20 -0
  190. data/generators/framework/templates/english.lproj/body.css +0 -0
  191. data/generators/framework/templates/english.lproj/body.rhtml +3 -0
  192. data/generators/framework/templates/english.lproj/controls.css +0 -0
  193. data/generators/framework/templates/english.lproj/strings.js +14 -0
  194. data/generators/language/USAGE +16 -0
  195. data/generators/language/language_generator.rb +47 -0
  196. data/generators/language/templates/strings.js +10 -0
  197. data/generators/model/USAGE +24 -0
  198. data/generators/model/model_generator.rb +55 -0
  199. data/generators/model/templates/fixture.js +11 -0
  200. data/generators/model/templates/model.js +20 -0
  201. data/generators/model/templates/test.rhtml +21 -0
  202. data/generators/test/USAGE +16 -0
  203. data/generators/test/templates/test.rhtml +21 -0
  204. data/generators/test/test_generator.rb +47 -0
  205. data/generators/view/USAGE +16 -0
  206. data/generators/view/templates/test.rhtml +21 -0
  207. data/generators/view/templates/view.js +20 -0
  208. data/generators/view/view_generator.rb +51 -0
  209. data/jsdoc/README.txt +119 -0
  210. data/jsdoc/app/DocFile.js +137 -0
  211. data/jsdoc/app/DocTag.js +110 -0
  212. data/jsdoc/app/Doclet.js +63 -0
  213. data/jsdoc/app/Dumper.js +143 -0
  214. data/jsdoc/app/JsDoc.js +103 -0
  215. data/jsdoc/app/JsHilite.js +45 -0
  216. data/jsdoc/app/JsIO.js +163 -0
  217. data/jsdoc/app/JsParse.js +385 -0
  218. data/jsdoc/app/JsPlate.js +130 -0
  219. data/jsdoc/app/JsTestrun.js +129 -0
  220. data/jsdoc/app/JsToke.js +564 -0
  221. data/jsdoc/app/Symbol.js +298 -0
  222. data/jsdoc/app/Transformer.js +14 -0
  223. data/jsdoc/app/Util.js +97 -0
  224. data/jsdoc/app/js.jar +0 -0
  225. data/jsdoc/app/run.js +144 -0
  226. data/jsdoc/plugins/min.js +316 -0
  227. data/jsdoc/plugins/strip.js +20 -0
  228. data/jsdoc/templates/sproutcore/class.tmpl +438 -0
  229. data/jsdoc/templates/sproutcore/default.css +241 -0
  230. data/jsdoc/templates/sproutcore/index.html +13 -0
  231. data/jsdoc/templates/sproutcore/index.tmpl +21 -0
  232. data/jsdoc/templates/sproutcore/prototype.js +4186 -0
  233. data/jsdoc/templates/sproutcore/publish.js +236 -0
  234. data/jsdoc/templates/sproutcore/splash.html +7 -0
  235. data/lib/sproutcore/build_tools/html_builder.rb +88 -0
  236. data/lib/sproutcore/build_tools/resource_builder.rb +194 -0
  237. data/lib/sproutcore/build_tools.rb +44 -0
  238. data/lib/sproutcore/bundle.rb +517 -0
  239. data/lib/sproutcore/bundle_manifest.rb +397 -0
  240. data/lib/sproutcore/generator_helper.rb +170 -0
  241. data/lib/sproutcore/helpers/capture_helper.rb +42 -0
  242. data/lib/sproutcore/helpers/static_helper.rb +80 -0
  243. data/lib/sproutcore/helpers/tag_helper.rb +110 -0
  244. data/lib/sproutcore/helpers/text_helper.rb +336 -0
  245. data/lib/sproutcore/helpers.rb +3 -0
  246. data/lib/sproutcore/jsdoc.rb +40 -0
  247. data/lib/sproutcore/jsmin.rb +247 -0
  248. data/lib/sproutcore/library.rb +258 -0
  249. data/lib/sproutcore/merb/bundle_controller.rb +179 -0
  250. data/lib/sproutcore/merb/router.rb +43 -0
  251. data/lib/sproutcore/merb.rb +27 -0
  252. data/lib/sproutcore/version.rb +9 -0
  253. data/lib/sproutcore/view_helpers/button_views.rb +302 -0
  254. data/lib/sproutcore/view_helpers/core_views.rb +284 -0
  255. data/lib/sproutcore/view_helpers/form_views.rb +258 -0
  256. data/lib/sproutcore/view_helpers/menu_views.rb +94 -0
  257. data/lib/sproutcore/view_helpers.rb +628 -0
  258. data/lib/sproutcore.rb +30 -0
  259. data/script/destroy +14 -0
  260. data/script/generate +14 -0
  261. data/script/txt2html +74 -0
  262. data/setup.rb +1585 -0
  263. data/spec/spec.opts +1 -0
  264. data/spec/spec_helper.rb +7 -0
  265. data/spec/sproutcore_spec.rb +11 -0
  266. data/tasks/deployment.rake +34 -0
  267. data/tasks/environment.rake +7 -0
  268. data/tasks/rspec.rake +21 -0
  269. data/tasks/website.rake +17 -0
  270. metadata +365 -0
@@ -0,0 +1,141 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('views/view') ;
7
+
8
+ lc_cnt = 0 ;
9
+
10
+ SC.ImageView = SC.View.extend({
11
+ emptyElement: '<img />',
12
+
13
+ status: 'unknown',
14
+
15
+ content: null, // becomes the url.
16
+ contentBindingDefault: SC.Binding.Single,
17
+
18
+ // override with your own function to transform content into a URL.
19
+ transform: function(content) { return content; },
20
+
21
+ contentObserver: function() {
22
+ var prop = this.get('content') || '' ;
23
+ var url = this.transform(prop) ;
24
+
25
+ if (url && url.length > 0) {
26
+ this.beginPropertyChanges() ;
27
+ this.set('status','loading') ;
28
+ SC.imageCache.loadImage(url, this, this._onLoadComplete) ;
29
+ this.endPropertyChanges() ;
30
+ } else {
31
+ this.rootElement.src = '' ;
32
+ this.set('status','unknown') ;
33
+ }
34
+ }.observes('content') ,
35
+
36
+ _onLoadComplete: function(url, status, img) {
37
+ this.beginPropertyChanges() ;
38
+ this.set('imageWidth', parseInt(img.width,0)) ;
39
+ this.set('imageHeight', parseInt(img.height,0)) ;
40
+ this.set('status',status) ;
41
+ this.endPropertyChanges() ;
42
+
43
+ if (status == 'loaded') {
44
+ if (this.imageDidLoad) this.imageDidLoad(url) ;
45
+ this.rootElement.src = url ;
46
+ } else {
47
+ if (this.imageDidFail) this.imageDidFail(url, status) ;
48
+ }
49
+ },
50
+
51
+ init: function() {
52
+ arguments.callee.base.apply(this,arguments) ;
53
+ if (this.rootElement.src) {
54
+ this.set('imageWidth',parseInt(this.rootElement.width,0)) ;
55
+ this.set('imageHeight',parseInt(this.rootElement.height,0)) ;
56
+ }
57
+ }
58
+
59
+ }) ;
60
+
61
+ // The image cache will create Image objects to preload a set of
62
+ // images. This will control the number of images being loaded to maximize
63
+ // browser throughput.
64
+ SC.imageCache = SC.Object.create({
65
+
66
+ // this restricts the maximum number of images that can load in.
67
+ loadLimit: 4,
68
+
69
+ // this is the primary entry point for the imageCache. Use this method to
70
+ // ask the cache to load an image and then invoke the callback when its
71
+ // available. You can pass either a function or an object + a function.
72
+ // Your callback should have this pattern:
73
+ //
74
+ // method(url, status, imgObject)
75
+ // url: the original URL you passed in.
76
+ // status: loaded | error | aborted
77
+ // imgObject: the image object. This parameter is optional.
78
+ //
79
+ loadImage: function(url, objOrFunc, method) {
80
+ var dta = this._images[url] = (this._images[url] || { url: url,
81
+ img: null, handlers: [], status: 'unknown' }) ;
82
+
83
+ if (dta.img == null) {
84
+ this._queue.push(dta) ;
85
+ if (!this._imgTimeout) {
86
+ this._imgTimeout = setTimeout(this.loadNextImage.bind(this),100) ;
87
+ }
88
+ }
89
+
90
+ // you can pass either just a function or an object + a method. This will
91
+ // handle both.
92
+ var handler = (method) ? [objOrFunc, method] : [this, objOrFunc] ;
93
+ if (dta.status == 'unknown') {
94
+ dta.handlers.push(handler) ;
95
+ } else if (handler[1]) {
96
+ handler[1].call(handler[0], url, dta.status, dta.img) ;
97
+ }
98
+ },
99
+
100
+ // this is called to load images that need
101
+ loadNextImage: function() {
102
+ this._imgTimeout = null ;
103
+ while((this._queue.length > 0) && (this._loading.length < this.loadLimit)) {
104
+ var dta = this._queue.pop() ;
105
+ var url = dta.url ;
106
+ dta.img = new Image() ;
107
+ dta.img.onabort = this._onAbort.bind(this,url) ;
108
+ dta.img.onerror = this._onError.bind(this,url) ;
109
+ dta.img.onload = this._onLoad.bind(this, url) ;
110
+ dta.img.src = dta.url ;
111
+
112
+ // add to loading queue.
113
+ this._loading.push(dta.url) ;
114
+ }
115
+ },
116
+
117
+ _onAbort: function(url) { this._changeStatus(url, 'aborted') ; },
118
+ _onError: function(url) { this._changeStatus(url, 'error'); },
119
+ _onLoad: function(url) { this._changeStatus(url, 'loaded'); },
120
+
121
+ // update the status in the queue and call any queued handlers.
122
+ _changeStatus: function(url, status) {
123
+ var dta = this._images[url] ;
124
+ if (!dta) return ;
125
+ dta.status = status ;
126
+
127
+ var handler ;
128
+ while(handler = dta.handlers.pop()) {
129
+ if (handler[1]) handler[1].call(handler[0], url, dta.status, dta.img) ;
130
+ }
131
+
132
+ // get the next image, if needed.
133
+ this._loading = this._loading.without(dta.url) ;
134
+ this.loadNextImage() ;
135
+ },
136
+
137
+ _images: {},
138
+ _loading: [],
139
+ _queue: []
140
+
141
+ });
@@ -0,0 +1,96 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ SC.inlineTextEditor = SC.View.extend({
7
+
8
+ multiline: true,
9
+
10
+ emptyElement: [
11
+ '<div class="inline_editor">',
12
+ '<div class="inline_editor_sizer"></div>',
13
+ '<textarea class="inline_editor_field" wrap="off"></textarea>',
14
+ //'<input type="text" class="inline_editor_field" />',
15
+ '</div>'
16
+ ].join(''),
17
+
18
+ /**
19
+ * Set the size of the textarea to the width and height of the text value
20
+ */
21
+ render: function()
22
+ {
23
+ var editor = this.get('rootElement');
24
+ var sizer = editor.childNodes[0];
25
+ var field = editor.childNodes[1];
26
+
27
+ // XSS attack waiting to happen... escape the form input;
28
+ var text = (this.field.get('value') || '').escapeHTML();
29
+ // we don't want the text to wrap inside of the sizer...
30
+ text = text.replace(/ /g, "&nbsp;");
31
+ // convert the textarea's newlines into something comparable for the sizer div
32
+ // appending a space to give a line with no text a visible height.
33
+ text = text.replace(/\n/g, "<br />&nbsp;");
34
+
35
+ // get the text size
36
+ sizer.innerHTML = text || "&nbsp;";
37
+ var w = sizer.offsetWidth;
38
+ var h = sizer.offsetHeight;
39
+
40
+ // add it to the editor w/ some wiggle room to prevent
41
+ // the textarea's scrollbars from fickering
42
+ field.style.width = (w + 20) + "px";
43
+ field.style.height = (h + 5) + "px";
44
+ },
45
+
46
+
47
+ outlets: ['field'],
48
+ field: SC.TextFieldView.extend({
49
+
50
+ mouseDown: function(e)
51
+ {
52
+ e._stopWhenHandled = false;
53
+ return this.owner.get('parentNode').get('isEditing');
54
+ },
55
+
56
+ /**
57
+ * resize the editor whenever the field value changes
58
+ * @private
59
+ * @observes value
60
+ */
61
+ valueObserver: function()
62
+ {
63
+ this.owner.render();
64
+ }.observes('value'),
65
+
66
+ willRemoveFromParent: function()
67
+ {
68
+ // [Safari] if you don't take key focus away from an element before you remove it from the DOM
69
+ // key events are no longer sent to the browser.
70
+ this.get('rootElement').blur();
71
+ },
72
+ willLoseFirstResponder: function()
73
+ {
74
+ // should have been covered by willRemoveFromParent, but this was needed too.
75
+ this.get('rootElement').blur();
76
+ var parentNode = this.owner.get('parentNode');
77
+ if ( parentNode )
78
+ {
79
+ if (parentNode.get('isEditing')) parentNode.endInlineEdit();
80
+ }
81
+ },
82
+
83
+ cancel: function()
84
+ {
85
+ var parentNode = this.owner.get('parentNode');
86
+ if (parentNode && parentNode.cancel) parentNode.cancel();
87
+ },
88
+ insertNewline: function()
89
+ {
90
+ var parentNode = this.owner.get('parentNode');
91
+ if (parentNode && parentNode.insertNewline) parentNode.insertNewline();
92
+ }
93
+
94
+ }).outletFor('.inline_editor_field?')
95
+
96
+ }).viewFor(null);
@@ -0,0 +1,176 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('views/view') ;
7
+
8
+ SC.LabelView = SC.View.extend({
9
+
10
+ /**
11
+ * Can the label be edited using the inline editor?
12
+ * @type Boolean
13
+ **/
14
+ isEditable: false,
15
+ /**
16
+ * Is the editor open?
17
+ * @type Boolean
18
+ **/
19
+ isEditing: false,
20
+
21
+
22
+ // set to true to have any markup in the content escaped.
23
+ escapeHTML: true,
24
+
25
+ // set to true to have the value you set automatically localized.
26
+ localize: false,
27
+
28
+
29
+ /**
30
+ * @constructor
31
+ */
32
+ init: function()
33
+ {
34
+ arguments.callee.base.call(this) ;
35
+ if (this.get("localize"))
36
+ {
37
+ var inner = this.get("asHTML");
38
+ if (inner !== "") this.set("content", inner);
39
+ }
40
+ },
41
+
42
+ /**
43
+ * Event dispatcher callback.
44
+ * If isEditable is set to true, opens the inline text editor view.
45
+ * @param {DOMMouseEvent} evt DOM event
46
+ */
47
+ doubleClick: function( evt )
48
+ {
49
+ this.beginInlineEdit();
50
+ },
51
+
52
+
53
+ /**
54
+ * Opens the inline text editor (closing it if it was already open for another view).
55
+ * @return void
56
+ **/
57
+ beginInlineEdit: function()
58
+ {
59
+ if ( !this.get('isEditable') ) return;
60
+ if ( this.get('isEditing') ) return;
61
+
62
+ this.set('isEditing', true);
63
+ this.set("asHTML", ''); // blank out the label contents
64
+ this.appendChild( SC.inlineTextEditor );
65
+ SC.inlineTextEditor.field.set('value', this.get('content'));
66
+ SC.inlineTextEditor.field.becomeFirstResponder();
67
+ },
68
+ /**
69
+ * Closes the inline text editor.
70
+ * @return void
71
+ **/
72
+ endInlineEdit: function()
73
+ {
74
+ if ( !this.get('isEditing') ) return;
75
+
76
+ // if there were changes, then commit them...
77
+ if ( SC.inlineTextEditor.field.get('value') != this.get('content') )
78
+ {
79
+ this._inlineEditValue = SC.inlineTextEditor.field.get('value') ;
80
+ this._closeInlineEditor(false) ;
81
+ }
82
+ else
83
+ {
84
+ this.cancelInlineEdit() ;
85
+ }
86
+ },
87
+
88
+ _inlineEditValue: '',
89
+
90
+ cancelInlineEdit: function()
91
+ {
92
+ if ( !this.get('isEditing') ) return;
93
+ this._closeInlineEditor(true);
94
+ },
95
+
96
+ _closeInlineEditor: function(canceled)
97
+ {
98
+ this.set('isEditing', false);
99
+ this.removeChild( SC.inlineTextEditor );
100
+ if(!canceled)
101
+ {
102
+ this.set('content',this._inlineEditValue) ;
103
+ this.commitInlineEdit();
104
+ }
105
+ else
106
+ {
107
+ this._updateValue() ; // restore value.
108
+ }
109
+ },
110
+
111
+ // abstract method... implement to persist changes made in the editor.
112
+ commitInlineEdit: function() {},
113
+
114
+
115
+ // setting this to a non-null value will cause the label to get the
116
+ // property value and use that for display.
117
+ property: function(key, value) {
118
+ if ((value !== undefined) && (value != this._property)) {
119
+ if (this._content) {
120
+ var func = this._boundObserver() ;
121
+ if (this._property && this._content && this._content.removeObserver) this._content.removeObserver(this._property,func);
122
+ this._property = value ;
123
+ if (this._property && this._content && this._content.addObserver) this._content.addObserver(this._property,func) ;
124
+ } else this._property = value ;
125
+ }
126
+ return this._property ;
127
+ }.property(),
128
+
129
+ // set to a validator object to have your content converted using the
130
+ // validator. The formatter will be applied before localization.
131
+ formatter: null,
132
+
133
+ // change this property value to update the content.
134
+ content: function(key,value) {
135
+ if ((value !== undefined) && (this._content != value)) {
136
+ var prop = this.get('property') ;
137
+ var func = this._boundObserver() ;
138
+ if (prop && this._content && this._content.removeObserver) this._content.removeObserver(prop, func) ;
139
+ this._content = value ;
140
+ if (prop && this._content && this._content.addObserver) this._content.addObserver(prop, func) ;
141
+ this._updateValue() ;
142
+ }
143
+ return this._content ;
144
+ }.property(),
145
+
146
+ contentBindingDefault: SC.Binding.Single,
147
+
148
+ _updateValue: function() {
149
+ var value = this._content ;
150
+ var prop = this.get('property') ;
151
+ if (prop && value && value.get) value = value.get(prop) ;
152
+
153
+ // apply formatter
154
+ var formatter = this.get('formatter') ;
155
+ if (formatter) {
156
+ var formattedValue = (SC.typeOf(formatter) == "function") ? formatter(value,this) : formatter.fieldValueForObject(value) ;
157
+ if (formattedValue) value = formattedValue ;
158
+ }
159
+
160
+ if ($type(value) == 'number') value = value.toString() ; // handle 0
161
+
162
+ // localize
163
+ if (value && this.get('localize')) value = value.loc() ;
164
+ if (value && this.get('escapeHTML') && value.escapeHTML) value = value.escapeHTML() ;
165
+
166
+ // set
167
+ this.set('asHTML',value || '') ;
168
+
169
+ },
170
+
171
+ _boundObserver: function() {
172
+ if (!this._observer) this._observer = this._updateValue.bind(this) ;
173
+ return this._observer ;
174
+ }
175
+
176
+ });
@@ -0,0 +1,90 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('views/view') ;
7
+
8
+ // This is a basic menu item for inclusion in a popup menu. This is a type
9
+ // of button that will automatically close the popup menu when it is
10
+ // pressed.
11
+ SC.MenuItemView = SC.ButtonView.extend({
12
+
13
+ emptyElement: [
14
+ '<li class="button menu-item">',
15
+ '<a href="javascript:;">',
16
+ '<span class="sel">&#x2713;</span>',
17
+ '<span class="mixed">-</span>',
18
+ '<span class="inner">',
19
+ '<span class="label"></span>',
20
+ '</span>',
21
+ '<span class="shortcut"></span>',
22
+ '</a>',
23
+ '</li>'].join(''),
24
+
25
+ // this method returns the computed required width. This is potentially
26
+ // expensive, so don't call it often. It is intended to be used with the
27
+ // wrapper MenuView that will decide how wide to make the menu.
28
+ computedRequiredWidth: function() {
29
+
30
+ var ret = 0;
31
+
32
+ // first, get the left edge offset for the .inner span.
33
+ // we expect this to make room for any checkboxes that might appear on
34
+ // the left and required spacing on the right.
35
+ var el = this.$sel('.inner') ;
36
+ if (el) {
37
+ ret = el.offsetLeft ;
38
+ ret += parseInt(Element.getStyle(el, 'padding-left'),0) ;
39
+ ret += parseInt(Element.getStyle(el, 'padding-right'),0) ;
40
+ }
41
+
42
+ // next, add in the width of any img tag.
43
+ var img = Element.$sel(el,'img') ;
44
+ if (img) {
45
+ ret += Element.getDimensions(img).width ;
46
+ }
47
+
48
+ // next add in the width of any label. We assume this includes the width
49
+ // of the label text itself.
50
+ el = Element.$sel(el, '.label') ;
51
+ if (el) {
52
+ ret += Element.getDimensions(el).width ;
53
+ }
54
+
55
+ // finally, add the width of any shortcut. We assume this includes any
56
+ // padding required to go between the label and the shortcut.
57
+ el = this.$sel('.shortcut') ;
58
+ if (el) {
59
+ ret += Element.getDimensions(el).width ;
60
+ }
61
+
62
+ // that should do it...
63
+ return ret ;
64
+ },
65
+
66
+ mouseMoved: function(evt)
67
+ {
68
+ if (!this.get('isDefault')) this.get('parentNode').set('currentSelectedMenuItem', this);
69
+ },
70
+ mouseOut: function(evt)
71
+ {
72
+ this.set('isDefault', false);
73
+ },
74
+
75
+ mouseUp: function(evt)
76
+ {
77
+ arguments.callee.base.apply(this, arguments);
78
+ this._closeParentMenu();
79
+ },
80
+ didTriggerAction: function()
81
+ {
82
+ this._closeParentMenu();
83
+ },
84
+ _closeParentMenu: function()
85
+ {
86
+ var menu = this.get('parentNode');
87
+ if (menu) menu.set('isVisible', false);
88
+ }
89
+
90
+ });
@@ -0,0 +1,54 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('views/view') ;
7
+ require('controllers/collection') ;
8
+
9
+ // A pagination view renders a widget for showing the total number of pages and
10
+ // for switching between them. It includes a forward arrow, back arrow, and
11
+ // a popup.
12
+ SC.PaginationView = SC.View.extend({
13
+
14
+ // ......................................
15
+ // PROPERTIES
16
+
17
+ // Bind these to the controller properties to support pagination.
18
+ pageSize: 0,
19
+ pageCount: 0,
20
+ currentPage: 0,
21
+
22
+ // This is the format string used for the page count. Will be localized.
23
+ currentPageString: "_%@-%@ of %@",
24
+
25
+ // This is the format string used for the page popup.
26
+ pageOptionString: "_Page %@: %@-%@",
27
+
28
+ hasPreviousPage: function() {
29
+ return this.get('currentPage') > 0 ;
30
+ }.property(),
31
+
32
+ hasNextPage: function() {
33
+ return this.get('currentPage') < this.get('pageCount') ;
34
+ }.property(),
35
+
36
+ // ......................................
37
+ // STRUCTURE
38
+
39
+ // This is the generated element.
40
+ emptyElement: '<div class="pagination">\
41
+ <button class="prev">«</button>\
42
+ <button class="page"></button>\
43
+ <button class="next">»</button>\
44
+ </div>',
45
+
46
+ outlets: ['prevButton','nextButton','pageButton'],
47
+
48
+ prevButton: SC.ButtonView.extend({
49
+ action: function() { this.owner.decrementProperty('currentPage'); },
50
+ isEnabledBinding: "*owner.hasPreviousPage"
51
+ })
52
+
53
+ }) ;
54
+
@@ -0,0 +1,86 @@
1
+ require('views/button') ;
2
+
3
+ /**
4
+ * @class
5
+ * @constructor
6
+ * @extends SC.ButtonView
7
+ * @author Skip Baney
8
+ * @copyright 2006-2007, Sprout Systems, Inc. and contributors.
9
+ * @version 0.1
10
+ */
11
+ SC.PopupButtonView = SC.ButtonView.extend({
12
+
13
+ /**
14
+ * Overriding the default SC.ButtonView#performKeyEquivalent method to pass it onto the menu
15
+ * @param {string} keystring method name corresponding to the keys pressed (i.e alt_shift_z)
16
+ * @param {DOMMouseEvent} evt mousedown event
17
+ */
18
+ performKeyEquivalent: function( keystring, evt )
19
+ {
20
+ if (!this.get('isEnabled')) return false;
21
+
22
+ // is it our own keyEquivalent?
23
+ if (arguments.callee.base.apply(this,arguments)) return true;
24
+
25
+ // is it any of our menu items keyEquivalent?
26
+ var menu = this.get('menu');
27
+ return (!!menu && menu.performKeyEquivalent(keystring, evt));
28
+ },
29
+
30
+ /**
31
+ * Name of the menu view to use.
32
+ * @type {string}
33
+ */
34
+ menuName: null,
35
+
36
+ /**
37
+ * PopupMenu reference. Will be lazy-loaded from the 'menuName' string.
38
+ * @type {SC.PopupMenu}
39
+ */
40
+ menu: function( key, value )
41
+ {
42
+ if ( value !== undefined )
43
+ {
44
+ value.set('isVisible', false);
45
+ this.set('_menu', value);
46
+ }
47
+ if ( !this._menu )
48
+ {
49
+ var menu = SC.page.get(this.get('menuName'));
50
+ if (menu) menu.set('isVisible', false);
51
+ // calling set so that the isSelectedBinding is triggered
52
+ this.set('_menu', menu);
53
+ }
54
+ return this._menu;
55
+ }.property(),
56
+ /**
57
+ * Binds the button's selection state to the menu's visibility.
58
+ * @private
59
+ */
60
+ isSelectedBinding: '*_menu.isVisible',
61
+
62
+ /**
63
+ * Button action handler
64
+ * @param {DOMMouseEvent} evt mouseup event that triggered the action
65
+ */
66
+ action: function( evt )
67
+ {
68
+ var menu = this.get('menu');
69
+ // no menu to toggle... bail...
70
+ if (!menu) return false;
71
+
72
+ if (!this._didFirstRun) {
73
+ // for some reason the menu#isVisible is true the first time we get it...
74
+ // and since this#isSelected is bound to it... we get an incorrect conditional check.
75
+ // hacking it here to keep moving.
76
+ menu.popup(this, evt);
77
+ this._didFirstRun = true;
78
+ } else {
79
+ // toggle the menu...
80
+ this.get('isSelected') ? menu.set('isVisible', false) : menu.popup(this, evt);
81
+ }
82
+
83
+ return true;
84
+ }
85
+
86
+ });