sproutcore 1.0.1037 → 1.0.1042

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/History.txt +31 -0
  2. data/README.txt +3 -1
  3. data/Rakefile +11 -4
  4. data/VERSION.yml +3 -3
  5. data/buildtasks/build.rake +5 -0
  6. data/frameworks/sproutcore/Buildfile +3 -1
  7. data/frameworks/sproutcore/frameworks/animation/Buildfile +3 -0
  8. data/frameworks/sproutcore/frameworks/animation/LICENSE +25 -0
  9. data/frameworks/sproutcore/frameworks/animation/README.md +102 -0
  10. data/frameworks/sproutcore/frameworks/animation/core.js +934 -0
  11. data/frameworks/sproutcore/frameworks/animation/tests/core.js +65 -0
  12. data/frameworks/sproutcore/frameworks/datastore/models/record.js +28 -16
  13. data/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +5 -2
  14. data/frameworks/sproutcore/frameworks/datastore/system/many_array.js +4 -0
  15. data/frameworks/sproutcore/frameworks/datastore/system/query.js +27 -13
  16. data/frameworks/sproutcore/frameworks/datastore/system/record_array.js +36 -6
  17. data/frameworks/sproutcore/frameworks/datastore/system/store.js +7 -7
  18. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/storeDidChangeProperties.js +2 -1
  19. data/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +13 -0
  20. data/frameworks/sproutcore/frameworks/debug/invoke_once_last_debugging.js +250 -0
  21. data/frameworks/sproutcore/frameworks/desktop/english.lproj/list_item.css +0 -12
  22. data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu_item_view.css +3 -6
  23. data/frameworks/sproutcore/frameworks/desktop/english.lproj/panel.css +0 -8
  24. data/frameworks/sproutcore/frameworks/desktop/english.lproj/picker.css +0 -4
  25. data/frameworks/sproutcore/frameworks/desktop/english.lproj/segmented.css +1 -0
  26. data/frameworks/sproutcore/frameworks/desktop/english.lproj/well.css +0 -1
  27. data/frameworks/sproutcore/frameworks/desktop/mixins/border.js +1 -1
  28. data/frameworks/sproutcore/frameworks/desktop/panes/alert.js +2 -1
  29. data/frameworks/sproutcore/frameworks/desktop/panes/menu.js +11 -4
  30. data/frameworks/sproutcore/frameworks/desktop/panes/palette.js +2 -0
  31. data/frameworks/sproutcore/frameworks/desktop/panes/panel.js +1 -5
  32. data/frameworks/sproutcore/frameworks/desktop/panes/picker.js +24 -23
  33. data/frameworks/sproutcore/frameworks/desktop/panes/select_button.js +91 -60
  34. data/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +124 -24
  35. data/frameworks/sproutcore/frameworks/desktop/system/drag.js +5 -5
  36. data/frameworks/sproutcore/frameworks/desktop/system/root_responder.js +33 -25
  37. data/frameworks/sproutcore/frameworks/desktop/tests/panes/pane_page.js +41 -0
  38. data/frameworks/sproutcore/frameworks/desktop/tests/panes/select_button/methods.js +30 -1
  39. data/frameworks/sproutcore/frameworks/desktop/tests/panes/select_button/ui.js +13 -0
  40. data/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/ui.js +27 -21
  41. data/frameworks/sproutcore/frameworks/desktop/tests/views/button/methods.js +81 -1
  42. data/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +3 -4
  43. data/frameworks/sproutcore/frameworks/desktop/views/button.js +65 -36
  44. data/frameworks/sproutcore/frameworks/desktop/views/collection.js +4 -7
  45. data/frameworks/sproutcore/frameworks/desktop/views/disclosure.js +8 -4
  46. data/frameworks/sproutcore/frameworks/desktop/views/list.js +1 -1
  47. data/frameworks/sproutcore/frameworks/desktop/views/list_item.js +38 -5
  48. data/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +5 -1
  49. data/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +4 -1
  50. data/frameworks/sproutcore/frameworks/desktop/views/progress.js +19 -13
  51. data/frameworks/sproutcore/frameworks/desktop/views/radio.js +30 -2
  52. data/frameworks/sproutcore/frameworks/desktop/views/scroll.js +2 -3
  53. data/frameworks/sproutcore/frameworks/desktop/views/segmented.js +14 -17
  54. data/frameworks/sproutcore/frameworks/desktop/views/select_field.js +5 -3
  55. data/frameworks/sproutcore/frameworks/desktop/views/slider.js +4 -2
  56. data/frameworks/sproutcore/frameworks/desktop/views/split.js +58 -59
  57. data/frameworks/sproutcore/frameworks/desktop/views/tab.js +2 -1
  58. data/frameworks/sproutcore/frameworks/desktop/views/well.js +1 -1
  59. data/frameworks/sproutcore/frameworks/foundation/core.js +6 -0
  60. data/frameworks/sproutcore/frameworks/foundation/english.lproj/view.css +2 -1
  61. data/frameworks/sproutcore/frameworks/foundation/mixins/button.js +33 -30
  62. data/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +8 -4
  63. data/frameworks/sproutcore/frameworks/foundation/mixins/string.js +15 -10
  64. data/frameworks/sproutcore/frameworks/foundation/panes/pane.js +61 -12
  65. data/frameworks/sproutcore/frameworks/foundation/system/bundle.js +2 -1
  66. data/frameworks/sproutcore/frameworks/foundation/system/core_query.js +151 -131
  67. data/frameworks/sproutcore/frameworks/foundation/system/datetime.js +29 -23
  68. data/frameworks/sproutcore/frameworks/foundation/system/event.js +18 -10
  69. data/frameworks/sproutcore/frameworks/foundation/system/page.js +7 -5
  70. data/frameworks/sproutcore/frameworks/foundation/system/ready.js +1 -0
  71. data/frameworks/sproutcore/frameworks/foundation/system/render_context.js +9 -6
  72. data/frameworks/sproutcore/frameworks/foundation/system/request.js +41 -6
  73. data/frameworks/sproutcore/frameworks/foundation/system/response.js +89 -24
  74. data/frameworks/sproutcore/frameworks/foundation/system/routes.js +1 -1
  75. data/frameworks/sproutcore/frameworks/foundation/system/utils.js +0 -1
  76. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/array_case.js +27 -8
  77. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_core.js +6 -6
  78. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_style.js +2 -2
  79. data/frameworks/sproutcore/frameworks/foundation/tests/system/request.js +65 -3
  80. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/append_remove.js +1 -1
  81. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/convertLayouts.js +145 -0
  82. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/didAppendToDocument.js +48 -0
  83. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/nextValidKeyView.js +91 -0
  84. data/frameworks/sproutcore/frameworks/foundation/validators/number.js +9 -5
  85. data/frameworks/sproutcore/frameworks/foundation/views/field.js +16 -14
  86. data/frameworks/sproutcore/frameworks/foundation/views/text_field.js +89 -67
  87. data/frameworks/sproutcore/frameworks/foundation/views/view.js +221 -73
  88. data/frameworks/sproutcore/frameworks/runtime/core.js +43 -22
  89. data/frameworks/sproutcore/frameworks/runtime/mixins/array.js +6 -0
  90. data/frameworks/sproutcore/frameworks/runtime/mixins/copyable.js +1 -1
  91. data/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +53 -34
  92. data/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +7 -3
  93. data/frameworks/sproutcore/frameworks/runtime/system/binding.js +19 -19
  94. data/frameworks/sproutcore/frameworks/runtime/system/logger.js +132 -88
  95. data/frameworks/sproutcore/frameworks/runtime/system/object.js +15 -9
  96. data/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +6 -0
  97. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +69 -0
  98. data/frameworks/sproutcore/frameworks/runtime/tests/system/logger.js +14 -2
  99. data/frameworks/sproutcore/license.js +3 -1
  100. data/frameworks/sproutcore/themes/standard_theme/Source/sc-theme-repeat-x.psd +0 -0
  101. data/frameworks/sproutcore/{frameworks/desktop → themes/standard_theme}/english.lproj/images/icons/mini_222222.png +0 -0
  102. data/frameworks/sproutcore/{frameworks/desktop → themes/standard_theme}/english.lproj/images/icons/mini_454545.png +0 -0
  103. data/frameworks/sproutcore/{frameworks/desktop → themes/standard_theme}/english.lproj/images/icons/mini_888888.png +0 -0
  104. data/frameworks/sproutcore/{frameworks/desktop → themes/standard_theme}/english.lproj/images/icons/mini_ffffff.png +0 -0
  105. data/frameworks/sproutcore/{frameworks/desktop → themes/standard_theme}/english.lproj/images/panels/sprite-x.png +0 -0
  106. data/frameworks/sproutcore/{frameworks/desktop → themes/standard_theme}/english.lproj/images/panels/sprite-y.png +0 -0
  107. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-repeat-x.png +0 -0
  108. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-ysprite.png +0 -0
  109. data/frameworks/sproutcore/themes/standard_theme/english.lproj/list_item.css +15 -1
  110. data/frameworks/sproutcore/themes/standard_theme/english.lproj/menu_item_view.css +9 -0
  111. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panel.css +33 -0
  112. data/frameworks/sproutcore/themes/standard_theme/english.lproj/picker.css +17 -0
  113. data/frameworks/sproutcore/themes/standard_theme/english.lproj/radio.css +9 -6
  114. data/frameworks/sproutcore/themes/standard_theme/english.lproj/tab.css +0 -4
  115. data/frameworks/sproutcore/themes/standard_theme/english.lproj/well.css +36 -0
  116. data/gen/controller/templates/controllers/@filename@.js +1 -1
  117. data/lib/sproutcore/builders/minify.rb +45 -13
  118. data/lib/sproutcore/helpers/static_helper.rb +2 -2
  119. data/lib/sproutcore/models/manifest_entry.rb +42 -1
  120. data/lib/sproutcore/tools/build.rb +18 -2
  121. data/spec/lib/models/manifest_entry/hyperdomain_prefix.rb +34 -0
  122. data/vendor/yui-compressor/SCyuicompressor-2.4.2.jar +0 -0
  123. metadata +28 -22
  124. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/background-fat.jpg +0 -0
  125. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/background-thin.jpg +0 -0
  126. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-edge.png +0 -0
  127. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-left-corner.png +0 -0
  128. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-right-corner.png +0 -0
  129. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/left-edge.png +0 -0
  130. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/overlay.png +0 -0
  131. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/right-edge.png +0 -0
  132. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-edge.png +0 -0
  133. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-left-corner.png +0 -0
  134. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-right-corner.png +0 -0
@@ -252,32 +252,34 @@ SC.DateTime = SC.Object.extend(SC.Freezable, SC.Copyable,
252
252
  like the C strftime function.
253
253
 
254
254
  The format parameter can contain the following characters:
255
- %a - The abbreviated weekday name (``Sun'')
256
- %A - The full weekday name (``Sunday'')
257
- %b - The abbreviated month name (``Jan'')
258
- %B - The full month name (``January'')
259
- %c - The preferred local date and time representation
260
- %d - Day of the month (01..31)
261
- %H - Hour of the day, 24-hour clock (00..23)
262
- %I - Hour of the day, 12-hour clock (01..12)
263
- %j - Day of the year (001..366)
264
- %m - Month of the year (01..12)
265
- %M - Minute of the hour (00..59)
266
- %p - Meridian indicator (``AM'' or ``PM'')
267
- %S - Second of the minute (00..60)
268
- %U - Week number of the current year,
255
+ - %a - The abbreviated weekday name (``Sun'')
256
+ - %A - The full weekday name (``Sunday'')
257
+ - %b - The abbreviated month name (``Jan'')
258
+ - %B - The full month name (``January'')
259
+ - %c - The preferred local date and time representation
260
+ - %d - Day of the month (01..31)
261
+ - %h - Hour of the day, 24-hour clock (0..23)
262
+ - %H - Hour of the day, 24-hour clock (00..23)
263
+ - %i - Hour of the day, 12-hour clock (1..12)
264
+ - %I - Hour of the day, 12-hour clock (01..12)
265
+ - %j - Day of the year (001..366)
266
+ - %m - Month of the year (01..12)
267
+ - %M - Minute of the hour (00..59)
268
+ - %p - Meridian indicator (``AM'' or ``PM'')
269
+ - %S - Second of the minute (00..60)
270
+ - %U - Week number of the current year,
269
271
  starting with the first Sunday as the first
270
272
  day of the first week (00..53)
271
- %W - Week number of the current year,
273
+ - %W - Week number of the current year,
272
274
  starting with the first Monday as the first
273
275
  day of the first week (00..53)
274
- %w - Day of the week (Sunday is 0, 0..6)
275
- %x - Preferred representation for the date alone, no time
276
- %X - Preferred representation for the time alone, no date
277
- %y - Year without a century (00..99)
278
- %Y - Year with century
279
- %Z - Time zone (ISO 8601 formatted)
280
- %% - Literal ``%'' character
276
+ - %w - Day of the week (Sunday is 0, 0..6)
277
+ - %x - Preferred representation for the date alone, no time
278
+ - %X - Preferred representation for the time alone, no date
279
+ - %y - Year without a century (00..99)
280
+ - %Y - Year with century
281
+ - %Z - Time zone (ISO 8601 formatted)
282
+ - %% - Literal ``%'' character
281
283
 
282
284
  @param {String} format the format string
283
285
  @return {String} the formatted string
@@ -783,7 +785,11 @@ SC.DateTime.mixin(SC.Comparable,
783
785
  case 'B': return this.monthNames[this._get('month')-1];
784
786
  case 'c': return this._date.toString();
785
787
  case 'd': return this._pad(this._get('day'));
788
+ case 'h': return this._get('hour');
786
789
  case 'H': return this._pad(this._get('hour'));
790
+ case 'i':
791
+ var hour = this._get('hour');
792
+ return (hour === 12 || hour === 0) ? 12 : (hour + 12) % 12;
787
793
  case 'I':
788
794
  var hour = this._get('hour');
789
795
  return this._pad((hour === 12 || hour === 0) ? 12 : (hour + 12) % 12);
@@ -897,7 +903,7 @@ if (SC.RecordAttribute && !SC.RecordAttribute.transforms[SC.guidFor(SC.DateTime)
897
903
  Convert a String to a DateTime
898
904
  */
899
905
  to: function(str, attr) {
900
- if (SC.none(str)) return str;
906
+ if (SC.none(str) || SC.instanceOf(str, SC.DateTime)) return str;
901
907
  var format = attr.get('format');
902
908
  return SC.DateTime.parse(str, format ? format : SC.DateTime.recordFormat);
903
909
  },
@@ -184,12 +184,12 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
184
184
  this.add(e, eventType, target, method, context);
185
185
  }, this);
186
186
  return this;
187
- } else elem = elem.get(0);
187
+ } else elem = elem[0];
188
188
  }
189
189
  if (!elem) return this; // nothing to do
190
190
 
191
191
  // cannot register events on text nodes, etc.
192
- if ( elem.nodeType == 3 || elem.nodeType == 8 ) return SC.Event;
192
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) return SC.Event;
193
193
 
194
194
  // For whatever reason, IE has trouble passing the window object
195
195
  // around, causing it to be cloned in the process
@@ -260,12 +260,12 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
260
260
  this.remove(e, eventType, target, method);
261
261
  }, this);
262
262
  return this;
263
- } else elem = elem.get(0);
263
+ } else elem = elem[0];
264
264
  }
265
265
  if (!elem) return this; // nothing to do
266
266
 
267
267
  // don't do events on text and comment nodes
268
- if ( elem.nodeType == 3 || elem.nodeType == 8 ) return SC.Event;
268
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) return SC.Event;
269
269
 
270
270
  // For whatever reason, IE has trouble passing the window object
271
271
  // around, causing it to be cloned in the process
@@ -389,18 +389,18 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
389
389
  this.trigger(e, eventType, args, donative);
390
390
  }, this);
391
391
  return this;
392
- } else elem = elem.get(0);
392
+ } else elem = elem[0];
393
393
  }
394
394
  if (!elem) return this; // nothing to do
395
395
 
396
396
  // don't do events on text and comment nodes
397
- if ( elem.nodeType == 3 || elem.nodeType == 8 ) return undefined;
397
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) return undefined;
398
398
 
399
399
  // Normalize to an array
400
400
  args = SC.A(args) ;
401
401
 
402
402
  var ret, fn = SC.typeOf(elem[eventType] || null) === SC.T_FUNCTION ,
403
- event, current, onfoo;
403
+ event, current, onfoo, isClick;
404
404
 
405
405
  // Get the event to pass, creating a fake one if necessary
406
406
  event = args[0];
@@ -690,7 +690,7 @@ SC.mixin(SC.Event, /** @scope SC.Event */ {
690
690
 
691
691
  /** @private Take an incoming event and convert it to a normalized event. */
692
692
  normalizeEvent: function(event) {
693
- if (event == window.event) {
693
+ if (event === window.event) {
694
694
  // IE can't do event.normalized on an Event object
695
695
  return SC.Event.create(event) ;
696
696
  } else {
@@ -768,8 +768,16 @@ SC.Event.prototype = {
768
768
  normalized: YES,
769
769
 
770
770
  /** Returns the pressed character (found in this.which) as a string. */
771
- getCharString: function() {
772
- return (this.charCode>0) ? String.fromCharCode(this.which) : null;
771
+ getCharString: function() {
772
+ if(SC.browser.msie){
773
+ if(this.keyCode == 8 || this.keyCode == 9 || (this.keyCode>=37 && this.keyCode<=40)){
774
+ return String.fromCharCode(0);
775
+ }else{
776
+ return (this.keyCode>0) ? String.fromCharCode(this.keyCode) : null;
777
+ }
778
+ }else{
779
+ return (this.charCode>0) ? String.fromCharCode(this.charCode) : null;
780
+ }
773
781
  },
774
782
 
775
783
  /** Returns character codes for the event. The first value is the normalized code string, with any shift or ctrl characters added to the begining. The second value is the char string by itself.
@@ -41,7 +41,7 @@ SC.Page = SC.Object.extend(
41
41
  this[key] = value = value.create({ page: this }) ;
42
42
  if (!this.get('inDesignMode')) value.awake() ;
43
43
  return value ;
44
- } else return sc_super() ;
44
+ } else return sc_super();
45
45
  },
46
46
 
47
47
  /**
@@ -54,9 +54,10 @@ SC.Page = SC.Object.extend(
54
54
  */
55
55
  awake: function() {
56
56
  // step through all views and build them
57
- for(var key in this) {
57
+ var value, key;
58
+ for(key in this) {
58
59
  if (!this.hasOwnProperty(key)) continue ;
59
- var value = this[key] ;
60
+ value = this[key] ;
60
61
  if (value && value.isViewClass) {
61
62
  this[key] = value = value.create({ page: this }) ;
62
63
  }
@@ -78,9 +79,10 @@ SC.Page = SC.Object.extend(
78
79
  Applies a localization to every view builder defined on the page. You must call this before you construct a view to apply the localization.
79
80
  */
80
81
  loc: function(locs) {
81
- for(var key in locs) {
82
+ var view, key;
83
+ for(key in locs) {
82
84
  if (!locs.hasOwnProperty(key)) continue ;
83
- var view = this[key] ;
85
+ view = this[key] ;
84
86
  if (!view || !view.isViewClass) continue ;
85
87
  view.loc(locs[key]);
86
88
  }
@@ -92,6 +92,7 @@ SC.mixin({
92
92
  // Only call once
93
93
  if (SC.isReady) return ;
94
94
  if (typeof SC.mapDisplayNames === SC.T_FUNCTION) SC.mapDisplayNames();
95
+ if (typeof SC.addInvokeOnceLastDebuggingInfo === SC.T_FUNCTION) SC.addInvokeOnceLastDebuggingInfo();
95
96
 
96
97
  // setup locale
97
98
  SC.Locale.createCurrentLocale();
@@ -297,6 +297,8 @@ SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
297
297
  var elem = this._elem,
298
298
  mode = this.updateMode,
299
299
  key, value, styles, factory, cur, next, before;
300
+
301
+ this._innerHTMLReplaced = NO;
300
302
 
301
303
  if (!elem) {
302
304
  // throw "Cannot update context because there is no source element";
@@ -309,6 +311,7 @@ SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
309
311
 
310
312
  // replace innerHTML
311
313
  if (this.length>0) {
314
+ this._innerHTMLReplaced = YES;
312
315
  if (mode === SC.MODE_REPLACE) {
313
316
  elem.innerHTML = this.join();
314
317
  } else {
@@ -398,9 +401,9 @@ SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
398
401
  // generate opening tag.
399
402
 
400
403
  // get attributes first. Copy in className + styles...
401
- var tag = this._TAG_ARRAY, pair, joined, key ;
402
- var attrs = this._attrs, className = this._classNames ;
403
- var id = this._id, styles = this._styles;
404
+ var tag = this._TAG_ARRAY, pair, joined, key ,
405
+ attrs = this._attrs, className = this._classNames,
406
+ id = this._id, styles = this._styles;
404
407
 
405
408
  // add tag to tag array
406
409
  tag[0] = '<'; tag[1] = this._tagName ;
@@ -422,7 +425,7 @@ SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
422
425
  pair[1] = styles[key];
423
426
  if (pair[1] === null) continue; // skip empty styles
424
427
 
425
- if(typeof pair[1] === SC.T_NUMBER) pair[1] = "%@px".fmt(pair[1]);
428
+ if(typeof pair[1] === SC.T_NUMBER) pair[1] = pair[1]+"px";
426
429
  joined.push(pair.join(': '));
427
430
  }
428
431
  attrs.style = joined.join('; ') ;
@@ -482,7 +485,7 @@ SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
482
485
  },
483
486
 
484
487
  /**
485
- Generates a with the passed options. Like calling context.begin().end().
488
+ Generates a tag with the passed options. Like calling context.begin().end().
486
489
 
487
490
  @param {String} tagName optional tag name. default 'div'
488
491
  @param {Hash} opts optional tag options. defaults to empty options.
@@ -695,7 +698,7 @@ SC.RenderContext = SC.Builder.create(/** SC.RenderContext.fn */ {
695
698
  // CSS Styles Support
696
699
  //
697
700
 
698
- _STYLE_REGEX: /\s*([^:\s]+)\s*:\s*([^;\s]+)\s*;?/g,
701
+ _STYLE_REGEX: /\s*([^:\s]+)\s*:\s*([^;]+)\s*;?/g,
699
702
 
700
703
  /**
701
704
  Retrieves or sets the current styles for the outer tag. If you retrieve
@@ -13,7 +13,7 @@ sc_require('system/response');
13
13
  Implements support for Ajax requests using XHR, JSON-P and other prototcols.
14
14
 
15
15
  SC.Request is much like an inverted version of the request/response objects
16
- you receive when implement HTTP servers.
16
+ you receive when implementing HTTP servers.
17
17
 
18
18
  To send a request, you just need to create your request object, configure
19
19
  your options, and call send() to initiate the request.
@@ -101,6 +101,21 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
101
101
  */
102
102
  type: 'GET',
103
103
 
104
+ /**
105
+ An optional timeout value of the request, in milliseconds. The timer
106
+ begins when SC.Response#fire is actually invoked by the request manager
107
+ and not necessarily when SC.Request#send is invoked. If this timeout is
108
+ reached before a response is received, the equivalent of
109
+ SC.Request.manager#cancel() will be invoked on the SC.Response instance
110
+ and the didTimeout() callback will be called.
111
+
112
+ An exception will be thrown if you try to invoke send() on a request that
113
+ has both a timeout and isAsyncronous set to NO.
114
+
115
+ @property {Number}
116
+ */
117
+ timeout: null,
118
+
104
119
  /**
105
120
  The body of the request. May be an object is isJSON or isXML is set,
106
121
  otherwise should be a string.
@@ -149,9 +164,9 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
149
164
 
150
165
  /**
151
166
  Invoked when a response has been received but not yet processed. This is
152
- your chance to fixup the response based on the results. If you don't want
153
- to continue processing the response call response.cancel().
154
-
167
+ your chance to fix up the response based on the results. If you don't
168
+ want to continue processing the response call response.cancel().
169
+
155
170
  @param {SC.Response} response the response
156
171
  @returns {void}
157
172
  */
@@ -168,11 +183,21 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
168
183
  */
169
184
  didReceive: function(request, response) {},
170
185
 
186
+ /**
187
+ Invoked when a request times out before a response has been received, as
188
+ determined by the 'timeout' property. Note that if a request times out,
189
+ neither willReceive() nor didReceive() will be called.
190
+
191
+ @param {SC.Response} response the response
192
+ @returns {void}
193
+ */
194
+ didTimeout: function(request, response) {},
195
+
171
196
  // ..........................................................
172
197
  // HELPER METHODS
173
198
  //
174
199
 
175
- COPY_KEYS: 'isAsynchronous isJSON isXML address type body responseClass willSend didSend willReceive didReceive'.w(),
200
+ COPY_KEYS: 'isAsynchronous isJSON isXML address type timeout body responseClass willSend didSend willReceive didReceive'.w(),
176
201
 
177
202
  /**
178
203
  Returns a copy of the current request. This will only copy certain
@@ -291,6 +316,16 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
291
316
  @returns {SC.Response} new response object
292
317
  */
293
318
  send: function(body) {
319
+ // Sanity-check: Be sure a timeout value was not specified if the request
320
+ // is synchronous (because it wouldn't work).
321
+ var timeout = this.get('timeout');
322
+ if (timeout) {
323
+ if (!this.get('isAsynchronous')) throw "Timeout values cannot be used with synchronous requests";
324
+ }
325
+ else if (timeout === 0) {
326
+ throw "The timeout value must either not be specified or must be greater than 0";
327
+ }
328
+
294
329
  if (body) this.set('body', body);
295
330
  return SC.Request.manager.sendRequest(this.copy()._prep());
296
331
  },
@@ -343,7 +378,7 @@ SC.Request = SC.Object.extend(SC.Copyable, SC.Freezable,
343
378
  notify: function(status, target, action, params) {
344
379
 
345
380
  // normalize status
346
- var hasStatus = YES, params ;
381
+ var hasStatus = YES ;
347
382
  if (SC.typeOf(status) !== SC.T_NUMBER) {
348
383
  params = SC.A(arguments).slice(2);
349
384
  action = target;
@@ -173,6 +173,18 @@ SC.Response = SC.Object.extend(
173
173
  */
174
174
  isCancelled: NO,
175
175
 
176
+ /**
177
+ Set to YES if the request timed out. Set to NO if the request has
178
+ completed before the timeout value. Set to null if the timeout timer is
179
+ still ticking.
180
+ */
181
+ timedOut: null,
182
+
183
+ /**
184
+ The timer tracking the timeout
185
+ */
186
+ timeoutTimer: null,
187
+
176
188
  // ..........................................................
177
189
  // METHODS
178
190
  //
@@ -183,7 +195,6 @@ SC.Response = SC.Object.extend(
183
195
  begin the actual request.
184
196
  */
185
197
  fire: function() {
186
-
187
198
  var req = this.get('request'),
188
199
  source = req ? req.get('source') : null;
189
200
 
@@ -198,6 +209,20 @@ SC.Response = SC.Object.extend(
198
209
  // immediately if it is synchronous.
199
210
  if (!this.get('isCancelled')) this.invokeTransport();
200
211
 
212
+
213
+ // If the request specified a timeout value, then set a timer for it now.
214
+ var timeout = req.get('timeout');
215
+ if (timeout) {
216
+ var timer = SC.Timer.schedule({
217
+ target: this,
218
+ action: 'timeoutReached',
219
+ interval: timeout,
220
+ repeats: NO
221
+ });
222
+ this.set('timeoutTimer', timer);
223
+ }
224
+
225
+
201
226
  // if the transport did not cancel the request for some reason, let the
202
227
  // source know that the request was sent
203
228
  if (!this.get('isCancelled') && source && source.didSend) {
@@ -210,9 +235,9 @@ SC.Response = SC.Object.extend(
210
235
  },
211
236
 
212
237
  /**
213
- Invoked by the transport when it receives a response. The passed
238
+ Invoked by the transport when it receives a response. The passed-in
214
239
  callback will be invoked to actually process the response. If cancelled
215
- we will pass NO. You sould cleanup instead.
240
+ we will pass NO. You should clean up instead.
216
241
 
217
242
  Invokes callbacks on the source request also.
218
243
 
@@ -221,25 +246,33 @@ SC.Response = SC.Object.extend(
221
246
  @returns {SC.Response} receiver
222
247
  */
223
248
  receive: function(callback, context) {
224
- var req = this.get('request');
225
- var source = req ? req.get('source') : null;
226
-
227
- // invoke the source, giving a chance to fixup the reponse or (more
228
- // likely) cancel the request.
229
- if (source && source.willReceive) source.willReceive(req, this);
230
-
231
- // invoke the callback. note if the response was cancelled or not
232
- callback.call(context, !this.get('isCancelled'));
233
-
234
- // if we weren't cancelled, then give the source first crack at handling
235
- // the response. if the source doesn't want listeners to be notified,
236
- // it will cancel the response.
237
- if (!this.get('isCancelled') && source && source.didReceive) {
238
- source.didReceive(req, this);
239
- }
249
+ // If we timed out, we should ignore this response.
250
+ if (!this.get('timedOut')) {
251
+ // If we had a timeout timer scheduled, invalidate it now.
252
+ var timer = this.get('timeoutTimer');
253
+ if (timer) timer.invalidate();
254
+ this.set('timedOut', NO);
255
+
256
+ var req = this.get('request');
257
+ var source = req ? req.get('source') : null;
258
+
259
+ // invoke the source, giving a chance to fixup the reponse or (more
260
+ // likely) cancel the request.
261
+ if (source && source.willReceive) source.willReceive(req, this);
262
+
263
+ // invoke the callback. note if the response was cancelled or not
264
+ callback.call(context, !this.get('isCancelled'));
265
+
266
+ // if we weren't cancelled, then give the source first crack at handling
267
+ // the response. if the source doesn't want listeners to be notified,
268
+ // it will cancel the response.
269
+ if (!this.get('isCancelled') && source && source.didReceive) {
270
+ source.didReceive(req, this);
271
+ }
240
272
 
241
- // notify listeners if we weren't cancelled.
242
- if (!this.get('isCancelled')) this.notify();
273
+ // notify listeners if we weren't cancelled.
274
+ if (!this.get('isCancelled')) this.notify();
275
+ }
243
276
 
244
277
  // no matter what, remove from inflight queue
245
278
  SC.Request.manager.transportDidClose(this) ;
@@ -252,12 +285,38 @@ SC.Response = SC.Object.extend(
252
285
  */
253
286
  cancel: function() {
254
287
  if (!this.get('isCancelled')) {
255
- this.set('isCancelled', YES);
256
- this.cancelTransport();
288
+ this.set('isCancelled', YES) ;
289
+ this.cancelTransport() ;
257
290
  SC.Request.manager.transportDidClose(this) ;
258
291
  }
259
292
  },
260
293
 
294
+ /**
295
+ Default method just closes the connection.
296
+ */
297
+ timeoutReached: function() {
298
+ // If we already received a response yet the timer still fired for some
299
+ // reason, do nothing.
300
+ if (this.get('timedOut') === null) {
301
+ this.set('timedOut', YES);
302
+ this.cancelTransport();
303
+ SC.Request.manager.transportDidClose(this);
304
+
305
+ // Set our value to an error.
306
+ var error = SC.$error("HTTP Request timed out", "Request", 408) ;
307
+ error.set("errorValue", this) ;
308
+ this.set('isError', YES);
309
+ this.set('errorObject', error);
310
+
311
+ // Invoke the didTimeout callback.
312
+ var req = this.get('request');
313
+ var source = req ? req.get('source') : null;
314
+ if (!this.get('isCancelled') && source && source.didTimeout) {
315
+ source.didTimeout(req, this);
316
+ }
317
+ }
318
+ },
319
+
261
320
  /**
262
321
  Override with concrete implementation to actually cancel the transport.
263
322
  */
@@ -453,7 +512,13 @@ SC.XHRResponse = SC.Response.extend({
453
512
 
454
513
  // if there was an error - setup error and save it
455
514
  if ((status < 200) || (status >= 300)) {
456
- msg = rawRequest.statusText;
515
+
516
+ try {
517
+ msg = rawRequest.statusText || '';
518
+ } catch(e2) {
519
+ msg = '';
520
+ }
521
+
457
522
  error = SC.$error(msg || "HTTP Request failed", "Request", status) ;
458
523
  error.set("errorValue", this) ;
459
524
  this.set('isError', YES);