riojs 0.0.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/LICENSE +20 -0
- data/README.rdoc +24 -0
- data/VERSION +1 -0
- data/bin/rio +5 -0
- data/generators/rio_app/USAGE +19 -0
- data/generators/rio_app/rio_app_generator.rb +40 -0
- data/generators/rio_app/templates/app.build +10 -0
- data/generators/rio_app/templates/app.css +0 -0
- data/generators/rio_app/templates/app.js +20 -0
- data/generators/rio_app/templates/app_view.html.erb +19 -0
- data/generators/rio_app/templates/fixture.js +4 -0
- data/generators/rio_app/templates/rio.html.erb +18 -0
- data/generators/rio_app/templates/rio_controller.rb +2 -0
- data/generators/rio_app/templates/spec.js +7 -0
- data/generators/rio_component/USAGE +13 -0
- data/generators/rio_component/rio_component_generator.rb +16 -0
- data/generators/rio_component/templates/component.css +0 -0
- data/generators/rio_component/templates/component.js +11 -0
- data/generators/rio_component/templates/fixture.js +3 -0
- data/generators/rio_component/templates/spec.js +6 -0
- data/generators/rio_model/USAGE +12 -0
- data/generators/rio_model/rio_model_generator.rb +21 -0
- data/generators/rio_model/templates/fixture.js +3 -0
- data/generators/rio_model/templates/model.js +9 -0
- data/generators/rio_model/templates/spec.js +6 -0
- data/generators/rio_page/USAGE +14 -0
- data/generators/rio_page/rio_page_generator.rb +16 -0
- data/generators/rio_page/templates/fixture.js +3 -0
- data/generators/rio_page/templates/page.css +12 -0
- data/generators/rio_page/templates/page.js +12 -0
- data/generators/rio_page/templates/page.jst +64 -0
- data/generators/rio_page/templates/spec.js +6 -0
- data/generators/rio_resource/USAGE +20 -0
- data/generators/rio_resource/rio_resource_generator.rb +10 -0
- data/generators/rio_resource/templates/controller.rb +3 -0
- data/init.rb +4 -0
- data/install/config/juggernaut_hosts.yml +18 -0
- data/install/lib/tasks/rio.rake +1 -0
- data/install/script/rio_server +37 -0
- data/lib/rio/autospec.rb +86 -0
- data/lib/rio/install.rb +90 -0
- data/lib/rio/juggernaut.rb +212 -0
- data/lib/rio/path.rb +3 -0
- data/lib/rio/rio_compressor.rb +219 -0
- data/lib/rio/rio_file_controller.rb +16 -0
- data/lib/rio/rio_on_rails.rb +586 -0
- data/lib/rio/rio_proxy_controller.rb +60 -0
- data/lib/rio/rio_push_controller.rb +48 -0
- data/lib/rio/rio_routes.rb +24 -0
- data/lib/rio/rio_spec_controller.rb +70 -0
- data/lib/riojs.rb +14 -0
- data/lib/tasks/rio.rb +63 -0
- data/public/images/background-chiffon.png +0 -0
- data/public/images/button-gradient-overlay-down.png +0 -0
- data/public/images/button-gradient-overlay.png +0 -0
- data/public/images/icons/add.png +0 -0
- data/public/images/icons/error-big.png +0 -0
- data/public/images/icons/warning-big.png +0 -0
- data/public/images/rio-logo-big.png +0 -0
- data/public/images/rio-logo.png +0 -0
- data/public/images/splitter-handle-horizontal.png +0 -0
- data/public/images/splitter-handle-vertical.png +0 -0
- data/public/images/tab-bar-gradient-overlay.png +0 -0
- data/public/images/title-gradient-overlay.png +0 -0
- data/public/images/trash.gif +0 -0
- data/public/javascripts/components/accordion.js +144 -0
- data/public/javascripts/components/alert_box.js +59 -0
- data/public/javascripts/components/base.js +47 -0
- data/public/javascripts/components/box.js +63 -0
- data/public/javascripts/components/button.js +98 -0
- data/public/javascripts/components/checkbox.js +44 -0
- data/public/javascripts/components/container.js +265 -0
- data/public/javascripts/components/grid_view.js +107 -0
- data/public/javascripts/components/image.js +19 -0
- data/public/javascripts/components/input.js +171 -0
- data/public/javascripts/components/label.js +15 -0
- data/public/javascripts/components/lightbox.js +160 -0
- data/public/javascripts/components/link.js +43 -0
- data/public/javascripts/components/list_item.js +44 -0
- data/public/javascripts/components/list_view.js +192 -0
- data/public/javascripts/components/marquee.js +131 -0
- data/public/javascripts/components/menu.js +89 -0
- data/public/javascripts/components/notification.js +75 -0
- data/public/javascripts/components/overlay.js +134 -0
- data/public/javascripts/components/panel.js +146 -0
- data/public/javascripts/components/radio.js +46 -0
- data/public/javascripts/components/splitter.js +65 -0
- data/public/javascripts/components/tab_bar.js +64 -0
- data/public/javascripts/components/tab_panel.js +57 -0
- data/public/javascripts/components/textarea.js +223 -0
- data/public/javascripts/components/toggle_button.js +22 -0
- data/public/javascripts/components/tooltip.js +80 -0
- data/public/javascripts/lib/application.js +482 -0
- data/public/javascripts/lib/attr.js +760 -0
- data/public/javascripts/lib/benchmark.js +235 -0
- data/public/javascripts/lib/blank.html +39 -0
- data/public/javascripts/lib/boot.js +300 -0
- data/public/javascripts/lib/clipboard.js +96 -0
- data/public/javascripts/lib/collection_entity.js +46 -0
- data/public/javascripts/lib/component.js +129 -0
- data/public/javascripts/lib/console.js +75 -0
- data/public/javascripts/lib/console/apps/console.build +43 -0
- data/public/javascripts/lib/console/apps/console.js +28 -0
- data/public/javascripts/lib/console/blank.html +39 -0
- data/public/javascripts/lib/console/components/benchmark.js +196 -0
- data/public/javascripts/lib/console/components/console.js +352 -0
- data/public/javascripts/lib/console/components/dependencies_list.js +17 -0
- data/public/javascripts/lib/console/components/docs.js +66 -0
- data/public/javascripts/lib/console/components/playground.js +30 -0
- data/public/javascripts/lib/console/console.html +27 -0
- data/public/javascripts/lib/console/console_commands.js +287 -0
- data/public/javascripts/lib/console/console_commands.js.rej +21 -0
- data/public/javascripts/lib/console/console_mixin.js +22 -0
- data/public/javascripts/lib/console/docs/files.html +579 -0
- data/public/javascripts/lib/console/docs/index.html +323 -0
- data/public/javascripts/lib/console/docs/symbols/Object.html +291 -0
- data/public/javascripts/lib/console/docs/symbols/_global_.html +413 -0
- data/public/javascripts/lib/console/docs/symbols/rio.AIM.html +490 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Application.html +841 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Attr.html +1075 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Binding.html +272 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Component.html +419 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Cookie.html +543 -0
- data/public/javascripts/lib/console/docs/symbols/rio.DelayedTask#initialize.html +270 -0
- data/public/javascripts/lib/console/docs/symbols/rio.DelayedTask.html +391 -0
- data/public/javascripts/lib/console/docs/symbols/rio.JsTemplate.html +271 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Juggernaut.html +329 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Model.html +822 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Page.html +383 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Template.html +328 -0
- data/public/javascripts/lib/console/docs/symbols/rio.Utils.html +617 -0
- data/public/javascripts/lib/console/docs/symbols/rio.html +506 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_components_base.js.html +54 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_application.js.html +490 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_attr.js.html +768 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_boot.js.html +308 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_clipboard.js.html +103 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_collection_entity.js.html +53 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_component.js.html +137 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_cookie.js.html +81 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_delayed_task.js.html +68 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_file.js.html +80 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_flash_detect.js.html +129 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_form.js.html +95 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_id.js.html +50 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_inflector.js.html +167 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_js_template.js.html +283 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_juggernaut.js.html +303 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_key_map.js.html +68 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_layout_manager.js.html +175 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_log.js.html +17 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_model.js.html +1074 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_page.js.html +246 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_parameters.js.html +66 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_protohack.js.html +305 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_push.js.html +12 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_rsh.js.html +659 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_swfobject.js.html +12 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_tag.js.html +60 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_template.js.html +64 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_theme.js.html +105 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_undo.js.html +142 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_utils.js.html +87 -0
- data/public/javascripts/lib/console/docs/symbols/src/public_javascripts_lib_yaml.js.html +88 -0
- data/public/javascripts/lib/console/file-small.png +0 -0
- data/public/javascripts/lib/console/green-circle.png +0 -0
- data/public/javascripts/lib/console/loading.gif +0 -0
- data/public/javascripts/lib/console/pages/console_page.js +149 -0
- data/public/javascripts/lib/console/pages/console_page.jst +27 -0
- data/public/javascripts/lib/console/red-circle.png +0 -0
- data/public/javascripts/lib/cookie.js +74 -0
- data/public/javascripts/lib/delayed_task.js +61 -0
- data/public/javascripts/lib/dependencies.js +76 -0
- data/public/javascripts/lib/environment.js +30 -0
- data/public/javascripts/lib/event.simulate.js +137 -0
- data/public/javascripts/lib/expressinstall.swf +0 -0
- data/public/javascripts/lib/file.js +72 -0
- data/public/javascripts/lib/flash_detect.js +122 -0
- data/public/javascripts/lib/flashembed.min.js +16 -0
- data/public/javascripts/lib/form.js +88 -0
- data/public/javascripts/lib/id.js +43 -0
- data/public/javascripts/lib/inflector.js +160 -0
- data/public/javascripts/lib/instrumenter.js +106 -0
- data/public/javascripts/lib/js_template.js +275 -0
- data/public/javascripts/lib/jslint.js +4950 -0
- data/public/javascripts/lib/juggernaut.js +295 -0
- data/public/javascripts/lib/juggernaut.swf +0 -0
- data/public/javascripts/lib/key_map.js +60 -0
- data/public/javascripts/lib/layout_manager.js +167 -0
- data/public/javascripts/lib/model.js +1067 -0
- data/public/javascripts/lib/page.js +238 -0
- data/public/javascripts/lib/parameters.js +59 -0
- data/public/javascripts/lib/png_fix.js +75 -0
- data/public/javascripts/lib/protohack.js +297 -0
- data/public/javascripts/lib/push.js +5 -0
- data/public/javascripts/lib/rio.build +28 -0
- data/public/javascripts/lib/rio_development.build +5 -0
- data/public/javascripts/lib/rio_lint.js +66 -0
- data/public/javascripts/lib/rsh.js +651 -0
- data/public/javascripts/lib/spec.js +545 -0
- data/public/javascripts/lib/spec_runner.js +242 -0
- data/public/javascripts/lib/swfobject.js +5 -0
- data/public/javascripts/lib/tag.js +52 -0
- data/public/javascripts/lib/undo.js +134 -0
- data/public/javascripts/lib/utils.js +80 -0
- data/public/javascripts/lib/yaml.js +80 -0
- data/public/javascripts/pages/playground_page.js +15 -0
- data/public/javascripts/prototype/builder.js +146 -0
- data/public/javascripts/prototype/controls.js +1004 -0
- data/public/javascripts/prototype/dragdrop.js +1030 -0
- data/public/javascripts/prototype/effects.js +1137 -0
- data/public/javascripts/prototype/prototype.js +4320 -0
- data/public/javascripts/prototype/slider.js +283 -0
- data/public/javascripts/prototype/sound.js +67 -0
- data/public/javascripts/specs/components/box_spec.js +6 -0
- data/public/javascripts/specs/components/checkbox_spec.js +26 -0
- data/public/javascripts/specs/components/container_spec.js +6 -0
- data/public/javascripts/specs/components/input_spec.js +71 -0
- data/public/javascripts/specs/components/panel_spec.js +6 -0
- data/public/javascripts/specs/components/radio_spec.js +40 -0
- data/public/javascripts/specs/fixtures/components/box.js +3 -0
- data/public/javascripts/specs/fixtures/components/checkbox.js +9 -0
- data/public/javascripts/specs/fixtures/components/container.js +3 -0
- data/public/javascripts/specs/fixtures/components/input.js +12 -0
- data/public/javascripts/specs/fixtures/components/menu.js +19 -0
- data/public/javascripts/specs/fixtures/components/menu_item.js +18 -0
- data/public/javascripts/specs/fixtures/components/radio.js +11 -0
- data/public/javascripts/specs/lib/application_spec.js +281 -0
- data/public/javascripts/specs/lib/attr_spec.js +1514 -0
- data/public/javascripts/specs/lib/benchmark_spec.js +361 -0
- data/public/javascripts/specs/lib/collection_entity_spec.js +131 -0
- data/public/javascripts/specs/lib/component_spec.js +86 -0
- data/public/javascripts/specs/lib/form_spec.js +171 -0
- data/public/javascripts/specs/lib/id_spec.js +21 -0
- data/public/javascripts/specs/lib/instrumenter_spec.js +5 -0
- data/public/javascripts/specs/lib/js_template_spec.js +131 -0
- data/public/javascripts/specs/lib/key_map_spec.js +227 -0
- data/public/javascripts/specs/lib/model_spec.js +2268 -0
- data/public/javascripts/specs/lib/parameters_spec.js +94 -0
- data/public/javascripts/specs/lib/spec_spec.js +943 -0
- data/public/javascripts/specs/lib/undo_spec.js +105 -0
- data/public/javascripts/specs/lib/yaml_spec.js +127 -0
- data/public/sounds/basso.wav +0 -0
- data/public/sounds/purr.wav +0 -0
- data/public/stylesheets/components/accordion.css +24 -0
- data/public/stylesheets/components/alert_box.css +35 -0
- data/public/stylesheets/components/box.css +0 -0
- data/public/stylesheets/components/button.css +39 -0
- data/public/stylesheets/components/checkbox.css +9 -0
- data/public/stylesheets/components/container.css +3 -0
- data/public/stylesheets/components/grid_view.css +52 -0
- data/public/stylesheets/components/input.css +10 -0
- data/public/stylesheets/components/label.css +3 -0
- data/public/stylesheets/components/lightbox.css +31 -0
- data/public/stylesheets/components/link.css +4 -0
- data/public/stylesheets/components/list_view.css +23 -0
- data/public/stylesheets/components/marquee.css +29 -0
- data/public/stylesheets/components/menu.css +34 -0
- data/public/stylesheets/components/notification.css +52 -0
- data/public/stylesheets/components/overlay.css +8 -0
- data/public/stylesheets/components/panel.css +36 -0
- data/public/stylesheets/components/radio.css +9 -0
- data/public/stylesheets/components/splitter.css +35 -0
- data/public/stylesheets/components/tab_bar.css +59 -0
- data/public/stylesheets/components/tab_panel.css +15 -0
- data/public/stylesheets/components/textarea.css +11 -0
- data/public/stylesheets/components/tooltip.css +10 -0
- data/public/stylesheets/console.css +151 -0
- data/public/stylesheets/css_reset.css +55 -0
- metadata +343 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
describe(rio.components.Radio, {
|
|
2
|
+
beforeEach: function() {
|
|
3
|
+
this.radio1 = rio.components.Radio.example("a1");
|
|
4
|
+
this.radio2 = rio.components.Radio.example("a2");
|
|
5
|
+
insertComponent(this.radio1);
|
|
6
|
+
insertComponent(this.radio2);
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
"should have an html radio element": function() {
|
|
10
|
+
this.radio1.html().childElements()[0].tagName.shouldEqual("INPUT");
|
|
11
|
+
this.radio1.html().childElements()[0].type.shouldEqual("radio");
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
"should have the proper checked attribute": function() {
|
|
15
|
+
this.radio1.html().childElements()[0].checked.shouldBeFalse();
|
|
16
|
+
this.radio2.html().childElements()[0].checked.shouldBeTrue();
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
"should update the checked attribute when updating the html checkbox": function() {
|
|
20
|
+
this.radio1.html().childElements()[0].simulate("click");
|
|
21
|
+
this.radio1.getChecked().shouldBeTrue();
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"should update the html checked attribute when update the checked attribute": function() {
|
|
25
|
+
this.radio1.setChecked(true);
|
|
26
|
+
this.radio1.html().childElements()[0].checked.shouldBeTrue();
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
"should update the other radio buttons html checked attributes when updating the checked attribute": function() {
|
|
30
|
+
this.radio1.setChecked(true);
|
|
31
|
+
this.radio2.html().childElements()[0].checked.shouldBeFalse();
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
"should update the other radio buttons checked attributes when updating the checked attribute": function() {
|
|
35
|
+
this.radio1.html().childElements()[0].simulate("click");
|
|
36
|
+
this.radio2.getChecked().shouldBeFalse();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
rio.components.Menu.setExamples({
|
|
2
|
+
|
|
3
|
+
empty: {
|
|
4
|
+
},
|
|
5
|
+
|
|
6
|
+
oneItem: {
|
|
7
|
+
items: [
|
|
8
|
+
example(rio.components.MenuItem, "hello")
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
manyItems: {
|
|
13
|
+
items: [
|
|
14
|
+
example(rio.components.MenuItem, "file"),
|
|
15
|
+
example(rio.components.MenuItem, "edit"),
|
|
16
|
+
example(rio.components.MenuItem, "view")
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
});
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
Untested methods:
|
|
4
|
+
|
|
5
|
+
applyHistoryEntry
|
|
6
|
+
addHistoryEntry
|
|
7
|
+
navigateTo
|
|
8
|
+
clearPage
|
|
9
|
+
reboot
|
|
10
|
+
getCurrentLocation
|
|
11
|
+
getCurrentPage
|
|
12
|
+
setCurrentPage
|
|
13
|
+
rootUrl
|
|
14
|
+
|
|
15
|
+
#include
|
|
16
|
+
#require
|
|
17
|
+
#includeCss
|
|
18
|
+
#getToken
|
|
19
|
+
#setToken
|
|
20
|
+
#fail
|
|
21
|
+
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
describe(rio.Application, {
|
|
25
|
+
|
|
26
|
+
"with no routes": {
|
|
27
|
+
beforeEach: function() {
|
|
28
|
+
this.lPressed = false;
|
|
29
|
+
var application = rio.Application.create({
|
|
30
|
+
methods: {
|
|
31
|
+
keyMap: function() {
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
map: { key: 'l' },
|
|
35
|
+
handler: function() {
|
|
36
|
+
this.lPressed = true;
|
|
37
|
+
}.bind(this)
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
}.bind(this)
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
this.applicationInstance = new application();
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"should have no routes": function() {
|
|
47
|
+
this.applicationInstance.noRoutes().shouldBeTrue();
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
"should avoid animation if IE": function() {
|
|
51
|
+
stub(Prototype.Browser, "IE").withValue(true);
|
|
52
|
+
this.applicationInstance.avoidAnimation().shouldBeTrue();
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
"should not avoid animation if not IE": function() {
|
|
56
|
+
stub(Prototype.Browser, "IE").withValue(false);
|
|
57
|
+
this.applicationInstance.avoidAnimation().shouldBeFalse();
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
"should reload the page on refresh": function() {
|
|
61
|
+
/* You can't stub document.location.reload in firefox, so just skip the test */
|
|
62
|
+
if (Prototype.Browser.Gecko) { return; }
|
|
63
|
+
|
|
64
|
+
stub(document.location, "reload").shouldBeCalled();
|
|
65
|
+
this.applicationInstance.refresh();
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
"should execute keymaps on keypress": function() {
|
|
69
|
+
this.applicationInstance.launch();
|
|
70
|
+
|
|
71
|
+
var keyEvent = { keyCode: 76 };
|
|
72
|
+
this.applicationInstance.keyDown(keyEvent);
|
|
73
|
+
this.lPressed.shouldBeTrue();
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
"with routes": {
|
|
78
|
+
beforeEach: function() {
|
|
79
|
+
stub(dhtmlHistory, "getCurrentLocation").andReturn("");
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
var page = rio.Page.create({
|
|
83
|
+
methods: {
|
|
84
|
+
buildHtml: function() {
|
|
85
|
+
return "";
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
render: function() {
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
this.lPressed = false;
|
|
94
|
+
this.myPage = new page();
|
|
95
|
+
this.application = rio.Application.create({
|
|
96
|
+
routes: {
|
|
97
|
+
"other": "otherPage",
|
|
98
|
+
":something/hello": "helloPage",
|
|
99
|
+
"hello/*world": "worldPage",
|
|
100
|
+
"": "myPage"
|
|
101
|
+
},
|
|
102
|
+
methods: {
|
|
103
|
+
myPage: function() {
|
|
104
|
+
return this.myPage;
|
|
105
|
+
}.bind(this),
|
|
106
|
+
|
|
107
|
+
keyMap: function() {
|
|
108
|
+
return [
|
|
109
|
+
{
|
|
110
|
+
map: { key: 'l' },
|
|
111
|
+
handler: function() {
|
|
112
|
+
this.lPressed = true;
|
|
113
|
+
}.bind(this)
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
}.bind(this)
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
this.applicationInstance = new this.application();
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
"should not have no routes": function() {
|
|
123
|
+
this.applicationInstance.noRoutes().shouldBeFalse();
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
"should fire its current page's resize event if the window is resized": function() {
|
|
127
|
+
this.applicationInstance.launch();
|
|
128
|
+
stub(this.myPage, "resize").shouldBeCalled();
|
|
129
|
+
this.applicationInstance.resize();
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
"should fire its current page's keyPress event on keyPress": function() {
|
|
133
|
+
this.applicationInstance.launch();
|
|
134
|
+
|
|
135
|
+
var expectedEvent = { a: 1 };
|
|
136
|
+
stub(this.myPage, "keyPress").withValue(function(actualEvent) {
|
|
137
|
+
(expectedEvent === actualEvent).shouldBeTrue();
|
|
138
|
+
}.shouldBeCalled());
|
|
139
|
+
this.applicationInstance.keyPress(expectedEvent);
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
"should execute keymaps on keypress": function() {
|
|
143
|
+
this.applicationInstance.launch();
|
|
144
|
+
|
|
145
|
+
var keyEvent = { keyCode: 76 };
|
|
146
|
+
this.applicationInstance.keyDown(keyEvent);
|
|
147
|
+
this.lPressed.shouldBeTrue();
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
"should fire its current page's _keyDown event on keyDown": function() {
|
|
151
|
+
this.applicationInstance.launch();
|
|
152
|
+
|
|
153
|
+
var expectedEvent = { a: 1 };
|
|
154
|
+
stub(this.myPage, "_keyDown").withValue(function(actualEvent) {
|
|
155
|
+
(expectedEvent === actualEvent).shouldBeTrue();
|
|
156
|
+
}.shouldBeCalled());
|
|
157
|
+
this.applicationInstance.keyDown(expectedEvent);
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
"should not be launched before launch": function() {
|
|
161
|
+
this.applicationInstance.launched().shouldBeFalse();
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
"should be launched after launch": function() {
|
|
165
|
+
this.applicationInstance.launch();
|
|
166
|
+
this.applicationInstance.launched().shouldBeTrue();
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
"should initialize the dhtmlHistory on launch": function() {
|
|
170
|
+
stub(window.dhtmlHistory, "initialize").shouldBeCalled();
|
|
171
|
+
this.applicationInstance.launch();
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
"should add applyHistoryEntry as a listener to the dhtmlHistory on launch": function() {
|
|
175
|
+
stub(this.applicationInstance, "applyHistoryEntry").shouldBeCalled();
|
|
176
|
+
stub(window.dhtmlHistory, "addListener").withValue(function(listener) {
|
|
177
|
+
listener();
|
|
178
|
+
}.shouldBeCalled());
|
|
179
|
+
this.applicationInstance.launch();
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
"should immediately execute Application#afterLaunch calls if rio.app exists and has been launched": function() {
|
|
183
|
+
stub(rio, "_afterLaunchFunctions").withValue([]);
|
|
184
|
+
stub(rio, "app").withValue(this.applicationInstance);
|
|
185
|
+
this.applicationInstance.launch();
|
|
186
|
+
rio.Application.afterLaunch(function() {}.shouldBeCalled());
|
|
187
|
+
rio.Application.afterLaunch(function() {}.shouldBeCalled());
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
"should not immediately execute Application#afterLaunch calls if rio.app does not exist": function() {
|
|
191
|
+
stub(rio, "_afterLaunchFunctions").withValue([]);
|
|
192
|
+
stub(rio, "app").withValue();
|
|
193
|
+
rio.Application.afterLaunch(function() {}.shouldNotBeCalled());
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
"should not immediately execute Application#afterLaunch calls if rio.app exists but is not launched": function() {
|
|
197
|
+
stub(rio, "_afterLaunchFunctions").withValue([]);
|
|
198
|
+
stub(rio, "app").withValue(this.applicationInstance);
|
|
199
|
+
rio.Application.afterLaunch(function() {}.shouldNotBeCalled());
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
"should process the Application class afterLaunch functions on launch": function() {
|
|
203
|
+
stub(rio, "app").withValue(this.applicationInstance);
|
|
204
|
+
rio.Application.afterLaunch(function() {}.shouldBeCalled());
|
|
205
|
+
rio.Application.afterLaunch(function() {}.shouldBeCalled());
|
|
206
|
+
this.applicationInstance.launch();
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
"should match exact matches": function() {
|
|
210
|
+
this.applicationInstance.matchRoutePath("other").shouldEqual("other");
|
|
211
|
+
this.applicationInstance.matchRoutePath("").shouldEqual("");
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
"should treat :part as wild cards separated by slashes": function() {
|
|
215
|
+
this.applicationInstance.matchRoutePath("123/hello").shouldEqual(":something/hello");
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
"should treat *part as optional": function() {
|
|
219
|
+
this.applicationInstance.matchRoutePath("hello/123").shouldEqual("hello/*world");
|
|
220
|
+
this.applicationInstance.matchRoutePath("hello").shouldEqual("hello/*world");
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
"should fail to create routes if the * is not on the last parameter": function() {
|
|
224
|
+
var f = function() {}.shouldBeCalled();
|
|
225
|
+
try {
|
|
226
|
+
rio.Application.create({
|
|
227
|
+
routes: {
|
|
228
|
+
"*hello/world": "worldPage"
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
} catch(e) {
|
|
232
|
+
f();
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
"should match anything to '' route": function() {
|
|
237
|
+
this.applicationInstance.matchRoutePath("asdf").shouldEqual("");
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
"should return the match route target name": function() {
|
|
241
|
+
this.applicationInstance.matchRouteTarget("asdf").shouldEqual("myPage");
|
|
242
|
+
this.applicationInstance.matchRouteTarget("123/hello").shouldEqual("helloPage");
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
"should return anything after a slash trailing a match as remainingPath": function() {
|
|
246
|
+
this.applicationInstance.remainingPath("asdf").shouldEqual("asdf");
|
|
247
|
+
this.applicationInstance.remainingPath("123/hello/3/something").shouldEqual("3/something");
|
|
248
|
+
this.applicationInstance.remainingPath("other/page").shouldEqual("page");
|
|
249
|
+
this.applicationInstance.remainingPath("hello/anything").shouldEqual("anything");
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
"should return an empty hash for path parts that match path's with no wild-cards": function() {
|
|
253
|
+
var parts = this.applicationInstance.pathParts("asdf");
|
|
254
|
+
(parts.constructor == Object).shouldBeTrue();
|
|
255
|
+
Object.keys(parts).shouldBeEmpty();
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
"should return a hash from the wildcard name to its value in the path for path parts": function() {
|
|
259
|
+
this.applicationInstance.pathParts("123/hello").something.shouldEqual("123");
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
"should return a hash from the optional name to its value in the path for path parts": function() {
|
|
263
|
+
this.applicationInstance.pathParts("hello/456").world.shouldEqual("456");
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
"should fail the application if a route can't be found": function() {
|
|
267
|
+
stub(rio.Application, "fail").shouldBeCalled();
|
|
268
|
+
var app = new (rio.Application.create({
|
|
269
|
+
routes: {
|
|
270
|
+
"world": "asdf"
|
|
271
|
+
}
|
|
272
|
+
}))({});
|
|
273
|
+
try {
|
|
274
|
+
app.navigateTo("hello");
|
|
275
|
+
} catch(e) {
|
|
276
|
+
/* It's going to error here */
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
});
|
|
@@ -0,0 +1,1514 @@
|
|
|
1
|
+
describe(rio.Attr, {
|
|
2
|
+
|
|
3
|
+
"should support declaritive attrReader": function() {
|
|
4
|
+
var attr = rio.Attr.create();
|
|
5
|
+
attr.attrReader("something");
|
|
6
|
+
rio.Attr.extend(attr, {});
|
|
7
|
+
|
|
8
|
+
var attrInstance = new attr({ something: "some value" });
|
|
9
|
+
|
|
10
|
+
attrInstance.getSomething().shouldEqual("some value");
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
"should support declaritive attrReader with default value": function() {
|
|
14
|
+
var attr = rio.Attr.create();
|
|
15
|
+
attr.attrReader("something", "some default");
|
|
16
|
+
rio.Attr.extend(attr, {});
|
|
17
|
+
|
|
18
|
+
var attrInstance = new attr();
|
|
19
|
+
|
|
20
|
+
attrInstance.getSomething().shouldEqual("some default");
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
"should support declaritive attrAccessor": function() {
|
|
24
|
+
var attr = rio.Attr.create();
|
|
25
|
+
attr.attrAccessor("something");
|
|
26
|
+
rio.Attr.extend(attr, {});
|
|
27
|
+
|
|
28
|
+
var attrInstance = new attr({ something: "some value" });
|
|
29
|
+
|
|
30
|
+
attrInstance.getSomething().shouldEqual("some value");
|
|
31
|
+
attrInstance.setSomething("another value");
|
|
32
|
+
attrInstance.getSomething().shouldEqual("another value");
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
"should support attr inheritance": function() {
|
|
36
|
+
var attr = rio.Attr.create();
|
|
37
|
+
attr.attrReader("something");
|
|
38
|
+
rio.Attr.extend(attr, {});
|
|
39
|
+
|
|
40
|
+
var subAttr = rio.Attr.create(attr);
|
|
41
|
+
|
|
42
|
+
var attrInstance = new subAttr({ something: "some value" });
|
|
43
|
+
|
|
44
|
+
attrInstance.getSomething().shouldEqual("some value");
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
"should support concise attrReader syntax": function() {
|
|
48
|
+
var attr = rio.Attr.create({
|
|
49
|
+
attrReaders: ["something", "anotherThing"]
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
var attrInstance = new attr({ something: "some value", anotherThing: "another thing" });
|
|
53
|
+
attrInstance.getSomething().shouldEqual("some value");
|
|
54
|
+
attrInstance.getAnotherThing().shouldEqual("another thing");
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
"should support concise attrReader syntax also generating an is- accessor": function() {
|
|
58
|
+
var attr = rio.Attr.create({
|
|
59
|
+
attrReaders: ["something"]
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
var attrInstance = new attr({ something: "some value" });
|
|
63
|
+
attrInstance.isSomething().shouldEqual("some value");
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
"should support concise attrReader syntax with default values": function() {
|
|
67
|
+
var attr = rio.Attr.create({
|
|
68
|
+
attrReaders: [["something", "some default"]]
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
var attrInstance = new attr();
|
|
72
|
+
|
|
73
|
+
attrInstance.getSomething().shouldEqual("some default");
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
"should support concise attrReader syntax with default array values that are cloned when creating new objects": function() {
|
|
77
|
+
var attr = rio.Attr.create({
|
|
78
|
+
attrReaders: [["something", [1]]]
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
var a = new attr();
|
|
82
|
+
a.getSomething().push(2);
|
|
83
|
+
a.getSomething().length.shouldEqual(2);
|
|
84
|
+
shouldBeUndefined(new attr().getSomething().length.shouldEqual(1));
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
"should support concise attrReader syntax with default object values that are cloned when creating new objects": function() {
|
|
88
|
+
var attr = rio.Attr.create({
|
|
89
|
+
attrReaders: [["something", {a: 1}]]
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
var a = new attr();
|
|
93
|
+
a.getSomething().b = 2;
|
|
94
|
+
shouldBeUndefined(new attr().getSomething().b);
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
"should support concise attrAccessor syntax": function() {
|
|
98
|
+
var attr = rio.Attr.create({
|
|
99
|
+
attrAccessors: ["something", "anotherThing"]
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
var attrInstance = new attr({ something: "some value", anotherThing: "another thing" });
|
|
103
|
+
|
|
104
|
+
attrInstance.getSomething().shouldEqual("some value");
|
|
105
|
+
attrInstance.getAnotherThing().shouldEqual("another thing");
|
|
106
|
+
|
|
107
|
+
attrInstance.setSomething("some value 2");
|
|
108
|
+
attrInstance.getSomething().shouldEqual("some value 2");
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
"should support concise attrAccessor syntax with default values": function() {
|
|
112
|
+
var attr = rio.Attr.create({
|
|
113
|
+
attrAccessors: [["something", "some default"]]
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
var attrInstance = new attr();
|
|
117
|
+
|
|
118
|
+
attrInstance.getSomething().shouldEqual("some default");
|
|
119
|
+
|
|
120
|
+
attrInstance.setSomething("some value");
|
|
121
|
+
attrInstance.getSomething().shouldEqual("some value");
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
"should support concise instance method extension": function() {
|
|
125
|
+
var attr = rio.Attr.create({
|
|
126
|
+
methods: {
|
|
127
|
+
hello: function() {
|
|
128
|
+
return "hello world";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
var attrInstance = new attr();
|
|
134
|
+
|
|
135
|
+
attrInstance.hello().shouldEqual("hello world");
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
"should support concise class method extension": function() {
|
|
139
|
+
var attr = rio.Attr.create({
|
|
140
|
+
classMethods: {
|
|
141
|
+
hello: function() {
|
|
142
|
+
return "hello world";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
attr.hello().shouldEqual("hello world");
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
/* BEGIN BINDING RELATED SPECS */
|
|
151
|
+
"with a bindable attribute named a": {
|
|
152
|
+
beforeEach: function() {
|
|
153
|
+
this.attr = rio.Attr.create({ attrAccessors: ["a"] });
|
|
154
|
+
this.attrB = rio.Attr.create({ attrAccessors: ["b"] });
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
"should immediately execute a binding on a": function() {
|
|
158
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
159
|
+
attrInstance.bind("a", function(newVal) {
|
|
160
|
+
newVal.shouldEqual("asdf");
|
|
161
|
+
}.shouldBeCalled());
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
"should pass the current value as the old value on bind": function() {
|
|
165
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
166
|
+
attrInstance.bind("a", function(newVal, oldVal) {
|
|
167
|
+
oldVal.shouldEqual("asdf");
|
|
168
|
+
}.shouldBeCalled());
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
"should not immediately execute a binding when passing true for skipInitialExecution": function() {
|
|
172
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
173
|
+
attrInstance.bind("a", function() {}.shouldNotBeCalled(), true);
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
"should allow binding a function to a using attr.bind('a', fcn) syntax": function() {
|
|
177
|
+
var attrInstance = new this.attr();
|
|
178
|
+
attrInstance.bind("a", function(newVal) {
|
|
179
|
+
newVal.shouldEqual("asdf");
|
|
180
|
+
}.shouldBeCalled(), true);
|
|
181
|
+
|
|
182
|
+
attrInstance.setA("asdf");
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
"should also pass the old value to the function on set": function() {
|
|
186
|
+
var attrInstance = new this.attr({ a: "something old" });
|
|
187
|
+
attrInstance.bind("a", function(newVal, oldVal) {
|
|
188
|
+
newVal.shouldEqual("asdf");
|
|
189
|
+
oldVal.shouldEqual("something old");
|
|
190
|
+
}.shouldBeCalled(), true);
|
|
191
|
+
|
|
192
|
+
attrInstance.setA("asdf");
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
"should not execute bindings during a #transaction until the transaction has completed": function() {
|
|
196
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
197
|
+
var lastCalledWith;
|
|
198
|
+
attrInstance.bind("a", function(val) {
|
|
199
|
+
lastCalledWith = val;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
lastCalledWith.shouldEqual("asdf");
|
|
203
|
+
rio.Attr.transaction(function() {
|
|
204
|
+
attrInstance.setA("qwer");
|
|
205
|
+
lastCalledWith.shouldNotEqual("qwer");
|
|
206
|
+
}.shouldBeCalled());
|
|
207
|
+
lastCalledWith.shouldEqual("qwer");
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
"should not reexecute bindings during a second #transaction": function() {
|
|
211
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
212
|
+
var lastCalledWith;
|
|
213
|
+
attrInstance.bind("a", function(val) {
|
|
214
|
+
lastCalledWith = val;
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
lastCalledWith.shouldEqual("asdf");
|
|
218
|
+
rio.Attr.transaction(function() {
|
|
219
|
+
attrInstance.setA("qwer");
|
|
220
|
+
lastCalledWith.shouldNotEqual("qwer");
|
|
221
|
+
}.shouldBeCalled());
|
|
222
|
+
lastCalledWith.shouldEqual("qwer");
|
|
223
|
+
|
|
224
|
+
lastCalledWith = undefined;
|
|
225
|
+
rio.Attr.transaction(function() {
|
|
226
|
+
|
|
227
|
+
});
|
|
228
|
+
shouldBeUndefined(lastCalledWith);
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
"should not execute bindings during nested #transactions until all transactions have completed": function() {
|
|
232
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
233
|
+
var lastCalledWith;
|
|
234
|
+
attrInstance.bind("a", function(val) {
|
|
235
|
+
lastCalledWith = val;
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
lastCalledWith.shouldEqual("asdf");
|
|
239
|
+
rio.Attr.transaction(function() {
|
|
240
|
+
rio.Attr.transaction(function() {
|
|
241
|
+
attrInstance.setA("qwer");
|
|
242
|
+
lastCalledWith.shouldNotEqual("qwer");
|
|
243
|
+
}.shouldBeCalled());
|
|
244
|
+
lastCalledWith.shouldNotEqual("qwer");
|
|
245
|
+
}.shouldBeCalled());
|
|
246
|
+
|
|
247
|
+
lastCalledWith.shouldEqual("qwer");
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
"should not execute bindings during a #transaction if the transaction fails": function() {
|
|
251
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
252
|
+
var lastCalledWith;
|
|
253
|
+
attrInstance.bind("a", function(val) {
|
|
254
|
+
lastCalledWith = val;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
lastCalledWith.shouldEqual("asdf");
|
|
258
|
+
try {
|
|
259
|
+
rio.Attr.transaction(function() {
|
|
260
|
+
attrInstance.setA("qwer");
|
|
261
|
+
throw("EEEK");
|
|
262
|
+
}.shouldBeCalled());
|
|
263
|
+
} catch(e) {
|
|
264
|
+
/* swallow this exception as part of the test */
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
lastCalledWith.shouldEqual("asdf");
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
"should not execute bindings during a #transaction if the transaction fails but should allow a binding to fire immediately after": function() {
|
|
271
|
+
var attrInstance = new this.attr({ a: "asdf" });
|
|
272
|
+
var lastCalledWith;
|
|
273
|
+
attrInstance.bind("a", function(val) {
|
|
274
|
+
lastCalledWith = val;
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
lastCalledWith.shouldEqual("asdf");
|
|
278
|
+
try {
|
|
279
|
+
rio.Attr.transaction(function() {
|
|
280
|
+
attrInstance.setA("qwer");
|
|
281
|
+
throw("EEEK");
|
|
282
|
+
}.shouldBeCalled());
|
|
283
|
+
} catch(e) {
|
|
284
|
+
/* swallow this exception as part of the test */
|
|
285
|
+
}
|
|
286
|
+
lastCalledWith.shouldEqual("asdf");
|
|
287
|
+
|
|
288
|
+
attrInstance.setA("zxcv");
|
|
289
|
+
lastCalledWith.shouldEqual("zxcv");
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
"should return an unbind function when binding a function to an a": function() {
|
|
293
|
+
var attrInstance = new this.attr();
|
|
294
|
+
var unbindFunction = attrInstance.bind("a", function() {}.shouldNotBeCalled(), true);
|
|
295
|
+
unbindFunction();
|
|
296
|
+
attrInstance.setA("asdf");
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
"should allow binding on a path 'a.b' and fire bindings when a's b value changes": function() {
|
|
300
|
+
var attrBInstance = new this.attrB();
|
|
301
|
+
var attrInstance = new this.attr({ a: attrBInstance });
|
|
302
|
+
attrInstance.bind("a.b", function(newVal) {
|
|
303
|
+
newVal.shouldEqual("asdf");
|
|
304
|
+
}.shouldBeCalled(), true);
|
|
305
|
+
|
|
306
|
+
attrBInstance.setB("asdf");
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
"should allow binding on a path 'a.b' and fire bindings immediately with the old value and new value the same": function() {
|
|
310
|
+
var attrInstance = new this.attr({ a: new this.attrB({ b: "asdf" }) });
|
|
311
|
+
attrInstance.bind("a.b", function(newVal, oldVal) {
|
|
312
|
+
oldVal.shouldEqual("asdf");
|
|
313
|
+
newVal.shouldEqual("asdf");
|
|
314
|
+
}.shouldBeCalled());
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
"should allow binding on a path 'a.b' and fire bindings when a's b value changes with the old value as well": function() {
|
|
318
|
+
var attrBInstance = new this.attrB({ b: "old" });
|
|
319
|
+
var attrInstance = new this.attr({ a: attrBInstance });
|
|
320
|
+
attrInstance.bind("a.b", function(newVal, oldVal) {
|
|
321
|
+
oldVal.shouldEqual("old");
|
|
322
|
+
}.shouldBeCalled(), true);
|
|
323
|
+
|
|
324
|
+
attrBInstance.setB("asdf");
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
"should allow binding on a path 'a.b' and fire bindings when a changes": function() {
|
|
328
|
+
var attrInstance = new this.attr();
|
|
329
|
+
attrInstance.bind("a.b", function(newVal) {
|
|
330
|
+
newVal.shouldEqual("asdf");
|
|
331
|
+
}.shouldBeCalled(), true);
|
|
332
|
+
|
|
333
|
+
attrInstance.setA(new this.attrB({ b: "asdf" }));
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
"should allow binding on a path 'a.b' and fire bindings when a changes with the old value also": function() {
|
|
337
|
+
var attrInstance = new this.attr({ a: new this.attrB({ b: "old" }) });
|
|
338
|
+
attrInstance.bind("a.b", function(newVal, oldVal) {
|
|
339
|
+
oldVal.shouldEqual("old");
|
|
340
|
+
}.shouldBeCalled(), true);
|
|
341
|
+
|
|
342
|
+
attrInstance.setA(new this.attrB({ b: "asdf" }));
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
"should properly unbind a path": function() {
|
|
346
|
+
var attrInstanceB = new this.attrB({ b: 0 });
|
|
347
|
+
var attrInstance = new this.attr({ a: attrInstanceB });
|
|
348
|
+
attrInstance.bind("a.b", function() {}.shouldBeCalled().times(2), true);
|
|
349
|
+
|
|
350
|
+
attrInstanceB.setB(1);
|
|
351
|
+
attrInstance.setA(new this.attrB({ b: 2 }));
|
|
352
|
+
attrInstanceB.setB(3);
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
"should properly unbind a long path": function() {
|
|
356
|
+
var attrInstanceA2 = new this.attr({ a: "asdf" });
|
|
357
|
+
var attrInstanceB = new this.attrB({ b: attrInstanceA2 });
|
|
358
|
+
var attrInstance = new this.attr({ a: attrInstanceB });
|
|
359
|
+
attrInstance.bind("a.b.a", function() {}.shouldBeCalled().times(2), true);
|
|
360
|
+
|
|
361
|
+
attrInstanceA2.setA(1);
|
|
362
|
+
attrInstance.setA(new this.attrB({ b: new this.attr({ a: 2 }) }));
|
|
363
|
+
attrInstanceA2.setA(3);
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
"should bind collection bindings at the end of a path": function() {
|
|
367
|
+
var arr = [1];
|
|
368
|
+
var attrInstanceB = new this.attrB({ b: arr });
|
|
369
|
+
var attrInstance = new this.attr({ a: attrInstanceB });
|
|
370
|
+
attrInstance.bind("a.b", {
|
|
371
|
+
insert: function(val) {
|
|
372
|
+
val.shouldEqual(2);
|
|
373
|
+
}.shouldBeCalled().once()
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
arr.push(2);
|
|
377
|
+
},
|
|
378
|
+
|
|
379
|
+
"should rebind collection bindings at the end of a path": function() {
|
|
380
|
+
var arr = [1];
|
|
381
|
+
var attrInstanceB = new this.attrB({ b: arr });
|
|
382
|
+
var attrInstance = new this.attr({ a: attrInstanceB });
|
|
383
|
+
attrInstance.bind("a.b", {
|
|
384
|
+
insert: function(val) {}.shouldNotBeCalled()
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
attrInstanceB.setB([]);
|
|
388
|
+
arr.push(2);
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
"should unbind collection bindings at the end of a long path": function() {
|
|
392
|
+
var arr = [1];
|
|
393
|
+
var attrInstanceA2 = new this.attr({ a: arr });
|
|
394
|
+
var attrInstanceB = new this.attrB({ b: attrInstanceA2 });
|
|
395
|
+
var attrInstance = new this.attr({ a: attrInstanceB });
|
|
396
|
+
attrInstance.bind("a.b.a", {
|
|
397
|
+
insert: function(val) { }.shouldNotBeCalled()
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
attrInstanceB.setB(new this.attr({ a: [] }));
|
|
401
|
+
arr.push(2);
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
/* This is a confusing test. */
|
|
406
|
+
"should allow you to pass the same list bindings to a binding path and a standard binding": function() {
|
|
407
|
+
var subInstance = new this.attrB({ b: "asdf" });
|
|
408
|
+
var attrInstance = new this.attr({
|
|
409
|
+
a: subInstance
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
var otherInstance = new this.attr({
|
|
413
|
+
a: [2,3]
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
var setValue = "asdf";
|
|
417
|
+
var insertValue = "";
|
|
418
|
+
var listBindings = {
|
|
419
|
+
set: function(newVal) {
|
|
420
|
+
newVal.shouldEqual(setValue);
|
|
421
|
+
}.shouldBeCalled().times(3),
|
|
422
|
+
|
|
423
|
+
insert: function(val) {
|
|
424
|
+
val.shouldEqual(insertValue);
|
|
425
|
+
}.shouldBeCalled().times(3)
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
attrInstance.bind("a.b", listBindings);
|
|
429
|
+
|
|
430
|
+
setValue = [2, 3];
|
|
431
|
+
otherInstance.a.bind(listBindings);
|
|
432
|
+
|
|
433
|
+
insertValue = 6;
|
|
434
|
+
otherInstance.getA().push(6);
|
|
435
|
+
|
|
436
|
+
setValue = [1,2,3];
|
|
437
|
+
subInstance.setB(setValue);
|
|
438
|
+
|
|
439
|
+
insertValue = 7;
|
|
440
|
+
otherInstance.getA().push(7);
|
|
441
|
+
|
|
442
|
+
insertValue = 4;
|
|
443
|
+
setValue.push(insertValue);
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
"should allow binding a collection attrAccessor to an object with set": function() {
|
|
447
|
+
var attrInstance = new this.attr();
|
|
448
|
+
|
|
449
|
+
attrInstance.bind("a", {
|
|
450
|
+
set: function(newVal) {
|
|
451
|
+
newVal.shouldEqual([1,2,3]);
|
|
452
|
+
}.shouldBeCalled()
|
|
453
|
+
}, true);
|
|
454
|
+
|
|
455
|
+
attrInstance.setA([1,2,3]);
|
|
456
|
+
},
|
|
457
|
+
|
|
458
|
+
"should allow binding a collection attrAccessor to an object with insert responding to push": function() {
|
|
459
|
+
var arr = [1,2,3];
|
|
460
|
+
var attrInstance = new this.attr({ a: arr });
|
|
461
|
+
|
|
462
|
+
attrInstance.bind("a", {
|
|
463
|
+
insert: function(newVal, index) {
|
|
464
|
+
newVal.shouldEqual(4);
|
|
465
|
+
index.shouldEqual(3);
|
|
466
|
+
}.shouldBeCalled()
|
|
467
|
+
});
|
|
468
|
+
arr.push(4);
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
"should allow binding a collection attrAccessor to an object with insert responding to splice": function() {
|
|
472
|
+
var arr = [1,2,3];
|
|
473
|
+
var attrInstance = new this.attr({ a: arr });
|
|
474
|
+
|
|
475
|
+
attrInstance.bind("a", {
|
|
476
|
+
insert: function(newVal, index) {
|
|
477
|
+
newVal.shouldEqual(1.5);
|
|
478
|
+
index.shouldEqual(1);
|
|
479
|
+
}.shouldBeCalled()
|
|
480
|
+
});
|
|
481
|
+
arr.splice(1, 0, 1.5);
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
"should allow binding a collection attrAccessor to an object with remove responding to splice": function() {
|
|
485
|
+
var arr = [1,2,3];
|
|
486
|
+
var attrInstance = new this.attr({ a: arr });
|
|
487
|
+
|
|
488
|
+
attrInstance.bind("a", {
|
|
489
|
+
remove: function(removeVal) {
|
|
490
|
+
removeVal.shouldEqual(2);
|
|
491
|
+
}.shouldBeCalled()
|
|
492
|
+
});
|
|
493
|
+
arr.splice(1, 1);
|
|
494
|
+
},
|
|
495
|
+
|
|
496
|
+
"should allow binding a collection attrAccessor to an object with remove responding to pop": function() {
|
|
497
|
+
var arr = [1,2,3];
|
|
498
|
+
var attrInstance = new this.attr({ a: arr });
|
|
499
|
+
|
|
500
|
+
attrInstance.bind("a", {
|
|
501
|
+
remove: function(removeVal) {
|
|
502
|
+
removeVal.shouldEqual(3);
|
|
503
|
+
}.shouldBeCalled()
|
|
504
|
+
});
|
|
505
|
+
arr.pop().shouldEqual(3);
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
"should allow binding a collection attrAccessor to an object with remove not responding to pop if already empty": function() {
|
|
509
|
+
var arr = [];
|
|
510
|
+
var attrInstance = new this.attr({ a: arr });
|
|
511
|
+
|
|
512
|
+
attrInstance.bind("a", {
|
|
513
|
+
remove: function(removeVal) {}.shouldNotBeCalled()
|
|
514
|
+
});
|
|
515
|
+
shouldBeUndefined(arr.pop());
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
"should allow binding a collection attrAccessor to an object with empty responding to pop": function() {
|
|
519
|
+
var arr = [1];
|
|
520
|
+
var attrInstance = new this.attr({ a: arr });
|
|
521
|
+
|
|
522
|
+
var lastEmptyValue;
|
|
523
|
+
attrInstance.bind("a", {
|
|
524
|
+
empty: function(val) {
|
|
525
|
+
lastEmptyValue = val;
|
|
526
|
+
}.shouldBeCalled()
|
|
527
|
+
});
|
|
528
|
+
lastEmptyValue.shouldBeFalse();
|
|
529
|
+
arr.pop();
|
|
530
|
+
lastEmptyValue.shouldBeTrue();
|
|
531
|
+
},
|
|
532
|
+
|
|
533
|
+
"should allow binding a collection attrAccessor to an object with empty not responding to pop if emptyness doesn't change": function() {
|
|
534
|
+
var arr = [1, 2];
|
|
535
|
+
var attrInstance = new this.attr({ a: arr });
|
|
536
|
+
|
|
537
|
+
var lastEmptyValue;
|
|
538
|
+
attrInstance.bind("a", {
|
|
539
|
+
empty: function(val) {
|
|
540
|
+
lastEmptyValue = val;
|
|
541
|
+
}.shouldBeCalled()
|
|
542
|
+
});
|
|
543
|
+
lastEmptyValue.shouldBeFalse();
|
|
544
|
+
lastEmptyValue = undefined;
|
|
545
|
+
arr.pop();
|
|
546
|
+
shouldBeUndefined(lastEmptyValue);
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
"should allow binding a collection attrAccessor to an object with empty": function() {
|
|
550
|
+
var attrInstance = new this.attr({ a: [] });
|
|
551
|
+
attrInstance.bind("a", {
|
|
552
|
+
empty: function(empty) {
|
|
553
|
+
empty.shouldBeTrue();
|
|
554
|
+
}.shouldBeCalled().once()
|
|
555
|
+
});
|
|
556
|
+
},
|
|
557
|
+
|
|
558
|
+
"should allow binding a collection attrAccessor to an object with empty responding true to set": function() {
|
|
559
|
+
var attrInstance = new this.attr();
|
|
560
|
+
attrInstance.bind("a", {
|
|
561
|
+
empty: function(empty) {
|
|
562
|
+
empty.shouldBeTrue();
|
|
563
|
+
}.shouldBeCalled().once()
|
|
564
|
+
});
|
|
565
|
+
attrInstance.setA([]);
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
"should allow binding a collection attrAccessor to an object with empty responding false to set": function() {
|
|
569
|
+
var attrInstance = new this.attr();
|
|
570
|
+
attrInstance.bind("a", {
|
|
571
|
+
empty: function(empty) {
|
|
572
|
+
empty.shouldBeFalse();
|
|
573
|
+
}.shouldBeCalled().once()
|
|
574
|
+
});
|
|
575
|
+
attrInstance.setA([1,2,3]);
|
|
576
|
+
},
|
|
577
|
+
|
|
578
|
+
"should allow binding a collection attrAccessor to an object with empty responding to insert": function() {
|
|
579
|
+
var arr = [];
|
|
580
|
+
var attrInstance = new this.attr({ a: arr });
|
|
581
|
+
|
|
582
|
+
/* When bind is called the empty binding will fire. Use this expectation variable to set an expectation on the subsequent firing. */
|
|
583
|
+
var expectation = Prototype.emptyFunction;
|
|
584
|
+
attrInstance.bind("a", {
|
|
585
|
+
empty: function(empty) {
|
|
586
|
+
expectation(empty);
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
expectation = function(empty) { empty.shouldBeFalse(); }.shouldBeCalled();
|
|
590
|
+
arr.push(4);
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
"should allow binding a collection attrAccessor to an object with empty responding to splice adding": function() {
|
|
594
|
+
var arr = [];
|
|
595
|
+
var attrInstance = new this.attr({ a: arr });
|
|
596
|
+
|
|
597
|
+
/* When bind is called the empty binding will fire. Use this expectation variable to set an expectation on the subsequent firing. */
|
|
598
|
+
var expectation = Prototype.emptyFunction;
|
|
599
|
+
attrInstance.bind("a", {
|
|
600
|
+
empty: function(empty) {
|
|
601
|
+
expectation(empty);
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
expectation = function(empty) { empty.shouldBeFalse(); }.shouldBeCalled();
|
|
605
|
+
|
|
606
|
+
arr.splice(0, 0, "a");
|
|
607
|
+
},
|
|
608
|
+
|
|
609
|
+
"should allow binding a collection attrAccessor to an object with empty responding to splice removing": function() {
|
|
610
|
+
var arr = [1];
|
|
611
|
+
var attrInstance = new this.attr({ a: arr });
|
|
612
|
+
|
|
613
|
+
/* When bind is called the empty binding will fire. Use this expectation variable to set an expectation on the subsequent firing. */
|
|
614
|
+
var expectation = Prototype.emptyFunction;
|
|
615
|
+
attrInstance.bind("a", {
|
|
616
|
+
empty: function(empty) {
|
|
617
|
+
expectation(empty);
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
expectation = function(empty) { empty.shouldBeTrue(); }.shouldBeCalled();
|
|
621
|
+
|
|
622
|
+
arr.splice(0, 1);
|
|
623
|
+
},
|
|
624
|
+
|
|
625
|
+
"should allow binding a collection attrAccessor to an object with empty not responding to splice adding or removing that don't change emptyness": function() {
|
|
626
|
+
var arr = [1];
|
|
627
|
+
var attrInstance = new this.attr({ a: arr });
|
|
628
|
+
|
|
629
|
+
/* When bind is called the empty binding will fire. Use this expectation variable to set an expectation on the subsequent firing. */
|
|
630
|
+
var expectation = Prototype.emptyFunction;
|
|
631
|
+
attrInstance.bind("a", {
|
|
632
|
+
empty: function(empty) {
|
|
633
|
+
expectation(empty);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
expectation = function() { }.shouldNotBeCalled();
|
|
637
|
+
|
|
638
|
+
arr.splice(0, 0, "a");
|
|
639
|
+
arr.splice(0, 1);
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
"should allow binding a collection attrAccessor to an object with set responding to clear": function() {
|
|
643
|
+
var arr = [1,2,3];
|
|
644
|
+
var attrInstance = new this.attr({ a: arr });
|
|
645
|
+
|
|
646
|
+
var expectation = Prototype.emptyFunction;
|
|
647
|
+
attrInstance.bind("a", {
|
|
648
|
+
set: function(val) {
|
|
649
|
+
expectation(val);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
expectation = function(val) {
|
|
653
|
+
val.shouldBeEmpty();
|
|
654
|
+
}.shouldBeCalled();
|
|
655
|
+
|
|
656
|
+
arr.clear();
|
|
657
|
+
},
|
|
658
|
+
|
|
659
|
+
"should allow binding a collection attrAccessor to an object with set not responding to clear if already empty": function() {
|
|
660
|
+
var arr = [];
|
|
661
|
+
var attrInstance = new this.attr({ a: arr });
|
|
662
|
+
|
|
663
|
+
var expectation = Prototype.emptyFunction;
|
|
664
|
+
attrInstance.bind("a", {
|
|
665
|
+
set: function(val) {
|
|
666
|
+
expectation(val);
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
expectation = function(val) {}.shouldNotBeCalled();
|
|
670
|
+
|
|
671
|
+
arr.clear();
|
|
672
|
+
},
|
|
673
|
+
|
|
674
|
+
"should allow binding a collection attrAccessor to an object with empty responding to clear": function() {
|
|
675
|
+
var arr = [1, 2, 3];
|
|
676
|
+
var attrInstance = new this.attr({ a: arr });
|
|
677
|
+
|
|
678
|
+
var expectation = Prototype.emptyFunction;
|
|
679
|
+
var lastEmptyValue;
|
|
680
|
+
attrInstance.bind("a", {
|
|
681
|
+
empty: function(val) {
|
|
682
|
+
lastEmptyValue = val;
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
arr.clear();
|
|
687
|
+
lastEmptyValue.shouldBeTrue();
|
|
688
|
+
},
|
|
689
|
+
|
|
690
|
+
"should allow binding a collection attrAccessor to an object with empty not responding to clear if already empty": function() {
|
|
691
|
+
var arr = [];
|
|
692
|
+
var attrInstance = new this.attr({ a: arr });
|
|
693
|
+
|
|
694
|
+
var expectation = Prototype.emptyFunction;
|
|
695
|
+
var lastEmptyValue;
|
|
696
|
+
attrInstance.bind("a", {
|
|
697
|
+
empty: function(val) {
|
|
698
|
+
lastEmptyValue = val;
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
lastEmptyValue = undefined;
|
|
703
|
+
arr.clear();
|
|
704
|
+
shouldBeUndefined(lastEmptyValue);
|
|
705
|
+
},
|
|
706
|
+
|
|
707
|
+
"should unbind collection clear binding when the value of an attrAccessor changes": function() {
|
|
708
|
+
var arr = [1,2,3];
|
|
709
|
+
var attrInstance = new this.attr({ a: arr });
|
|
710
|
+
|
|
711
|
+
var expectation = Prototype.emptyFunction;
|
|
712
|
+
attrInstance.bind("a", {
|
|
713
|
+
set: function(val) {
|
|
714
|
+
expectation(val);
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
expectation = function(val) {}.shouldBeCalled().once();
|
|
718
|
+
|
|
719
|
+
attrInstance.setA([]);
|
|
720
|
+
arr.clear();
|
|
721
|
+
arr.clear();
|
|
722
|
+
},
|
|
723
|
+
|
|
724
|
+
"should unbind collection bindings when the value of an attrAccessor changes": function() {
|
|
725
|
+
var arr = [1,2,3];
|
|
726
|
+
var attrInstance = new this.attr({ a: arr });
|
|
727
|
+
|
|
728
|
+
attrInstance.bind("a", {
|
|
729
|
+
insert: function(insertVal) {}.shouldBeCalled().once()
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
attrInstance.setA([5,6,7,8]);
|
|
733
|
+
attrInstance.setA(arr);
|
|
734
|
+
|
|
735
|
+
arr.push(4);
|
|
736
|
+
},
|
|
737
|
+
|
|
738
|
+
"should unbind collection bindings when the value of an attrAccessor changes and the collection was bound in multiple attr's": function() {
|
|
739
|
+
var arr = [1,2,3];
|
|
740
|
+
var attrInstance1 = new this.attr({ a: arr });
|
|
741
|
+
var attrInstance2 = new this.attr({ a: arr });
|
|
742
|
+
|
|
743
|
+
attrInstance1.bind("a", {
|
|
744
|
+
insert: function(insertVal) {}.shouldBeCalled().once()
|
|
745
|
+
});
|
|
746
|
+
attrInstance2.bind("a", {
|
|
747
|
+
insert: function(insertVal) {}.shouldBeCalled().once()
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
attrInstance1.setA([5,6,7,8]);
|
|
751
|
+
attrInstance1.setA(arr);
|
|
752
|
+
|
|
753
|
+
attrInstance2.setA([5,6,7,8]);
|
|
754
|
+
attrInstance2.setA(arr);
|
|
755
|
+
|
|
756
|
+
arr.push(4);
|
|
757
|
+
},
|
|
758
|
+
|
|
759
|
+
"should unbind collection bindings when calling the unbind function": function() {
|
|
760
|
+
var arr = [1,2,3];
|
|
761
|
+
var attrInstance = new this.attr({ a: arr });
|
|
762
|
+
|
|
763
|
+
var unbind = attrInstance.bind("a", {
|
|
764
|
+
insert: function(insertVal) {}.shouldBeCalled().once()
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
arr.push(4);
|
|
768
|
+
unbind();
|
|
769
|
+
arr.push(5);
|
|
770
|
+
},
|
|
771
|
+
|
|
772
|
+
"should not execute collection bindings for push during a #transaction until the transaction completes": function() {
|
|
773
|
+
var arr = [];
|
|
774
|
+
var attrInstance = new this.attr({ a: arr });
|
|
775
|
+
|
|
776
|
+
var insertLastCalledWith;
|
|
777
|
+
var emptyLastCalledWith;
|
|
778
|
+
attrInstance.bind("a", {
|
|
779
|
+
insert: function(val) {
|
|
780
|
+
insertLastCalledWith = val;
|
|
781
|
+
},
|
|
782
|
+
|
|
783
|
+
empty: function(val) {
|
|
784
|
+
emptyLastCalledWith = val;
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
shouldBeUndefined(insertLastCalledWith);
|
|
789
|
+
emptyLastCalledWith.shouldBeTrue();
|
|
790
|
+
|
|
791
|
+
rio.Attr.transaction(function() {
|
|
792
|
+
arr.push(4);
|
|
793
|
+
|
|
794
|
+
shouldBeUndefined(insertLastCalledWith);
|
|
795
|
+
emptyLastCalledWith.shouldBeTrue();
|
|
796
|
+
}.shouldBeCalled());
|
|
797
|
+
|
|
798
|
+
insertLastCalledWith.shouldEqual(4);
|
|
799
|
+
emptyLastCalledWith.shouldBeFalse();
|
|
800
|
+
},
|
|
801
|
+
|
|
802
|
+
"should not execute collection bindings for pop during a #transaction until the transaction completes": function() {
|
|
803
|
+
var arr = [1];
|
|
804
|
+
var attrInstance = new this.attr({ a: arr });
|
|
805
|
+
|
|
806
|
+
var removeLastCalledWith;
|
|
807
|
+
var emptyLastCalledWith;
|
|
808
|
+
attrInstance.bind("a", {
|
|
809
|
+
remove: function(val) {
|
|
810
|
+
removeLastCalledWith = val;
|
|
811
|
+
},
|
|
812
|
+
|
|
813
|
+
empty: function(val) {
|
|
814
|
+
emptyLastCalledWith = val;
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
shouldBeUndefined(removeLastCalledWith);
|
|
819
|
+
emptyLastCalledWith.shouldBeFalse();
|
|
820
|
+
|
|
821
|
+
rio.Attr.transaction(function() {
|
|
822
|
+
arr.pop().shouldEqual(1);
|
|
823
|
+
|
|
824
|
+
shouldBeUndefined(removeLastCalledWith);
|
|
825
|
+
emptyLastCalledWith.shouldBeFalse();
|
|
826
|
+
}.shouldBeCalled());
|
|
827
|
+
|
|
828
|
+
removeLastCalledWith.shouldEqual(1);
|
|
829
|
+
emptyLastCalledWith.shouldBeTrue();
|
|
830
|
+
},
|
|
831
|
+
|
|
832
|
+
"should not execute collection bindings for splice during a #transaction until the transaction completes": function() {
|
|
833
|
+
var arr = [];
|
|
834
|
+
var attrInstance = new this.attr({ a: arr });
|
|
835
|
+
|
|
836
|
+
var insertLastCalledWith;
|
|
837
|
+
var removeLastCalledWith;
|
|
838
|
+
var emptyLastCalledWith;
|
|
839
|
+
attrInstance.bind("a", {
|
|
840
|
+
insert: function(val) {
|
|
841
|
+
insertLastCalledWith = val;
|
|
842
|
+
},
|
|
843
|
+
|
|
844
|
+
remove: function(val) {
|
|
845
|
+
removeLastCalledWith = val;
|
|
846
|
+
},
|
|
847
|
+
|
|
848
|
+
empty: function(val) {
|
|
849
|
+
emptyLastCalledWith = val;
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
shouldBeUndefined(insertLastCalledWith);
|
|
854
|
+
shouldBeUndefined(removeLastCalledWith);
|
|
855
|
+
emptyLastCalledWith.shouldBeTrue();
|
|
856
|
+
|
|
857
|
+
rio.Attr.transaction(function() {
|
|
858
|
+
arr.splice(0, 0, 2);
|
|
859
|
+
arr.splice(1, 0, 5);
|
|
860
|
+
|
|
861
|
+
arr.splice(0, 1);
|
|
862
|
+
|
|
863
|
+
shouldBeUndefined(insertLastCalledWith);
|
|
864
|
+
shouldBeUndefined(removeLastCalledWith);
|
|
865
|
+
emptyLastCalledWith.shouldBeTrue();
|
|
866
|
+
}.shouldBeCalled());
|
|
867
|
+
|
|
868
|
+
insertLastCalledWith.shouldEqual(5);
|
|
869
|
+
removeLastCalledWith.shouldEqual(2);
|
|
870
|
+
emptyLastCalledWith.shouldBeFalse();
|
|
871
|
+
},
|
|
872
|
+
|
|
873
|
+
"should not execute collection bindings for clear during a #transaction until the transaction completes": function() {
|
|
874
|
+
var arr = [1, 2, 3];
|
|
875
|
+
var attrInstance = new this.attr({ a: arr });
|
|
876
|
+
|
|
877
|
+
var setLastCalledWith;
|
|
878
|
+
var emptyLastCalledWith;
|
|
879
|
+
attrInstance.bind("a", {
|
|
880
|
+
set: function(val) {
|
|
881
|
+
setLastCalledWith = val;
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
empty: function(val) {
|
|
885
|
+
emptyLastCalledWith = val;
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
setLastCalledWith = undefined;
|
|
890
|
+
emptyLastCalledWith.shouldBeFalse();
|
|
891
|
+
|
|
892
|
+
rio.Attr.transaction(function() {
|
|
893
|
+
arr.clear();
|
|
894
|
+
|
|
895
|
+
shouldBeUndefined(setLastCalledWith);
|
|
896
|
+
emptyLastCalledWith.shouldBeFalse();
|
|
897
|
+
}.shouldBeCalled());
|
|
898
|
+
|
|
899
|
+
setLastCalledWith.shouldEqual([]);
|
|
900
|
+
emptyLastCalledWith.shouldBeTrue();
|
|
901
|
+
},
|
|
902
|
+
|
|
903
|
+
"has a binding object at attrInstance.a that": {
|
|
904
|
+
beforeEach: function() {
|
|
905
|
+
this.attrInstance = new this.attr({ a: "asdf" });
|
|
906
|
+
},
|
|
907
|
+
|
|
908
|
+
"should expose the value of a": function() {
|
|
909
|
+
this.attrInstance.a.value().shouldEqual("asdf");
|
|
910
|
+
},
|
|
911
|
+
|
|
912
|
+
"should allow binding a function to it": function() {
|
|
913
|
+
this.attrInstance.a.bind(function(newVal) {
|
|
914
|
+
newVal.shouldEqual("qwer");
|
|
915
|
+
}.shouldBeCalled(), true);
|
|
916
|
+
|
|
917
|
+
this.attrInstance.setA("qwer");
|
|
918
|
+
},
|
|
919
|
+
|
|
920
|
+
"should provide an update method that changes the underlying attribute value": function() {
|
|
921
|
+
this.attrInstance.a.update("qwer");
|
|
922
|
+
this.attrInstance.getA().shouldEqual("qwer");
|
|
923
|
+
},
|
|
924
|
+
|
|
925
|
+
"provides a bindTo method that": {
|
|
926
|
+
beforeEach: function() {
|
|
927
|
+
this.otherInstance = new this.attrB({ b: "qwer" });
|
|
928
|
+
},
|
|
929
|
+
|
|
930
|
+
"should bind itself to another binding initializing the binding value with 'asdf'": function() {
|
|
931
|
+
this.attrInstance.a.bindTo(this.otherInstance.b);
|
|
932
|
+
this.attrInstance.getA().shouldEqual("asdf");
|
|
933
|
+
this.otherInstance.getB().shouldEqual("asdf");
|
|
934
|
+
},
|
|
935
|
+
|
|
936
|
+
"should bind itself to another binding and update the other binding when it updates": function() {
|
|
937
|
+
this.attrInstance.a.bindTo(this.otherInstance.b);
|
|
938
|
+
this.attrInstance.setA("1234");
|
|
939
|
+
this.otherInstance.getB().shouldEqual("1234");
|
|
940
|
+
},
|
|
941
|
+
|
|
942
|
+
"should bind itself to another binding and update itself when the other binding is updated": function() {
|
|
943
|
+
this.attrInstance.a.bindTo(this.otherInstance.b);
|
|
944
|
+
this.otherInstance.setB("4321");
|
|
945
|
+
this.attrInstance.getA().shouldEqual("4321");
|
|
946
|
+
},
|
|
947
|
+
|
|
948
|
+
"should provid an unbind object that cleans up the bindings in both directions": function() {
|
|
949
|
+
var unbind = this.attrInstance.a.bindTo(this.otherInstance.b);
|
|
950
|
+
this.attrInstance.setA('initial');
|
|
951
|
+
unbind();
|
|
952
|
+
|
|
953
|
+
this.attrInstance.setA('newA');
|
|
954
|
+
this.otherInstance.getB().shouldEqual('initial');
|
|
955
|
+
|
|
956
|
+
this.otherInstance.setB('newB');
|
|
957
|
+
this.attrInstance.getA().shouldEqual('newA');
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
|
|
962
|
+
"will bind a to another attrAccessor if its binding is passed in on initialization and": {
|
|
963
|
+
beforeEach: function() {
|
|
964
|
+
this.subInstance = new this.attrB({ b: "1234" });
|
|
965
|
+
this.otherInstance = new this.attrB({ b: this.subInstance });
|
|
966
|
+
this.attrInstance = new this.attr({ a: this.otherInstance.binding("b.b") });
|
|
967
|
+
},
|
|
968
|
+
|
|
969
|
+
"should initialize a with the value of the other binding": function() {
|
|
970
|
+
this.attrInstance.getA().shouldEqual("1234");
|
|
971
|
+
},
|
|
972
|
+
|
|
973
|
+
"should update a when the sub binding value is updated": function() {
|
|
974
|
+
this.subInstance.setB("4321");
|
|
975
|
+
this.attrInstance.getA().shouldEqual("4321");
|
|
976
|
+
},
|
|
977
|
+
|
|
978
|
+
"should update the sub binding value when a is updated": function() {
|
|
979
|
+
this.attrInstance.setA("4321");
|
|
980
|
+
this.subInstance.getB().shouldEqual("4321");
|
|
981
|
+
},
|
|
982
|
+
|
|
983
|
+
"should update a when the binding value is changed": function() {
|
|
984
|
+
this.otherInstance.setB(new this.attrB({ b: "9876" }));
|
|
985
|
+
this.attrInstance.getA().shouldEqual("9876");
|
|
986
|
+
}
|
|
987
|
+
},
|
|
988
|
+
|
|
989
|
+
"has a freeze method that": {
|
|
990
|
+
"sets frozen to true": function() {
|
|
991
|
+
var attrInstance = new this.attr({ a: 1 });
|
|
992
|
+
attrInstance.freeze();
|
|
993
|
+
attrInstance.frozen().shouldBeTrue();
|
|
994
|
+
},
|
|
995
|
+
|
|
996
|
+
"makes all attrAccessor set methods no-ops": function() {
|
|
997
|
+
var attrInstance = new this.attr({ a: 1 });
|
|
998
|
+
attrInstance.freeze();
|
|
999
|
+
attrInstance.setA(2);
|
|
1000
|
+
attrInstance.getA().shouldEqual(1);
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
|
|
1004
|
+
"has an unfreeze method that": {
|
|
1005
|
+
"sets frozen to false": function() {
|
|
1006
|
+
var attrInstance = new this.attr({ a: 1 });
|
|
1007
|
+
attrInstance.freeze();
|
|
1008
|
+
attrInstance.unfreeze();
|
|
1009
|
+
attrInstance.frozen().shouldBeFalse();
|
|
1010
|
+
},
|
|
1011
|
+
|
|
1012
|
+
"makes all attrAccessor set methods no-ops": function() {
|
|
1013
|
+
var attrInstance = new this.attr({ a: 1 });
|
|
1014
|
+
attrInstance.freeze();
|
|
1015
|
+
attrInstance.unfreeze();
|
|
1016
|
+
attrInstance.setA(2);
|
|
1017
|
+
attrInstance.getA().shouldEqual(2);
|
|
1018
|
+
}
|
|
1019
|
+
},
|
|
1020
|
+
|
|
1021
|
+
"supports an invert method on bindings that": {
|
|
1022
|
+
"should have value true for underlying false": function() {
|
|
1023
|
+
new this.attr({ a: false }).a.invert().value().shouldEqual(true);
|
|
1024
|
+
},
|
|
1025
|
+
|
|
1026
|
+
"should have value false for underlying true": function() {
|
|
1027
|
+
new this.attr({ a: true }).a.invert().value().shouldEqual(false);
|
|
1028
|
+
},
|
|
1029
|
+
|
|
1030
|
+
"should have value true for underlying falsy values": function() {
|
|
1031
|
+
new this.attr({ a: 0 }).a.invert().value().shouldEqual(true);
|
|
1032
|
+
new this.attr({ a: "" }).a.invert().value().shouldEqual(true);
|
|
1033
|
+
new this.attr({ a: null }).a.invert().value().shouldEqual(true);
|
|
1034
|
+
},
|
|
1035
|
+
|
|
1036
|
+
"should have value false for underlying truthy values": function() {
|
|
1037
|
+
new this.attr({ a: 1 }).a.invert().value().shouldEqual(false);
|
|
1038
|
+
new this.attr({ a: "asdf" }).a.invert().value().shouldEqual(false);
|
|
1039
|
+
new this.attr({ a: [1] }).a.invert().value().shouldEqual(false);
|
|
1040
|
+
},
|
|
1041
|
+
|
|
1042
|
+
"should have value true for underlying undefined": function() {
|
|
1043
|
+
new this.attr().a.invert().value().shouldEqual(true);
|
|
1044
|
+
},
|
|
1045
|
+
|
|
1046
|
+
"should update the underlying value to false for true": function() {
|
|
1047
|
+
var attrInstance = new this.attr();
|
|
1048
|
+
attrInstance.a.invert().update(true);
|
|
1049
|
+
attrInstance.getA().shouldEqual(false);
|
|
1050
|
+
},
|
|
1051
|
+
|
|
1052
|
+
"should update the underlying value to true for false": function() {
|
|
1053
|
+
var attrInstance = new this.attr();
|
|
1054
|
+
attrInstance.a.invert().update(false);
|
|
1055
|
+
attrInstance.getA().shouldEqual(true);
|
|
1056
|
+
},
|
|
1057
|
+
|
|
1058
|
+
"should update the underlying value to false for truthy values": function() {
|
|
1059
|
+
var attrInstance = new this.attr();
|
|
1060
|
+
attrInstance.a.invert().update(1);
|
|
1061
|
+
attrInstance.getA().shouldEqual(false);
|
|
1062
|
+
attrInstance.a.invert().update("asdf");
|
|
1063
|
+
attrInstance.getA().shouldEqual(false);
|
|
1064
|
+
attrInstance.a.invert().update([1]);
|
|
1065
|
+
attrInstance.getA().shouldEqual(false);
|
|
1066
|
+
},
|
|
1067
|
+
|
|
1068
|
+
"should update the underlying value to true for falsy values": function() {
|
|
1069
|
+
var attrInstance = new this.attr();
|
|
1070
|
+
attrInstance.a.invert().update(0);
|
|
1071
|
+
attrInstance.getA().shouldEqual(true);
|
|
1072
|
+
attrInstance.a.invert().update("");
|
|
1073
|
+
attrInstance.getA().shouldEqual(true);
|
|
1074
|
+
attrInstance.a.invert().update(null);
|
|
1075
|
+
attrInstance.getA().shouldEqual(true);
|
|
1076
|
+
},
|
|
1077
|
+
|
|
1078
|
+
"should update the underlying value to true for undefined": function() {
|
|
1079
|
+
var attrInstance = new this.attr();
|
|
1080
|
+
attrInstance.a.invert().update();
|
|
1081
|
+
attrInstance.getA().shouldEqual(true);
|
|
1082
|
+
},
|
|
1083
|
+
|
|
1084
|
+
"should honor true for skipInitialExecution flag on bind": function() {
|
|
1085
|
+
new this.attr().a.invert().bind(function() {}.shouldNotBeCalled(), true);
|
|
1086
|
+
},
|
|
1087
|
+
|
|
1088
|
+
"should honor false for skipInitialExecution flag on bind": function() {
|
|
1089
|
+
new this.attr().a.invert().bind(function() {}.shouldBeCalled(), false);
|
|
1090
|
+
},
|
|
1091
|
+
|
|
1092
|
+
"should honor a default of false for skipInitialExecution flag on bind": function() {
|
|
1093
|
+
new this.attr().a.invert().bind(function() {}.shouldBeCalled());
|
|
1094
|
+
},
|
|
1095
|
+
|
|
1096
|
+
"should invert true to false for observers on bind": function() {
|
|
1097
|
+
new this.attr({ a: true }).a.invert().bind(function(a) { a.shouldEqual(false); }.shouldBeCalled());
|
|
1098
|
+
},
|
|
1099
|
+
|
|
1100
|
+
"should invert false to true for observers on bind": function() {
|
|
1101
|
+
new this.attr({ a: false }).a.invert().bind(function(a) { a.shouldEqual(true); }.shouldBeCalled());
|
|
1102
|
+
},
|
|
1103
|
+
|
|
1104
|
+
"should invert truthy values to false for observers on bind": function() {
|
|
1105
|
+
new this.attr({ a: 1 }).a.invert().bind(function(a) { a.shouldEqual(false); }.shouldBeCalled());
|
|
1106
|
+
new this.attr({ a: "asdf" }).a.invert().bind(function(a) { a.shouldEqual(false); }.shouldBeCalled());
|
|
1107
|
+
new this.attr({ a: [1] }).a.invert().bind(function(a) { a.shouldEqual(false); }.shouldBeCalled());
|
|
1108
|
+
},
|
|
1109
|
+
|
|
1110
|
+
"should invert falsy values to true for observers on bind": function() {
|
|
1111
|
+
new this.attr({ a: 0 }).a.invert().bind(function(a) { a.shouldEqual(true); }.shouldBeCalled());
|
|
1112
|
+
new this.attr({ a: "" }).a.invert().bind(function(a) { a.shouldEqual(true); }.shouldBeCalled());
|
|
1113
|
+
new this.attr({ a: null }).a.invert().bind(function(a) { a.shouldEqual(true); }.shouldBeCalled());
|
|
1114
|
+
},
|
|
1115
|
+
|
|
1116
|
+
"should invert undefined to true for observers on bind": function() {
|
|
1117
|
+
new this.attr().a.invert().bind(function(a) { a.shouldEqual(true); }.shouldBeCalled());
|
|
1118
|
+
},
|
|
1119
|
+
|
|
1120
|
+
"should return an unbinding function from bind": function() {
|
|
1121
|
+
var attrInstance = new this.attr();
|
|
1122
|
+
var unbinding = attrInstance.a.invert().bind(function() {}.shouldNotBeCalled(), true);
|
|
1123
|
+
unbinding();
|
|
1124
|
+
attrInstance.setA(1);
|
|
1125
|
+
},
|
|
1126
|
+
|
|
1127
|
+
"should update a second attribute with true for undelying false on bindTo": function() {
|
|
1128
|
+
var attrInstance = new this.attr({ a: false });
|
|
1129
|
+
var otherAttrInstance = new this.attr();
|
|
1130
|
+
|
|
1131
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1132
|
+
|
|
1133
|
+
otherAttrInstance.getA().shouldEqual(true);
|
|
1134
|
+
},
|
|
1135
|
+
|
|
1136
|
+
"should update a second attribute with false for undelying true on bindTo": function() {
|
|
1137
|
+
var attrInstance = new this.attr({ a: true });
|
|
1138
|
+
var otherAttrInstance = new this.attr();
|
|
1139
|
+
|
|
1140
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1141
|
+
|
|
1142
|
+
otherAttrInstance.getA().shouldEqual(false);
|
|
1143
|
+
},
|
|
1144
|
+
|
|
1145
|
+
"should update a second attribute with true for undelying falsy on bindTo": function() {
|
|
1146
|
+
var attrInstance = new this.attr({ a: 0 });
|
|
1147
|
+
var otherAttrInstance = new this.attr();
|
|
1148
|
+
|
|
1149
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1150
|
+
|
|
1151
|
+
otherAttrInstance.getA().shouldEqual(true);
|
|
1152
|
+
},
|
|
1153
|
+
|
|
1154
|
+
"should update a second attribute with false for undelying truthy on bindTo": function() {
|
|
1155
|
+
var attrInstance = new this.attr({ a: 1 });
|
|
1156
|
+
var otherAttrInstance = new this.attr();
|
|
1157
|
+
|
|
1158
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1159
|
+
|
|
1160
|
+
otherAttrInstance.getA().shouldEqual(false);
|
|
1161
|
+
},
|
|
1162
|
+
|
|
1163
|
+
"should update a second attribute with true for undelying undefined on bindTo": function() {
|
|
1164
|
+
var attrInstance = new this.attr();
|
|
1165
|
+
var otherAttrInstance = new this.attr();
|
|
1166
|
+
|
|
1167
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1168
|
+
|
|
1169
|
+
otherAttrInstance.getA().shouldEqual(true);
|
|
1170
|
+
},
|
|
1171
|
+
|
|
1172
|
+
"should update itself with true from a second attribute with false on bindTo": function() {
|
|
1173
|
+
var attrInstance = new this.attr();
|
|
1174
|
+
var otherAttrInstance = new this.attr();
|
|
1175
|
+
|
|
1176
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1177
|
+
|
|
1178
|
+
otherAttrInstance.setA(false);
|
|
1179
|
+
attrInstance.getA().shouldEqual(true);
|
|
1180
|
+
},
|
|
1181
|
+
|
|
1182
|
+
"should update itself with false from a second attribute with true on bindTo": function() {
|
|
1183
|
+
var attrInstance = new this.attr();
|
|
1184
|
+
var otherAttrInstance = new this.attr();
|
|
1185
|
+
|
|
1186
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1187
|
+
|
|
1188
|
+
otherAttrInstance.setA(true);
|
|
1189
|
+
attrInstance.getA().shouldEqual(false);
|
|
1190
|
+
},
|
|
1191
|
+
|
|
1192
|
+
"should update itself with true from a second attribute with falsy on bindTo": function() {
|
|
1193
|
+
var attrInstance = new this.attr();
|
|
1194
|
+
var otherAttrInstance = new this.attr();
|
|
1195
|
+
|
|
1196
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1197
|
+
|
|
1198
|
+
otherAttrInstance.setA(0);
|
|
1199
|
+
attrInstance.getA().shouldEqual(true);
|
|
1200
|
+
},
|
|
1201
|
+
|
|
1202
|
+
"should update itself with false from a second attribute with truthy on bindTo": function() {
|
|
1203
|
+
var attrInstance = new this.attr();
|
|
1204
|
+
var otherAttrInstance = new this.attr();
|
|
1205
|
+
|
|
1206
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1207
|
+
|
|
1208
|
+
otherAttrInstance.setA(1);
|
|
1209
|
+
attrInstance.getA().shouldEqual(false);
|
|
1210
|
+
},
|
|
1211
|
+
|
|
1212
|
+
"should update itself with true from a second attribute with undefined on bindTo": function() {
|
|
1213
|
+
var attrInstance = new this.attr();
|
|
1214
|
+
var otherAttrInstance = new this.attr();
|
|
1215
|
+
|
|
1216
|
+
attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1217
|
+
|
|
1218
|
+
otherAttrInstance.setA();
|
|
1219
|
+
attrInstance.getA().shouldEqual(true);
|
|
1220
|
+
},
|
|
1221
|
+
|
|
1222
|
+
"should return an unbinding function from bindTo": function() {
|
|
1223
|
+
var attrInstance = new this.attr();
|
|
1224
|
+
var otherAttrInstance = new this.attr();
|
|
1225
|
+
|
|
1226
|
+
var unbinding = attrInstance.a.invert().bindTo(otherAttrInstance.a);
|
|
1227
|
+
|
|
1228
|
+
unbinding();
|
|
1229
|
+
|
|
1230
|
+
attrInstance.setA(3);
|
|
1231
|
+
otherAttrInstance.setA(false);
|
|
1232
|
+
attrInstance.getA().shouldEqual(3);
|
|
1233
|
+
|
|
1234
|
+
otherAttrInstance.setA(3);
|
|
1235
|
+
attrInstance.setA(true);
|
|
1236
|
+
otherAttrInstance.getA().shouldEqual(3);
|
|
1237
|
+
},
|
|
1238
|
+
|
|
1239
|
+
"should has attribute BINDING true": function() {
|
|
1240
|
+
new this.attr().a.invert().BINDING.shouldBeTrue();
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
},
|
|
1245
|
+
|
|
1246
|
+
"with two bindable attributes": {
|
|
1247
|
+
beforeEach: function() {
|
|
1248
|
+
this.attr = rio.Attr.create({ attrAccessors: ["a", "helloWorld"] });
|
|
1249
|
+
},
|
|
1250
|
+
|
|
1251
|
+
"should allow multiple attributes to be updated with updateAttributes": function() {
|
|
1252
|
+
var attrInstance = new this.attr({ a: 1, helloWorld: 2 });
|
|
1253
|
+
attrInstance.updateAttributes({ a: 3, helloWorld: 4 });
|
|
1254
|
+
attrInstance.getA().shouldEqual(3);
|
|
1255
|
+
attrInstance.getHelloWorld().shouldEqual(4);
|
|
1256
|
+
},
|
|
1257
|
+
|
|
1258
|
+
"should update all attributes before firing bindings on updateAttributes": function() {
|
|
1259
|
+
var attrInstance = new this.attr({ a: 1, helloWorld: 2 });
|
|
1260
|
+
var f = function() {
|
|
1261
|
+
attrInstance.getA().shouldEqual(3);
|
|
1262
|
+
attrInstance.getHelloWorld().shouldEqual(4);
|
|
1263
|
+
}.shouldBeCalled().times(2);
|
|
1264
|
+
attrInstance.a.bind(f, true);
|
|
1265
|
+
attrInstance.helloWorld.bind(f, true);
|
|
1266
|
+
attrInstance.updateAttributes({ a: 3, helloWorld: 4 });
|
|
1267
|
+
},
|
|
1268
|
+
|
|
1269
|
+
"should update all attributes of multiple Attr instances on Attr#updateAttributes": function() {
|
|
1270
|
+
var attrInstance1 = new this.attr({ a: 1, helloWorld: 2 });
|
|
1271
|
+
var attrInstance2 = new this.attr({ a: 3, helloWorld: 4 });
|
|
1272
|
+
rio.Attr.updateAttributes([
|
|
1273
|
+
{ object: attrInstance1, attributes: { a: 5, helloWorld: 6 } },
|
|
1274
|
+
{ object: attrInstance2, attributes: { a: 7, helloWorld: 8 } }
|
|
1275
|
+
]);
|
|
1276
|
+
attrInstance1.getA().shouldEqual(5);
|
|
1277
|
+
attrInstance1.getHelloWorld().shouldEqual(6);
|
|
1278
|
+
attrInstance2.getA().shouldEqual(7);
|
|
1279
|
+
attrInstance2.getHelloWorld().shouldEqual(8);
|
|
1280
|
+
},
|
|
1281
|
+
|
|
1282
|
+
"should update all attributes of multiple Attr instances before firing bindings on Attr#updateAttributes": function() {
|
|
1283
|
+
var attrInstance1 = new this.attr({ a: 1, helloWorld: 2 });
|
|
1284
|
+
var attrInstance2 = new this.attr({ a: 3, helloWorld: 4 });
|
|
1285
|
+
var f = function() {
|
|
1286
|
+
attrInstance1.getA().shouldEqual(5);
|
|
1287
|
+
attrInstance1.getHelloWorld().shouldEqual(6);
|
|
1288
|
+
attrInstance2.getA().shouldEqual(7);
|
|
1289
|
+
attrInstance2.getHelloWorld().shouldEqual(8);
|
|
1290
|
+
}.shouldBeCalled().times(4);
|
|
1291
|
+
attrInstance1.a.bind(f, true);
|
|
1292
|
+
attrInstance1.helloWorld.bind(f, true);
|
|
1293
|
+
attrInstance2.a.bind(f, true);
|
|
1294
|
+
attrInstance2.helloWorld.bind(f, true);
|
|
1295
|
+
rio.Attr.updateAttributes([
|
|
1296
|
+
{ object: attrInstance1, attributes: { a: 5, helloWorld: 6 } },
|
|
1297
|
+
{ object: attrInstance2, attributes: { a: 7, helloWorld: 8 } }
|
|
1298
|
+
]);
|
|
1299
|
+
}
|
|
1300
|
+
},
|
|
1301
|
+
|
|
1302
|
+
/* END BINDING RELATED SPECS */
|
|
1303
|
+
|
|
1304
|
+
"with a declared event called poof": {
|
|
1305
|
+
beforeEach: function() {
|
|
1306
|
+
this.attr = rio.Attr.create({ attrEvents: ["poof"] });
|
|
1307
|
+
this.attrInstance = new this.attr();
|
|
1308
|
+
},
|
|
1309
|
+
|
|
1310
|
+
"should observe and fire the event": function() {
|
|
1311
|
+
this.attrInstance.observe("poof", function() {}.shouldBeCalled());
|
|
1312
|
+
this.attrInstance.fire("poof");
|
|
1313
|
+
},
|
|
1314
|
+
|
|
1315
|
+
"should support stop observing functionality": function() {
|
|
1316
|
+
var f = function() {}.shouldNotBeCalled();
|
|
1317
|
+
this.attrInstance.observe("poof", f);
|
|
1318
|
+
this.attrInstance.stopObserving("poof", f);
|
|
1319
|
+
this.attrInstance.fire("poof");
|
|
1320
|
+
},
|
|
1321
|
+
|
|
1322
|
+
"should return a stop observing function on observing an event": function() {
|
|
1323
|
+
var f = function() {}.shouldBeCalled().once();
|
|
1324
|
+
var stopObserving = this.attrInstance.observe("poof", f);
|
|
1325
|
+
this.attrInstance.fire("poof");
|
|
1326
|
+
stopObserving();
|
|
1327
|
+
this.attrInstance.fire("poof");
|
|
1328
|
+
},
|
|
1329
|
+
|
|
1330
|
+
"should pass on any parameters to the observers": function() {
|
|
1331
|
+
this.attrInstance.observe("poof", function(a,b,c) {
|
|
1332
|
+
a.shouldEqual(1);
|
|
1333
|
+
b.shouldEqual(2);
|
|
1334
|
+
c.shouldEqual(3);
|
|
1335
|
+
}.shouldBeCalled());
|
|
1336
|
+
this.attrInstance.fire("poof", 1, 2, 3);
|
|
1337
|
+
},
|
|
1338
|
+
|
|
1339
|
+
"should create an observer when initialized with an onPoof argument": function() {
|
|
1340
|
+
var attrInstance = new this.attr({
|
|
1341
|
+
onPoof: function(a) {
|
|
1342
|
+
a.shouldEqual(1);
|
|
1343
|
+
}.shouldBeCalled()
|
|
1344
|
+
});
|
|
1345
|
+
attrInstance.fire("poof", 1);
|
|
1346
|
+
}
|
|
1347
|
+
},
|
|
1348
|
+
|
|
1349
|
+
"should set the attr NAME property": function() {
|
|
1350
|
+
var attr = rio.Attr.create("SomeAttr");
|
|
1351
|
+
|
|
1352
|
+
attr.NAME.shouldEqual("SomeAttr");
|
|
1353
|
+
},
|
|
1354
|
+
|
|
1355
|
+
"should return NAME from toString": function() {
|
|
1356
|
+
var attr = rio.Attr.create("SomeAttr");
|
|
1357
|
+
|
|
1358
|
+
attr.toString().shouldEqual("SomeAttr");
|
|
1359
|
+
},
|
|
1360
|
+
|
|
1361
|
+
"inheritance": {
|
|
1362
|
+
"on initialize": {
|
|
1363
|
+
"should call the initialize method of the super class if the subclass has no initialize method": function() {
|
|
1364
|
+
var SuperAttr = rio.Attr.create("Super", {
|
|
1365
|
+
methods: {
|
|
1366
|
+
initialize: function() {}.shouldBeCalled()
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
|
|
1370
|
+
var SubAttr = rio.Attr.create(SuperAttr, "Sub");
|
|
1371
|
+
new SubAttr();
|
|
1372
|
+
},
|
|
1373
|
+
|
|
1374
|
+
"should pass in $super and options if both super and sub classes provide initializers": function() {
|
|
1375
|
+
var SuperAttr = rio.Attr.create("Super", {
|
|
1376
|
+
methods: {
|
|
1377
|
+
initialize: function(options) {
|
|
1378
|
+
options.hello.shouldEqual("world");
|
|
1379
|
+
options.foo.shouldEqual("bar");
|
|
1380
|
+
}.shouldBeCalled()
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1384
|
+
var SubAttr = rio.Attr.create(SuperAttr, "Sub", {
|
|
1385
|
+
methods: {
|
|
1386
|
+
initialize: function($super, options) {
|
|
1387
|
+
$super(Object.extend({
|
|
1388
|
+
foo: "bar"
|
|
1389
|
+
}, options));
|
|
1390
|
+
options.hello.shouldEqual("world");
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
new SubAttr({hello: "world"});
|
|
1395
|
+
},
|
|
1396
|
+
|
|
1397
|
+
"should handle 3 level heirarchy": function() {
|
|
1398
|
+
var SuperAttr = rio.Attr.create("Super", {
|
|
1399
|
+
methods: {
|
|
1400
|
+
initialize: function(options) {
|
|
1401
|
+
options.hello.shouldEqual("world");
|
|
1402
|
+
options.foo.shouldEqual("bar");
|
|
1403
|
+
options.bar.shouldEqual("baz");
|
|
1404
|
+
}.shouldBeCalled()
|
|
1405
|
+
}
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
var SubAttr = rio.Attr.create(SuperAttr, "Sub", {
|
|
1409
|
+
methods: {
|
|
1410
|
+
initialize: function($super, options) {
|
|
1411
|
+
$super(Object.extend({
|
|
1412
|
+
foo: "bar"
|
|
1413
|
+
}, options));
|
|
1414
|
+
options.hello.shouldEqual("world");
|
|
1415
|
+
options.bar.shouldEqual("baz");
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
var SubSubAttr = rio.Attr.create(SubAttr, "SubSub", {
|
|
1421
|
+
methods: {
|
|
1422
|
+
initialize: function($super, options) {
|
|
1423
|
+
$super(Object.extend({
|
|
1424
|
+
bar: "baz"
|
|
1425
|
+
}, options));
|
|
1426
|
+
options.hello.shouldEqual("world");
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
});
|
|
1430
|
+
new SubSubAttr({hello: "world"});
|
|
1431
|
+
},
|
|
1432
|
+
|
|
1433
|
+
"should handle 3 level heirarchy, where the middle level omits initialize": function() {
|
|
1434
|
+
var SuperAttr = rio.Attr.create("Super", {
|
|
1435
|
+
methods: {
|
|
1436
|
+
initialize: function(options) {
|
|
1437
|
+
options.hello.shouldEqual("world");
|
|
1438
|
+
options.bar.shouldEqual("baz");
|
|
1439
|
+
}.shouldBeCalled()
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
|
|
1443
|
+
var SubAttr = rio.Attr.create(SuperAttr, "Sub");
|
|
1444
|
+
|
|
1445
|
+
var SubSubAttr = rio.Attr.create(SubAttr, "SubSub", {
|
|
1446
|
+
methods: {
|
|
1447
|
+
initialize: function($super, options) {
|
|
1448
|
+
$super(Object.extend({
|
|
1449
|
+
bar: "baz"
|
|
1450
|
+
}, options));
|
|
1451
|
+
options.hello.shouldEqual("world");
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
new SubSubAttr({hello: "world"});
|
|
1456
|
+
}
|
|
1457
|
+
},
|
|
1458
|
+
|
|
1459
|
+
beforeEach: function() {
|
|
1460
|
+
var SuperAttr = rio.Attr.create("Super", {
|
|
1461
|
+
attrAccessors: ["a", ["hello", "super"]],
|
|
1462
|
+
attrHtmls: ["super"],
|
|
1463
|
+
methods: { buildSuperHtml: function() { return "foo"; } }
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
var SubAttr = rio.Attr.create(SuperAttr, "Sub", {
|
|
1467
|
+
attrAccessors: ["b"],
|
|
1468
|
+
attrHtmls: ["sub"],
|
|
1469
|
+
methods: { buildSubHtml: function() { return "bar"; } }
|
|
1470
|
+
});
|
|
1471
|
+
|
|
1472
|
+
var SubSubAttr = rio.Attr.create(SubAttr, "SubSub", {
|
|
1473
|
+
attrAccessors: ["c", ["hello", "subsub"]],
|
|
1474
|
+
attrHtmls: ["subSub"],
|
|
1475
|
+
methods: { buildSubSubHtml: function() { return "baz"; } }
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
this.attr = new SubSubAttr({ a: 1, b: 2, c: 3 });
|
|
1479
|
+
this.superAttr = new SuperAttr();
|
|
1480
|
+
},
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
"should inherit the attributes of its parent": function() {
|
|
1484
|
+
this.attr.getB().shouldEqual(2);
|
|
1485
|
+
this.attr.getC().shouldEqual(3);
|
|
1486
|
+
},
|
|
1487
|
+
|
|
1488
|
+
"should inherit the attributes of its grandparent": function() {
|
|
1489
|
+
this.attr.getA().shouldEqual(1);
|
|
1490
|
+
this.attr.getB().shouldEqual(2);
|
|
1491
|
+
this.attr.getC().shouldEqual(3);
|
|
1492
|
+
},
|
|
1493
|
+
|
|
1494
|
+
"should inherit the attrHtmls of it's parent": function() {
|
|
1495
|
+
this.attr.superHtml().shouldEqual("foo");
|
|
1496
|
+
this.attr.subHtml().shouldEqual("bar");
|
|
1497
|
+
},
|
|
1498
|
+
|
|
1499
|
+
"should inherit the attrHtmls of it's grandparent": function() {
|
|
1500
|
+
this.attr.superHtml().shouldEqual("foo");
|
|
1501
|
+
this.attr.subHtml().shouldEqual("bar");
|
|
1502
|
+
this.attr.subSubHtml().shouldEqual("baz");
|
|
1503
|
+
},
|
|
1504
|
+
|
|
1505
|
+
"should use it's own default value for an attribute if defined": function() {
|
|
1506
|
+
this.attr.getHello().shouldEqual("subsub");
|
|
1507
|
+
},
|
|
1508
|
+
|
|
1509
|
+
"should not override default value for instances of superclasses": function() {
|
|
1510
|
+
this.superAttr.getHello().shouldEqual("super");
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
}
|
|
1514
|
+
});
|