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.
- data/History.txt +233 -0
- data/Manifest.txt +67 -34
- data/bin/sc-build +12 -1
- data/bin/sc-gen +1 -1
- data/bin/sproutcore +14 -0
- data/clients/sc_docs/controllers/docs.js +38 -8
- data/clients/sc_docs/english.lproj/body.css +80 -127
- data/clients/sc_docs/english.lproj/body.rhtml +43 -23
- data/clients/sc_docs/english.lproj/no_docs.rhtml +2 -1
- data/clients/sc_docs/english.lproj/tabs.rhtml +16 -0
- data/clients/sc_docs/main.js +14 -9
- data/clients/sc_docs/models/doc.js +1 -1
- data/clients/sc_docs/tests/controllers/docs.rhtml +1 -2
- data/clients/sc_docs/tests/models/doc.rhtml +1 -2
- data/clients/sc_docs/tests/views/doc_frame.rhtml +1 -2
- data/clients/sc_docs/tests/views/doc_label_view.rhtml +1 -2
- data/clients/sc_docs/views/doc_frame.js +1 -1
- data/clients/sc_test_runner/controllers/runner.js +31 -8
- data/clients/sc_test_runner/english.lproj/body.css +62 -122
- data/clients/sc_test_runner/english.lproj/body.rhtml +62 -26
- data/clients/sc_test_runner/main.js +1 -6
- data/clients/sc_test_runner/models/test.js +14 -1
- data/clients/sc_test_runner/views/runner_frame.js +4 -2
- data/clients/view_builder/builders/builder.js +339 -0
- data/clients/view_builder/builders/button.js +81 -0
- data/clients/view_builder/controllers/document.js +21 -0
- data/clients/view_builder/core.js +19 -0
- data/clients/view_builder/english.lproj/body.css +77 -0
- data/clients/view_builder/english.lproj/body.rhtml +41 -0
- data/clients/{sc_docs → view_builder}/english.lproj/controls.css +0 -0
- data/clients/view_builder/english.lproj/strings.js +14 -0
- data/clients/view_builder/main.js +38 -0
- data/clients/view_builder/tests/controllers/document.rhtml +20 -0
- data/clients/view_builder/tests/views/builder.rhtml +20 -0
- data/clients/view_builder/views/builder.js +23 -0
- data/frameworks/prototype/prototype.js +1 -1
- data/frameworks/sproutcore/Core.js +32 -7
- data/frameworks/sproutcore/README +1 -1
- data/frameworks/sproutcore/animation/animation.js +411 -0
- data/frameworks/sproutcore/controllers/array.js +17 -9
- data/frameworks/sproutcore/controllers/collection.js +9 -110
- data/frameworks/sproutcore/controllers/controller.js +1 -1
- data/frameworks/sproutcore/controllers/object.js +2 -1
- data/frameworks/sproutcore/drag/drag.js +267 -56
- data/frameworks/sproutcore/drag/drag_data_source.js +24 -16
- data/frameworks/sproutcore/drag/drag_source.js +53 -42
- data/frameworks/sproutcore/drag/drop_target.js +2 -2
- data/frameworks/sproutcore/english.lproj/buttons.css +337 -236
- data/frameworks/sproutcore/english.lproj/core.css +115 -0
- data/frameworks/sproutcore/english.lproj/icons.css +227 -0
- data/{clients/sc_docs → frameworks/sproutcore}/english.lproj/images/indicator.gif +0 -0
- data/frameworks/sproutcore/english.lproj/images/sc-theme-sprite.png +0 -0
- data/frameworks/sproutcore/english.lproj/images/sc-theme-ysprite.png +0 -0
- data/frameworks/sproutcore/english.lproj/images/shared-icons.png +0 -0
- data/frameworks/sproutcore/english.lproj/menu.css +1 -1
- data/frameworks/sproutcore/english.lproj/strings.js +1 -1
- data/frameworks/sproutcore/english.lproj/theme.css +405 -31
- data/frameworks/sproutcore/foundation/application.js +15 -11
- data/frameworks/sproutcore/foundation/benchmark.js +1 -1
- data/frameworks/sproutcore/foundation/binding.js +2 -2
- data/frameworks/sproutcore/foundation/date.js +1 -1
- data/frameworks/sproutcore/foundation/error.js +1 -1
- data/frameworks/sproutcore/foundation/input_manager.js +32 -21
- data/frameworks/sproutcore/foundation/mock.js +1 -1
- data/frameworks/sproutcore/foundation/node_descriptor.js +9 -6
- data/frameworks/sproutcore/foundation/object.js +249 -177
- data/frameworks/sproutcore/foundation/page.js +5 -2
- data/frameworks/sproutcore/foundation/path_module.js +11 -10
- data/frameworks/sproutcore/foundation/responder.js +5 -2
- data/frameworks/sproutcore/foundation/routes.js +17 -13
- data/frameworks/sproutcore/foundation/run_loop.js +249 -11
- data/frameworks/sproutcore/foundation/server.js +1 -1
- data/frameworks/sproutcore/foundation/set.js +3 -3
- data/frameworks/sproutcore/foundation/string.js +5 -3
- data/frameworks/sproutcore/foundation/timer.js +371 -0
- data/frameworks/sproutcore/foundation/undo_manager.js +1 -1
- data/frameworks/sproutcore/foundation/unittest.js +3 -3
- data/frameworks/sproutcore/foundation/utils.js +161 -2
- data/frameworks/sproutcore/globals/panels.js +1 -1
- data/frameworks/sproutcore/globals/popups.js +4 -3
- data/frameworks/sproutcore/globals/window.js +44 -4
- data/frameworks/sproutcore/lib/button_views.rb +328 -0
- data/frameworks/sproutcore/lib/collection_view.rb +80 -0
- data/frameworks/sproutcore/lib/core_views.rb +281 -0
- data/frameworks/sproutcore/lib/form_views.rb +253 -0
- data/frameworks/sproutcore/lib/index.rhtml +2 -0
- data/frameworks/sproutcore/lib/menu_views.rb +88 -0
- data/frameworks/sproutcore/{foundation → mixins}/array.js +60 -29
- data/frameworks/sproutcore/mixins/control.js +265 -0
- data/frameworks/sproutcore/mixins/delegate_support.js +66 -0
- data/frameworks/sproutcore/{foundation → mixins}/observable.js +176 -6
- data/frameworks/sproutcore/mixins/scrollable.js +245 -0
- data/frameworks/sproutcore/mixins/selection_support.js +148 -0
- data/frameworks/sproutcore/mixins/validatable.js +152 -0
- data/frameworks/sproutcore/models/collection.js +5 -5
- data/frameworks/sproutcore/models/record.js +1 -1
- data/frameworks/sproutcore/models/store.js +1 -1
- data/frameworks/sproutcore/panes/dialog.js +1 -1
- data/frameworks/sproutcore/panes/manager.js +1 -1
- data/frameworks/sproutcore/panes/menu.js +1 -1
- data/frameworks/sproutcore/panes/overlay.js +2 -2
- data/frameworks/sproutcore/panes/panel.js +1 -1
- data/frameworks/sproutcore/panes/picker.js +1 -1
- data/frameworks/sproutcore/tests/controllers/array.rhtml +44 -4
- data/frameworks/sproutcore/tests/foundation/timer/invalidate.rhtml +33 -0
- data/frameworks/sproutcore/tests/foundation/timer/invokeLater.rhtml +145 -0
- data/frameworks/sproutcore/tests/foundation/timer/isPaused.rhtml +70 -0
- data/frameworks/sproutcore/tests/foundation/timer/schedule.rhtml +145 -0
- data/frameworks/sproutcore/tests/views/{scroll.rhtml → checkbox.rhtml} +3 -3
- data/frameworks/sproutcore/tests/views/{collection.rhtml → collection/base.rhtml} +33 -32
- data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +260 -0
- data/frameworks/sproutcore/tests/views/image_cell.rhtml +19 -0
- data/frameworks/sproutcore/tests/views/label_item.rhtml +2 -4
- data/frameworks/sproutcore/tests/views/list.rhtml +2 -3
- data/frameworks/sproutcore/tests/views/list_item.rhtml +20 -0
- data/frameworks/sproutcore/tests/views/slider.rhtml +20 -0
- data/frameworks/sproutcore/tests/views/text_cell.rhtml +19 -0
- data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +395 -0
- data/frameworks/sproutcore/tests/views/view/frame.rhtml +353 -0
- data/frameworks/sproutcore/tests/views/view/innerFrame.rhtml +347 -0
- data/frameworks/sproutcore/tests/views/view/isVisibleInWindow.rhtml +148 -0
- data/frameworks/sproutcore/tests/views/view/scrollFrame.rhtml +468 -0
- data/frameworks/sproutcore/validators/credit_card.js +33 -13
- data/frameworks/sproutcore/validators/date.js +26 -6
- data/frameworks/sproutcore/validators/email.js +21 -3
- data/frameworks/sproutcore/validators/not_empty.js +11 -1
- data/frameworks/sproutcore/validators/number.js +18 -4
- data/frameworks/sproutcore/validators/password.js +12 -1
- data/frameworks/sproutcore/validators/validator.js +204 -194
- data/frameworks/sproutcore/views/{button.js → button/button.js} +96 -94
- data/frameworks/sproutcore/views/button/checkbox.js +29 -0
- data/frameworks/sproutcore/views/button/disclosure.js +42 -0
- data/frameworks/sproutcore/views/button/radio.js +29 -0
- data/frameworks/sproutcore/views/{collection.js → collection/collection.js} +1373 -1024
- data/frameworks/sproutcore/views/collection/grid.js +124 -46
- data/frameworks/sproutcore/views/collection/image_cell.js +17 -46
- data/frameworks/sproutcore/views/collection/list.js +45 -35
- data/frameworks/sproutcore/views/collection/source_list.js +386 -0
- data/frameworks/sproutcore/views/collection/table.js +118 -0
- data/frameworks/sproutcore/views/container.js +7 -2
- data/frameworks/sproutcore/views/error_explanation.js +23 -10
- data/frameworks/sproutcore/views/{checkbox_field.js → field/checkbox_field.js} +16 -6
- data/frameworks/sproutcore/views/field/field.js +219 -0
- data/frameworks/sproutcore/views/{radio_field.js → field/radio_field.js} +27 -12
- data/frameworks/sproutcore/views/{select_field.js → field/select_field.js} +116 -90
- data/frameworks/sproutcore/views/{text_field.js → field/text_field.js} +57 -8
- data/frameworks/sproutcore/views/{textarea_field.js → field/textarea_field.js} +13 -3
- data/frameworks/sproutcore/views/filter_button.js +2 -2
- data/frameworks/sproutcore/views/form.js +3 -3
- data/frameworks/sproutcore/views/image.js +128 -21
- data/frameworks/sproutcore/views/inline_text_editor.js +1 -1
- data/frameworks/sproutcore/views/label.js +149 -92
- data/frameworks/sproutcore/views/list_item.js +225 -0
- data/frameworks/sproutcore/views/menu_item.js +10 -4
- data/frameworks/sproutcore/views/pagination.js +11 -4
- data/frameworks/sproutcore/views/popup_button.js +25 -21
- data/frameworks/sproutcore/views/popup_menu.js +10 -4
- data/frameworks/sproutcore/views/progress.js +29 -16
- data/frameworks/sproutcore/views/radio_group.js +1 -1
- data/frameworks/sproutcore/views/scroll.js +60 -20
- data/frameworks/sproutcore/views/segmented.js +1 -1
- data/frameworks/sproutcore/views/slider.js +132 -0
- data/frameworks/sproutcore/views/source_list_group.js +130 -0
- data/frameworks/sproutcore/views/spinner.js +1 -1
- data/frameworks/sproutcore/views/split.js +292 -0
- data/frameworks/sproutcore/views/split_divider.js +109 -0
- data/frameworks/sproutcore/views/tab.js +1 -1
- data/frameworks/sproutcore/views/toolbar.js +1 -1
- data/frameworks/sproutcore/views/view.js +1272 -591
- data/generators/client/templates/english.lproj/body.css +1 -1
- data/generators/controller/controller_generator.rb +1 -1
- data/generators/controller/templates/test.rhtml +2 -1
- data/generators/model/templates/test.rhtml +1 -1
- data/generators/test/templates/test.rhtml +1 -1
- data/generators/view/templates/test.rhtml +1 -1
- data/jsdoc/templates/sproutcore/class.tmpl +241 -338
- data/jsdoc/templates/sproutcore/default.css +105 -155
- data/jsdoc/templates/sproutcore/index.tmpl +43 -8
- data/jsdoc/templates/sproutcore/publish.js +9 -4
- data/lib/sproutcore/build_tools/html_builder.rb +29 -13
- data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
- data/lib/sproutcore/bundle.rb +86 -25
- data/lib/sproutcore/jsdoc.rb +2 -0
- data/lib/sproutcore/version.rb +1 -1
- data/lib/sproutcore/view_helpers.rb +36 -3
- data/tasks/deployment.rake +1 -1
- metadata +69 -36
- data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
- data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
- data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
- data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
- data/clients/sc_docs/english.lproj/warning.rhtml +0 -6
- data/clients/sc_test_runner/english.lproj/warning.rhtml +0 -6
- data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
- data/frameworks/sproutcore/english.lproj/collections.css +0 -82
- data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
- data/frameworks/sproutcore/views/collection/collection_item.js +0 -36
- data/frameworks/sproutcore/views/collection/text_cell.js +0 -128
- data/frameworks/sproutcore/views/field.js +0 -214
- data/frameworks/sproutcore/views/workspace.js +0 -170
- data/generators/client/templates/english.lproj/controls.css +0 -0
- data/generators/framework/templates/english.lproj/body.css +0 -0
- data/generators/framework/templates/english.lproj/body.rhtml +0 -3
- data/generators/framework/templates/english.lproj/controls.css +0 -0
- data/lib/sproutcore/view_helpers/button_views.rb +0 -302
- data/lib/sproutcore/view_helpers/core_views.rb +0 -292
- data/lib/sproutcore/view_helpers/form_views.rb +0 -258
- 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-
|
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
|
4
4
|
// ========================================================================
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
@namespace
|
|
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) {
|
|
380
|
+
if (timeoutObject) { timeoutObject.invalidate(); }
|
|
359
381
|
} ;
|
|
360
382
|
|
|
361
383
|
target.addObserver(key,handler) ;
|
|
362
|
-
if (timeout) timeoutObject =
|
|
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
|
+
|