Skip to content
Browse files

Merge branch 'postback'

  • Loading branch information...
2 parents e7070ba + 205887c commit b460b3f505550aaeb7d5c12b6d3b134d26465831 @wagenet wagenet committed
Showing with 4,299 additions and 774 deletions.
  1. +5 −1 Buildfile
  2. +12 −0 apps/test_controls/controllers/select.js
  3. +19 −5 apps/test_controls/resources/select_page.js
  4. +28 −27 frameworks/ajax/system/request.js
  5. +7 −0 frameworks/ajax/system/response.js
  6. +1 −1 frameworks/core_foundation/mixins/responder_context.js
  7. +2 −0 frameworks/core_foundation/panes/keyboard.js
  8. +11 −3 frameworks/core_foundation/panes/pane.js
  9. +80 −0 frameworks/core_foundation/resources/base.css
  10. +39 −0 frameworks/core_foundation/resources/fonts.css
  11. +126 −0 frameworks/core_foundation/resources/reset.css
  12. +157 −5 frameworks/core_foundation/system/locale.js
  13. +5 −5 frameworks/core_foundation/system/render_context.js
  14. +9 −3 frameworks/core_foundation/system/root_responder.js
  15. +100 −0 frameworks/core_foundation/system/string.js
  16. +3 −56 frameworks/core_foundation/system/theme.js
  17. +41 −1 frameworks/core_foundation/tests/mixins/string.js
  18. +10 −6 frameworks/core_foundation/tests/views/view/insertBefore.js
  19. +18 −1 frameworks/core_foundation/tests/views/view/keyboard.js
  20. +7 −2 frameworks/core_foundation/views/view.js
  21. +15 −3 frameworks/core_foundation/views/view/keyboard.js
  22. +8 −18 frameworks/core_foundation/views/view/theming.js
  23. +1 −1 frameworks/datastore/system/nested_store.js
  24. +1 −0 frameworks/desktop/panes/alert.js
  25. +18 −1 frameworks/desktop/panes/menu.js
  26. +9 −0 frameworks/desktop/panes/panel.js
  27. +1 −1 frameworks/desktop/render_delegates/button.js
  28. +1 −1 frameworks/desktop/render_delegates/checkbox.js
  29. +1 −1 frameworks/desktop/render_delegates/collection.js
  30. +1 −1 frameworks/desktop/render_delegates/disclosure.js
  31. +1 −1 frameworks/desktop/render_delegates/image_button.js
  32. +3 −2 frameworks/desktop/render_delegates/master_detail.js
  33. +12 −2 frameworks/desktop/render_delegates/menu.js
  34. +1 −1 frameworks/desktop/render_delegates/panel.js
  35. +1 −1 frameworks/desktop/render_delegates/picker.js
  36. +1 −1 frameworks/desktop/render_delegates/progress.js
  37. +1 −1 frameworks/desktop/render_delegates/radio.js
  38. +2 −2 frameworks/desktop/render_delegates/radio_group.js
  39. +1 −1 frameworks/desktop/render_delegates/segment.js
  40. +1 −1 frameworks/desktop/render_delegates/segmented.js
  41. +1 −1 frameworks/desktop/render_delegates/slider.js
  42. +1 −1 frameworks/desktop/render_delegates/toolbar.js
  43. +1 −1 frameworks/desktop/render_delegates/well.js
  44. +1 −1 frameworks/desktop/render_delegates/workspace.js
  45. +1 −0 frameworks/desktop/resources/segmented.css
  46. +20 −1 frameworks/desktop/tests/panes/panel/methods.js
  47. +10 −3 frameworks/desktop/tests/views/checkbox/methods.js
  48. +34 −7 frameworks/desktop/tests/views/date_field/methods.js
  49. +14 −15 frameworks/desktop/views/button.js
  50. +40 −14 frameworks/desktop/views/checkbox.js
  51. +2 −2 frameworks/desktop/views/list_item.js
  52. +11 −1 frameworks/desktop/views/master_detail.js
  53. +16 −6 frameworks/desktop/views/menu_item.js
  54. +49 −7 frameworks/desktop/views/radio.js
  55. +4 −1 frameworks/desktop/views/select_field.js
  56. +4 −26 frameworks/desktop/views/slider.js
  57. +20 −19 frameworks/desktop/views/web.js
  58. +0 −5 frameworks/experimental/frameworks/forms/english.lproj/default_styles.css
  59. +0 −15 frameworks/experimental/frameworks/forms/english.lproj/strings.js
  60. +13 −5 frameworks/experimental/frameworks/forms/mixins/edit_mode.js
  61. +53 −37 frameworks/experimental/frameworks/forms/mixins/emptiness.js
  62. +2 −1 frameworks/experimental/frameworks/forms/render_delegates/form.js
  63. +3 −11 frameworks/experimental/frameworks/forms/render_delegates/form_row.js
  64. +53 −0 frameworks/experimental/frameworks/forms/tests/mixins/edit_mode.js
  65. +114 −0 frameworks/experimental/frameworks/forms/tests/mixins/emptiness.js
  66. +174 −6 frameworks/experimental/frameworks/forms/tests/views/form.js
  67. +0 −17 frameworks/experimental/frameworks/forms/tests/views/form_checkbox_field.js
  68. +0 −17 frameworks/experimental/frameworks/forms/tests/views/form_field.js
  69. +0 −17 frameworks/experimental/frameworks/forms/tests/views/form_label.js
  70. +0 −17 frameworks/experimental/frameworks/forms/tests/views/form_radio_field.js
  71. +86 −6 frameworks/experimental/frameworks/forms/tests/views/form_row.js
  72. +0 −17 frameworks/experimental/frameworks/forms/tests/views/form_text_field.js
  73. +80 −110 frameworks/experimental/frameworks/forms/views/form.js
  74. +96 −97 frameworks/experimental/frameworks/forms/views/form_row.js
  75. +121 −0 frameworks/experimental/frameworks/select_view/ext/menu.js
  76. +90 −0 frameworks/experimental/frameworks/select_view/ext/menu_item.js
  77. +139 −0 frameworks/experimental/frameworks/select_view/mixins/select_view_menu.js
  78. +14 −0 frameworks/experimental/frameworks/select_view/render_delegates/select_button.js
  79. +25 −0 frameworks/experimental/frameworks/select_view/tests/ext/menu_resizing.js
  80. +43 −0 frameworks/experimental/frameworks/select_view/tests/mixins/select_view_menu/bindings.js
  81. +32 −0 frameworks/experimental/frameworks/select_view/tests/mixins/select_view_menu/check_selected.js
  82. +40 −0 frameworks/experimental/frameworks/select_view/tests/views/popup_button/menu_setup.js
  83. +45 −0 frameworks/experimental/frameworks/select_view/tests/views/popup_button/show_menu.js
  84. +49 −0 frameworks/experimental/frameworks/select_view/tests/views/select/menu_width.js
  85. +191 −0 frameworks/experimental/frameworks/select_view/tests/views/select/selected_item.js
  86. +264 −0 frameworks/experimental/frameworks/select_view/views/popup_button.js
  87. +450 −0 frameworks/experimental/frameworks/select_view/views/select.js
  88. +13 −5 frameworks/experimental/frameworks/split_view/mixins/split_child.js
  89. +1 −1 frameworks/experimental/frameworks/split_view/render_delegates/split.js
  90. +1 −1 frameworks/experimental/frameworks/split_view/render_delegates/split_divider.js
  91. +9 −0 frameworks/experimental/frameworks/split_view/views/split.js
  92. +7 −17 frameworks/foundation/mixins/auto_resize.js
  93. +35 −8 frameworks/foundation/mixins/flowed_layout.js
  94. +1 −1 frameworks/foundation/render_delegates/canvas_image.js
  95. +1 −1 frameworks/foundation/render_delegates/image.js
  96. +1 −1 frameworks/foundation/render_delegates/label.js
  97. +6 −6 frameworks/foundation/render_delegates/render_delegate.js
  98. BIN frameworks/foundation/resources/images/favicon.ico
  99. +0 −2 frameworks/foundation/resources/text_field.css
  100. +4 −2 frameworks/foundation/system/exception_handler.js
  101. +13 −0 frameworks/foundation/system/module.js
  102. +6 −9 frameworks/foundation/system/utils/string_measurement.js
  103. +912 −0 frameworks/foundation/tests/mixins/flowed_layout/tests.js
  104. +0 −15 frameworks/foundation/views/field.js
  105. +1 −1 frameworks/foundation/views/text_field.js
  106. +1 −1 frameworks/handlebars/handlebars.js
  107. +13 −7 frameworks/runtime/core.js
  108. +3 −2 frameworks/runtime/mixins/copyable.js
  109. +14 −14 frameworks/runtime/system/binding.js
  110. +3 −0 frameworks/runtime/system/error.js
  111. +1 −1 frameworks/runtime/system/logger.js
  112. +3 −3 frameworks/runtime/system/run_loop.js
  113. +15 −16 frameworks/runtime/system/set.js
  114. +6 −2 frameworks/runtime/tests/core/itemType.js
  115. +30 −0 frameworks/runtime/tests/system/object/enhance.js
  116. +4 −0 frameworks/statechart/system/state.js
  117. +2 −0 frameworks/statechart/system/statechart.js
  118. +0 −1 frameworks/testing/resources/runner.css
  119. +0 −4 frameworks/yuireset/resources/core.css
  120. +2 −1 lib/index.rhtml
  121. +3 −3 themes/ace/resources/collection/normal/list.css
  122. +2 −2 themes/ace/resources/collection/normal/list_item.css
  123. +9 −0 themes/ace/resources/form/form.css
  124. +3 −1 themes/ace/resources/menu/menu.css
  125. +1 −1 themes/ace/resources/picker/popover/picker.js
  126. +1 −1 themes/ace/resources/picker/popover/workspace.js
  127. +1 −1 themes/legacy_theme/render_delegates/button.js
  128. +1 −1 themes/legacy_theme/render_delegates/panel.js
  129. +2 −0 themes/legacy_theme/render_delegates/progress.js
  130. +1 −1 themes/legacy_theme/render_delegates/slider.js
  131. +1 −1 themes/legacy_theme/render_delegates/well.js
View
6 Buildfile
@@ -86,7 +86,11 @@ config :ace,
# CONFIGURE APPS
config :core_tools, :required => [
:desktop, :datastore, :animation, "sproutcore/experimental/forms",
- "sproutcore/ace", "sproutcore/experimental/split_view"
+ "sproutcore/ace",
+
+ # The SC apps will use the experimental version of these controls:
+ "sproutcore/experimental/select_view",
+ "sproutcore/experimental/split_view"
]
# mode :debug do
View
12 apps/test_controls/controllers/select.js
@@ -0,0 +1,12 @@
+// ==========================================================================
+// Project: SproutCore - JavaScript Application Framework
+// Copyright: ©2006-2011 Strobe Inc. and contributors.
+// Portions ©2008-2011 Apple Inc. All rights reserved.
+// License: Licensed under MIT license (see license.js)
+// ==========================================================================
+/*globals TestControls */
+
+TestControls.buttonsController = SC.Controller.create({
+ selectedValue: 'printer:a'
+});
+
View
24 apps/test_controls/resources/select_page.js
@@ -11,7 +11,7 @@ TestControls.selectPage = SC.View.design({
form: SC.FormView.design({
classNames: ["sample_controls"],
layout: { left: 20, top: 40, right: 20, bottom: 40 },
- childViews: "header normal disabled".w(),
+ childViews: "header normal strings disabled".w(),
// Plain Views
header: SC.LabelView.design({
@@ -27,16 +27,30 @@ TestControls.selectPage = SC.View.design({
{"name": "Printer A", "value": "printer:a"},
{"name": "Printer B", "value": "printer:b"},
{"name": "Printer C", "value": "printer:c"},
- {"separator": YES, name: "none" },
+
{"name": "Printer D", "value": "printer:d"},
{"name": "Printer E", "value": "printer:e"},
{"name": "Printer F", "value": "printer:f"},
+
+ {"separator": YES, name: "none" },
{"name": "MICR 1", "value": "printer:m1"},
- {"name": "MICR 2", "value": "printer:m2"}
+ {"name": "MICR 2", "value": "printer:m2"},
+
+ {"separator": YES, name: "Hi" },
+ {"name": "This name is Really Really Long, OK?", "value": "LONG" }
],
itemTitleKey: "name", itemValueKey: "value", itemSeparatorKey: "separator",
- value: null
+ value: 'printer:a',
+ valueBinding: 'TestControls.buttonsController.selectedValue'
})),
+
+ strings: SC.FormView.row(SC.SelectView.design({
+ layout: { width: 150, height: 24 },
+ items: ["printer:a", "printer:b", "printer:c", "printer:d", "printer:e", "printer:f", "printer:m1", "printer:m2", "LONG"],
+ value: 'printer:a',
+ valueBinding: 'TestControls.buttonsController.selectedValue'
+ })),
+
disabled: SC.FormView.row(SC.SelectView.design({
layout: { width: 150, height: 24 },
@@ -58,4 +72,4 @@ TestControls.selectPage = SC.View.design({
value: null
}))
})
-});
+});
View
55 frameworks/ajax/system/request.js
@@ -64,6 +64,12 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
X-SproutCore-Version headers to all outgoing requests. This allows
you to override that behavior.
+ You may want to set this to NO if you are making simple CORS requests
+ in compatible browsers. See <a href="http://www.w3.org/TR/cors/">CORS
+ Spec for more informatinon.</a>
+
+ TODO: Add unit tests for this feature
+
@type Boolean
@default YES
*/
@@ -71,11 +77,6 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
init: function() {
sc_super();
-
- if (this.get('attachIdentifyingHeaders') !== NO) {
- this.header('X-Requested-With', 'XMLHttpRequest');
- this.header('X-SproutCore-Version', SC.VERSION);
- }
},
/**
@@ -354,15 +355,19 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
if (flag) { this.set('isJSON', NO); }
return this.set('isXML', flag);
},
-
- /**
- @private
-
- Called just before a request is enqueued. This will encode the body
- into JSON if it is not already encoded.
+
+ /**
+ Called just before a request is enqueued. This will encode the body
+ into JSON if it is not already encoded, and set identifying headers
*/
_prep: function() {
var hasContentType = !!this.header('Content-Type');
+
+ if(this.get('attachIdentifyingHeaders')) {
+ this.header('X-Requested-With', 'XMLHttpRequest');
+ this.header('X-SproutCore-Version', SC.VERSION);
+ }
+
if (this.get('isJSON') && !hasContentType) {
this.header('Content-Type', 'application/json');
} else if (this.get('isXML') && !hasContentType) {
@@ -469,11 +474,10 @@ SC.Request.mixin(
Helper method for quickly setting up a GET request.
@param {String} address url of request
- @param {Boolean} [attachHeaders] See documentation for SC.Request#attachIdentifyingHeaders
@returns {SC.Request} receiver
*/
- getUrl: function(address, attachHeaders) {
- return this.create({attachIdentifyingHeaders: attachHeaders}).set('address', address).set('type', 'GET');
+ getUrl: function(address) {
+ return this.create().set('address', address).set('type', 'GET');
},
/**
@@ -481,24 +485,22 @@ SC.Request.mixin(
@param {String} address url of request
@param {String} body
- @param {Boolean} [attachHeaders] See documentation for SC.Request#attachIdentifyingHeaders
@returns {SC.Request} receiver
*/
- postUrl: function(address, body, attachHeaders) {
- var req = this.create({attachIdentifyingHeaders: attachHeaders}).set('address', address).set('type', 'POST');
- if(body) { req.set('body', body); }
- return req;
+ postUrl: function(address, body) {
+ var req = this.create().set('address', address).set('type', 'POST');
+ if(body) { req.set('body', body) ; }
+ return req ;
},
/**
Helper method for quickly setting up a DELETE request.
@param {String} address url of request
- @param {Boolean} [attachHeaders] See documentation for SC.Request#attachIdentifyingHeaders
@returns {SC.Request} receiver
*/
- deleteUrl: function(address, attachHeaders) {
- return this.create({attachIdentifyingHeaders: attachHeaders}).set('address', address).set('type', 'DELETE');
+ deleteUrl: function(address) {
+ return this.create().set('address', address).set('type', 'DELETE');
},
/**
@@ -506,13 +508,12 @@ SC.Request.mixin(
@param {String} address url of request
@param {String} body
- @param {Boolean} [attachHeaders] See documentation for SC.Request#attachIdentifyingHeaders
@returns {SC.Request} receiver
*/
- putUrl: function(address, body, attachHeaders) {
- var req = this.create({attachIdentifyingHeaders: attachHeaders}).set('address', address).set('type', 'PUT');
- if(body) { req.set('body', body); }
- return req;
+ putUrl: function(address, body) {
+ var req = this.create().set('address', address).set('type', 'PUT');
+ if(body) { req.set('body', body) ; }
+ return req ;
}
});
View
7 frameworks/ajax/system/response.js
@@ -23,6 +23,13 @@ SC.Response = SC.Object.extend(
/** @scope SC.Response.prototype */ {
/**
+ Walk like a duck
+
+ @type Boolean
+ */
+ isResponse: YES,
+
+ /**
Becomes true if there was a failure. Makes this into an error object.
@type Boolean
View
2 frameworks/core_foundation/mixins/responder_context.js
@@ -167,7 +167,7 @@ SC.ResponderContext = {
if (responder) responder.set('isFirstResponder', YES);
this._notifyDidBecomeFirstResponder(responder, responder, common);
-
+
// now, tell everyone the good news!
this.endPropertyChanges();
View
2 frameworks/core_foundation/panes/keyboard.js
@@ -52,6 +52,8 @@ SC.Pane.reopen(
if (nextValidKeyView) {
this.makeFirstResponder(nextValidKeyView);
return YES;
+ }else if(!SC.TABBING_ONLY_INSIDE_DOCUMENT){
+ evt.allowDefault();
}
}
View
14 frameworks/core_foundation/panes/pane.js
@@ -260,7 +260,9 @@ SC.Pane = SC.View.extend(SC.ResponderContext,
// if we are currently key pane, then notify key views of change also
if (isKeyPane) {
if (current) { current.tryToPerform('willLoseKeyResponderTo', view); }
- if (view) { view.tryToPerform('willBecomeKeyResponderFrom', current); }
+ if (view) {
+ view.tryToPerform('willBecomeKeyResponderFrom', current);
+ }
}
if (current) {
@@ -280,8 +282,12 @@ SC.Pane = SC.View.extend(SC.ResponderContext,
// and notify again if needed.
if (isKeyPane) {
- if (view) { view.tryToPerform('didBecomeKeyResponderFrom', current); }
- if (current) { current.tryToPerform('didLoseKeyResponderTo', view); }
+ if (view) {
+ console.log(view.toString());
+ view.tryToPerform('didBecomeKeyResponderFrom', current); }
+ if (current) {
+ current.tryToPerform('didLoseKeyResponderTo', view);
+ }
}
return this ;
@@ -315,6 +321,8 @@ SC.Pane = SC.View.extend(SC.ResponderContext,
},
+ didBecomeKeyResponderFrom: function(responder) {},
+
/**
Called just after the pane has lost its keyPane status. Notifies the
current keyView of the change. The keyView can use this method to do any
View
80 frameworks/core_foundation/resources/base.css
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 3.3.0
+build: 3167
+*/
+/* base.css, part of YUI's CSS Foundation */
+h1 {
+ /*18px via YUI Fonts CSS foundation*/
+ font-size:138.5%;
+}
+h2 {
+ /*16px via YUI Fonts CSS foundation*/
+ font-size:123.1%;
+}
+h3 {
+ /*14px via YUI Fonts CSS foundation*/
+ font-size:108%;
+}
+h1,h2,h3 {
+ /* top & bottom margin based on font size */
+ margin:1em 0;
+}
+h1,h2,h3,h4,h5,h6,strong {
+ /*bringing boldness back to headers and the strong element*/
+ font-weight:bold;
+}
+abbr,acronym {
+ /*indicating to users that more info is available */
+ border-bottom:1px dotted #000;
+ cursor:help;
+}
+em {
+ /*bringing italics back to the em element*/
+ font-style:italic;
+}
+blockquote,ul,ol,dl {
+ /*giving blockquotes and lists room to breath*/
+ margin:1em;
+}
+ol,ul,dl {
+ /*bringing lists on to the page with breathing room */
+ margin-left:2em;
+}
+ol li {
+ /*giving OL's LIs generated numbers*/
+ list-style: decimal outside;
+}
+ul li {
+ /*giving UL's LIs generated disc markers*/
+ list-style: disc outside;
+}
+dl dd {
+ /*providing spacing for definition terms*/
+ margin-left:1em;
+}
+th,td {
+ /*borders and padding to make the table readable*/
+ border:1px solid #000;
+ padding:.5em;
+}
+th {
+ /*distinguishing table headers from data cells*/
+ font-weight:bold;
+ text-align:center;
+}
+caption {
+ /*coordinated margin to match cell's padding*/
+ margin-bottom:.5em;
+ /*centered so it doesn't blend in to other content*/
+ text-align:center;
+}
+p,fieldset,table,pre {
+ /*so things don't run into each other*/
+ margin-bottom:1em;
+}
+/* setting a consistent width, 160px;
+ control of type=file still not possible */
+input[type=text],input[type=password],textarea{width:12.25em;*width:11.9em;}
View
39 frameworks/core_foundation/resources/fonts.css
@@ -0,0 +1,39 @@
+/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 3.3.0
+build: 3167
+*/
+
+
+/**
+ * Nudge down to get to 13px equivalent for these form elements
+ */
+select,
+input,
+button,
+textarea {
+ font:99% arial,helvetica,clean,sans-serif;
+}
+
+/**
+ * To help tables remember to inherit
+ */
+table {
+ font-size:inherit;
+ font:100%;
+}
+
+/**
+ * Bump up IE to get to 13px equivalent for these fixed-width elements
+ */
+pre,
+code,
+kbd,
+samp,
+tt {
+ font-family:monospace;
+ *font-size:108%;
+ line-height:100%;
+}
View
126 frameworks/core_foundation/resources/reset.css
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 3.3.0
+build: 3167
+*/
+/*
+ TODO will need to remove settings on HTML since we can't namespace it.
+ TODO with the prefix, should I group by selector or property for weight savings?
+*/
+html{
+ color:#000;
+ background:#FFF;
+}
+/*
+ TODO remove settings on BODY since we can't namespace it.
+*/
+/*
+ TODO test putting a class on HEAD.
+ - Fails on FF.
+*/
+body,
+div,
+dl,
+dt,
+dd,
+ul,
+ol,
+li,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+pre,
+code,
+form,
+fieldset,
+legend,
+input,
+textarea,
+p,
+blockquote,
+th,
+td {
+ margin:0;
+ padding:0;
+}
+table {
+ border-collapse:collapse;
+ border-spacing:0;
+}
+fieldset,
+img {
+ border:0;
+}
+/*
+ TODO think about hanlding inheritence differently, maybe letting IE6 fail a bit...
+*/
+address,
+caption,
+cite,
+code,
+dfn,
+em,
+strong,
+th,
+var {
+ font-style:normal;
+ font-weight:normal;
+}
+/*
+ TODO Figure out where this list-style rule is best set. Hedger has a request to investigate.
+*/
+li {
+ list-style:none;
+}
+
+caption,
+th {
+ text-align:left;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size:100%;
+ font-weight:normal;
+}
+q:before,
+q:after {
+ content:'';
+}
+abbr,
+acronym {
+ border:0;
+ font-variant:normal;
+}
+/* to preserve line-height and selector appearance */
+sup {
+ vertical-align:text-top;
+}
+sub {
+ vertical-align:text-bottom;
+}
+input,
+textarea,
+select {
+ font-family:inherit;
+ font-size:inherit;
+ font-weight:inherit;
+}
+/*to enable resizing for IE*/
+input,
+textarea,
+select {
+ *font-size:100%;
+}
+/*because legend doesn't inherit in IE */
+legend {
+ color:#000;
+}
View
162 frameworks/core_foundation/system/locale.js
@@ -66,6 +66,12 @@ SC.Locale = SC.Object.extend({
/** The strings hash for this locale. */
strings: {},
+ /**
+ The metrics for this locale. A metric is a singular value that is usually
+ used in a user interface layout, such as "width of the OK button".
+ */
+ metrics: {},
+
toString: function() {
if (!this.language) SC.Locale._assignLocales() ;
return "SC.Locale["+this.language+"]"+SC.guidFor(this) ;
@@ -86,9 +92,107 @@ SC.Locale = SC.Object.extend({
if (SC.typeOf(ret) === SC.T_STRING) return ret;
else if (SC.typeOf(def) === SC.T_STRING) return def;
return string;
+ },
+
+ /**
+ Returns the localized value of the metric for the specified key, or
+ undefined if no match is found.
+
+ @param {String} key
+ @returns {Number} ret
+ */
+ locMetric: function(key) {
+ var ret = this.metrics[key];
+ if (SC.typeOf(ret) === SC.T_NUMBER) {
+ return ret;
+ }
+ else if (ret === undefined) {
+ SC.warn("No localized metric found for key \"" + key + "\"");
+ return undefined;
+ }
+ else {
+ SC.warn("Unexpected metric type for key \"" + key + "\"");
+ return undefined;
+ }
+ },
+
+ /**
+ Creates and returns a new hash suitable for use as an SC.View’s 'layout'
+ hash. This hash will be created by looking for localized metrics following
+ a pattern based on the “base key” you specify.
+
+ For example, if you specify "Button.Confirm", the following metrics will be
+ used if they are defined:
+
+ Button.Confirm.left
+ Button.Confirm.top
+ Button.Confirm.right
+ Button.Confirm.bottom
+ Button.Confirm.width
+ Button.Confirm.height
+ Button.Confirm.midWidth
+ Button.Confirm.minHeight
+ Button.Confirm.centerX
+ Button.Confirm.centerY
+
+ Additionally, you can optionally specify a hash which will be merged on top
+ of the returned hash. For example, if you wish to allow a button’s width
+ to be configurable per-locale, but always wish for it to be centered
+ vertically and horizontally, you can call:
+
+ locLayout("Button.Confirm", {centerX:0, centerY:0})
+
+ …so that you can combine both localized and non-localized elements in the
+ returned hash. (An exception will be thrown if there is a locale-specific
+ key that matches a key specific in this hash.)
+
+ @param {String} baseKey
+ @param {String} (optional) additionalHash
+ @returns {Hash}
+ */
+ locLayout: function(baseKey, additionalHash) {
+ // Note: In this method we'll directly access this.metrics rather than
+ // going through locMetric() for performance and to avoid
+ // locMetric()'s sanity checks.
+
+ var i, len, layoutKey, key, value,
+ layoutKeys = SC.Locale.layoutKeys,
+ metrics = this.metrics,
+
+ // Cache, to avoid repeated lookups
+ typeOfFunc = SC.typeOf,
+ numberType = SC.T_NUMBER,
+
+ ret = {};
+
+
+ // Start off by mixing in the additionalHash; we'll look for collisions with
+ // the localized values in the loop below.
+ if (additionalHash) SC.mixin(ret, additionalHash);
+
+
+ // For each possible key that can be included in a layout hash, see whether
+ // we have a localized value.
+ for (i = 0, len = layoutKeys.length; i < len; ++i) {
+ layoutKey = layoutKeys[i];
+ key = baseKey + "." + layoutKey;
+ value = metrics[key];
+
+ if (typeOfFunc(value) === numberType) {
+ // We have a localized value! As a sanity check, if the caller
+ // specified an additional hash and it has the same key, we'll throw an
+ // error.
+ if (additionalHash && additionalHash[layoutKey]) {
+ throw "locLayout(): There is a localized value for the key '" + key + "' but a value for '" + layoutKey + "' was also specified in the non-localized hash";
+ }
+
+ ret[layoutKey] = value;
+ }
+ }
+
+ return ret;
}
-
-
+
}) ;
SC.Locale.mixin(/** @scope SC.Locale */ {
@@ -98,12 +202,19 @@ SC.Locale.mixin(/** @scope SC.Locale */ {
preferred one.
*/
useAutodetectedLanguage: NO,
-
+
/**
This property is set by the build tools to the current build language.
*/
preferredLanguage: null,
-
+
+ /**
+ This property holds all attributes name which can be used for a layout hash
+ (for an SC.View). These are what we support inside the layoutFor() method.
+ */
+ layoutKeys: ['left', 'top', 'right', 'bottom', 'width', 'height',
+ 'minWidth', 'minHeight', 'centerX', 'centerY'],
+
/**
Invoked at the start of SproutCore's document onready handler to setup
the currentLocale. This will use the language properties you have set on
@@ -211,7 +322,37 @@ SC.Locale.mixin(/** @scope SC.Locale */ {
this.prototype.hasStrings = YES ;
return this;
},
-
+
+ /**
+ Adds the passed hash of metrics to the locale's metrics table, much as
+ addStrings() is used to add in strings. Note that if the receiver locale
+ inherits its metrics from its parent, then the metrics table will be cloned
+ first.
+
+ @returns {Object} receiver
+ */
+ addMetrics: function(metricsHash) {
+ // make sure the target metrics hash exists and belongs to the locale
+ var metrics = this.prototype.metrics;
+ if (metrics) {
+ if (!this.prototype.hasOwnProperty(metrics)) {
+ this.prototype.metrics = SC.clone(metrics) ;
+ }
+ }
+ else {
+ metrics = this.prototype.metrics = {} ;
+ }
+
+ // add metrics hash
+ if (metricsHash) this.prototype.metrics = SC.mixin(metrics, metricsHash);
+
+ // Note: We don't need the equivalent of this.hasStrings here, because we
+ // are not burdened by an older API to look for like the strings
+ // support is.
+
+ return this;
+ },
+
_map: { english: 'en', french: 'fr', german: 'de', japanese: 'ja', jp: 'ja', spanish: 'es' },
/**
@@ -286,4 +427,15 @@ SC.stringsFor = function(languageCode, strings) {
return this ;
} ;
+/**
+ Just like SC.stringsFor, but for metrics.
+ @param {String} languageCode
+ @param {Hash} metrics
+ @returns {Object} receiver
+*/
+SC.metricsFor = function(languageCode, metrics) {
+ var locale = SC.Locale.localeClassFor(languageCode);
+ locale.addMetrics(metrics);
+ return this;
+};
View
10 frameworks/core_foundation/system/render_context.js
@@ -260,7 +260,7 @@ SC.RenderContext = SC.Builder.create(
@returns {DOMElement} the element
*/
element: function() {
- return this._elem ? this._elem : SC.$(this.join())[0]
+ return this._elem ? this._elem : SC.$(this.join())[0];
},
/**
@@ -296,7 +296,7 @@ SC.RenderContext = SC.Builder.create(
update: function() {
var elem = this._elem,
mode = this.updateMode,
- cq, key, value, attr, styles, factory, cur, next, before;
+ cq, value, factory, cur, next;
this._innerHTMLReplaced = NO;
@@ -319,14 +319,13 @@ SC.RenderContext = SC.Builder.create(
} else {
factory = elem.cloneNode(false);
factory.innerHTML = this.join() ;
- before = (mode === SC.MODE_APPEND) ? null : elem.firstChild;
cur = factory.firstChild ;
while(cur) {
next = cur.nextSibling ;
elem.insertBefore(cur, next);
cur = next ;
}
- cur = next = factory = before = null ; // cleanup
+ cur = next = factory = null ; // cleanup
}
}
@@ -596,8 +595,9 @@ SC.RenderContext = SC.Builder.create(
this._classNamesDidChange = YES ;
}
} else {
+ var cl;
for(var i = 0, iLen= nameOrClasses.length; i<iLen; i++){
- var cl = nameOrClasses[i];
+ cl = nameOrClasses[i];
if (classNames.indexOf(cl)<0) {
classNames.push(cl);
this._classNamesDidChange = YES ;
View
12 frameworks/core_foundation/system/root_responder.js
@@ -344,9 +344,18 @@ SC.RootResponder = SC.Object.extend(
(removing sc-blur). Also notify panes.
*/
focus: function() {
+
if (!this.get('hasFocus')) {
SC.$('body').addClass('sc-focus').removeClass('sc-blur');
+ // If the app is getting focus again set the first responder to the first
+ // valid firstResponder view in the view's tree
+ if(!SC.TABBING_ONLY_INSIDE_DOCUMENT){
+ var mainPane = this.get('mainPane'),
+ nextValidKeyView = mainPane ? mainPane.get('nextValidKeyView') : null;
+ if (nextValidKeyView) mainPane.makeFirstResponder(nextValidKeyView);
+ }
+
SC.run(function() {
this.set('hasFocus', YES);
}, this);
@@ -689,7 +698,6 @@ SC.RootResponder = SC.Object.extend(
// do some initial set
this.set('currentWindowSize', this.computeWindowSize()) ;
- this.focus(); // assume the window is focused when you load.
if (SC.browser.mobileSafari) {
@@ -1717,8 +1725,6 @@ SC.RootResponder = SC.Object.extend(
return YES;
}
- if(!SC.browser.msie) window.focus();
-
// First, save the click count. The click count resets if the mouse down
// event occurs more than 250 ms later than the mouse up event or more
// than 8 pixels away from the mouse down event.
View
100 frameworks/core_foundation/system/string.js
@@ -143,6 +143,98 @@ SC.mixin(SC.String, {
},
/**
+ Returns the localized metric value for the specified key. A metric is a
+ single value intended to be used in your interface’s layout, such as
+ "Button.Confirm.Width" = 100.
+
+ If you would like to return a set of metrics for use in a layout hash, you
+ may prefer to use the locLayout() method instead.
+
+ @param str {String} key
+ @returns {Number} the localized metric
+ */
+ locMetric: function(key) {
+ var K = SC.Locale,
+ currentLocale = K.currentLocale;
+
+ if (!currentLocale) {
+ K.createCurrentLocale();
+ currentLocale = K.currentLocale;
+ }
+ return currentLocale.locMetric(key);
+ },
+
+ /**
+ Creates and returns a new hash suitable for use as an SC.View’s 'layout'
+ hash. This hash will be created by looking for localized metrics following
+ a pattern based on the “base key” you specify.
+
+ For example, if you specify "Button.Confirm", the following metrics will be
+ used if they are defined:
+
+ Button.Confirm.left
+ Button.Confirm.top
+ Button.Confirm.right
+ Button.Confirm.bottom
+ Button.Confirm.width
+ Button.Confirm.height
+ Button.Confirm.midWidth
+ Button.Confirm.minHeight
+ Button.Confirm.centerX
+ Button.Confirm.centerY
+
+ Additionally, you can optionally specify a hash which will be merged on top
+ of the returned hash. For example, if you wish to allow a button’s width
+ to be configurable per-locale, but always wish for it to be centered
+ vertically and horizontally, you can call:
+
+ locLayout("Button.Confirm", {centerX:0, centerY:0})
+
+ …so that you can combine both localized and non-localized elements in the
+ returned hash. (An exception will be thrown if there is a locale-specific
+ key that matches a key specific in this hash.)
+
+
+ For example, if your locale defines:
+
+ Button.Confirm.left
+ Button.Confirm.top
+ Button.Confirm.right
+ Button.Confirm.bottom
+
+
+ …then these two code snippets will produce the same result:
+
+ layout: {
+ left: "Button.Confirm.left".locMetric(),
+ top: "Button.Confirm.top".locMetric(),
+ right: "Button.Confirm.right".locMetric(),
+ bottom: "Button.Confirm.bottom".locMetric()
+ }
+
+ layout: "Button.Confirm".locLayout()
+
+ The former is slightly more efficient because it doesn’t have to iterate
+ through the possible localized layout keys, but in virtually all situations
+ you will likely wish to use the latter.
+
+ @param str {String} key
+ @param {str} (optional) additionalHash
+ @param {String} (optional) additionalHash
+ @returns {Number} the localized metric
+ */
+ locLayout: function(key, additionalHash) {
+ var K = SC.Locale,
+ currentLocale = K.currentLocale;
+
+ if (!currentLocale) {
+ K.createCurrentLocale();
+ currentLocale = K.currentLocale;
+ }
+ return currentLocale.locLayout(key, additionalHash);
+ },
+
+ /**
Works just like loc() except that it will return the passed default
string if a matching key is not found.
@@ -217,6 +309,14 @@ SC.mixin(String.prototype,
loc: function() {
return SC.String.loc(this.toString(), SC.$A(arguments));
+ },
+
+ locMetric: function() {
+ return SC.String.locMetric(this.toString());
+ },
+
+ locLayout: function(additionalHash) {
+ return SC.String.locLayout(this.toString(), additionalHash);
}
});
View
59 frameworks/core_foundation/system/theme.js
@@ -23,21 +23,6 @@
by SC.View when you name a theme that doesn't actually exist: it creates
a theme based on the parent theme.
- Renderers
- ---------------------------
- Themes are used to keep track of theme class names and, more important,
- to keep track of renderers.
-
- Renderers are added to a theme using theme.addRenderer(theRenderer). After
- this has been done, they may be instantiated using theme.renderer(rendererName).
-
- Instantiating with renderer() instantiates a version of that renderer
- specialized for this specific theme-- not any parent themes. The renderer
- will include all class names for _this_ theme. This means that you can
- theme controls differently without overriding any renderers: just subclass
- the original theme that _has_ the renderers, give it its own name, and
- all renderers will render with that name as a class name.
-
Locating Child Themes
----------------------------
Locating child themes is relatively simple for the most part: it looks in
@@ -51,7 +36,7 @@
base classes; if the theme is a global theme, those class names should not
be included.
- This makes sense logically as well, because when searching for a renderer,
+ This makes sense logically as well, because when searching for a render delegate,
it will locate it in any base theme that has it, but that doesn't mean
class names from the derived theme shouldn't be included.
@@ -143,10 +128,6 @@ SC.Theme = {
// method.
result._privateThemes = {};
- // the theme also specializes all renderers it creates so that they
- // have the theme's classNames and have their 'theme' property set.
- result._specializedRenderers = {};
-
// also, the theme specializes all child themes as they are created
// to ensure that all of the class names on this theme are included.
result._specializedThemes = {};
@@ -263,40 +244,6 @@ SC.Theme = {
*/
addTheme: function(theme) {
this.themes[theme.name] = theme;
- },
-
- /**
- Adds a renderer to the theme. The renderer's name will be used to
- keep track of it and identify it later.
-
- The biggest responsibility of addRenderer is to ensure that renderer()
- can be used to instantiate that renderer. If a renderer is not instantiated
- through renderer(), it will not know its theme's classNames.
- */
- addRenderer: function(renderer) {
- this[renderer.name] = renderer;
- },
-
- /**
- Finds the named renderer and instantiates it, returning the result.
- It also ensures it is using a version of the renderer specialized for
- this theme. It keeps a cache of specialized versions of the renderer.
-
- Any arguments after the name are passed on to the instantiated
- renderer.
- */
- renderer: function(name) {
- var renderer = this._specializedRenderers[name], base = this[name];
- if (!renderer || renderer._specializedFrom !== base) {
- if (!base) return null;
-
- renderer = base.extend({ classNames: this.classNames, theme: this });
- }
-
- var args = SC.$A(arguments);
- args.shift();
- renderer = renderer.create.apply(renderer, args);
- return renderer;
}
};
@@ -304,8 +251,8 @@ SC.Theme = {
// optimal, but the reasoning is because of test running: the
// test runner, when running foundation unit tests, cannot load
// the theme. As such, foundation must include default versions of
-// all of its renderers, and it does so in BaseTheme. All SproutCore
-// controls have renderers in BaseTheme.
+// all of its render delegates, and it does so in BaseTheme. All SproutCore
+// controls have render delegates in BaseTheme.
SC.BaseTheme = SC.Theme.create({
name: '' // it is a base class, and doesn't need a class name or such
});
View
42 frameworks/core_foundation/tests/mixins/string.js
@@ -4,7 +4,7 @@
// ©2008-2011 Apple Inc. All rights reserved.
// License: Licensed under MIT license (see license.js)
// ==========================================================================
-/*global module test equals context ok same */
+/*global module test equals context ok same should_throw*/
var LocaleObject;
module('SC.Object', {
@@ -26,6 +26,13 @@ module('SC.Object', {
'Test': '%@',
'Test.Multiple': '%@ %@'
});
+
+ SC.metricsFor('English', {
+ 'Button.left': 10,
+ 'Button.top': 20,
+ 'Button.width': 80,
+ 'Button.height': 30
+ });
}
});
@@ -76,3 +83,36 @@ test("Localize a string even if localized version is empty", function() {
equals("empty".locWithDefault("Empty"), "", "Using String.prototype.locWithDefault");
equals(SC.String.locWithDefault("empty", "Empty"), "", "Using SC.String.locWithDefault");
});
+
+test("Access a localized metric", function() {
+ equals(10, "Button.left".locMetric());
+ equals(20, "Button.top".locMetric());
+ equals(undefined, "Button.notThere".locMetric());
+});
+
+test("Access a localized layout hash", function() {
+ // Simple case (if we ever get a full hash comparison function, we should use
+ // it here).
+ var layout = "Button".locLayout();
+ equals(10, layout.left);
+ equals(20, layout.top);
+ equals(80, layout.width);
+ equals(30, layout.height);
+ equals(undefined, layout.right); // No localized key
+
+
+ // Slightly more involved case: allow the user to specify an additional hash.
+ layout = "Button".locLayout({right:50});
+ equals(10, layout.left);
+ equals(20, layout.top);
+ equals(80, layout.width);
+ equals(30, layout.height);
+ equals(50, layout.right); // No localized key
+
+
+ // Sanity-check case: Since we have both a localized key for 'left' and we'll
+ // pass it in, an exception should be thrown.
+ should_throw(function() {
+ "Button".locLayout({left:10});
+ }, Error, "locLayout(): There is a localized value for the key 'Button.left' but a value for 'left' was also specified in the non-localized hash");
+});
View
16 frameworks/core_foundation/tests/views/view/insertBefore.js
@@ -80,7 +80,7 @@ test("invokes willAddChild() on receiver if defined before adding child" ,functi
parent.insertBefore(child, otherChild);
- ok(callCount, 1, 'invoked');
+ equals(callCount, 1, 'invoked');
});
test("invokes willAddToParent() on child view if defined before adding child" ,function() {
@@ -102,7 +102,7 @@ test("invokes willAddToParent() on child view if defined before adding child" ,f
parent.insertBefore(child, otherChild);
- ok(callCount, 1, 'invoked');
+ equals(callCount, 1, 'invoked');
});
test("invokes didAddChild() on receiver if defined after adding child" ,function() {
@@ -122,9 +122,11 @@ test("invokes didAddChild() on receiver if defined after adding child" ,function
callCount++;
};
-
+ SC.RunLoop.begin();
parent.insertBefore(child, otherChild);
- ok(callCount, 1, 'invoked');
+ SC.RunLoop.end();
+
+ equals(callCount, 1, 'invoked');
});
test("invokes didAddToParent() on child view if defined after adding child" ,function() {
@@ -144,9 +146,11 @@ test("invokes didAddToParent() on child view if defined after adding child" ,fun
callCount++;
};
-
+ SC.RunLoop.begin();
parent.insertBefore(child, otherChild);
- ok(callCount, 1, 'invoked');
+ SC.RunLoop.end();
+
+ equals(callCount, 1, 'invoked');
});
test("invokes parentViewDidChange() on child view. this is used by the view internals to update layer loc", function() {
View
19 frameworks/core_foundation/tests/views/view/keyboard.js
@@ -4,7 +4,18 @@
// ©2008-2011 Apple Inc. All rights reserved.
// License: Licensed under MIT license (see license.js)
// ==========================================================================
-module("SC.View - Keyboard support");
+
+var originalTabbing;
+
+module("SC.View - Keyboard support with Tabbing Only Inside Document", {
+ setup: function(){
+ originalTabbing = SC.TABBING_ONLY_INSIDE_DOCUMENT;
+ SC.TABBING_ONLY_INSIDE_DOCUMENT = YES;
+ },
+ teardown: function(){
+ SC.TABBING_ONLY_INSIDE_DOCUMENT = originalTabbing;
+ }
+});
test("Views only attempt to call performKeyEquivalent on child views that support it", function() {
var performKeyEquivalentCalled = 0;
@@ -422,3 +433,9 @@ test("previousValidKeyView prioritizes parent's firstKeyView even if previousKey
equals(pane.view2.view6.get('previousValidKeyView'), pane.view1.view4, "firstKeyView was respected; views before firstKeyView were skipped");
});
+
+module("SC.View - Keyboard support with Tabbing Outside of Document");
+
+test("forward tab with no next responder moves out of document");
+
+test("backwards tab with no previous responder moves out of document");
View
9 frameworks/core_foundation/views/view.js
@@ -24,7 +24,7 @@ SC.CONTEXT_MENU_ENABLED = YES;
Default property to disable or enable if the focus can jump to the address
bar or not.
*/
-SC.TABBING_ONLY_INSIDE_DOCUMENT = YES;
+SC.TABBING_ONLY_INSIDE_DOCUMENT = NO;
/**
Tells the property (when fetched with themed()) to get its value from the renderer (if any).
@@ -674,7 +674,12 @@ SC.CoreView.reopen(
if (this.get('isTextSelectable')) { context.addClass('allow-select'); }
if (!this.get('isVisible')) { context.addClass('sc-hidden'); }
- if (this.get('isFirstResponder')) { context.addClass('focus'); }
+ if (this.get('isFirstResponder')) {
+ context.addClass('focus');
+ context.attr('tabindex', '0');
+ }else{
+ context.attr('tabindex', '-1');
+ }
context.id(this.get('layerId'));
context.attr('role', this.get('ariaRole'));
View
18 frameworks/core_foundation/views/view/keyboard.js
@@ -39,13 +39,20 @@ SC.View.reopen(
/**
Invokved just after the responder loses key responder status.
+ @param {SC.Responder} responder
*/
didLoseKeyResponderTo: function(responder) {},
/**
Invoked just after the responder gains key responder status.
+ By default, it calls focus on the view root element. For accessibility
+ purposes.
+
+ @param {SC.Responder} responder
*/
- didBecomeKeyResponderFrom: function(responder) {},
+ didBecomeKeyResponderFrom: function(responder) {
+ this.$().focus();
+ },
/**
This method will process a key input event, attempting to convert it to
@@ -276,7 +283,10 @@ SC.View.reopen(
}
// if no parents have a next sibling, start over from the beginning
- if(!next) next = this.get('pane');
+ if(!next) {
+ if(!SC.TABBING_ONLY_INSIDE_DOCUMENT) break;
+ else next = this.get('pane');
+ }
// if it's a valid firstResponder, we're done!
if(next.get('isVisibleInWindow') && next.get('acceptsFirstResponder')) return next;
@@ -287,7 +297,6 @@ SC.View.reopen(
// this will only happen if no views are visible and accept first responder
return null;
-
}.property('nextKeyView'),
/**
@@ -355,6 +364,9 @@ SC.View.reopen(
// normally, just try to get previous view's last child
if(cur.get('parentView')) prev = cur._getPreviousKeyView();
+ // if we are the pane and address bar tabbing is enabled, trigger it now
+ else if(!SC.TABBING_ONLY_INSIDE_DOCUMENT) break;
+
// if we are the pane, get our own last child
else prev = cur;
View
26 frameworks/core_foundation/views/view/theming.js
@@ -117,23 +117,6 @@ SC.View.reopen(
}.property('baseThemeName', 'parentView').cacheable(),
/**
- * Returns the named property if it is specified on the view, and
- * otherwise returns the named constant from the view's theme.
- *
- * @param {String} property The property on the view.
- * @param {String} constantName The name of the constant on the theme.
- */
- getThemedProperty: function(property, constantName){
- var value = this.get(property);
- if (value !== undefined) { return value; }
-
- var theme = this.get('theme');
- if (!theme) { return undefined; }
-
- return theme[constantName];
- },
-
- /**
The object to which rendering and updating the HTML representation of this
view should be delegated.
@@ -253,9 +236,16 @@ SC.View.reopen(
original(context);
var renderDelegate = this.get('renderDelegate');
+ if (renderDelegate && renderDelegate.className) {
+ context.addClass(renderDelegate.className);
+ }
+
+ // @if(debug)
if (renderDelegate && renderDelegate.name) {
- context.addClass(renderDelegate.name);
+ SC.Logger.error("Render delegates now use 'className' instead of 'name'.");
+ SC.Logger.error("Name '%@' will be ignored.", renderDelegate.name);
}
+ // @endif
}.enhance()
});
View
2 frameworks/datastore/system/nested_store.js
@@ -318,7 +318,7 @@ SC.NestedStore = SC.Store.extend(
if (!editables) editables = this.editables = [];
editables[storeKey] = 1 ; // mark as editable
- } else this.dataHashes[storeKey] = this.dataHashes[storeKey];
+ } else this.dataHashes[storeKey] = pstore.dataHashes[storeKey];
// also copy the status + revision
this.statuses[storeKey] = this.statuses[storeKey];
View
1 frameworks/desktop/panes/alert.js
@@ -444,6 +444,7 @@ SC.AlertPane.mixin(
if(buttons) {
buttons.forEach(function(button) {
idx++;
+ if(!button) return;
buttonView = pane.get('button%@'.fmt(idx));
title = button.title;
View
19 frameworks/desktop/panes/menu.js
@@ -604,11 +604,28 @@ SC.MenuPane = SC.PickerPane.extend(
This computed property parses `displayItems` and constructs an
`SC.MenuItemView` (or whatever class you have set as the `exampleView`) for every item.
+ This calls createMenuItemViews. If you want to override this property, override
+ that method.
+
+ This calls createMenuItemViews. If you want to override this property, override
+ that method.
+
@property
@type Array
@readOnly
*/
menuItemViews: function() {
+ return this.createMenuItemViews();
+ }.property('displayItems').cacheable(),
+
+ /**
+ Processes the displayItems and creates menu item views for each item.
+
+ Override this method to change how menuItemViews is calculated.
+
+ @return Array
+ */
+ createMenuItemViews: function() {
var views = [], items = this.get('displayItems'),
exampleView = this.get('exampleView'), item, view,
height, heightKey, separatorKey, defaultHeight, separatorHeight,
@@ -663,7 +680,7 @@ SC.MenuPane = SC.PickerPane.extend(
this.set('menuHeight', menuHeight+menuHeightPadding);
return views;
- }.property('displayItems').cacheable(),
+ },
/**
Returns the menu item view for the content object at the specified index.
View
9 frameworks/desktop/panes/panel.js
@@ -164,6 +164,15 @@ SC.PanelPane = SC.Pane.extend(
}
return ret ;
},
+
+ destroy: function() {
+ var modal = this.get('modalPane');
+ if (modal && !modal.isClass) {
+ modal.destroy();
+ }
+
+ sc_super();
+ },
/** @private - if isModal state changes, update pane state if needed. */
_isModalDidChange: function() {
View
2 frameworks/desktop/render_delegates/button.js
@@ -10,7 +10,7 @@
Renders and updates the HTML representation of a button.
*/
SC.BaseTheme.buttonRenderDelegate = SC.RenderDelegate.create({
- name: 'button',
+ className: 'button',
//
// SIZE DEFINITIONS
View
2 frameworks/desktop/render_delegates/checkbox.js
@@ -27,7 +27,7 @@
*/
SC.BaseTheme.checkboxRenderDelegate = SC.RenderDelegate.create({
- name: 'checkbox',
+ className: 'checkbox',
render: function(dataSource, context) {
this.addSizeClassName(dataSource, context);
View
2 frameworks/desktop/render_delegates/collection.js
@@ -9,7 +9,7 @@
// collections don't need their own rendering; however, in future, constants
// like the row height will likely be specified on the render delegate.
SC.BaseTheme.collectionRenderDelegate = SC.RenderDelegate.create({
- name: 'collection',
+ className: 'collection',
render: function(dataSource, context) {
context.setClass('focus', dataSource.get('isFirstResponder'));
View
2 frameworks/desktop/render_delegates/disclosure.js
@@ -7,7 +7,7 @@
SC.BaseTheme.disclosureRenderDelegate = SC.RenderDelegate.create({
- name: 'disclosure',
+ className: 'disclosure',
render: function(dataSource, context) {
this.addSizeClassName(dataSource, context);
View
2 frameworks/desktop/render_delegates/image_button.js
@@ -7,7 +7,7 @@
SC.BaseTheme.imageButtonRenderDelegate = SC.RenderDelegate.create({
- name: 'image-button',
+ className: 'image-button',
render: function(dataSource, context) {
var image = dataSource.get('image'),
View
5 frameworks/desktop/render_delegates/master_detail.js
@@ -16,7 +16,8 @@
SC.BaseTheme.MASTER_DETAIL_DIVIDER_WIDTH = 1;
SC.BaseTheme.masterDetailRenderDelegate = SC.RenderDelegate.create({
- name: 'master-detail',
+ className: 'master-detail',
+ dividerWidth: 1,
render: function(dataSource, context) {
context.setClass('round-toolbars', SC.platform.touch);
@@ -26,4 +27,4 @@ SC.BaseTheme.masterDetailRenderDelegate = SC.RenderDelegate.create({
jquery.setClass('round-toolbars', SC.platform.touch);
}
-});
+});
View
14 frameworks/desktop/render_delegates/menu.js
@@ -9,7 +9,7 @@ sc_require('render_delegates/picker');
// This is the same as a pickerRenderDelegate, but is named 'menu' instead.
SC.BaseTheme.menuRenderDelegate = SC.BaseTheme.pickerRenderDelegate.create({
- name: 'menu',
+ className: 'menu',
render: function(orig, dataSource, context) {
this.addSizeClassName(dataSource, context);
@@ -21,11 +21,21 @@ SC.BaseTheme.menuRenderDelegate = SC.BaseTheme.pickerRenderDelegate.create({
orig(dataSource, jquery);
}.enhance(),
+ // height for items in this menu size
itemHeight: 20,
+
+ // height of separator items
itemSeparatorHeight: 9,
+
+ // amount to add to the calculated menu height
menuHeightPadding: 6,
- submenuOffsetX: 2,
+ // amount to add to any calculated menu width to determine the actual width
+ menuWidthPadding: 50,
+
+ minimumMenuWidth: 50,
+
+ submenuOffsetX: 2,
verticalOffset: 23,
'sc-tiny-size': {
View
2 frameworks/desktop/render_delegates/panel.js
@@ -7,7 +7,7 @@
SC.BaseTheme.panelRenderDelegate = SC.RenderDelegate.create({
- name: 'panel',
+ className: 'panel',
render: function(dataSource, context) {
context = context.begin('div').addClass('panel-background');
View
2 frameworks/desktop/render_delegates/picker.js
@@ -8,7 +8,7 @@
sc_require('render_delegates/panel');
SC.BaseTheme.pickerRenderDelegate = SC.RenderDelegate.create({
- name: 'picker',
+ className: 'picker',
render: function(dataSource, context) {
var panelRenderDelegate = dataSource.get('theme').panelRenderDelegate;
View
2 frameworks/desktop/render_delegates/progress.js
@@ -23,7 +23,7 @@
any theme constants.
*/
SC.BaseTheme.progressRenderDelegate = SC.RenderDelegate.create({
- name: 'progress',
+ className: 'progress',
render: function(dataSource, context) {
this.addSizeClassName(dataSource, context);
View
2 frameworks/desktop/render_delegates/radio.js
@@ -26,7 +26,7 @@
*/
SC.BaseTheme.radioRenderDelegate = SC.RenderDelegate.create({
- name: 'radio',
+ className: 'radio',
render: function(dataSource, context) {
this.addSizeClassName(dataSource, context);
View
4 frameworks/desktop/render_delegates/radio_group.js
@@ -27,7 +27,7 @@
button, there is a method to update a specific index.
*/
SC.BaseTheme.radioGroupRenderDelegate = SC.RenderDelegate.create({
- name: 'radio-group',
+ className: 'radio-group',
render: function(dataSource, context) {
this.addSizeClassName(dataSource, context);
@@ -47,7 +47,7 @@ SC.BaseTheme.radioGroupRenderDelegate = SC.RenderDelegate.create({
.addClass('radio-' + idx)
.attr('index', idx)
.addClass(theme.classNames)
- .addClass(theme.radioRenderDelegate.name)
+ .addClass(theme.radioRenderDelegate.className)
// so we can identify it in event handling
.addClass('sc-radio-button');
View
2 frameworks/desktop/render_delegates/segment.js
@@ -11,7 +11,7 @@
SC.SegmentedView.
*/
SC.BaseTheme.segmentRenderDelegate = SC.RenderDelegate.create({
- name: 'segment',
+ className: 'segment',
render: function(dataSource, context) {
var theme = dataSource.get('theme'),
View
2 frameworks/desktop/render_delegates/segmented.js
@@ -9,7 +9,7 @@
Renders and updates the HTML representation of SC.SegmentedView.
*/
SC.BaseTheme.segmentedRenderDelegate = SC.RenderDelegate.create({
- name: 'segmented',
+ className: 'segmented',
/*
We render everything external to the segments and let each segment use it's own render
View
2 frameworks/desktop/render_delegates/slider.js
@@ -18,7 +18,7 @@
SC.BaseTheme.sliderRenderDelegate = SC.RenderDelegate.create({
- name: 'slider',
+ className: 'slider',
render: function(dataSource, context) {
this.addSizeClassName(dataSource, context);
View
2 frameworks/desktop/render_delegates/toolbar.js
@@ -6,7 +6,7 @@
// ==========================================================================
SC.BaseTheme.toolbarRenderDelegate = SC.RenderDelegate.create({
- name: 'toolbar',
+ className: 'toolbar',
render: function(dataSource, context) {
// toolbar has nothing in it
View
2 frameworks/desktop/render_delegates/well.js
@@ -6,7 +6,7 @@
// ==========================================================================
SC.BaseTheme.wellRenderDelegate = SC.RenderDelegate.create({
- name: 'well',
+ className: 'well',
render: function(dataSource, context) {
this.includeSlices(dataSource, context, SC.NINE_SLICE);
},
View
2 frameworks/desktop/render_delegates/workspace.js
@@ -6,7 +6,7 @@
// ==========================================================================
SC.BaseTheme.workspaceRenderDelegate = SC.RenderDelegate.create({
- name: 'workspace',
+ className: 'workspace',
render: function() {
// No DOM to generate -- uses CSS3 to style.
View
1 frameworks/desktop/resources/segmented.css
@@ -1,6 +1,7 @@
.sc-segmented-view {
display: block;
white-space: nowrap;
+ z-index: 1;
img.icon {
position: relative;
vertical-align: middle;
View
21 frameworks/desktop/tests/panes/panel/methods.js
@@ -7,4 +7,23 @@
/*global module test htmlbody ok equals same stop start */
-module("TODO: Test SC.PanelPane Methods");
+module("PanelPane - Methods");
+
+function getViewCount() {
+ var i = 0; for (key in SC.View.views) ++i;
+ return i;
+}
+
+test("PanelPane destroy", function() {
+ var start = getViewCount();
+
+ var pane = SC.PanelPane.create({
+ isModal: YES
+ });
+ pane.append();
+ pane.remove();
+ pane.destroy();
+
+ var end = getViewCount();
+ equals(start, end, "No extra views lying about after calling .destroy");
+});
View
13 frameworks/desktop/tests/views/checkbox/methods.js
@@ -13,15 +13,22 @@
module("SC.Checkbox", {
setup: function() {
SC.RunLoop.begin();
+
+ // actions must be strings, and there must be a target. So, we need this dummy.
+ var act = SC.Object.create({
+ action: function() {
+ triggered = true;
+ }
+ });
+
pane = SC.MainPane.create({
childViews: [
SC.CheckboxView.extend({
layout: { right: 20, bottom: 20, width: 100, height: 23 },
title: "First Name",
value: YES,
- action: function() {
- triggered = true;
- }
+ target: act,
+ action: 'action'
})]
});
pane.append(); // make sure there is a layer...
View
41 frameworks/desktop/tests/views/date_field/methods.js
@@ -66,11 +66,38 @@ function() {
ok(view0.$().hasClass('disabled'), 'should have disabled class');
});
-test("isEnabled and isEditable mapping",
-function() {
- var obj = SC.DateFieldView.create();
- obj.set('isEnabled', false);
- equals(obj.get('isEditable'), false);
- obj.set('isEnabled', true);
- equals(obj.get('isEditable'), true);
+test("isEnabled=NO isEditable=NO should add disabled attribute", function() {
+ SC.RunLoop.begin();
<