sproutcore 0.9.1 → 0.9.2

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 (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
@@ -0,0 +1,66 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ /**
7
+ @namespace
8
+
9
+ Support methods for the Delegate design pattern.
10
+
11
+ The Delegate design pattern makes it easy to delegate a portion of your
12
+ application logic to another object. This is most often used in views to
13
+ delegate various application-logic decisions to controllers in order to
14
+ avoid having to bake application-logic directly into the view itself.
15
+
16
+ The methods provided by this mixin make it easier to implement this pattern
17
+ but they are not required to support delegates.
18
+
19
+ h2. The Pattern
20
+
21
+ The delegate design pattern typically means that you provide a property,
22
+ usually ending in "delegate", that can be set to another object in the
23
+ system.
24
+
25
+ When events occur or logic decisions need to be made that you would prefer
26
+ to delegate, you can call methods on the delegate if it is set. If the
27
+ delegate is not set, you should provide some default functionality instead.
28
+
29
+ Note that typically delegates are not observable, hence it is not necessary
30
+ to use get() to retrieve the value of the delegate.
31
+
32
+ */
33
+ SC.DelegateSupport = {
34
+
35
+ /**
36
+ Invokes the named method on the delegate that you pass. If no delegate
37
+ is defined or if the delegate does not implement the method, then a
38
+ method of the same name on the receiver will be called instead.
39
+
40
+ You can pass any arguments you want to pass onto the delegate after the
41
+ delegate and methodName.
42
+
43
+ @param {Object} delegate a delegate object. May be null.
44
+ @param {String} methodName a method name
45
+ @param {*} args (OPTIONAL) any additional arguments
46
+
47
+ @returns value returned by delegate
48
+ */
49
+ invokeDelegateMethod: function(delegate, methodName, args) {
50
+ args = $A(arguments); args = args.slice(2, args.length) ;
51
+ if (!delegate || !delegate[methodName]) delegate = this ;
52
+ return delegate[methodName].apply(delegate, args) ;
53
+ },
54
+
55
+ /**
56
+ Gets the named property from the delegate if the delegate exists and it
57
+ defines the property. Otherwise, gets the property from the receiver.
58
+
59
+ @param {Object} delegate the delegate or null
60
+ @param {String} key the property to get.
61
+ */
62
+ getDelegateProperty: function(delegate, key) {
63
+ return (delegate && (delegate[key] != null)) ? delegate.get(key) : this.get(key) ;
64
+ }
65
+
66
+ };
@@ -1,11 +1,11 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
6
  /**
7
- @namespace Implements Key-Value Observing
8
-
7
+ @namespace
8
+
9
9
  Key-Value Observing is one of the fundamental ways that models, controllers
10
10
  and views communicate with each other in a SproutCore application. Any
11
11
  object that has this module applied to it can be used in KVO-operations.
@@ -160,6 +160,15 @@ SC.Observable = {
160
160
  return ret ;
161
161
  },
162
162
 
163
+ /**
164
+ sets the property only if the passed value is different from the
165
+ current value. Depending on how expensive a get() is on this property,
166
+ this may be more efficient.
167
+ */
168
+ setIfChanged: function(key, value) {
169
+ return (this.get(key) != value) ? this.set(key, value) : value ;
170
+ },
171
+
163
172
  /**
164
173
  use this to automatically navigate a property path.
165
174
  */
@@ -339,6 +348,19 @@ SC.Observable = {
339
348
  addProbe: function(key) { this.addObserver(key,logChange); },
340
349
  removeProbe: function(key) { this.removeObserver(key,logChange); },
341
350
 
351
+ /**
352
+ Logs the named properties to the console.
353
+
354
+ @param propertyNames one or more property names
355
+ */
356
+ logProperty: function() {
357
+ var props = $A(arguments) ;
358
+ for(var idx=0;idx<props.length; idx++) {
359
+ var prop = props[idx] ;
360
+ console.log('%@:%@: '.fmt(this._guid, prop), this.get(prop)) ;
361
+ }
362
+ },
363
+
342
364
  /**
343
365
  This method will listen for the observed value to change one time and
344
366
  then will remove itself. You can also set an optional timeout that
@@ -355,13 +377,13 @@ SC.Observable = {
355
377
  var handler = function(theTarget,theKey,theValue,didTimeout) {
356
378
  func(theTarget,theKey,theValue,didTimeout) ;
357
379
  target.removeObserver(key,handler) ;
358
- if (timeoutObject) { clearTimeout(timeoutObject); }
380
+ if (timeoutObject) { timeoutObject.invalidate(); }
359
381
  } ;
360
382
 
361
383
  target.addObserver(key,handler) ;
362
- if (timeout) timeoutObject = setTimeout(function() {
384
+ if (timeout) timeoutObject = function() {
363
385
  handler(target,key,target.get(key),true) ;
364
- }, timeout) ;
386
+ }.invokeLater(this, timeout) ;
365
387
 
366
388
  handler.cancel = function() { target.removeObserver(key,handler); } ;
367
389
  return handler ;
@@ -510,3 +532,151 @@ SC.Observable = {
510
532
  }
511
533
 
512
534
  } ;
535
+
536
+ // ........................................................................
537
+ // FUNCTION ENHANCEMENTS
538
+ //
539
+ // Enhance function.
540
+ Object.extend(Function.prototype,{
541
+
542
+ // Declare a function as a property. This makes it something that can be
543
+ // accessed via get/set.
544
+ property: function() {
545
+ this.dependentKeys = $A(arguments) ;
546
+ this.isProperty = true; return this;
547
+ },
548
+
549
+ // Declare that a function should observe an object at the named path. Note
550
+ // that the path is used only to construct the observation one time.
551
+ observes: function(propertyPaths) {
552
+ this.propertyPaths = $A(arguments);
553
+ return this;
554
+ },
555
+
556
+ typeConverter: function() {
557
+ this.isTypeConverter = true; return this ;
558
+ },
559
+
560
+ /**
561
+ Creates a timer that will execute the function after a specified
562
+ period of time.
563
+
564
+ If you pass an optional set of arguments, the arguments will be passed
565
+ to the function as well. Otherwise the function should have the
566
+ signature:
567
+
568
+ {{{
569
+ function functionName(timer)
570
+ }}}
571
+
572
+ @param interval {Number} the time to wait, in msec
573
+ @param target {Object} optional target object to use as this
574
+ @returns {SC.Timer} scheduled timer
575
+ */
576
+ invokeLater: function(target, interval) {
577
+ if (interval === undefined) interval = 1 ;
578
+ var f = this;
579
+ if (arguments.length > 2) {
580
+ var args =$A(arguments).slice(2,arguments.length);
581
+ args.unshift(target);
582
+ f = f.bind.apply(f, args) ;
583
+ }
584
+ return SC.Timer.schedule({ target: target, action: f, interval: interval });
585
+ }
586
+
587
+ }) ;
588
+
589
+ // ........................................................................
590
+ // OBSERVER QUEUE
591
+ //
592
+ // This queue is used to hold observers when the object you tried to observe
593
+ // does not exist yet. This queue is flushed just before any property
594
+ // notification is sent.
595
+ SC.Observers = {
596
+ queue: {},
597
+
598
+ addObserver: function(propertyPath, func) {
599
+ // try to get the tuple for this.
600
+ if (typeof(propertyPath) == "string") {
601
+ var tuple = SC.Object.tupleForPropertyPath(propertyPath) ;
602
+ } else {
603
+ var tuple = propertyPath;
604
+ }
605
+
606
+ if (tuple) {
607
+ tuple[0].addObserver(tuple[1],func) ;
608
+ } else {
609
+ var ary = this.queue[propertyPath] || [] ;
610
+ ary.push(func) ;
611
+ this.queue[propertyPath] = ary ;
612
+ }
613
+ },
614
+
615
+ removeObserver: function(propertyPath, func) {
616
+ var tuple = SC.Object.tupleForPropertyPath(propertyPath) ;
617
+ if (tuple) {
618
+ tuple[0].removeObserver(tuple[1],func) ;
619
+ }
620
+
621
+ var ary = this.queue[propertyPath] ;
622
+ if (ary) {
623
+ ary = ary.without(func) ;
624
+ this.queue[propertyPath] = ary ;
625
+ }
626
+ },
627
+
628
+ flush: function() {
629
+ var newQueue = {} ;
630
+ for(var path in this.queue) {
631
+ var funcs = this.queue[path] ;
632
+ var tuple = SC.Object.tupleForPropertyPath(path) ;
633
+ if (tuple) {
634
+ var loc = funcs.length ;
635
+ while(--loc >= 0) {
636
+ var func = funcs[loc] ;
637
+ tuple[0].addObserver(tuple[1],func) ;
638
+ }
639
+ } else newQueue[path] = funcs ;
640
+ }
641
+
642
+ // set queue to remaining items
643
+ this.queue = newQueue ;
644
+ }
645
+ } ;
646
+
647
+ // ........................................................................
648
+ // NOTIFCATION QUEUE
649
+ //
650
+ // Property notifications are placed into this queue first and then processed
651
+ // to keep the stack size down.
652
+ SC.NotificationQueue = {
653
+ queue: [],
654
+ maxFlush: 5000, // max time you can spend flushing before we reschedule.
655
+ _flushing: false,
656
+ add: function(target, func, args) { this.queue.push([target, func, args]);},
657
+ flush: function(force) {
658
+ if (this._flushing && !force) return ;
659
+ this._flushing = true ;
660
+
661
+ var start = new Date().getTime() ;
662
+ var now = start ;
663
+ var n = null ;
664
+ while(((now - start) < this.maxFlush) && (n = this.queue.pop())) {
665
+ try {
666
+ var t = n[0] || n[1] ;
667
+ n[1].apply(t,n[2]) ;
668
+ }
669
+ catch(e) {
670
+ console.log("Exception while notify("+n[2]+"): " + e) ;
671
+ } // catch
672
+ now = Date.now() ;
673
+ }
674
+ this._flushing = false ;
675
+
676
+ if (this.queue.length > 0) {
677
+ this.invokeLater(this._reflush, 1) ;
678
+ }
679
+ },
680
+
681
+ _reflush: function() { SC.NotificationQueue.flush(); }
682
+ } ;
@@ -0,0 +1,245 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ /**
7
+ @namespace
8
+
9
+ Any views you implement that are scrollable should include this mixin to
10
+ provide basic support for scrolling actions. You can also override any
11
+ of these methods as needed for your own specific behaviors.
12
+
13
+ Often times instead of adding SC.Scrollable to your view, you should
14
+ place your view inside of an SC.ScrollView. See that class for more
15
+ info.
16
+
17
+ Note that isScrollable must always be true.
18
+
19
+ */
20
+ SC.Scrollable = {
21
+
22
+ /** Informs the view system that the receiver is scrollable.
23
+
24
+ Must always be true.
25
+ */
26
+ isScrollable: true,
27
+
28
+ /**
29
+ Amount to scroll one vertical line.
30
+
31
+ Used by the default implementation of scrollDownLine() and scrollUpLine(). Defaults
32
+ to 20px.
33
+ */
34
+ verticalLineScroll: 20,
35
+
36
+ /**
37
+ Amount to scroll one horizontal line.
38
+
39
+ Used by the default implementation of scrollLeftLine() and scrollRightLine(). Defaults
40
+ to 20px.
41
+ */
42
+ horizontalLineScroll: 20,
43
+
44
+ /**
45
+ Amount to scroll one vertical page.
46
+
47
+ Used by the default implementation of scrollUpPage() and scrollDownPage(). Defaults to
48
+ current innerFrame height.
49
+ */
50
+ verticalPageScroll: function() {
51
+ return this.get('innerFrame').height ;
52
+ }.property('innerFrame'),
53
+
54
+ /**
55
+ Amount to scroll one horizontal page.
56
+
57
+ Used by the default implementation of scrollLeftPage() and scrollRightPage(). Defaults
58
+ to current innerFrame width.
59
+ */
60
+ horizontalPageScroll: function() {
61
+ return this.get('innerFrame').width ;
62
+ }.property('innerFrame'),
63
+
64
+ /**
65
+ Returns true if the receiver has enough vertical content to require
66
+ scrolling.
67
+
68
+ If you do not want to allow vertical scrolling, override this to be false
69
+ and set the appropriate CSS.
70
+
71
+ */
72
+ hasVerticalScroller: function() {
73
+ return this.get('scrollFrame').height > this.get('innerFrame').height ;
74
+ }.property('scrollFrame'),
75
+
76
+ /**
77
+ Returns true if the receiver has enough horizontal content to require
78
+ scrolling.
79
+
80
+ If you do not want to allow horizontal scrolling, override this to be
81
+ false and set the appropriate CSS.
82
+
83
+ */
84
+ hasHorizontalScroller: function() {
85
+ return this.get('scrollFrame').width > this.get('innerFrame').width ;
86
+ }.property('scrollFrame'),
87
+
88
+ /**
89
+ Scrolls the receiver in the horizontal and vertical directions by the
90
+ amount specified, if allowed.
91
+
92
+ @param {Point} amount the amount to scroll. Must include x, y or both
93
+ @returns {Point} the actual amount scrolled.
94
+ */
95
+ scrollBy: function(amount) {
96
+ var sf = this.get('scrollFrame') ;
97
+ var f = this.get('innerFrame') ;
98
+
99
+ if (!this.get('hasVerticalScroller')) amount.y = 0 ;
100
+ if (sf.height <= f.height) amount.y = 0 ;
101
+
102
+ if (!this.get('hasHorizontalScroller')) amount.x = 0 ;
103
+ if (sf.width <= f.width) amount.x = 0 ;
104
+
105
+ // compute new sf
106
+ var newSf = { x: sf.x - (amount.x || 0), y: sf.y - (amount.y || 0) } ;
107
+ newSf = this.set('scrollFrame', newSf) ;
108
+ return { x: newSf.x - sf.x, y: newSf.y - sf.y };
109
+ },
110
+
111
+ /**
112
+ Scrolls the receiver to the specified x,y coordinate
113
+ */
114
+ scrollTo: function(x,y) {
115
+ console.log('scrollTo(%@,%@)'.fmt(x,y)) ;
116
+ this.set('scrollFrame', { x: 0-x, y: 0-y }) ;
117
+ },
118
+
119
+ /**
120
+ Scroll the view to make the passed frame visible.
121
+
122
+ Frame must be relative to the receiver's offsetParent.
123
+
124
+ @param {SC.View} view the view you want to make visible
125
+ */
126
+ scrollToVisible: function(view) {
127
+
128
+ // get frames and convert them to proper offsets
129
+ var f = this.get('innerFrame') ;
130
+ var sf = this.get('scrollFrame') ;
131
+
132
+ // frame of the view, relative to the top of the scroll frame
133
+ var vf = this.convertFrameFromView(view.get('frame'), view) ;
134
+ vf.x -= (f.x + sf.x); vf.y -= (f.y + sf.y);
135
+
136
+ // first visible origin
137
+ var vo = {
138
+ x: 0-sf.x,
139
+ y: 0-sf.y,
140
+ width: f.width,
141
+ height: f.height
142
+ };
143
+
144
+ // if top edge is not visible, shift origin
145
+ vo.y += Math.max(0, SC.minY(vo) - SC.minY(vf)) ;
146
+ vo.x += Math.max(0, SC.minX(vo) - SC.minX(vf)) ;
147
+
148
+ // if bottom edge is not visible, shift origin
149
+ vo.y += Math.max(0, SC.maxY(vf) - SC.maxY(vo)) ;
150
+ vo.x += Math.max(0, SC.maxX(vf) - SC.maxX(vo)) ;
151
+
152
+ // scroll to that origin.
153
+ this.scrollTo(vo.x, vo.y) ;
154
+ },
155
+
156
+ /**
157
+ Scrolls the receiver down one line if allowed.
158
+
159
+ @param {Number} lines number of lines to scroll
160
+ @returns {Number} the amount actually scrolled.
161
+ */
162
+ scrollDownLine: function(lines) {
163
+ if (lines === undefined) lines = 1 ;
164
+ return this.scrollBy({ y: this.get('verticalLineScroll')*lines }).y ;
165
+ },
166
+
167
+ /**
168
+ Scrolls the receiver down up line if allowed.
169
+
170
+ @param {Number} lines number of lines to scroll
171
+ @returns {Number} the amount actually scrolled.
172
+ */
173
+ scrollUpLine: function(lines) {
174
+ if (lines === undefined) lines = 1 ;
175
+ return 0-this.scrollBy({ y: 0-this.get('verticalLineScroll')*lines }).y ;
176
+ },
177
+
178
+ /**
179
+ Scrolls the receiver right one line if allowed.
180
+
181
+ @param {Number} lines number of lines to scroll
182
+ @returns {Number} the amount actually scrolled.
183
+ */
184
+ scrollRightLine: function(lines) {
185
+ if (lines === undefined) lines = 1 ;
186
+ return this.scrollTo({ y: this.get('horizontalLineScroll')*lines }).x ;
187
+ },
188
+
189
+ /**
190
+ Scrolls the receiver left one line if allowed.
191
+
192
+ @param {Number} lines number of lines to scroll
193
+ @returns {Number} the amount actually scrolled.
194
+ */
195
+ scrollLeftLine: function(lines) {
196
+ if (lines === undefined) lines = 1 ;
197
+ return 0-this.scrollTo({ y: 0-this.get('horizontalLineScroll')*lines }).x ;
198
+ },
199
+
200
+ /**
201
+ Scrolls the receiver down one page if allowed.
202
+
203
+ @param {Number} pages number of pages to scroll
204
+ @returns {Number} the amount actually scrolled.
205
+ */
206
+ scrollDownPage: function(pages) {
207
+ if (pages === undefined) pages = 1 ;
208
+ return this.scrollBy({ y: this.get('verticalPageScroll')*pages }).y ;
209
+ },
210
+
211
+ /**
212
+ Scrolls the receiver down up page if allowed.
213
+
214
+ @param {Number} pages number of pages to scroll
215
+ @returns {Number} the amount actually scrolled.
216
+ */
217
+ scrollUpPage: function(pages) {
218
+ if (pages === undefined) pages = 1 ;
219
+ return 0-this.scrollBy({ y: 0-this.get('verticalPageScroll')*pages }).y ;
220
+ },
221
+
222
+ /**
223
+ Scrolls the receiver right one page if allowed.
224
+
225
+ @param {Number} pages number of pages to scroll
226
+ @returns {Number} the amount actually scrolled.
227
+ */
228
+ scrollRightPage: function(pages) {
229
+ if (pages === undefined) pages = 1 ;
230
+ return this.scrollTo({ y: this.get('horizontalPageScroll')*pages }).x ;
231
+ },
232
+
233
+ /**
234
+ Scrolls the receiver left one page if allowed.
235
+
236
+ @param {Number} pages number of pages to scroll
237
+ @returns {Number} the amount actually scrolled.
238
+ */
239
+ scrollLeftPage: function(pages) {
240
+ if (pages === undefined) pages = 1 ;
241
+ return 0-this.scrollTo({ y: 0-this.get('horizontalPageScroll')*pages }).x ;
242
+ }
243
+
244
+ } ;
245
+