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.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +269 -0
- data/README.txt +67 -0
- data/Rakefile +4 -0
- data/app_generators/sproutcore/USAGE +5 -0
- data/app_generators/sproutcore/sproutcore_generator.rb +66 -0
- data/app_generators/sproutcore/templates/README +77 -0
- data/app_generators/sproutcore/templates/environment.yml +4 -0
- data/bin/sc-build +145 -0
- data/bin/sc-gen +24 -0
- data/bin/sc-server +63 -0
- data/bin/sproutcore +21 -0
- data/clients/sc_docs/controllers/docs.js +118 -0
- data/clients/sc_docs/core.js +19 -0
- data/clients/sc_docs/english.lproj/body.css +159 -0
- data/clients/sc_docs/english.lproj/body.rhtml +33 -0
- data/clients/sc_docs/english.lproj/controls.css +0 -0
- 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/indicator.gif +0 -0
- data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
- data/clients/sc_docs/english.lproj/no_docs.rhtml +7 -0
- data/clients/sc_docs/english.lproj/strings.js +14 -0
- data/clients/sc_docs/english.lproj/warning.rhtml +6 -0
- data/clients/sc_docs/fixtures/doc.js +11 -0
- data/clients/sc_docs/main.js +21 -0
- data/clients/sc_docs/models/doc.js +9 -0
- data/clients/sc_docs/tests/controllers/docs.rhtml +21 -0
- data/clients/sc_docs/tests/models/doc.rhtml +21 -0
- data/clients/sc_docs/tests/views/doc_frame.rhtml +21 -0
- data/clients/sc_docs/tests/views/doc_label_view.rhtml +21 -0
- data/clients/sc_docs/views/doc_frame.js +33 -0
- data/clients/sc_docs/views/doc_label.js +20 -0
- data/clients/sc_test_runner/controllers/runner.js +175 -0
- data/clients/sc_test_runner/core.js +19 -0
- data/clients/sc_test_runner/english.lproj/body.css +151 -0
- data/clients/sc_test_runner/english.lproj/body.rhtml +35 -0
- data/clients/sc_test_runner/english.lproj/controls.css +0 -0
- data/clients/sc_test_runner/english.lproj/icons/small/next.png +0 -0
- data/clients/sc_test_runner/english.lproj/icons/small/reset.png +0 -0
- data/clients/sc_test_runner/english.lproj/images/gradients.png +0 -0
- data/clients/sc_test_runner/english.lproj/images/indicator.gif +0 -0
- data/clients/sc_test_runner/english.lproj/images/toolbar.png +0 -0
- data/clients/sc_test_runner/english.lproj/no_tests.rhtml +6 -0
- data/clients/sc_test_runner/english.lproj/strings.js +14 -0
- data/clients/sc_test_runner/english.lproj/warning.rhtml +6 -0
- data/clients/sc_test_runner/fixtures/test.js +12 -0
- data/clients/sc_test_runner/main.js +26 -0
- data/clients/sc_test_runner/models/test.js +11 -0
- data/clients/sc_test_runner/views/runner_frame.js +72 -0
- data/clients/sc_test_runner/views/test_label.js +20 -0
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/environment.yml +9 -0
- data/frameworks/prototype/prototype.js +4186 -0
- data/frameworks/sproutcore/Core.js +378 -0
- data/frameworks/sproutcore/README +3 -0
- data/frameworks/sproutcore/controllers/array.js +236 -0
- data/frameworks/sproutcore/controllers/collection.js +305 -0
- data/frameworks/sproutcore/controllers/controller.js +323 -0
- data/frameworks/sproutcore/controllers/object.js +372 -0
- data/frameworks/sproutcore/drag/drag.js +549 -0
- data/frameworks/sproutcore/drag/drag_data_source.js +32 -0
- data/frameworks/sproutcore/drag/drag_source.js +64 -0
- data/frameworks/sproutcore/drag/drop_target.js +153 -0
- data/frameworks/sproutcore/english.lproj/blank.gif +0 -0
- data/frameworks/sproutcore/english.lproj/buttons.css +589 -0
- data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
- data/frameworks/sproutcore/english.lproj/inline_text_editor.css +21 -0
- data/frameworks/sproutcore/english.lproj/menu.css +121 -0
- data/frameworks/sproutcore/english.lproj/panels/background-fat.jpg +0 -0
- data/frameworks/sproutcore/english.lproj/panels/background-thin.jpg +0 -0
- data/frameworks/sproutcore/english.lproj/panels/bottom-edge.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/bottom-left-corner.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/bottom-right-corner.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/left-edge.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/overlay.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/right-edge.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/top-edge.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/top-left-corner.png +0 -0
- data/frameworks/sproutcore/english.lproj/panels/top-right-corner.png +0 -0
- data/frameworks/sproutcore/english.lproj/panes.css +155 -0
- data/frameworks/sproutcore/english.lproj/picker.css +22 -0
- data/frameworks/sproutcore/english.lproj/strings.js +15 -0
- data/frameworks/sproutcore/english.lproj/tab.css +23 -0
- data/frameworks/sproutcore/english.lproj/tests.css +67 -0
- data/frameworks/sproutcore/english.lproj/theme.css +77 -0
- data/frameworks/sproutcore/foundation/animator.js +670 -0
- data/frameworks/sproutcore/foundation/application.js +199 -0
- data/frameworks/sproutcore/foundation/array.js +348 -0
- data/frameworks/sproutcore/foundation/benchmark.js +211 -0
- data/frameworks/sproutcore/foundation/binding.js +384 -0
- data/frameworks/sproutcore/foundation/date.js +357 -0
- data/frameworks/sproutcore/foundation/error.js +39 -0
- data/frameworks/sproutcore/foundation/input_manager.js +153 -0
- data/frameworks/sproutcore/foundation/json.js +296 -0
- data/frameworks/sproutcore/foundation/mock.js +42 -0
- data/frameworks/sproutcore/foundation/node_descriptor.js +56 -0
- data/frameworks/sproutcore/foundation/object.js +777 -0
- data/frameworks/sproutcore/foundation/observable.js +451 -0
- data/frameworks/sproutcore/foundation/page.js +63 -0
- data/frameworks/sproutcore/foundation/path_module.js +413 -0
- data/frameworks/sproutcore/foundation/responder.js +310 -0
- data/frameworks/sproutcore/foundation/routes.js +371 -0
- data/frameworks/sproutcore/foundation/run_loop.js +21 -0
- data/frameworks/sproutcore/foundation/server.js +491 -0
- data/frameworks/sproutcore/foundation/set.js +96 -0
- data/frameworks/sproutcore/foundation/string.js +149 -0
- data/frameworks/sproutcore/foundation/undo_manager.js +186 -0
- data/frameworks/sproutcore/foundation/unittest.js +622 -0
- data/frameworks/sproutcore/foundation/utils.js +61 -0
- data/frameworks/sproutcore/globals/panels.js +182 -0
- data/frameworks/sproutcore/globals/popups.js +60 -0
- data/frameworks/sproutcore/globals/window.js +381 -0
- data/frameworks/sproutcore/lib/index.rhtml +66 -0
- data/frameworks/sproutcore/models/collection.js +395 -0
- data/frameworks/sproutcore/models/record.js +622 -0
- data/frameworks/sproutcore/models/store.js +295 -0
- data/frameworks/sproutcore/panes/dialog.js +16 -0
- data/frameworks/sproutcore/panes/manager.js +164 -0
- data/frameworks/sproutcore/panes/menu.js +45 -0
- data/frameworks/sproutcore/panes/overlay.js +231 -0
- data/frameworks/sproutcore/panes/pane.js +90 -0
- data/frameworks/sproutcore/panes/panel.js +19 -0
- data/frameworks/sproutcore/panes/picker.js +45 -0
- data/frameworks/sproutcore/tests/controllers/array.rhtml +86 -0
- data/frameworks/sproutcore/tests/controllers/controller.rhtml +273 -0
- data/frameworks/sproutcore/tests/controllers/object.rhtml +327 -0
- data/frameworks/sproutcore/tests/foundation/application.rhtml +125 -0
- data/frameworks/sproutcore/tests/foundation/array.rhtml +221 -0
- data/frameworks/sproutcore/tests/foundation/object.rhtml +69 -0
- data/frameworks/sproutcore/tests/globals/window.rhtml +45 -0
- data/frameworks/sproutcore/tests/panes/pane.rhtml +88 -0
- data/frameworks/sproutcore/tests/views/collection.rhtml +137 -0
- data/frameworks/sproutcore/tests/views/popup_button.rhtml +115 -0
- data/frameworks/sproutcore/tests/views/text_field.rhtml +37 -0
- data/frameworks/sproutcore/validators/credit_card.js +92 -0
- data/frameworks/sproutcore/validators/date.js +36 -0
- data/frameworks/sproutcore/validators/email.js +29 -0
- data/frameworks/sproutcore/validators/not_empty.js +24 -0
- data/frameworks/sproutcore/validators/number.js +55 -0
- data/frameworks/sproutcore/validators/password.js +78 -0
- data/frameworks/sproutcore/validators/validator.js +304 -0
- data/frameworks/sproutcore/views/button.js +425 -0
- data/frameworks/sproutcore/views/checkbox_field.js +30 -0
- data/frameworks/sproutcore/views/collection.js +1521 -0
- data/frameworks/sproutcore/views/container.js +62 -0
- data/frameworks/sproutcore/views/error_explanation.js +45 -0
- data/frameworks/sproutcore/views/field.js +214 -0
- data/frameworks/sproutcore/views/filter_button.js +29 -0
- data/frameworks/sproutcore/views/form.js +591 -0
- data/frameworks/sproutcore/views/image.js +141 -0
- data/frameworks/sproutcore/views/inline_text_editor.js +96 -0
- data/frameworks/sproutcore/views/label.js +176 -0
- data/frameworks/sproutcore/views/menu_item.js +90 -0
- data/frameworks/sproutcore/views/pagination.js +54 -0
- data/frameworks/sproutcore/views/popup_button.js +86 -0
- data/frameworks/sproutcore/views/popup_menu.js +137 -0
- data/frameworks/sproutcore/views/progress.js +100 -0
- data/frameworks/sproutcore/views/radio_field.js +107 -0
- data/frameworks/sproutcore/views/radio_group.js +48 -0
- data/frameworks/sproutcore/views/segmented.js +80 -0
- data/frameworks/sproutcore/views/select_field.js +272 -0
- data/frameworks/sproutcore/views/spinner.js +11 -0
- data/frameworks/sproutcore/views/tab.js +126 -0
- data/frameworks/sproutcore/views/text_field.js +179 -0
- data/frameworks/sproutcore/views/textarea_field.js +14 -0
- data/frameworks/sproutcore/views/toolbar.js +29 -0
- data/frameworks/sproutcore/views/view.js +1389 -0
- data/frameworks/sproutcore/views/workspace.js +170 -0
- data/generators/client/README +3 -0
- data/generators/client/USAGE +12 -0
- data/generators/client/client_generator.rb +53 -0
- data/generators/client/templates/core.js +19 -0
- data/generators/client/templates/english.lproj/body.css +0 -0
- data/generators/client/templates/english.lproj/body.rhtml +3 -0
- data/generators/client/templates/english.lproj/controls.css +0 -0
- data/generators/client/templates/english.lproj/strings.js +14 -0
- data/generators/client/templates/main.js +37 -0
- data/generators/controller/USAGE +16 -0
- data/generators/controller/controller_generator.rb +51 -0
- data/generators/controller/templates/controller.js +21 -0
- data/generators/controller/templates/test.rhtml +21 -0
- data/generators/framework/README +7 -0
- data/generators/framework/USAGE +12 -0
- data/generators/framework/framework_generator.rb +53 -0
- data/generators/framework/templates/core.js +20 -0
- data/generators/framework/templates/english.lproj/body.css +0 -0
- data/generators/framework/templates/english.lproj/body.rhtml +3 -0
- data/generators/framework/templates/english.lproj/controls.css +0 -0
- data/generators/framework/templates/english.lproj/strings.js +14 -0
- data/generators/language/USAGE +16 -0
- data/generators/language/language_generator.rb +47 -0
- data/generators/language/templates/strings.js +10 -0
- data/generators/model/USAGE +24 -0
- data/generators/model/model_generator.rb +55 -0
- data/generators/model/templates/fixture.js +11 -0
- data/generators/model/templates/model.js +20 -0
- data/generators/model/templates/test.rhtml +21 -0
- data/generators/test/USAGE +16 -0
- data/generators/test/templates/test.rhtml +21 -0
- data/generators/test/test_generator.rb +47 -0
- data/generators/view/USAGE +16 -0
- data/generators/view/templates/test.rhtml +21 -0
- data/generators/view/templates/view.js +20 -0
- data/generators/view/view_generator.rb +51 -0
- data/jsdoc/README.txt +119 -0
- data/jsdoc/app/DocFile.js +137 -0
- data/jsdoc/app/DocTag.js +110 -0
- data/jsdoc/app/Doclet.js +63 -0
- data/jsdoc/app/Dumper.js +143 -0
- data/jsdoc/app/JsDoc.js +103 -0
- data/jsdoc/app/JsHilite.js +45 -0
- data/jsdoc/app/JsIO.js +163 -0
- data/jsdoc/app/JsParse.js +385 -0
- data/jsdoc/app/JsPlate.js +130 -0
- data/jsdoc/app/JsTestrun.js +129 -0
- data/jsdoc/app/JsToke.js +564 -0
- data/jsdoc/app/Symbol.js +298 -0
- data/jsdoc/app/Transformer.js +14 -0
- data/jsdoc/app/Util.js +97 -0
- data/jsdoc/app/js.jar +0 -0
- data/jsdoc/app/run.js +144 -0
- data/jsdoc/plugins/min.js +316 -0
- data/jsdoc/plugins/strip.js +20 -0
- data/jsdoc/templates/sproutcore/class.tmpl +438 -0
- data/jsdoc/templates/sproutcore/default.css +241 -0
- data/jsdoc/templates/sproutcore/index.html +13 -0
- data/jsdoc/templates/sproutcore/index.tmpl +21 -0
- data/jsdoc/templates/sproutcore/prototype.js +4186 -0
- data/jsdoc/templates/sproutcore/publish.js +236 -0
- data/jsdoc/templates/sproutcore/splash.html +7 -0
- data/lib/sproutcore/build_tools/html_builder.rb +88 -0
- data/lib/sproutcore/build_tools/resource_builder.rb +194 -0
- data/lib/sproutcore/build_tools.rb +44 -0
- data/lib/sproutcore/bundle.rb +517 -0
- data/lib/sproutcore/bundle_manifest.rb +397 -0
- data/lib/sproutcore/generator_helper.rb +170 -0
- data/lib/sproutcore/helpers/capture_helper.rb +42 -0
- data/lib/sproutcore/helpers/static_helper.rb +80 -0
- data/lib/sproutcore/helpers/tag_helper.rb +110 -0
- data/lib/sproutcore/helpers/text_helper.rb +336 -0
- data/lib/sproutcore/helpers.rb +3 -0
- data/lib/sproutcore/jsdoc.rb +40 -0
- data/lib/sproutcore/jsmin.rb +247 -0
- data/lib/sproutcore/library.rb +258 -0
- data/lib/sproutcore/merb/bundle_controller.rb +179 -0
- data/lib/sproutcore/merb/router.rb +43 -0
- data/lib/sproutcore/merb.rb +27 -0
- data/lib/sproutcore/version.rb +9 -0
- data/lib/sproutcore/view_helpers/button_views.rb +302 -0
- data/lib/sproutcore/view_helpers/core_views.rb +284 -0
- data/lib/sproutcore/view_helpers/form_views.rb +258 -0
- data/lib/sproutcore/view_helpers/menu_views.rb +94 -0
- data/lib/sproutcore/view_helpers.rb +628 -0
- data/lib/sproutcore.rb +30 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/sproutcore_spec.rb +11 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +17 -0
- metadata +365 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
// ========================================================================
|
|
2
|
+
// SproutCore
|
|
3
|
+
// copyright 2006-2007 Sprout Systems, Inc.
|
|
4
|
+
// ========================================================================
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
@namespace Implements Key-Value Observing
|
|
8
|
+
|
|
9
|
+
Key-Value Observing is one of the fundamental ways that models, controllers
|
|
10
|
+
and views communicate with each other in a SproutCore application. Any
|
|
11
|
+
object that has this module applied to it can be used in KVO-operations.
|
|
12
|
+
|
|
13
|
+
This module is applied automatically to all objects that inherit from
|
|
14
|
+
SC.Object, which includes most objects bundled with the SproutCore
|
|
15
|
+
framework. You will not generally apply this module to classes yourself,
|
|
16
|
+
but you will use the features provided by this module frequently, so it is
|
|
17
|
+
important to understand how to use it.
|
|
18
|
+
|
|
19
|
+
h2. About Key Value Observing
|
|
20
|
+
|
|
21
|
+
Key-Value-Observing (KVO) simply allows one object to observe changes to a
|
|
22
|
+
property on another object. This can replace much of the "glue code" that
|
|
23
|
+
you often have to write to make parts of your application work together.
|
|
24
|
+
|
|
25
|
+
Using KVO is easy. All you have to do is use the KVO methods to get and set
|
|
26
|
+
properties. Instead of writing:
|
|
27
|
+
|
|
28
|
+
{{{
|
|
29
|
+
var aName = contact.firstName ;
|
|
30
|
+
contact.firstName = 'Charles' ;
|
|
31
|
+
}}}
|
|
32
|
+
|
|
33
|
+
you use:
|
|
34
|
+
|
|
35
|
+
{{{
|
|
36
|
+
var aName = contact.get('firstName') ;
|
|
37
|
+
contact.set('firstName', 'Charles') ;
|
|
38
|
+
}}}
|
|
39
|
+
|
|
40
|
+
get() and set() work just like the normal "dot operators" provided by
|
|
41
|
+
JavaScript but they provide you with much more power, including not only
|
|
42
|
+
observing but computed properties as well.
|
|
43
|
+
|
|
44
|
+
INCOMPLETE
|
|
45
|
+
|
|
46
|
+
*/
|
|
47
|
+
SC.Observable = {
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
Manually add a new binding to an object. This is the same as doing
|
|
51
|
+
the more familiar propertyBinding: 'property.path' approach.
|
|
52
|
+
*/
|
|
53
|
+
bind: function(toKey, fromPropertyPath) {
|
|
54
|
+
|
|
55
|
+
var r = SC.idt.active ;
|
|
56
|
+
|
|
57
|
+
var binding ;
|
|
58
|
+
var props = { to: [this, toKey] } ;
|
|
59
|
+
|
|
60
|
+
// for strings try to do default relay
|
|
61
|
+
var pathType = $type(fromPropertyPath) ;
|
|
62
|
+
if (pathType == T_STRING || pathType == T_ARRAY) {
|
|
63
|
+
binding = this[toKey + 'BindingDefault'] || SC.Binding.From;
|
|
64
|
+
binding = binding(fromPropertyPath) ;
|
|
65
|
+
} else binding = fromPropertyPath ;
|
|
66
|
+
|
|
67
|
+
// check the 'from' value of the relay. if it starts w/
|
|
68
|
+
// '.' || '*' then convert to a local tuple.
|
|
69
|
+
var relayFrom = binding.prototype.from ;
|
|
70
|
+
if ($type(relayFrom) == T_STRING) switch(relayFrom.slice(0,1)) {
|
|
71
|
+
case '*':
|
|
72
|
+
case '.':
|
|
73
|
+
relayFrom = [this,relayFrom.slice(1,relayFrom.length)];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if(r) bt = new Date().getTime();
|
|
77
|
+
|
|
78
|
+
binding = binding.create(props, { from: relayFrom }) ;
|
|
79
|
+
this.bindings.push(binding) ;
|
|
80
|
+
|
|
81
|
+
if (r) SC.idt.b1_t += (new Date().getTime()) - bt ;
|
|
82
|
+
|
|
83
|
+
return binding ;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
didChangeFor makes it easy for you to verify that you haven't seen any
|
|
88
|
+
changed values. You need to use this if your method observes multiple
|
|
89
|
+
properties. To use this, call it like this:
|
|
90
|
+
|
|
91
|
+
if (this.didChangeFor('render','height','width')) {
|
|
92
|
+
// DO SOMETHING HERE IF CHANGED.
|
|
93
|
+
}
|
|
94
|
+
*/
|
|
95
|
+
didChangeFor: function(context) {
|
|
96
|
+
var keys = $A(arguments) ;
|
|
97
|
+
context = keys.shift() ;
|
|
98
|
+
|
|
99
|
+
var ret = false ;
|
|
100
|
+
if (!this._didChangeCache) this._didChangeCache = {} ;
|
|
101
|
+
if (!this._didChangeRevisionCache) this._didChangeRevisionCache = {};
|
|
102
|
+
|
|
103
|
+
var seen = this._didChangeCache[context] || {} ;
|
|
104
|
+
var seenRevisions = this._didChangeRevisionCache[context] || {} ;
|
|
105
|
+
var loc = keys.length ;
|
|
106
|
+
var rev = this._kvo().revision ;
|
|
107
|
+
|
|
108
|
+
while(--loc >= 0) {
|
|
109
|
+
var key = keys[loc] ;
|
|
110
|
+
if (seenRevisions[key] != rev) {
|
|
111
|
+
var val = this.get(key) ;
|
|
112
|
+
if (seen[key] !== val) ret = true ;
|
|
113
|
+
seen[key] = val ;
|
|
114
|
+
}
|
|
115
|
+
seenRevisions[key] = rev ;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this._didChangeCache[context] = seen ;
|
|
119
|
+
this._didChangeRevisionCache[context] = seenRevisions ;
|
|
120
|
+
return ret ;
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// ..........................................
|
|
124
|
+
// PROPERTIES
|
|
125
|
+
//
|
|
126
|
+
// Use these methods to get/set properties. This will handle observing
|
|
127
|
+
// notifications as well as allowing you to define functions that can be
|
|
128
|
+
// used as properties.
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
Use this to get a property value instead of obj.key.
|
|
132
|
+
*/
|
|
133
|
+
get: function(key) {
|
|
134
|
+
var ret = this[key] ;
|
|
135
|
+
if (ret === undefined) {
|
|
136
|
+
return this.unknownProperty(key) ;
|
|
137
|
+
} else if (ret && (ret instanceof Function) && ret.isProperty) {
|
|
138
|
+
return ret.call(this,key) ;
|
|
139
|
+
} else return ret ;
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
use this to set a property value instead of obj.key = value.
|
|
144
|
+
*/
|
|
145
|
+
set: function(key, value) {
|
|
146
|
+
var func = this[key] ;
|
|
147
|
+
var ret = value ;
|
|
148
|
+
|
|
149
|
+
this.propertyWillChange(key) ;
|
|
150
|
+
|
|
151
|
+
// set the value.
|
|
152
|
+
if (func && (func instanceof Function) && (func.isProperty)) {
|
|
153
|
+
ret = func.call(this,key,value) ;
|
|
154
|
+
} else if (func === undefined) {
|
|
155
|
+
ret = this.unknownProperty(key,value) ;
|
|
156
|
+
} else ret = this[key] = value ;
|
|
157
|
+
|
|
158
|
+
// post out notifications.
|
|
159
|
+
this.propertyDidChange(key, ret) ;
|
|
160
|
+
return ret ;
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
use this to automatically navigate a property path.
|
|
165
|
+
*/
|
|
166
|
+
getPath: function(path) {
|
|
167
|
+
var tuple = SC.Object.tupleForPropertyPath(path, this) ;
|
|
168
|
+
if (tuple[0] == null) return null ;
|
|
169
|
+
return tuple[0].get(tuple[1]) ;
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
setPath: function(path, value) {
|
|
173
|
+
var tuple = SC.Object.tupleForPropertyPath(path, this) ;
|
|
174
|
+
if (tuple[0] == null) return null ;
|
|
175
|
+
return tuple[0].set(tuple[1], value) ;
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
Increments the value of a property.
|
|
180
|
+
*/
|
|
181
|
+
incrementProperty: function(key) {
|
|
182
|
+
return this.set(key,(this.get(key) || 0)+1);
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
decrements a property
|
|
187
|
+
*/
|
|
188
|
+
decrementProperty: function(key) {
|
|
189
|
+
return this.set(key,(this.get(key) || 0) - 1 ) ;
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
inverts a property. Property should be a bool.
|
|
194
|
+
*/
|
|
195
|
+
toggleProperty: function(key,value,alt) {
|
|
196
|
+
if (value === undefined) value = true ;
|
|
197
|
+
if (alt == undefined) alt = false ;
|
|
198
|
+
value = (this.get(key) == value) ? alt : value ;
|
|
199
|
+
this.set(key,value);
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
This is a generic property handler. If you define it, it will be called
|
|
204
|
+
when the named property is not yet set in the object. The default does
|
|
205
|
+
nothing.
|
|
206
|
+
*/
|
|
207
|
+
unknownProperty: function(key,value) {
|
|
208
|
+
if (!(value === undefined)) { this[key] = value; }
|
|
209
|
+
return value ;
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
Override to receive generic observation notices.
|
|
214
|
+
*/
|
|
215
|
+
propertyObserver: function(observer,target,key,value) {},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
You can wrap property changes with these methods to cause notifications
|
|
219
|
+
to be delivered only after groups are closed.
|
|
220
|
+
*/
|
|
221
|
+
beginPropertyChanges: function() {
|
|
222
|
+
this._kvo().changes++ ;
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
endPropertyChanges: function() {
|
|
226
|
+
var kvo = this._kvo() ; kvo.changes--;
|
|
227
|
+
if (kvo.changes <= 0) this._notifyPropertyObservers() ;
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
If you are not going to use get/set, you can notify observers this way.
|
|
232
|
+
*/
|
|
233
|
+
propertyWillChange: function(key) {
|
|
234
|
+
this._kvo().changes++ ;
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
propertyDidChange: function(key,value) {
|
|
238
|
+
this._kvo().changed[key] = value ;
|
|
239
|
+
var kvo = this._kvo() ; kvo.changes--; kvo.revision++ ;
|
|
240
|
+
if (kvo.changes <= 0) this._notifyPropertyObservers() ;
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
This may be a simpler way to notify of changes if you are making a major
|
|
245
|
+
update or don't know exactly which properties have changed. This ignores
|
|
246
|
+
property gorups.
|
|
247
|
+
*/
|
|
248
|
+
allPropertiesDidChange: function() {
|
|
249
|
+
this._notifyPropertyObservers(true) ;
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
Add an observer
|
|
254
|
+
*/
|
|
255
|
+
addObserver: function(key,func) {
|
|
256
|
+
var kvo = this._kvo() ;
|
|
257
|
+
|
|
258
|
+
// if the key contains a '.', then create a chained observer.
|
|
259
|
+
key = key.toString() ;
|
|
260
|
+
var parts = key.split('.') ;
|
|
261
|
+
if (parts.length > 1) {
|
|
262
|
+
var co = SC._ChainObserver.createChain(this,parts,func) ;
|
|
263
|
+
co.masterFunc = func ;
|
|
264
|
+
var chainObservers = kvo.chainObservers[key] || [] ;
|
|
265
|
+
chainObservers.push(co) ;
|
|
266
|
+
kvo.chainObservers[key] = chainObservers ;
|
|
267
|
+
|
|
268
|
+
// otherwise, bind as a normal property
|
|
269
|
+
} else {
|
|
270
|
+
var observers = kvo.observers[key] = (kvo.observers[key] || []) ;
|
|
271
|
+
var found = false; var loc = observers.length;
|
|
272
|
+
while(!found && --loc >= 0) found = (observers[loc] == func) ;
|
|
273
|
+
if (!found) observers.push(func) ;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
addProbe: function(key) { this.addObserver(key,logChange); },
|
|
279
|
+
removeProbe: function(key) { this.removeObserver(key,logChange); },
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
This method will listen for the observed value to change one time and
|
|
283
|
+
then will remove itself. You can also set an optional timeout that
|
|
284
|
+
will cause the function to be triggered (and the observer removed) after
|
|
285
|
+
a set amount of time even if the value never changes. The function
|
|
286
|
+
can expect an extra parameter, 'didTimeout', set to true.
|
|
287
|
+
|
|
288
|
+
The returned value is the function actually set as the observer. You
|
|
289
|
+
can manually remove this observer by calling the cancel() method on it.
|
|
290
|
+
*/
|
|
291
|
+
observeOnce: function(key, func, timeout) {
|
|
292
|
+
var timeoutObject = null ;
|
|
293
|
+
var target = this ;
|
|
294
|
+
var handler = function(theTarget,theKey,theValue,didTimeout) {
|
|
295
|
+
func(theTarget,theKey,theValue,didTimeout) ;
|
|
296
|
+
target.removeObserver(key,handler) ;
|
|
297
|
+
if (timeoutObject) { clearTimeout(timeoutObject); }
|
|
298
|
+
} ;
|
|
299
|
+
|
|
300
|
+
target.addObserver(key,handler) ;
|
|
301
|
+
if (timeout) timeoutObject = setTimeout(function() {
|
|
302
|
+
handler(target,key,target.get(key),true) ;
|
|
303
|
+
}, timeout) ;
|
|
304
|
+
|
|
305
|
+
handler.cancel = function() { target.removeObserver(key,handler); } ;
|
|
306
|
+
return handler ;
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
removeObserver: function(key,func) {
|
|
310
|
+
var kvo = this._kvo() ;
|
|
311
|
+
|
|
312
|
+
// if the key contains a '.', this is a chained observer.
|
|
313
|
+
key = key.toString() ;
|
|
314
|
+
var parts = key.split('.') ;
|
|
315
|
+
if (parts.length > 1) {
|
|
316
|
+
var chainObservers = kvo.chainObserver[key] || [] ;
|
|
317
|
+
var newObservers = [] ;
|
|
318
|
+
chainObservers.each(function(co) {
|
|
319
|
+
if (co.masterFunc != func) newObservers.push(co) ;
|
|
320
|
+
}) ;
|
|
321
|
+
kvo.chainObservers[key] = newObservers ;
|
|
322
|
+
|
|
323
|
+
// otherwise, just like a normal observer.
|
|
324
|
+
} else {
|
|
325
|
+
var observers = kvo.observers[key] || [] ;
|
|
326
|
+
observers = observers.without(func) ;
|
|
327
|
+
kvo.observers[key] = observers ;
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
Use this to indicate that one key changes if other keys it depends on
|
|
333
|
+
change.
|
|
334
|
+
*/
|
|
335
|
+
registerDependentKey: function(key) {
|
|
336
|
+
var keys = $A(arguments) ;
|
|
337
|
+
var dependent = keys.shift() ;
|
|
338
|
+
var kvo = this._kvo() ;
|
|
339
|
+
for(var loc=0;loc<keys.length;loc++) {
|
|
340
|
+
var key = keys[loc];
|
|
341
|
+
if (key instanceof Array) {
|
|
342
|
+
key.push(dependent) ;
|
|
343
|
+
this.registerDependentKey.apply(this,key) ;
|
|
344
|
+
} else {
|
|
345
|
+
var dependents = kvo.dependents[key] || [] ;
|
|
346
|
+
dependents.push(dependent) ;
|
|
347
|
+
kvo.dependents[key] = dependents ;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
// INTERNAL PROPERTY SUPPORT
|
|
353
|
+
|
|
354
|
+
// returns the kvo object.
|
|
355
|
+
_kvo: function() {
|
|
356
|
+
if (!this._kvod) this._kvod = {
|
|
357
|
+
changes: 0, changed: {}, observers: {}, dependents: {},
|
|
358
|
+
chainObservers: {}, revision: 0
|
|
359
|
+
} ;
|
|
360
|
+
return this._kvod ;
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
propertyRevision: 1,
|
|
364
|
+
|
|
365
|
+
// this is invoked when the properties changed.
|
|
366
|
+
_notifyPropertyObservers: function(allObservers) {
|
|
367
|
+
// locals
|
|
368
|
+
var key ; var observers ; var keys = [] ;
|
|
369
|
+
var loc; var oloc ; var value ;
|
|
370
|
+
var kvo = this._kvo() ;
|
|
371
|
+
|
|
372
|
+
SC.Observers.flush() ; // hookup as many observers as possible.
|
|
373
|
+
|
|
374
|
+
// increment revision
|
|
375
|
+
this.propertyRevision++;
|
|
376
|
+
|
|
377
|
+
// find the keys to notify on.
|
|
378
|
+
var keySource = (allObservers) ? kvo.observers : kvo.changed ;
|
|
379
|
+
var allKeys = {} ;
|
|
380
|
+
|
|
381
|
+
// This private function is used to recursively discover all
|
|
382
|
+
// dependent keys.
|
|
383
|
+
var _addDependentKeys = function(key) {
|
|
384
|
+
if (allKeys[key] !== undefined) return ;
|
|
385
|
+
allKeys[key] = key ;
|
|
386
|
+
|
|
387
|
+
if (allObservers) return ;
|
|
388
|
+
var dependents = kvo.dependents[key] ;
|
|
389
|
+
if (dependents && dependents.length > 0) {
|
|
390
|
+
var loc = dependents.length ;
|
|
391
|
+
while(--loc >= 0) {
|
|
392
|
+
var depKey = dependents[loc] ;
|
|
393
|
+
_addDependentKeys(depKey) ;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
} ;
|
|
397
|
+
|
|
398
|
+
// loop throught keys to notify. find all dependent keys as well.
|
|
399
|
+
// note that this loops recursively.
|
|
400
|
+
for(key in keySource) {
|
|
401
|
+
if (!keySource.hasOwnProperty(key)) continue ;
|
|
402
|
+
_addDependentKeys(key) ;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Convert the found keys into an array
|
|
406
|
+
for(key in allKeys) {
|
|
407
|
+
if (!allKeys.hasOwnProperty(key)) continue ;
|
|
408
|
+
keys.push(key) ;
|
|
409
|
+
}
|
|
410
|
+
var starObservers = kvo.observers['*'] ;
|
|
411
|
+
|
|
412
|
+
// clear out changed to avoid recursion.
|
|
413
|
+
var changed = kvo.changed ; kvo.changed = {} ;
|
|
414
|
+
|
|
415
|
+
// notify all observers.
|
|
416
|
+
var target = this ;
|
|
417
|
+
loc = keys.length ;
|
|
418
|
+
|
|
419
|
+
var notifiedKeys = {} ; // avoid duplicates.
|
|
420
|
+
while(--loc >= 0) {
|
|
421
|
+
key = keys[loc] ; observers = kvo.observers[key] ;
|
|
422
|
+
if (!notifiedKeys[key]) {
|
|
423
|
+
notifiedKeys[key] = key ;
|
|
424
|
+
value = (allObservers || (!changed[key])) ? this.get(key) : changed[key];
|
|
425
|
+
|
|
426
|
+
if (starObservers) {
|
|
427
|
+
observers = (observers) ? observers.concat(starObservers) : starObservers ;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (observers) {
|
|
431
|
+
oloc = observers.length ;
|
|
432
|
+
var args = [target, key, value, this.propertyRevision] ;
|
|
433
|
+
while(--oloc >= 0) {
|
|
434
|
+
var observer = observers[oloc] ;
|
|
435
|
+
SC.NotificationQueue.add(null, observer, args) ;
|
|
436
|
+
} // while(oloc)
|
|
437
|
+
} // if (observers)
|
|
438
|
+
|
|
439
|
+
// notify self.
|
|
440
|
+
if (this.propertyObserver != SC.Object.prototype.propertyObserver) {
|
|
441
|
+
SC.NotificationQueue.add(this, this.propertyObserver,
|
|
442
|
+
[null, target, key, value, this.propertyRevision]) ;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
} // while(--loc)
|
|
447
|
+
|
|
448
|
+
SC.NotificationQueue.flush() ;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
} ;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// ========================================================================
|
|
2
|
+
// SproutCore
|
|
3
|
+
// copyright 2006-2007 Sprout Systems, Inc.
|
|
4
|
+
// ========================================================================
|
|
5
|
+
|
|
6
|
+
require('foundation/path_module') ;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@class SC.Page
|
|
10
|
+
|
|
11
|
+
The Page object is used to store a set of views that can be lazily
|
|
12
|
+
configured on page load. Page assumes that all of its properties are
|
|
13
|
+
basically outlets and will try to configure them as such.
|
|
14
|
+
|
|
15
|
+
@extends SC.Object
|
|
16
|
+
*/
|
|
17
|
+
SC.Page = SC.Object.extend(
|
|
18
|
+
/** @scope SC.Page.prototype */
|
|
19
|
+
{
|
|
20
|
+
|
|
21
|
+
get: function(key) {
|
|
22
|
+
var value = this[key] ;
|
|
23
|
+
if (value && (value instanceof Function) && (value.isOutlet)) {
|
|
24
|
+
var ret = this.outlet(key) ;
|
|
25
|
+
if (SC.window && !ret.parentNode) {
|
|
26
|
+
SC.window._insertBefore(ret, null, false) ;
|
|
27
|
+
SC.window._rebuildChildNodes();
|
|
28
|
+
}
|
|
29
|
+
ret.awake() ;
|
|
30
|
+
return ret ;
|
|
31
|
+
} else return arguments.callee.base.apply(this,arguments) ;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// in addition to activating bindings, calling awake on the page object
|
|
35
|
+
// will cause any outlet properties to be loaded.
|
|
36
|
+
awake: function() {
|
|
37
|
+
arguments.callee.base.call(this) ;
|
|
38
|
+
for(var key in this) {
|
|
39
|
+
if (this.hasOwnProperty(key) && this[key] && this[key].isOutlet) {
|
|
40
|
+
this.get(key) ; // convert to outlet.
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
init: function() {
|
|
46
|
+
arguments.callee.base.apply(this,arguments) ;
|
|
47
|
+
var el = this.rootElement = $('resources') ;
|
|
48
|
+
SC.callOnLoad(function() {
|
|
49
|
+
if (el && el.parentNode) el.parentNode.removeChild(el) ;
|
|
50
|
+
}) ;
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// returns the property, but only if it is already configured.
|
|
54
|
+
getIfConfigured: function(key) {
|
|
55
|
+
var value = this[key] ;
|
|
56
|
+
if (value && (value instanceof Function) && (value.isOutlet)) {
|
|
57
|
+
return null ;
|
|
58
|
+
} else return value ;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
}) ;
|
|
62
|
+
|
|
63
|
+
Object.extend(SC.Page.prototype, SC.PathModule) ;
|