sproutcore 1.0.1009 → 1.0.1024

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.
Files changed (64) hide show
  1. data/DISTRIBUTION.yml +14 -0
  2. data/Rakefile +150 -23
  3. data/VERSION.yml +4 -2
  4. data/frameworks/sproutcore/Buildfile +1 -1
  5. data/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +1 -0
  6. data/frameworks/sproutcore/frameworks/datastore/models/record.js +66 -5
  7. data/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +14 -0
  8. data/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +28 -3
  9. data/frameworks/sproutcore/frameworks/desktop/english.lproj/alert.css +1 -1
  10. data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu_item_view.css +22 -2
  11. data/frameworks/sproutcore/frameworks/desktop/english.lproj/panel.css +5 -1
  12. data/frameworks/sproutcore/frameworks/desktop/english.lproj/well.css +72 -0
  13. data/frameworks/sproutcore/frameworks/desktop/panes/alert.js +1 -1
  14. data/frameworks/sproutcore/frameworks/desktop/panes/picker.js +1 -1
  15. data/frameworks/sproutcore/frameworks/desktop/panes/select_button.js +33 -7
  16. data/frameworks/sproutcore/frameworks/desktop/system/root_responder.js +24 -23
  17. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_alternatingrows.js +130 -0
  18. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_row_heights.js +9 -10
  19. data/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +4 -0
  20. data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +18 -9
  21. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/methods.js +7 -6
  22. data/frameworks/sproutcore/frameworks/desktop/tests/views/well/ui.js +54 -0
  23. data/frameworks/sproutcore/frameworks/desktop/views/button.js +21 -9
  24. data/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +4 -3
  25. data/frameworks/sproutcore/frameworks/desktop/views/collection.js +1 -1
  26. data/frameworks/sproutcore/frameworks/desktop/views/grid.js +23 -14
  27. data/frameworks/sproutcore/frameworks/desktop/views/list_item.js +2 -2
  28. data/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +3 -3
  29. data/frameworks/sproutcore/frameworks/desktop/views/radio.js +1 -2
  30. data/frameworks/sproutcore/frameworks/desktop/views/scroll.js +1 -1
  31. data/frameworks/sproutcore/frameworks/desktop/views/segmented.js +1 -1
  32. data/frameworks/sproutcore/frameworks/desktop/views/slider.js +1 -1
  33. data/frameworks/sproutcore/frameworks/desktop/views/source_list_group.js +1 -1
  34. data/frameworks/sproutcore/frameworks/desktop/views/well.js +80 -0
  35. data/frameworks/sproutcore/frameworks/foundation/fixtures/malformed.json +11 -0
  36. data/frameworks/sproutcore/frameworks/foundation/mixins/button.js +1 -1
  37. data/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +5 -1
  38. data/frameworks/sproutcore/frameworks/foundation/panes/pane.js +1 -1
  39. data/frameworks/sproutcore/frameworks/foundation/system/cursor.js +11 -10
  40. data/frameworks/sproutcore/frameworks/foundation/system/event.js +16 -15
  41. data/frameworks/sproutcore/frameworks/foundation/system/render_context.js +3 -3
  42. data/frameworks/sproutcore/frameworks/foundation/system/request.js +6 -5
  43. data/frameworks/sproutcore/frameworks/foundation/system/response.js +26 -8
  44. data/frameworks/sproutcore/frameworks/foundation/system/root_responder.js +2 -2
  45. data/frameworks/sproutcore/frameworks/foundation/system/timer.js +2 -2
  46. data/frameworks/sproutcore/frameworks/foundation/system/utils.js +122 -13
  47. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_core.js +2 -3
  48. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/tag.js +9 -9
  49. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/update.js +3 -3
  50. data/frameworks/sproutcore/frameworks/foundation/tests/system/request.js +27 -0
  51. data/frameworks/sproutcore/frameworks/foundation/tests/system/utils/rect.js +99 -0
  52. data/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +1 -1
  53. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayer.js +1 -1
  54. data/frameworks/sproutcore/frameworks/foundation/views/image.js +3 -1
  55. data/frameworks/sproutcore/frameworks/foundation/views/label.js +1 -1
  56. data/frameworks/sproutcore/frameworks/runtime/system/cookie.js +160 -0
  57. data/frameworks/sproutcore/frameworks/runtime/system/object.js +1 -1
  58. data/frameworks/sproutcore/frameworks/runtime/tests/system/cookie.js +163 -0
  59. data/frameworks/sproutcore/themes/standard_theme/english.lproj/pane.css +12 -2
  60. data/lib/sproutcore/rack/proxy.rb +4 -2
  61. data/sproutcore-abbot.gemspec +23 -9
  62. metadata +32 -5
  63. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/000000.png +0 -0
  64. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/ffffff.png +0 -0
@@ -113,7 +113,9 @@ SC.Response = SC.Object.extend(
113
113
  }.property('request').cacheable(),
114
114
 
115
115
  /**
116
- The response status code.
116
+ The response status code.
117
+
118
+ @property {Number}
117
119
  */
118
120
  status: -100, // READY
119
121
 
@@ -133,14 +135,24 @@ SC.Response = SC.Object.extend(
133
135
  encodedBody: null,
134
136
 
135
137
  /**
136
- Response body. If isJSON was set, will be parsed automatically.
138
+ Response body. If isJSON was set, will be parsed automatically.
137
139
 
138
- @property {Hash|String}
140
+ @response {Hash|String|SC.Error} the response body or the parsed JSON.
141
+ Returns a SC.Error instance if there is a JSON parsing error.
139
142
  */
140
143
  body: function() {
141
144
  // TODO: support XML
142
145
  var ret = this.get('encodedBody');
143
- if (ret && this.get('isJSON')) ret = SC.json.decode(ret);
146
+ if (ret && this.get('isJSON')) {
147
+ try {
148
+ ret = SC.json.decode(ret);
149
+ } catch(e) {
150
+ return SC.Error.create({
151
+ message: e.name + ': ' + e.message,
152
+ label: 'Response',
153
+ errorValue: this });
154
+ }
155
+ }
144
156
  return ret;
145
157
  }.property('encodedBody').cacheable(),
146
158
 
@@ -251,6 +263,10 @@ SC.Response = SC.Object.extend(
251
263
  */
252
264
  cancelTransport: function() {},
253
265
 
266
+
267
+ /** @private
268
+ Will notify each listener.
269
+ */
254
270
  _notifyListener: function(listeners, status) {
255
271
  var info = listeners[status], params, target, action;
256
272
  if (!info) return NO ;
@@ -287,6 +303,9 @@ SC.Response = SC.Object.extend(
287
303
  return this ;
288
304
  },
289
305
 
306
+ /**
307
+ String representation of the response object
308
+ */
290
309
  toString: function() {
291
310
  var ret = sc_super();
292
311
  return "%@<%@ %@, status=%@".fmt(ret, this.get('type'), this.get('address'), this.get('status'));
@@ -385,7 +404,7 @@ SC.XHRResponse = SC.Response.extend({
385
404
  handleReadyStateChange = function() {
386
405
  if (!transport) return null ;
387
406
  var ret = transport.finishRequest();
388
- transport = null ; // cleanup memory
407
+ if (ret) transport = null ; // cleanup memory
389
408
  return ret ;
390
409
  };
391
410
  rawRequest.onreadystatechange = handleReadyStateChange;
@@ -445,12 +464,11 @@ SC.XHRResponse = SC.Response.extend({
445
464
  this.set('status', status);
446
465
 
447
466
  }, this);
448
- }
449
-
450
- if (readyState === 4) {
451
467
  // avoid memory leak in MSIE: clean up
452
468
  rawRequest.onreadystatechange = function() {} ;
469
+ return YES;
453
470
  }
471
+ return NO;
454
472
  }
455
473
 
456
474
 
@@ -149,7 +149,7 @@ SC.RootResponder = SC.Object.extend({
149
149
  // the top of the stack and make the specified pane the new keyPane.
150
150
  // First, though, do a sanity-check to make sure it's not already the
151
151
  // key pane, in which case we have nothing to do.
152
- var previousKeyPane = this.get('keyPane') ;
152
+ previousKeyPane = this.get('keyPane') ;
153
153
  if (previousKeyPane === pane) {
154
154
  return this ;
155
155
  }
@@ -172,7 +172,7 @@ SC.RootResponder = SC.Object.extend({
172
172
  previousKeyPane = this.get('keyPane') ;
173
173
  previousKeyPanes = this.get('previousKeyPanes') ;
174
174
 
175
- var newKeyPane = null ;
175
+ newKeyPane = null ;
176
176
  while (previousKeyPanes.length > 0) {
177
177
  var candidate = previousKeyPanes.pop();
178
178
  if (candidate.get('isPaneAttached') && candidate.get('acceptsKeyPane')) {
@@ -150,7 +150,7 @@ SC.Timer = SC.Object.extend(
150
150
 
151
151
  @property {Boolean}
152
152
  */
153
- isPooled: YES,
153
+ isPooled: NO,
154
154
 
155
155
  /**
156
156
  The time interval in milliseconds.
@@ -408,7 +408,7 @@ SC.Timer = SC.Object.extend(
408
408
  /** @private - Default values to reset reused timers to. */
409
409
  RESET_DEFAULTS: {
410
410
  target: null, action: null,
411
- isPooled: YES, isPaused: NO, isScheduled: NO, isValid: YES,
411
+ isPooled: NO, isPaused: NO, isScheduled: NO, isValid: YES,
412
412
  interval: 0, repeats: NO, until: null,
413
413
  startTime: null, lastFireTime: 0
414
414
  },
@@ -12,6 +12,12 @@ SC.mixin( /** @scope SC */ {
12
12
 
13
13
  _downloadFrames: 0, // count of download frames inserted into document
14
14
 
15
+ _copy_computed_props: [
16
+ "maxWidth", "maxHeight", "paddingLeft", "paddingRight", "paddingTop", "paddingBottom",
17
+ "fontFamily", "fontSize", "fontStyle", "fontWeight", "fontVariant", "lineHeight",
18
+ "whiteSpace"
19
+ ],
20
+
15
21
  /**
16
22
  Starts a download of the file at the named path.
17
23
 
@@ -132,13 +138,13 @@ SC.mixin( /** @scope SC */ {
132
138
  */
133
139
  rectsEqual: function(r1, r2, delta) {
134
140
  if (!r1 || !r2) return (r1 == r2) ;
135
-
136
- if (delta === null) delta = 0.1;
141
+
142
+ if (!delta && delta !== 0) delta = 0.1;
137
143
  if ((r1.y != r2.y) && (Math.abs(r1.y - r2.y) > delta)) return NO ;
138
144
  if ((r1.x != r2.x) && (Math.abs(r1.x - r2.x) > delta)) return NO ;
139
145
  if ((r1.width != r2.width) && (Math.abs(r1.width - r2.width) > delta)) return NO ;
140
146
  if ((r1.height != r2.height) && (Math.abs(r1.height - r2.height) > delta)) return NO ;
141
- return true ;
147
+ return YES ;
142
148
  },
143
149
 
144
150
  /** Returns the insersection between two rectangles.
@@ -269,19 +275,122 @@ SC.mixin( /** @scope SC */ {
269
275
  }
270
276
 
271
277
  style = '%@; width: %@px; left: %@px; position: absolute'.fmt(style, width, (-1*width));
272
- elem.setAttribute('style', style);
278
+ SC.$(elem).attr('style', style);
273
279
 
274
280
  if (classes !== '') {
275
- elem.setAttribute('class', classes);
281
+ SC.$(elem).attr('class', classes);
276
282
  }
277
283
 
278
- elem.textContent = str;
284
+ elem.innerHTML = str;
279
285
  height = elem.clientHeight;
280
286
 
281
287
  elem = null; // don't leak memory
282
288
  return height;
283
289
  },
284
290
 
291
+ /**
292
+ Given a string and an example element or style string, and an optional
293
+ set of class names, calculates the width and height of that block of text.
294
+
295
+ To constrain the width, set max-width on the exampleElement or in the style string.
296
+
297
+ @param string {String} The string to measure.
298
+ @param exampleElement The example element to grab styles from, or the style string to use.
299
+ @param classNames {String} (Optional) Class names to add to the test element.
300
+ */
301
+ metricsForString: function(string, exampleElement, classNames)
302
+ {
303
+ var element = this._metricsCalculationElement, width, height, classes, styles, style;
304
+
305
+ // collect the class names
306
+ classes = SC.A(classNames).join(' ');
307
+
308
+ // get the calculation element
309
+ if (!element) {
310
+ element = this._metricsCalculationElement = document.createElement("div");
311
+ document.body.insertBefore(element, null);
312
+ }
313
+
314
+ // two possibilities: example element or type string
315
+ if (SC.typeOf(exampleElement) != SC.T_STRING) {
316
+ var computed = null;
317
+ if (document.defaultView && document.defaultView.getComputedStyle) {
318
+ computed = document.defaultView.getComputedStyle(exampleElement, null);
319
+ } else {
320
+ computed = exampleElement.currentStyle;
321
+ }
322
+
323
+ // set (lovely cssText property here helps a lot—if it works. Unfortunately, only Safari supplies it.)
324
+ style = computed.cssText;
325
+
326
+ // if that didn't work (Safari-only?) go alternate route. This is SLOW code...
327
+ if (!style || style.trim() === "") {
328
+ // there is only one way to do it...
329
+ var props = this._copy_computed_props;
330
+
331
+ // firefox ONLY allows this method
332
+ for (var i = 0; i < props.length; i++) {
333
+ var prop = props[i], val = computed[prop];
334
+ element.style[prop] = val;
335
+ }
336
+
337
+ // and why does firefox specifically need "font" set?
338
+ var cs = element.style; // cached style
339
+ if (cs.font === "") {
340
+ var font = "";
341
+ if (cs.fontStyle) font += cs.fontStyle + " ";
342
+ if (cs.fontVariant) font += cs.fontVariant + " ";
343
+ if (cs.fontWeight) font += cs.fontWeight + " ";
344
+ if (cs.fontSize) font += cs.fontSize; else font += "10px"; //force a default
345
+ if (cs.lineHeight) font += "/" + cs.lineHeight;
346
+ font += " ";
347
+ if (cs.fontFamily) font += cs.fontFamily; else cs += "sans-serif";
348
+
349
+ element.style.font = font;
350
+ }
351
+
352
+ SC.mixin(element.style, {
353
+ left: "0px", top: "0px", position: "absolute", bottom: "auto", right: "auto", width: "auto", height: "auto"
354
+ });
355
+ }
356
+ else
357
+ {
358
+ // set style
359
+ element.setAttribute("style", style + "; position:absolute; left: 0px; top: 0px; bottom: auto; right: auto; width: auto; height: auto;");
360
+ }
361
+
362
+ // clean up
363
+ computed = null;
364
+ } else {
365
+ // it is a style string already
366
+ style = exampleElement;
367
+
368
+ // set style
369
+ element.setAttribute("style", style + "; position:absolute; left: 0px; top: 0px; bottom: auto; right: auto; width: auto; height: auto;");
370
+ }
371
+
372
+ // the conclusion of which to use (innerText or textContent) should be cached
373
+ if (typeof element.innerText != "undefined") element.innerText = string;
374
+ else element.textContent = string;
375
+
376
+ element.className = classes;
377
+
378
+ // measure
379
+ var result = {
380
+ width: element.clientWidth,
381
+ height: element.clientHeight
382
+ };
383
+
384
+ // clear element
385
+ element.innerHTML = "";
386
+ element.className = "";
387
+ element.setAttribute("style", ""); // get rid of any junk from computed style.
388
+
389
+ // clean up
390
+ element = null;
391
+ return result;
392
+ },
393
+
285
394
  /** Finds the absolute viewportOffset for a given element.
286
395
  This method is more accurate than the version provided by prototype.
287
396
 
@@ -378,8 +487,8 @@ SC.mixin( /** @scope SC */ {
378
487
  /** Returns the union of two ranges. If one range is null, the other
379
488
  range will be returned. */
380
489
  unionRanges: function(r1, r2) {
381
- if ((r1 === null) || (r1.length < 0)) return r2 ;
382
- if ((r2 === null) || (r2.length < 0)) return r1 ;
490
+ if ((r1 == null) || (r1.length < 0)) return r2 ;
491
+ if ((r2 == null) || (r2.length < 0)) return r1 ;
383
492
 
384
493
  var min = Math.min(r1.start, r2.start) ;
385
494
  var max = Math.max(SC.maxRange(r1), SC.maxRange(r2)) ;
@@ -388,7 +497,7 @@ SC.mixin( /** @scope SC */ {
388
497
 
389
498
  /** Returns the intersection of the two ranges or SC.RANGE_NOT_FOUND */
390
499
  intersectRanges: function(r1, r2) {
391
- if ((r1 === null) || (r2 === null)) return SC.RANGE_NOT_FOUND ;
500
+ if ((r1 == null) || (r2 == null)) return SC.RANGE_NOT_FOUND ;
392
501
  if ((r1.length < 0) || (r2.length < 0)) return SC.RANGE_NOT_FOUND;
393
502
  var min = Math.max(SC.minRange(r1), SC.minRange(r2)) ;
394
503
  var max = Math.min(SC.maxRange(r1), SC.maxRange(r2)) ;
@@ -398,7 +507,7 @@ SC.mixin( /** @scope SC */ {
398
507
 
399
508
  /** Returns the difference of the two ranges or SC.RANGE_NOT_FOUND */
400
509
  subtractRanges: function(r1, r2) {
401
- if ((r1 === null) || (r2 === null)) return SC.RANGE_NOT_FOUND ;
510
+ if ((r1 == null) || (r2 == null)) return SC.RANGE_NOT_FOUND ;
402
511
  if ((r1.length < 0) || (r2.length < 0)) return SC.RANGE_NOT_FOUND;
403
512
  var max = Math.max(SC.minRange(r1), SC.minRange(r2)) ;
404
513
  var min = Math.min(SC.maxRange(r1), SC.maxRange(r2)) ;
@@ -416,8 +525,8 @@ SC.mixin( /** @scope SC */ {
416
525
  */
417
526
  rangesEqual: function(r1, r2) {
418
527
  if (r1===r2) return true ;
419
- if (r1 === null) return r2.length < 0 ;
420
- if (r2 === null) return r1.length < 0 ;
528
+ if (r1 == null) return r2.length < 0 ;
529
+ if (r2 == null) return r1.length < 0 ;
421
530
  return (r1.start == r2.start) && (r1.length == r2.length) ;
422
531
  },
423
532
 
@@ -449,7 +558,7 @@ SC.mixin( /** @scope SC */ {
449
558
 
450
559
  var h = (max == min) ? 0 : ((max == rgb[0]) ? ((rgb[1]-rgb[2])/(max-min)/6) : ((max == rgb[1]) ? ((rgb[2]-rgb[0])/(max-min)/6+1/3) : ((rgb[0]-rgb[1])/(max-min)/6+2/3)));
451
560
  h = (h < 0) ? (h + 1) : ((h > 1) ? (h - 1) : h);
452
- var s = (max === 0) ? 0 : (1 - min/max);
561
+ var s = (max == 0) ? 0 : (1 - min/max);
453
562
  var v = max/255;
454
563
  return [h, s, v];
455
564
  },
@@ -213,7 +213,6 @@ div#show-tests * { display: none; }\
213
213
  <b id="floatTest">Float test.</b>\
214
214
  <iframe id="iframe" name="iframe"></iframe>\
215
215
  <form id="lengthtest">\
216
- <input type="text" id="length" name="test"/>\
217
216
  <input type="text" id="idTest" name="id"/>\
218
217
  </form>\
219
218
  <table id="table"></table>\
@@ -663,7 +662,7 @@ test("width()", function() {
663
662
  // IE is off by one on this. We don't really care at this point since ems
664
663
  // is not really central to most SC apps.
665
664
  $div.css("padding", "2em");
666
- var e = SC.browser.msie ? 29 : 30;
665
+ var e = SC.browser.msie==8 ? 29 : 30;
667
666
  equals($div.width(), e, "Test padding specified with ems");
668
667
 
669
668
  $div.css("border", "1em solid #fff");
@@ -697,7 +696,7 @@ test("height()", function() {
697
696
  // IE is off by one on this. We don't really care at this point since ems
698
697
  // is not really central to most SC apps.
699
698
  $div.css("padding", "2em");
700
- var e = SC.browser.msie ? 29 : 30;
699
+ var e = SC.browser.msie==8 ? 29 : 30;
701
700
  equals($div.height(), e, "Test padding specified with ems");
702
701
 
703
702
  $div.css("border", "1em solid #fff");
@@ -17,30 +17,30 @@ module("SC.RenderContext#tag", {
17
17
 
18
18
  test("should emit a self closing tag. like calling begin().end()", function() {
19
19
  context.tag("input");
20
- equals(context.get(1), "<input />");
20
+ equals(SC.RenderContext.escapeHTML(context.get(1)), SC.RenderContext.escapeHTML("<input />"));
21
21
  });
22
22
 
23
23
  test("should respect passed opts when emitting", function() {
24
24
  context.tag("foo") ;
25
25
  equals(context.length, 3);
26
- equals(context.get(1), "<foo>");
27
- equals(context.get(2), '<'+'/foo>');
26
+ equals(SC.RenderContext.escapeHTML(context.get(1)), SC.RenderContext.escapeHTML("<foo>"));
27
+ equals(SC.RenderContext.escapeHTML(context.get(2)), SC.RenderContext.escapeHTML('<'+'/foo>'));
28
28
  });
29
29
 
30
30
  test("should NOT emit self closing tag if tag is script", function() {
31
31
  context.tag("script");
32
- equals(context.get(1), '<script>');
33
- equals(context.get(2), '<'+'/script>');
32
+ equals(SC.RenderContext.escapeHTML(context.get(1)), SC.RenderContext.escapeHTML('<script>'));
33
+ equals(SC.RenderContext.escapeHTML(context.get(2)), SC.RenderContext.escapeHTML('<'+'/script>'));
34
34
  });
35
35
 
36
36
  test("should NOT emit self closing tag if tag is div", function() {
37
37
  context.tag("div");
38
- equals(context.get(1), '<div>');
39
- equals(context.get(2), '<'+'/div>');
38
+ equals(SC.RenderContext.escapeHTML(context.get(1)), SC.RenderContext.escapeHTML('<div>'));
39
+ equals(SC.RenderContext.escapeHTML(context.get(2)), SC.RenderContext.escapeHTML('<'+'/div>'));
40
40
  });
41
41
 
42
42
  test("should NOT emit self closing tag if no tag is passed", function() {
43
43
  context.tag();
44
- equals(context.get(1), '<div>');
45
- equals(context.get(2), '<'+'/div>');
44
+ equals(SC.RenderContext.escapeHTML(context.get(1)), SC.RenderContext.escapeHTML('<div>'));
45
+ equals(SC.RenderContext.escapeHTML(context.get(2)), SC.RenderContext.escapeHTML('<'+'/div>'));
46
46
  });
@@ -137,20 +137,20 @@ module("SC.RenderContext#update - className", {
137
137
  test("does not change class names if retrieved but not edited", function() {
138
138
  context.classNames();
139
139
  context.update();
140
- equals(elem.getAttribute("class"), "foo bar", "class");
140
+ equals(SC.$(elem).attr("class"), "foo bar", "class");
141
141
  });
142
142
 
143
143
  test("replaces class name if classNames edited", function() {
144
144
  context.classNames('bar baz'.w());
145
145
  context.update();
146
- equals(elem.getAttribute("class"), "bar baz", "attribute");
146
+ equals(SC.$(elem).attr("class"), "bar baz", "attribute");
147
147
  });
148
148
 
149
149
  test("set class names override class attr", function() {
150
150
  context.attr("class", "bar");
151
151
  context.classNames('baz'.w());
152
152
  context.update();
153
- equals(elem.getAttribute("class"), "baz", "should use classNames");
153
+ equals(SC.$(elem).attr("class"), "baz", "should use classNames");
154
154
  });
155
155
 
156
156
  // ..........................................................
@@ -83,6 +83,33 @@ test("Test Asynchronous GET Request, auto-deserializing JSON", function() {
83
83
 
84
84
  });
85
85
 
86
+ test("Test auto-deserializing malformed JSON", function() {
87
+ request = SC.Request.getUrl(sc_static('malformed.json')).set('isJSON', YES);
88
+
89
+ var timer = setTimeout(function() {
90
+ ok(false, 'response did not invoke notify()');
91
+ window.start();
92
+ }, 1000);
93
+
94
+ request.notify(this, function(response) {
95
+ ok(SC.ok(response), 'response should not be error');
96
+
97
+ try {
98
+ var body = response.get('body');
99
+ ok(!SC.ok(body), 'body should be an error');
100
+ } catch(e) {
101
+ ok(false, 'getting the body should not throw an exception');
102
+ }
103
+
104
+ clearTimeout(timer);
105
+ window.start();
106
+ });
107
+
108
+ request.send();
109
+
110
+ stop();
111
+ });
112
+
86
113
  test("Test Synchronous GET Request, auto-deserializing JSON", function() {
87
114
  request.set("isAsynchronous", false);
88
115
  request.set("isJSON", true);
@@ -0,0 +1,99 @@
1
+ // ========================================================================
2
+ // Rect utility Tests
3
+ // ========================================================================
4
+
5
+
6
+ module("Rect utilities");
7
+
8
+ test("Get the X & Y points of a rect", function() {
9
+ var frame = { x: 50, y: 40, width: 700, height: 9000 };
10
+ expect(6);
11
+ equals(SC.minX(frame),50,'Left edge');
12
+ equals(SC.maxX(frame),750,'Right edge');
13
+ equals(SC.midX(frame),400,'Horizontal midpoint');
14
+
15
+ equals(SC.minY(frame),40, 'Top edge');
16
+ equals(SC.maxY(frame),9040,'Bottom edge');
17
+ equals(SC.midY(frame),4540,'Vertical midpoint');
18
+ });
19
+
20
+ test("Treat empty object as frame with 0 width and height", function() {
21
+ var frame = { };
22
+ expect(6);
23
+ equals(SC.minX(frame),0,'Left edge');
24
+ equals(SC.maxX(frame),0,'Right edge');
25
+ equals(SC.midX(frame),0,'Horizontal midpoint');
26
+
27
+ equals(SC.minY(frame),0,'Top edge');
28
+ equals(SC.maxY(frame),0,'Bottom edge');
29
+ equals(SC.midY(frame),0,'Vertical midpoint');
30
+ });
31
+
32
+ test("pointInRect() to test if a given point is inside the rect", function(){
33
+ var frame = { x: 50, y: 40, width: 700, height: 9000 };
34
+
35
+ ok(SC.pointInRect({ x: 100, y: 100 }, frame), "Point in rect");
36
+ equals(NO, SC.pointInRect({ x: 40, y: 100 }, frame), "Point out of rect horizontally");
37
+ equals(NO, SC.pointInRect({ x: 600, y: 9100 }, frame), "Point out of rect vertically");
38
+ equals(NO, SC.pointInRect({ x: 0, y: 0 }, frame), "Point up and left from rect");
39
+ equals(NO, SC.pointInRect({ x: 800, y: 9500 }, frame), "Point down and right from rect");
40
+ });
41
+
42
+ test("rectsEqual() tests equality with default delta", function() {
43
+ var frame = { x: 50, y: 50, width: 100, height: 100 };
44
+
45
+ equals(SC.rectsEqual(frame, frame), YES, "Frames are same object");
46
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100 }), YES, "Frames have same position and dimensions");
47
+ equals(SC.rectsEqual(frame, { x: 50.08, y: 50, width: 100, height: 100 }), YES, "Frame.x above, within delta");
48
+ equals(SC.rectsEqual(frame, { x: 49.92, y: 50, width: 100, height: 100 }), YES, "Frame.x below, within delta");
49
+ equals(SC.rectsEqual(frame, { x: 50, y: 50.099, width: 100, height: 100 }), YES, "Frame.y within delta");
50
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100.001, height: 100 }), YES, "Frame.width within delta");
51
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100.09999 }), YES, "Frame.height within delta");
52
+ equals(SC.rectsEqual(frame, { x: 55, y: 50, width: 100, height: 100 }), NO, "Frame.x not equal");
53
+ equals(SC.rectsEqual(frame, { x: 50, y: 55, width: 100, height: 100 }), NO, "Frame.y not equal");
54
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 105, height: 100 }), NO, "Frame.width not equal");
55
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 105 }), NO, "Frame.height not equal");
56
+ });
57
+
58
+ test("rectsEqual() tests equality with null delta", function() {
59
+ var frame = { x: 50, y: 50, width: 100, height: 100 };
60
+
61
+ equals(SC.rectsEqual(frame, frame), YES, "Frames are same object");
62
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100 }, null), YES, "Frames have same position and dimensions");
63
+ equals(SC.rectsEqual(frame, { x: 50.08, y: 50, width: 100, height: 100 }, null), YES, "Frame.x above, within delta");
64
+ equals(SC.rectsEqual(frame, { x: 49.92, y: 50, width: 100, height: 100 }, null), YES, "Frame.x below, within delta");
65
+ equals(SC.rectsEqual(frame, { x: 50, y: 50.099, width: 100, height: 100 }, null), YES, "Frame.y within delta");
66
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100.001, height: 100 }, null), YES, "Frame.width within delta");
67
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100.01 }, null), YES, "Frame.height within delta");
68
+ equals(SC.rectsEqual(frame, { x: 55, y: 50, width: 100, height: 100 }, null), NO, "Frame.x not equal");
69
+ equals(SC.rectsEqual(frame, { x: 50, y: 55, width: 100, height: 100 }, null), NO, "Frame.y not equal");
70
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 105, height: 100 }, null), NO, "Frame.width not equal");
71
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 105 }, null), NO, "Frame.height not equal");
72
+ });
73
+
74
+ test("rectsEqual() tests equality with delta of 10", function() {
75
+ var frame = { x: 50, y: 50, width: 100, height: 100 };
76
+
77
+ equals(SC.rectsEqual(frame, frame), YES, "Frames are same object");
78
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100 }, 10), YES, "Frames have same position and dimensions");
79
+ equals(SC.rectsEqual(frame, { x: 59.99, y: 50, width: 100, height: 100 }, 10), YES, "Frame.x above, within delta");
80
+ equals(SC.rectsEqual(frame, { x: 41, y: 50, width: 100, height: 100 }, 10), YES, "Frame.x below, within delta");
81
+ equals(SC.rectsEqual(frame, { x: 50, y: 59, width: 100, height: 100 }, 10), YES, "Frame.y within delta");
82
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 109, height: 100 }, 10), YES, "Frame.width within delta");
83
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100.000002 }, 10), YES, "Frame.height within delta");
84
+ equals(SC.rectsEqual(frame, { x: 61, y: 50, width: 100, height: 100 }, 10), NO, "Frame.x not equal");
85
+ equals(SC.rectsEqual(frame, { x: 50, y: 92, width: 100, height: 100 }, 10), NO, "Frame.y not equal");
86
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 89, height: 100 }, 10), NO, "Frame.width not equal");
87
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 89.99999 }, 10), NO, "Frame.height not equal");
88
+ });
89
+
90
+ test("rectsEqual() tests equality with delta of 0", function() {
91
+ var frame = { x: 50, y: 50, width: 100, height: 100 };
92
+
93
+ equals(SC.rectsEqual(frame, frame), YES, "Frames are same object");
94
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 100 }, 0), YES, "Frames have same position and dimensions");
95
+ equals(SC.rectsEqual(frame, { x: 50.0001, y: 50, width: 100, height: 100 }, 0), NO, "Frame.x not equal");
96
+ equals(SC.rectsEqual(frame, { x: 50, y: 51, width: 100, height: 100 }, 0), NO, "Frame.y not equal");
97
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 99, height: 100 }, 0), NO, "Frame.width not equal");
98
+ equals(SC.rectsEqual(frame, { x: 50, y: 50, width: 100, height: 102 }, 0), NO, "Frame.height not equal");
99
+ });